5

How can I take colornames from a datafile? I didn't expect this to be so difficult, but apparently it is. Why do version 1 and version 2 give wrong colors? Is there a simpler way to achieve correct colors without using arrays as in version 3? And ...lc var only works with index values but not with colornames.

### colornames from data
reset session

$Data <<EOD
1   40  orange
2   35  cyan
3   25  red
4   15  yellow
5   5   green
EOD

set yrange [0:]
set multiplot layout 3,1
MyColor = "black"
plot \
    $Data u 1:(MyColor=strcol(3),$2):(0.7) w boxes fs solid 1.0 lc rgb MyColor notitle,\
    $Data u 1:($2/2):(strcol(3)) with labels tc rgb "white" notitle

plot \
    for [i=1:|$Data|] $Data u (MyColor=strcol(3),$1):2:(0.7) every ::i-1::i-1 w boxes fs solid 1.0 lc rgb MyColor notitle,\
    $Data u 1:($2/2):(strcol(3)) with labels notitle

array MyColors[|$Data|]
plot \
    $Data u (NaN):(MyColors[$0+1]=strcol(3)) notitle,\
    for [i=1:|$Data|] $Data u 1:2:(0.7) every ::i-1::i-1 w boxes fs solid 1.0 lc rgb MyColors[i] notitle,\
    $Data u 1:($2/2):(strcol(3)) with labels notitle

print MyColors
unset multiplot
### end of code

enter image description here

theozh
  • 22,244
  • 5
  • 28
  • 72

3 Answers3

19

In case somebody wants to use a lookup table as @Ethan suggested, here are the 111 predefined gnuplot colors in arrays (taken from the gnuplot manual).

array ColorNames[111] = \
['white', 'black', 'dark-grey', 'red', 'web-green', 'web-blue', 'dark-magenta', 'dark-cyan', 'dark-orange', 'dark-yellow', \
'royalblue', 'goldenrod', 'dark-spring-green', 'purple', 'steelblue', 'dark-red', 'dark-chartreuse', 'orchid', 'aquamarine', 'brown', \
'yellow', 'turquoise', 'grey0', 'grey10', 'grey20', 'grey30', 'grey40', 'grey50', 'grey60', 'grey70', \
'grey', 'grey80', 'grey90', 'grey100', 'light-red', 'light-green', 'light-blue', 'light-magenta', 'light-cyan', 'light-goldenrod', \
'light-pink', 'light-turquoise', 'gold', 'green', 'dark-green', 'spring-green', 'forest-green', 'sea-green', 'blue', 'dark-blue', \
'midnight-blue', 'navy', 'medium-blue', 'skyblue', 'cyan', 'magenta', 'dark-turquoise', 'dark-pink', 'coral', 'light-coral', \
'orange-red', 'salmon', 'dark-salmon', 'khaki', 'dark-khaki', 'dark-goldenrod', 'beige', 'olive', 'orange', 'violet', \
'dark-violet', 'plum', 'dark-plum', 'dark-olivegreen', 'orangered4', 'brown4', 'sienna4', 'orchid4', 'mediumpurple3', 'slateblue1', \
'yellow4', 'sienna1', 'tan1', 'sandybrown', 'light-salmon', 'pink', 'khaki1', 'lemonchiffon', 'bisque', 'honeydew', \
'slategrey', 'seagreen', 'antiquewhite', 'chartreuse', 'greenyellow', 'gray', 'light-gray', 'light-grey', 'dark-gray', 'slategray', \
'gray0', 'gray10', 'gray20', 'gray30', 'gray40', 'gray50', 'gray60', 'gray70', 'gray80', 'gray90', \
'gray100']
 
