我有一些代码可以生成饼图的图像。它是一个通用类,因此任何数量的切片都可以作为输入。现在我有问题为切片选择好的颜色。是否有一些擅长的算法?
或许我应该亲自挑选并列出固定颜色?但是有多少。也许有10种颜色,希望永远不会超过10片?还有哪10种颜色可供选择?
颜色需要遵循一些规则:
一些使用RGB值进行操作的算法将是首选解决方案。
答案 0 :(得分:67)
我解决了它如下:
baseHue
)。hue = baseHue + ((240 / pieces) * piece % 240
在C#中:
int n = 12;
Color baseColor = System.Drawing.ColorTranslator.FromHtml("#8A56E2");
double baseHue = (new HSLColor(baseColor)).Hue;
List<Color> colors = new List<Color>();
colors.Add(baseColor);
double step = (240.0 / (double)n);
for (int i = 1; i < n; ++i)
{
HSLColor nextColor = new HSLColor(baseColor);
nextColor.Hue = (baseHue + step * ((double)i)) % 240.0;
colors.Add((Color)nextColor);
}
string colors = string.Join(",", colors.Select(e => e.Name.Substring(2)).ToArray());
我使用了HSLColor class。
Google Charts example使用12件,基色为#8A56E2:
答案 1 :(得分:17)
我会预编译大约20种颜色的列表,然后开始用 2nd 颜色重复。这样你就不会破坏你的第二条规则。此外,如果有人制作超过20个切片的饼图,他们会遇到更大的问题。 :)
答案 2 :(得分:12)
查看Color Brewer,这是一个有助于定义着色方案以传达定性或定量信息的工具:地图,图表等。此工具可以生成的三种“调色板类型” - 顺序,定性和分歧 - 你可能需要后者,分歧......
您甚至可以下载所有调色板的RGB定义的Excel文件。
答案 3 :(得分:10)
在this solution的基础上解决问题的规则#2,以下算法在饼的中点周围交换颜色。这两个参数:
我使用 ColorHSL , ColorRGB 和 ColorUtils (下方提供)。
public static function ColorArrayGenerator(
pNbColors:int,
pNonAdjacentSimilarColor:Boolean = false):Array
{
var colors:Array = new Array();
var baseRGB:ColorRGB = new ColorRGB();
baseRGB.setRGBFromUint(0x8A56E2);
var baseHSL:ColorHSL = new ColorHSL();
rgbToHsl(baseHSL, baseRGB);
var currentHue:Number = baseHSL.Hue;
colors.push(baseRGB.getUintFromRGB());
var step:Number = (360.0 / pNbColors);
var nextHSL:ColorHSL;
var nextRGB:ColorRGB;
var i:int;
for (i = 1; i < pNbColors; i++)
{
currentHue += step;
if (currentHue > 360)
{
currentHue -= 360;
}
nextHSL = new ColorHSL(currentHue, baseHSL.Saturation, aseHSL.Luminance);
nextRGB = new ColorRGB();
hslToRgb(nextRGB, nextHSL);
colors.push(nextRGB.getUintFromRGB());
}
if (pNonAdjacentSimilarColor == true &&
pNbColors > 2)
{
var holder:uint = 0;
var j:int;
for (i = 0, j = pNbColors / 2; i < pNbColors / 2; i += 2, j += 2)
{
holder = colors[i];
colors[i] = colors[j];
colors[j] = holder;
}
}
return colors;
}
这会产生右侧输出:
ColorHSL类:
final public class ColorHSL
{
private var _hue:Number; // 0.0 .. 359.99999
private var _sat:Number; // 0.0 .. 100.0
private var _lum:Number; // 0.0 .. 100.0
public function ColorHSL(
hue:Number = 0,
sat:Number = 0,
lum:Number = 0)
{
_hue = hue;
_sat = sat;
_lum = lum;
}
[Bindable]public function get Hue():Number
{
return _hue;
}
public function set Hue(value:Number):void
{
if (value > 360)
{
_hue = value % 360;
} // remember, hue is modulo 360
else if (value < 0)
{
_hue = 0;
}
else
{
_hue = value;
}
}
[Bindable]public function get Saturation():Number
{
return _sat;
}
public function set Saturation(value:Number):void
{
if (value > 100.0)
{
_sat = 100.0;
}
else if (value < 0)
{
_sat = 0;
}
else
{
_sat = value;
}
}
[Bindable]public function get Luminance():Number
{
return _lum;
}
public function set Luminance(value:Number):void
{
if (value > 100.0)
{
_lum = 100.0;
}
else if (value < 0)
{
_lum = 0;
}
else
{
_lum = value;
}
}
}
ColorRGB类:
final public class ColorRGB
{
private var _red:uint;
private var _grn:uint;
private var _blu:uint;
private var _rgb:uint; // composite form: 0xRRGGBB or #RRGGBB
public function ColorRGB(red:uint = 0, grn:uint = 0, blu:uint = 0)
{
setRGB(red, grn, blu);
}
[Bindable]public function get red():uint
{
return _red;
}
public function set red(value:uint):void
{
_red = (value & 0xFF);
updateRGB();
}
[Bindable]public function get grn():uint
{
return _grn;
}
public function set grn(value:uint):void
{
_grn = (value & 0xFF);
updateRGB();
}
[Bindable]public function get blu():uint
{
return _blu;
}
public function set blu(value:uint):void
{
_blu = (value & 0xFF);
updateRGB();
}
[Bindable]public function get rgb():uint
{
return _rgb;
}
public function set rgb(value:uint):void
{
_rgb = value;
_red = (value >> 16) & 0xFF;
_grn = (value >> 8) & 0xFF;
_blu = value & 0xFF;
}
public function setRGB(red:uint, grn:uint, blu:uint):void
{
this.red = red;
this.grn = grn;
this.blu = blu;
}
public function setRGBFromUint(pValue:uint):void
{
setRGB((( pValue >> 16 ) & 0xFF ), ( (pValue >> 8) & 0xFF ), ( pValue & 0xFF ));
}
public function getUintFromRGB():uint
{
return ( ( red << 16 ) | ( grn << 8 ) | blu );
}
private function updateRGB():void
{
_rgb = (_red << 16) + (_grn << 8) + blu;
}
}
ColorUtils类:
final public class ColorUtils
{
public static function HSV2RGB(hue:Number, sat:Number, val:Number):uint
{
var red:Number = 0;
var grn:Number = 0;
var blu:Number = 0;
var i:Number;
var f:Number;
var p:Number;
var q:Number;
var t:Number;
hue%=360;
sat/=100;
val/=100;
hue/=60;
i = Math.floor(hue);
f = hue-i;
p = val*(1-sat);
q = val*(1-(sat*f));
t = val*(1-(sat*(1-f)));
if (i==0)
{
red=val;
grn=t;
blu=p;
}
else if (i==1)
{
red=q;
grn=val;
blu=p;
}
else if (i==2)
{
red=p;
grn=val;
blu=t;
}
else if (i==3)
{
red=p;
grn=q;
blu=val;
}
else if (i==4)
{
red=t;
grn=p;
blu=val;
}
else if (i==5)
{
red=val;
grn=p;
blu=q;
}
red = Math.floor(red*255);
grn = Math.floor(grn*255);
blu = Math.floor(blu*255);
return (red<<16) | (grn << 8) | (blu);
}
//
public static function RGB2HSV(pColor:uint):Object
{
var red:uint = (pColor >> 16) & 0xff;
var grn:uint = (pColor >> 8) & 0xff;
var blu:uint = pColor & 0xff;
var x:Number;
var val:Number;
var f:Number;
var i:Number;
var hue:Number;
var sat:Number;
red/=255;
grn/=255;
blu/=255;
x = Math.min(Math.min(red, grn), blu);
val = Math.max(Math.max(red, grn), blu);
if (x==val){
return({h:undefined, s:0, v:val*100});
}
f = (red == x) ? grn-blu : ((grn == x) ? blu-red : red-grn);
i = (red == x) ? 3 : ((grn == x) ? 5 : 1);
hue = Math.floor((i-f/(val-x))*60)%360;
sat = Math.floor(((val-x)/val)*100);
val = Math.floor(val*100);
return({h:hue, s:sat, v:val});
}
/**
* Generates an array of pNbColors colors (uint)
* The colors are generated to fill a pie chart (meaning that they circle back to the starting color)
* @param pNbColors The number of colors to generate (ex: Number of slices in the pie chart)
* @param pNonAdjacentSimilarColor Should the colors stay Adjacent or not ?
*/
public static function ColorArrayGenerator(
pNbColors:int,
pNonAdjacentSimilarColor:Boolean = false):Array
{
// Based on http://www.flexspectrum.com/?p=10
var colors:Array = [];
var baseRGB:ColorRGB = new ColorRGB();
baseRGB.setRGBFromUint(0x8A56E2);
var baseHSL:ColorHSL = new ColorHSL();
rgbToHsl(baseHSL, baseRGB);
var currentHue:Number = baseHSL.Hue;
colors.push(baseRGB.getUintFromRGB());
var step:Number = (360.0 / pNbColors);
var nextHSL:ColorHSL;
var nextRGB:ColorRGB;
var i:int;
for (i = 1; i < pNbColors; i++)
{
currentHue += step;
if (currentHue > 360)
{
currentHue -= 360;
}
nextHSL = new ColorHSL(currentHue, baseHSL.Saturation, baseHSL.Luminance);
nextRGB = new ColorRGB();
hslToRgb(nextRGB, nextHSL);
colors.push(nextRGB.getUintFromRGB());
}
if (pNonAdjacentSimilarColor == true &&
pNbColors > 2)
{
var holder:uint = 0;
var j:int;
for (i = 0, j = pNbColors / 2; i < pNbColors / 2; i += 2, j += 2)
{
holder = colors[i];
colors[i] = colors[j];
colors[j] = holder;
}
}
return colors;
}
static public function rgbToHsl(hsl:ColorHSL, rgb:ColorRGB):void
{
var h:Number = 0;
var s:Number = 0;
var l:Number = 0;
// Normalizes incoming RGB values.
//
var dRed:Number = (Number)(rgb.red / 255.0);
var dGrn:Number = (Number)(rgb.grn / 255.0);
var dBlu:Number = (Number)(rgb.blu / 255.0);
var dMax:Number = Math.max(dRed, Math.max(dGrn, dBlu));
var dMin:Number = Math.min(dRed, Math.min(dGrn, dBlu));
//-------------------------
// hue
//
if (dMax == dMin)
{
h = 0; // undefined
}
else if (dMax == dRed && dGrn >= dBlu)
{
h = 60.0 * (dGrn - dBlu) / (dMax - dMin);
}
else if (dMax == dRed && dGrn < dBlu)
{
h = 60.0 * (dGrn - dBlu) / (dMax - dMin) + 360.0;
}
else if (dMax == dGrn)
{
h = 60.0 * (dBlu - dRed) / (dMax-dMin) + 120.0;
}
else if (dMax == dBlu)
{
h = 60.0 * (dRed - dGrn) / (dMax - dMin) + 240.0;
}
//-------------------------
// luminance
//
l = (dMax + dMin) / 2.0;
//-------------------------
// saturation
//
if (l == 0 || dMax == dMin)
{
s = 0;
}
else if (0 < l && l <= 0.5)
{
s = (dMax - dMin) / (dMax + dMin);
}
else if (l>0.5)
{
s = (dMax - dMin) / (2 - (dMax + dMin)); //(dMax-dMin > 0)?
}
hsl.Hue = h;
hsl.Luminance = l;
hsl.Saturation = s;
} // rgbToHsl
//---------------------------------------
// Convert the input RGB values to the corresponding HSL values.
//
static public function hslToRgb(rgb:ColorRGB, hsl:ColorHSL):void
{
if (hsl.Saturation == 0)
{
// Achromatic color case, luminance only.
//
var lumScaled:int = (int)(hsl.Luminance * 255.0);
rgb.setRGB(lumScaled, lumScaled, lumScaled);
return;
}
// Chromatic case...
//
var dQ:Number = (hsl.Luminance < 0.5) ? (hsl.Luminance * (1.0 + hsl.Saturation)): ((hsl.Luminance + hsl.Saturation) - (hsl.Luminance * hsl.Saturation));
var dP:Number = (2.0 * hsl.Luminance) - dQ;
var dHueAng:Number = hsl.Hue / 360.0;
var dFactor:Number = 1.0 / 3.0;
var adT:Array = [];
adT[0] = dHueAng + dFactor; // Tr
adT[1] = dHueAng; // Tg
adT[2] = dHueAng - dFactor; // Tb
for (var i:int = 0; i < 3; i++)
{
if (adT[i] < 0)
{
adT[i] += 1.0;
}
if (adT[i] > 1)
{
adT[i] -= 1.0;
}
if ((adT[i] * 6) < 1)
{
adT[i] = dP + ((dQ - dP) * 6.0 * adT[i]);
}
else if ((adT[i] * 2.0) < 1) // (1.0 / 6.0) <= adT[i] && adT[i] < 0.5
{
adT[i] = dQ;
}
else if ((adT[i] * 3.0) < 2) // 0.5 <= adT[i] && adT[i] < (2.0 / 3.0)
{
adT[i] = dP + (dQ-dP) * ((2.0/3.0) - adT[i]) * 6.0;
}
else
{
adT[i] = dP;
}
}
rgb.setRGB(adT[0] * 255.0, adT[1] * 255.0, adT[2] * 255.0);
} // hslToRgb
//---------------------------------------
// Adjust the luminance value by the specified factor.
//
static public function adjustRgbLuminance(rgb:ColorRGB, factor:Number):void
{
var hsl:ColorHSL = new ColorHSL();
rgbToHsl(hsl, rgb);
hsl.Luminance *= factor;
if (hsl.Luminance < 0.0)
{
hsl.Luminance = 0.0;
}
if (hsl.Luminance > 1.0)
{
hsl.Luminance = 1.0;
}
hslToRgb(rgb, hsl);
}
//---------------------------------------
//
static public function uintTo2DigitHex(value:uint):String
{
var str:String = value.toString(16).toUpperCase();
if (1 == str.length)
{
str = "0" + str;
}
return str;
}
//---------------------------------------
//
static public function uintTo6DigitHex(value:uint):String
{
var str:String = value.toString(16).toUpperCase();
if (1 == str.length) {return "00000" + str;}
if (2 == str.length) {return "0000" + str;}
if (3 == str.length) {return "000" + str;}
if (4 == str.length) {return "00" + str;}
if (5 == str.length) {return "0" + str;}
return str;
}
}
答案 4 :(得分:5)
从RGB转换为HSV然后调整色调(如answered here)会产生不一致的感知亮度。黄色/绿色明显比蓝色/紫色浅:
没有这种变化的类似结果是可能的:
然而,该算法要复杂得多:
(360.0 div $wedges) * $wedge
以下是XSLT 1.0中的示例实现:
<?xml version="1.0"?>
<!--
| The MIT License
|
| Copyright 2014 White Magic Software, Inc.
|
| Permission is hereby granted, free of charge, to any person
| obtaining a copy of this software and associated documentation
| files (the "Software"), to deal in the Software without
| restriction, including without limitation the rights to use,
| copy, modify, merge, publish, distribute, sublicense, and/or
| sell copies of the Software, and to permit persons to whom the
| Software is furnished to do so, subject to the following
| conditions:
|
| The above copyright notice and this permission notice shall be
| included in all copies or substantial portions of the Software.
|
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
| EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
| OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
| NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
| HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
| WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
| FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
| OTHER DEALINGS IN THE SOFTWARE.
+-->
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<!-- Reference white (X, Y, and Z components) -->
<xsl:variable name="X_r" select="0.950456"/>
<xsl:variable name="Y_r" select="1.000000"/>
<xsl:variable name="Z_r" select="1.088754"/>
<xsl:variable name="LAB_EPSILON" select="216.0 div 24389.0"/>
<xsl:variable name="LAB_K" select="24389.0 div 27.0"/>
<!-- Pie wedge colours based on this hue. -->
<xsl:variable name="base_colour" select="'46A5E5'"/>
<!-- Pie wedge stroke colour. -->
<xsl:variable name="stroke_colour" select="'white'"/>
<!--
| Creates a colour for a particular pie wedge.
|
| http://en.wikipedia.org/wiki/HSL_and_HSV
+-->
<xsl:template name="fill">
<!-- Current wedge number for generating a colour. -->
<xsl:param name="wedge"/>
<!-- Total number of wedges in the pie. -->
<xsl:param name="wedges"/>
<!-- RGB colour in hexadecimal. -->
<xsl:param name="colour"/>
<!-- Derive the colour decimal values from $colour's HEX code. -->
<xsl:variable name="r">
<xsl:call-template name="hex2dec">
<xsl:with-param name="hex"
select="substring( $colour, 1, 2 )"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="g">
<xsl:call-template name="hex2dec">
<xsl:with-param name="hex"
select="substring( $colour, 3, 2 )"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="b">
<xsl:call-template name="hex2dec">
<xsl:with-param name="hex"
select="substring( $colour, 5, 2 )"/>
</xsl:call-template>
</xsl:variable>
<!--
| Convert RGB to XYZ, using nominal range for RGB.
| http://www.brucelindbloom.com/index.html?Eqn_RGB_to_XYZ.html
+-->
<xsl:variable name="r_n" select="$r div 255" />
<xsl:variable name="g_n" select="$g div 255" />
<xsl:variable name="b_n" select="$b div 255" />
<!--
| Assume colours are in sRGB.
| http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html
-->
<xsl:variable name="x"
select=".4124564 * $r_n + .3575761 * $g_n + .1804375 * $b_n"/>
<xsl:variable name="y"
select=".2126729 * $r_n + .7151522 * $g_n + .0721750 * $b_n"/>
<xsl:variable name="z"
select=".0193339 * $r_n + .1191920 * $g_n + .9503041 * $b_n"/>
<!--
| Convert XYZ to L*a*b.
| http://www.brucelindbloom.com/index.html?Eqn_XYZ_to_Lab.html
+-->
<xsl:variable name="if_x">
<xsl:call-template name="lab_f">
<xsl:with-param name="xyz_n" select="$x div $X_r"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="if_y">
<xsl:call-template name="lab_f">
<xsl:with-param name="xyz_n" select="$y div $Y_r"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="if_z">
<xsl:call-template name="lab_f">
<xsl:with-param name="xyz_n" select="$z div $Z_r"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="lab_l" select="(116.0 * $if_y) - 16.0"/>
<xsl:variable name="lab_a" select="500.0 * ($if_x - $if_y)"/>
<xsl:variable name="lab_b" select="200.0 * ($if_y - $if_z)"/>
<!--
| Convert L*a*b to LCH.
| http://www.brucelindbloom.com/index.html?Eqn_Lab_to_LCH.html
+-->
<xsl:variable name="lch_l" select="$lab_l"/>
<xsl:variable name="lch_c">
<xsl:call-template name="sqrt">
<xsl:with-param name="n" select="($lab_a * $lab_a) + ($lab_b * $lab_b)"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="lch_h">
<xsl:call-template name="atan2">
<xsl:with-param name="x" select="$lab_b"/>
<xsl:with-param name="y" select="$lab_a"/>
</xsl:call-template>
</xsl:variable>
<!--
| Prevent similar adjacent colours.
| http://math.stackexchange.com/a/936767/7932
+-->
<xsl:variable name="wi" select="$wedge"/>
<xsl:variable name="wt" select="$wedges"/>
<xsl:variable name="w">
<xsl:choose>
<xsl:when test="$wt > 5">
<xsl:variable name="weven" select="(($wi+4) mod ($wt + $wt mod 2))"/>
<xsl:value-of
select="$weven * (1-($wi mod 2)) + ($wi mod 2 * $wi)"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$wedge"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<!-- lch_l, lch_c, and lch_h are now set; rotate the hue. -->
<xsl:variable name="lch_wedge_h" select="(360.0 div $wedges) * $wedge"/>
<!--
| Convert wedge's hue-adjusted LCH to L*a*b.
| http://www.brucelindbloom.com/index.html?Eqn_LCH_to_Lab.html
+-->
<xsl:variable name="lab_sin_h">
<xsl:call-template name="sine">
<xsl:with-param name="degrees" select="$lch_wedge_h"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="lab_cos_h">
<xsl:call-template name="cosine">
<xsl:with-param name="degrees" select="$lch_wedge_h"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="final_lab_l" select="$lch_l"/>
<xsl:variable name="final_lab_a" select="$lch_c * $lab_cos_h"/>
<xsl:variable name="final_lab_b" select="$lch_c * $lab_sin_h"/>
<!--
| Convert L*a*b to XYZ.
| http://www.brucelindbloom.com/index.html?Eqn_Lab_to_XYZ.html
+-->
<xsl:variable name="of_y" select="($final_lab_l + 16.0) div 116.0"/>
<xsl:variable name="of_x" select="($final_lab_a div 500.0) + $of_y"/>
<xsl:variable name="of_z" select="$of_y - ($final_lab_b div 200.0)"/>
<xsl:variable name="of_x_pow">
<xsl:call-template name="power">
<xsl:with-param name="base" select="$of_x"/>
<xsl:with-param name="exponent" select="3"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="of_z_pow">
<xsl:call-template name="power">
<xsl:with-param name="base" select="$of_z"/>
<xsl:with-param name="exponent" select="3"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="ox_r">
<xsl:choose>
<xsl:when test="$of_x_pow > $LAB_EPSILON">
<xsl:value-of select="$of_x_pow"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="((116.0 * $of_x) - 16.0) div $LAB_K"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:variable name="oy_r">
<xsl:choose>
<xsl:when test="$final_lab_l > ($LAB_K * $LAB_EPSILON)">
<xsl:call-template name="power">
<xsl:with-param name="base"
select="($final_lab_l + 16.0) div 116.0"/>
<xsl:with-param name="exponent"
select="3"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$final_lab_l div $LAB_K"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:variable name="oz_r">
<xsl:choose>
<xsl:when test="$of_z_pow > $LAB_EPSILON">
<xsl:value-of select="$of_z_pow"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="((116.0 * $of_z) - 16.0) div $LAB_K"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:variable name="X" select="$ox_r * $X_r"/>
<xsl:variable name="Y" select="$oy_r * $Y_r"/>
<xsl:variable name="Z" select="$oz_r * $Z_r"/>
<!--
| Convert XYZ to sRGB.
| http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html
+-->
<xsl:variable name="R"
select="3.2404542 * $X + -1.5371385 * $Y + -0.4985314 * $Z"/>
<xsl:variable name="G"
select="-0.9692660 * $X + 1.8760108 * $Y + 0.0415560 * $Z"/>
<xsl:variable name="B"
select="0.0556434 * $X + -0.2040259 * $Y + 1.0572252 * $Z"/>
<!-- Round the result. -->
<xsl:variable name="R_r" select="round( $R * 255 )"/>
<xsl:variable name="G_r" select="round( $G * 255 )"/>
<xsl:variable name="B_r" select="round( $B * 255 )"/>
<xsl:text>rgb(</xsl:text>
<xsl:value-of select="concat( $R_r, ',', $G_r, ',', $B_r )"/>
<xsl:text>)</xsl:text>
</xsl:template>
<xsl:template name="lab_f">
<xsl:param name="xyz_n"/>
<xsl:choose>
<xsl:when test="$xyz_n > $LAB_EPSILON">
<xsl:call-template name="nthroot">
<xsl:with-param name="index" select="3"/>
<xsl:with-param name="radicand" select="$xyz_n"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="($LAB_K * $xyz_n + 16.0) div 116.0" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<!-- Converts a two-digit hexadecimal number to decimal. -->
<xsl:template name="hex2dec">
<xsl:param name="hex"/>
<xsl:variable name="digits" select="'0123456789ABCDEF'"/>
<xsl:variable name="X" select="substring( $hex, 1, 1 )"/>
<xsl:variable name="Y" select="substring( $hex, 2, 1 )"/>
<xsl:variable name="Xval"
select="string-length(substring-before($digits,$X))"/>
<xsl:variable name="Yval"
select="string-length(substring-before($digits,$Y))"/>
<xsl:value-of select="16 * $Xval + $Yval"/>
</xsl:template>
</xsl:stylesheet>
trig,root和其他数学函数留给读者练习。此外,没有人在他们正确的思想中想要在XSLT 1.0中编写所有这些代码。另一方面,XSLT 2.0有一个implementation here。
进一步阅读:
答案 5 :(得分:4)
1985年的文章“ROSS E. ROLEY,CAPT”给出了一种算法,可以最大化任意颜色组的颜色分离(complete with code in FORTRAN)。
(分色似乎是军队防止蓝蓝事件的重要可视化问题。)
然而,如果你想坚持一组20种颜色,一个快速而简单的解决方案是选择十二面体的顶点并将(x,y,z)坐标(适当缩放)转换为(r ,G,b)。
答案 6 :(得分:2)
有一个生成器here。它适用于网页设计,但颜色在饼图上看起来也很棒。
你可以预先编译漂亮的颜色列表,或者检查生成器背后的逻辑并自己做类似的事情。
答案 7 :(得分:1)
我发现这个伪代码公式可能有所帮助。你可以从一套开始播种它。
色差公式
以下是W3C建议的用于确定两种颜色之间差异的公式。
(最大值(红色值1,红色值2) - 最小值(红色值1,红色值2))+(最大值(绿色值1,绿色值2) - 最小值(绿色值1,绿色值2)) +(最大值(蓝色值1,蓝色值2) - 最小值(蓝色值1,蓝色值2))
背景颜色和前景色之间的差异应大于500.