如何select饼图的颜色?

我有一些代码生成饼图的图像。 这是一个通用的类,所以任何数量的切片可以作为input。 现在我有问题为切片挑选良好的颜色。 有一些好的algorithm吗?

或者,也许我应该手工挑选和列出固定的颜色? 但是有多less。 也许10种颜色,希望有没有超过10片有史以来? 另外,还有哪十种颜色可供select?

颜色需要遵循一些规则:

  • 他们需要看起来不错
  • 相邻的颜色不应该相似(蓝色旁边的绿色是不行的)
  • 馅饼背景颜色是白色的,所以白色是不可选的

某些用RGB值操作的algorithm将是一个首选的解决scheme。

我会预编译一个约20种颜色的列表,然后开始重复使用第二种颜色。 这样你就不会破坏你的第二条规则。 另外,如果有人制作了超过20片的饼图,它们的问题就更大了。 🙂

我解决它如下:

  1. select一种基本颜色
  2. 计算其色调baseHue )。
  3. 创build具有相同饱和度和亮度的颜色,其色调计算如下:
       hue = baseHue +((240 /件)*件%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类 。

Google图表示例 ,使用12件和#8A56E2的基本颜色:

图例

Color Brewer可以帮助定义一个着色scheme来传递定性或定量的信息:地图,图表等。这个工具可以生成三个“types”的调色板 – 顺序,定性和分歧 -你可能需要后者,发散…

您甚至可以使用所有调色板的RGB定义下载Excel文件。

基于这个解决scheme来解决问题的规则#2,下面的algorithm交换颜色在派的中间点。 这两个参数:

  1. pNbColors是派的片数
  2. pNonAdjacentSimilarColor布尔值,指示是否要使用相邻的相似颜色。

我正在使用ColorHSLColorRGBColorUtils (下面提供)。

 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((if/(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; } } 

概观

从RGB转换到HSV,然后调整色调(在这里回答 )会产生不一致的感知亮度。 黄色/绿色明显比蓝色/紫色轻:

不符

类似的结果没有这样的变化是可能的:

一贯

algorithm

但是,该algorithm要复杂得多:

  1. 将HTMLhex代码转换为标称RGB值(将组件除以255)。
  2. 将RGB值转换为XYZ色彩空间 ; 使用D65参考白色 sRGB 工作空间 。
  3. 从XYZ转换为L b颜色空间 。
  4. 从L a b转换到LCH色彩空间 。
  5. 计算LCH色彩空间中的馅饼楔形色调:
      (360.0 div $楔子)* $楔子 
  6. 重新计算弧度的新色调。
  7. 使用新色相从LCH转换回L b色彩空间 。
  8. 从L a b转换到XYZ色彩空间 。
  9. 从XYZ转换到sRGB色彩空间 。
  10. 将RGB值乘以255。

履行

以下是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 &gt; 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 &gt; $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 &gt; ($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 &gt; $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 &gt; $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和杂项math函数留给读者练习。 而且,没有一个人正确的想要在XSLT 1.0中编写所有的代码。 另一方面,XSLT 2.0在这里有一个实现 。

资源

进一步阅读:

  • 使用直观的参数生成调色板
  • 调色板的合成
  • 有用的颜色等式
  • 色彩空间简介
  • 均匀分布的颜色在一个敏感的连贯空间
  • 一种用于select高对比度颜色集合的algorithm
  • select统计graphics的颜色
  • Colourspace转换
  • 布鲁尔调色板

这篇由“ROSS E. ROLEY,CAPT”发表的1985年的论文给出了一个algorithm,用于最大化颜色分离任意一组颜色( 在FORTRAN中用代码完成 )。

(颜色分离似乎是防止蓝军事事件的军事力量的一个重要的可视化问题。)

然而,如果你想要坚持一组20种颜色,一个简单而快速的解决scheme是挑选十二面体的顶点,并将(x,y,z)坐标(适当缩放)转换为(r,g, b)。

这里有一个发生器。 它是用于网页devise的,但颜色在饼图上看起来也很棒。

你可以预先编译一个漂亮的颜色列表,或者检查生成器背后的逻辑,并自己做类似的事情。

我发现这个伪代码公式可能有帮助。 你可以从一个集合开始播种。

色差公式

以下是W3Cbuild议的公式,以确定两种颜色之间的差异。

(最大值(红色值1,红色值2) – 最小值(红色值1,红色值2))+(最大值(绿色值1,绿色值2) – 最小值(绿色值1,绿色值2))+ (蓝色值1,蓝色值2) – 最小值(蓝色值1,蓝色值2))

背景颜色和前景颜色之间的差异应该大于500。

这是来源