array ColorValues[111] = \
[0xffffff, 0x000000, 0xa0a0a0, 0xff0000, 0x00c000, 0x0080ff, 0xc000ff, 0x00eeee, 0xc04000, 0xc8c800, \
0x4169e1, 0xffc020, 0x008040, 0xc080ff, 0x306080, 0x8b0000, 0x408000, 0xff80ff, 0x7fffd4, 0xa52a2a, \
0xffff00, 0x40e0d0, 0x000000, 0x1a1a1a, 0x333333, 0x4d4d4d, 0x666666, 0x7f7f7f, 0x999999, 0xb3b3b3, \
0xc0c0c0, 0xcccccc, 0xe5e5e5, 0xffffff, 0xf03232, 0x90ee90, 0xadd8e6, 0xf055f0, 0xe0ffff, 0xeedd82, \
0xffb6c1, 0xafeeee, 0xffd700, 0x00ff00, 0x006400, 0x00ff7f, 0x228b22, 0x2e8b57, 0x0000ff, 0x00008b, \
0x191970, 0x000080, 0x0000cd, 0x87ceeb, 0x00ffff, 0xff00ff, 0x00ced1, 0xff1493, 0xff7f50, 0xf08080, \
0xff4500, 0xfa8072, 0xe9967a, 0xf0e68c, 0xbdb76b, 0xb8860b, 0xf5f5dc, 0xa08020, 0xffa500, 0xee82ee, \
0x9400d3, 0xdda0dd, 0x905040, 0x556b2f, 0x801400, 0x801414, 0x804014, 0x804080, 0x8060c0, 0x8060ff, \
0x808000, 0xff8040, 0xffa040, 0xffa060, 0xffa070, 0xffc0c0, 0xffff80, 0xffffc0, 0xcdb79e, 0xf0fff0, \
0xa0b6cd, 0xc1ffc1, 0xcdc0b0, 0x7cff40, 0xa0ff20, 0xbebebe, 0xd3d3d3, 0xd3d3d3, 0xa0a0a0, 0xa0b6cd, \
0x000000, 0x1a1a1a, 0x333333, 0x4d4d4d, 0x666666, 0x7f7f7f, 0x999999, 0xb3b3b3, 0xcccccc, 0xe5e5e5, \
0xffffff]

Addition: for what it's worth, just for completeness and illustration... Below some code to generate an overview about the predefined gnuplot colors.

Edit: code cleaned up and modified that it will also work with gnuplot 4.6 (no arrays and bitshift at that time).

Code:

### display all predefined gnuplot colors, gnuplot >=4.6.0
reset
set term wxt size 1000,700 enhanced   # or change to another terminal

ColorNames = '\
white black dark-grey red web-green web-blue dark-magenta dark-cyan dark-orange dark-yellow \
royalblue goldenrod dark-spring-green purple steelblue dark-red dark-chartreuse orchid aquamarine brown \
yellow turquoise grey0 grey10 grey20 grey30 grey40 grey50 grey60 grey70 \
grey grey80 grey90 grey100 light-red light-green light-blue light-magenta light-cyan light-goldenrod \
light-pink light-turquoise gold green dark-green spring-green forest-green sea-green blue dark-blue \
midnight-blue navy medium-blue skyblue cyan magenta dark-turquoise dark-pink coral light-coral \
orange-red salmon dark-salmon khaki dark-khaki dark-goldenrod beige olive orange violet \
dark-violet plum dark-plum dark-olivegreen orangered4 brown4 sienna4 orchid4 mediumpurple3 slateblue1 \
yellow4 sienna1 tan1 sandybrown light-salmon pink khaki1 lemonchiffon bisque honeydew \
slategrey seagreen antiquewhite chartreuse greenyellow gray light-gray light-grey dark-gray slategray \
gray0 gray10 gray20 gray30 gray40 gray50 gray60 gray70 gray80 gray90 \
gray100'

