fahd
fahd

Reputation: 151

How to specify fill color and border line color from column data in gnuplot

I want to plot my data using boxxyerror bar in gnuplot

data looks like this:

#x  y   fill-color   border-color
2   2      0.50          1.00
8   2      0.25          0.50
8   8      0.40          0.40
2   8      0.50          0.50

column 1 gives x cordinates, column 2 gives y cordinates column 3 gives border color and column 4 gives fill color I will be placing squares of side 2 at all these points effectively. Color is chosen from a palette with a range [0.0:1.0]

The plot will look something like this(this is just sample): enter image description here

if I was taking only fill colour from data I will plot it using boxxyerrorbar as

plot "data.txt" u 1:2:(1.0):(1.0):3 with boxxyerrorbar fs solid lc palette

if I was taking only border colour from data I will plot it using boxxyerrorbar as

plot "data.txt" u 1:2:(1.0):(1.0):4 with boxxyerrorbar fs border lc palette

using palette for both is also fine:

plot "data.txt" u 1:2:(1.0):(1.0):4 with boxxyerrorbar fs border lc palette fc palette

But we are using column 4 for both colours, but I need them to be read from columns 3 and 4 separately. Or at least I would like to have something like one colour is a function of the same column data using for palette, like:

plot "data.txt" u 1:2:(1.0):(1.0):4 with boxxyerrorbar fs border lc (column(4)*0.5) fc palette

More generally, I want to use numbers in some columns to be used for determining the colour of border or fill color in my plot, I could be able to do something like:

plot "data.txt" u 1:2:(1.0):(1.0):4 with boxxyerrorbar fs border lc (2*(column 5)-0.60) fc (palette * 0.24)

I need some kind of solution to this problem please help me.

Finally, this Is the plot I want to make(but basic requirement covers in above question). This is a phase diagram, grey borders are data I have, red borders means it's extrapolated! It was done by plotting two files which store fill color and border color separately(Inspired by @theozh 's answer)-

Upvotes: 0

Views: 1511

Answers (2)

theozh
theozh

Reputation: 25734

The first "quick and dirty" solution which comes to my mind is to plot the boxes twice: once with variable color fill and the second time empty for the border with variable color. Plotting twice should work the same with a palette.

Hopefully there will be a better solution for this.

Script:

### different colors for fill and border from datafile
reset session

$Data <<EOD
#x  y   fill-color  border-color
2   2   0x0000ff    0x000000
8   2   0x00ff00    0xffaa00
8   8   0xffffff    0xff0000
2   8   0xffff00    0x0000ff
EOD

set size square
set offsets 1,1,1,1
set style fill solid 1.0 border lc rgb var
set key noautotitle

plot $Data u 1:2:(1.0):(1.0):3 w boxxy fs solid lc rgb var, \
        '' u 1:2:(1.0):(1.0):4 w boxxy fs empty lc rgb var lw 2
### end of script

Result:

enter image description here

Addition:

Based on the comments and modified question, here is another suggestion. My understanding is that you want to have only one number to define the colors for fill and border of a square. In your example you only have 2 colors for fill and 2 colors for border, which makes 4 possible combinations in total.

The example below expands this to 16 colors each for border and fill, which makes it 256 combinations. Check the table $myColors and select a color for the fill and a color for the border. Add the corresponding numbers and put the result into your datafile as third column. For example:

black  fill=0 + red  border=16    -->  16
green  fill=2 + grey border=128   --> 130
yellow fill=4 + blue border=48    -->  52

You can easily change the colors or expand it accordingly to many more combinations. By the way, you can find predefined gnuplot colors by typing show colors or here as an overview.

Furthermore, I noticed that plotting borders of adjacent squares will "overwrite" each other in the graph, i.e. visibility of a border depends on the plotting sequence. In order to be independent of this, I would suggest to plot larger and smaller filled squares instead of bordered squares.

Another suggestion: instead of going for logscale (making the size for your boxes difficult) you can stay in linear scale and simply adjust the tic-labels via xtic() and ytic(), check help xticlabels.

All these are just suggestions, since I might not know all the background and details for your specific plotting case.

Script: (only 5x5 table for illustration)

### define fill and border by a single number
reset session

$Data <<EOD
# x  y   colors
 1   1   128
 1   2   128
 1   3   128
 1   4   16
 1   5   52
 2   1   128
 2   2   128
 2   3   128
 2   4   16
 2   5   16
 3   1   130
 3   2   128
 3   3   128
 3   4   16
 3   5   241
 4   1   130
 4   2   130
 4   3   128
 4   4   16
 4   5   16
 5   1   18
 5   2   18
 5   3   130
 5   4   16
 5   5   16
EOD

# color   fill  border   name
$myColors <<EOD
0x000000     0       0   black
0xff0000     1      16   red
0x00ff00     2      32   green
0x0000ff     3      48   blue
0xffff00     4      64   yellow
0xffa500     5      80   orange
0xff00ff     6      96   magenta
0x00ffff     7     112   cyan 
0xc0c0c0     8     128   grey
0xd3d3d3     9     144   light-grey
0xa0a0a0    10     160   dark-grey
0xc080ff    11     176   purple
0x00c000    12     192   web-green
0x0080ff    13     208   web-blue
0xffb6c1    14     224   light-pink
0xffffff    15     240   white
EOD

fillColor(n)   = int(word($myColors[int(n)%16+1],1))
borderColor(n) = int(word($myColors[(int(n)/16)%16+1],1))   # integer division!

set size square
set xrange [:] noextend
set yrange [:] noextend
set tics out
set style fill solid 1.0 noborder
set key noautotitle

plot $Data u 1:2:(0.50):(0.50):(borderColor($3)): \
             xtic(sprintf("%g",2**($1+1))):ytic(sprintf("%g",2**($2+1))) \
             w boxxy lc rgb var, \
        '' u 1:2:(0.46):(0.46):(fillColor($3)) w boxxy lc rgb var
### end of script

Result:

enter image description here

Upvotes: 2

fahd
fahd

Reputation: 151

I got a temporary solution to the actual problem I had.

I defined my palette as

set palette model RGB defined ( 0 'black', 0.3 'red', 0.6 'grey', 1 'green')

stored my border colors in 'border.dat' and fill color in 'fill.dat' enter image description here

enter image description here

and plotted them like this:

plot for [i=1:13] "fill.dat" u 1:(2**(i+1)):($1/2.0**0.5):($1*2.0**0.5):(2**(i+1)/2.0**0.5):(2**(i+1)*2.0**0.5):i+1  with boxxyerror fc palette,\
for [i=1:13] "border.dat" u 1:(2**(i+1)):($1/2.0**0.5):($1*2.0**0.5):(2**(i+1)/2.0**0.5):(2**(i+1)*2.0**0.5):i+1  with boxxyerror fs empty lc palette lw 2

( sorry, cordinates and box dimensions will appear messy because I am plotting on log scale)

and Finally got this! (red borders means it is extrapolated[which I don't have data for]) enter image description here

Upvotes: 0

Related Questions