ColorValues = '\
0xffffff 0x000000 0xa0a0a0 0xff0000 0x00c000 0x0080ff 0xc000ff 0x00eeee 0xc04000 0xc8c800 \
0x4169e1 0xffc020 0x008040 0xc080ff 0x306080 0x8b0000 0x408000 0xff80ff 0x7fffd4 0xa52a2a \
0xffff00 0x40e0d0 0x000000 0x1a1a1a 0x333333 0x4d4d4d 0x666666 0x7f7f7f 0x999999 0xb3b3b3 \
0xc0c0c0 0xcccccc 0xe5e5e5 0xffffff 0xf03232 0x90ee90 0xadd8e6 0xf055f0 0xe0ffff 0xeedd82 \
0xffb6c1 0xafeeee 0xffd700 0x00ff00 0x006400 0x00ff7f 0x228b22 0x2e8b57 0x0000ff 0x00008b \
0x191970 0x000080 0x0000cd 0x87ceeb 0x00ffff 0xff00ff 0x00ced1 0xff1493 0xff7f50 0xf08080 \
0xff4500 0xfa8072 0xe9967a 0xf0e68c 0xbdb76b 0xb8860b 0xf5f5dc 0xa08020 0xffa500 0xee82ee \
0x9400d3 0xdda0dd 0x905040 0x556b2f 0x801400 0x801414 0x804014 0x804080 0x8060c0 0x8060ff \
0x808000 0xff8040 0xffa040 0xffa060 0xffa070 0xffc0c0 0xffff80 0xffffc0 0xcdb79e 0xf0fff0 \
0xa0b6cd 0xc1ffc1 0xcdc0b0 0x7cff40 0xa0ff20 0xbebebe 0xd3d3d3 0xd3d3d3 0xa0a0a0 0xa0b6cd \
0x000000 0x1a1a1a 0x333333 0x4d4d4d 0x666666 0x7f7f7f 0x999999 0xb3b3b3 0xcccccc 0xe5e5e5 \
0xffffff'

# get R,G,B components
R(Color) = (Color & 0xff0000)/0x10000
G(Color) = (Color & 0x00ff00)/0x100
B(Color) = (Color & 0xff)
   
PosX(i) = int(i)%10
PosY(i) = floor(i/10.)*10
ColorName(i) = word(ColorNames,int(i))
ColorValue(i) = int(word(ColorValues,int(i)))
ColorValueLabel(i) = sprintf('#%06x',ColorValue(i))
# "empirical" formula do decide whether using a white or a black label on the colored background
ColorLabelColor(c) = (R(c) + G(c)*1.5 + B(c)*0.5)/3. > 127 ? 0x000000 : 0xffffff

set title "Predefined colors in gnuplot" font ",18"
set xrange[-0.5:9.5]
set x2range[-0.5:9.5]
set xtics 1
set x2tics 1
set yrange[119:-5]
set y2range[119:-5]
set ytics 10
set y2tics 10

set style fill solid 1.0 border lc rgb "black"
set samples 111
unset key

plot '+' u (c=$0+1,PosX(c)):(PosY(c)):(0.4):(2.5):(ColorValue(c)) w boxxy lc rgb var, \
     '+' u (c=$0+1,PosX(c)):(PosY(c)+4.2):(ColorName(c)) w labels, \
     '+' u (c=$0+1,PosX(c)):(PosY(c)):(ColorValueLabel(c)):(ColorLabelColor(ColorValue(c))) \
         w labels tc rgb var font "Courier Bold,10"
### end of code

Result:

enter image description here

theozh
  • 22,244
  • 5
  • 28
  • 72
3

I'm amazed that any of those methods work at all!

The intended method of reading color information from a file is

plot foo using 1:2:3 lc rgb variable

See for example the online demo rgb_variable.dem that reads colors from data file rgb_variable.dat.

However that assumes column 3 contains a hexadecimal RGB (or ARGB) value, not an English word that is a color name. The color word names recognized by gnuplot are a built-in subset of the name->RGB mapping that used to be universally provided for X11 in a system file X11/rgb.txt. See Wikipedia X11 colors. A variant of this list became part of the SVG standard. The inclusion in gnuplot was intended for use in interactive commands, not as data file content.

It is of course possible to script an expanded name->RGB mapping using gnuplot arrays and user functions. For example:

$Data <<EOD
1   40  orange
2   35  cyan
3   25  red
4   15  yellow
5   5   green
EOD

array colorname  = ["orange", "cyan", "red", "yellow", "green"]
array colorvalue = [0xFFD700, 0x00DDDD, 0xDD0000, 0xFFFF00, 0x00DD00]
N = |colorname|
name2RGB(name) = sum [i=1:N] (name eq colorname[i] ? colorvalue[i] : 0) 

set yrange [0:]
set boxwidth 0.7
set style fill solid 1.0
unset key

plot $Data u 1:2:(name2RGB(strcol(3))) w boxes fc rgb variable

enter image description here

If you deal with such file content often, I suppose you could automate conversion of the entire SVG or X11 color name tables into such a pair of gnuplot arrays and load that from your ~/.gnuplot initialization.

Ethan
  • 13,715
  • 2
  • 12
  • 21
  • Thank you for your detailed answer. Right, a lookup table is another approach, although it gets a bit lengthy if you want to include all 111 predefined gnuplot colors (or even the "endless" list of X11 color names). Haven't yet played with ~/.gnuplot. For the time being, I am still satisfied with my version 3. – theozh Feb 12 '19 at 22:44
  • actually, what are the reasons why variables defined in the `using` part cannot be re-used in the `with` part? For example `plot '+' using 0:(i=$1) with p lc i` or `plot $Data using 1:(myColor=strcol(3),$2) with p lc rgb myColor`. Although, `plot DATA using x:y:pointsize:pointtype:color with points lc variable pt variable ps variable` is going to this direction, but unfortunately not for string variables. – theozh Feb 13 '19 at 09:01
  • Several reasons, the most basic of which is that "with " is evaluated only once per plot, whereas "using ..." is re-evaluated for each point in the data set. – Ethan Feb 13 '19 at 16:28
  • ok, I see. `with ` is evaluated only once per plot, unless it is `with variable` which, however, only takes numerical values. – theozh Feb 13 '19 at 19:59
  • 1
    'with ' is only evaluated once per plot. No exceptions. If that evaluation includes a property with the keyword "variable" then a flag is set so that during data input the required data value is filled in. This mechanism imposes no special restriction on numerical vs. string values, but so far the properties that accept "variable" happen to want numbers rather than strings. The only plot style that expects string input ("with labels") doesn't need a "variable" keyword because it _always_ acts that way. – Ethan Feb 13 '19 at 21:04
  • well, `lc rgb variable` or `fc rgb variable` in principle would/could/should also take strings. – theozh Feb 13 '19 at 21:13
  • 1
    Added in 2020: gnuplot 5.5 provides a function `rgbcolor("colorname")` that provides the missing step. `plot FOO using 1:2:(rgbcolor(stringcolumn(3))) lc rgb variable`. – Ethan Nov 18 '20 at 19:26
1

Here is another approach by using an autmatically generated palette from your datafile or datablock. With this you don't have to care about the Hex-numbers or any number or codes of colors. You only need to make sure that you are not using invalid color names. This should work unless there is a limitation on the length of the color palette for long datasets.

### colornames from data
reset session

$Data <<EOD
1   40  red
2   35  orange
3   25  yellow
4   20  greenyellow
5   15  web-green
6   12  web-blue
7   10  violet
EOD

MyPalette = '('
set table $Dummy
    plot $Data u (MyPalette = MyPalette.sprintf('%d "%s", ',$0,strcol(3))) with table
unset table
MyPalette = MyPalette[:strlen(MyPalette)-2].')'
set palette model RGB defined @MyPalette
unset colorbox 

set yrange[0:]
plot $Data u 1:2:(0.7):0 w boxes fs solid 1.0 lc palette notitle,\
    '' u 1:($2/2):(strcol(3)) with labels notitle
### end of code

enter image description here

theozh
  • 22,244
  • 5
  • 28
  • 72