Using Gnuplot to plot point colors conditionally - gnuplot

I have a file with four columns of data. I am using just the first three to plot a 3D plot and do not need the fourth one right now.
I want to know how to change the color of a point if it meets certain conditions. For example, if a point's values (x,y,z) are greater than (16,400,65), I want to plot it in grey. If they are lesser than that, I want to use red.
I am trying to use awk for the same and it plots just two points in a different color. Here is my code.
gnuplot>splot "< awk '{if( ($2 > \"16\") || ($1 > \"400\") || ($3 > \"65\")) print}'
./8_77_non_pareto_data.dat " u 2:1:3 w p pt 8 lc rgb "grey", \
"< awk '{if( ($2 < \"16\") || ($1 < \"400\") || ($3 < \"65\")) print}'
./8_77_non_pareto_data.dat " u 2:1:3 w p pt 8 lc rgb "red", \
"./8_77_pareto_data.dat" u 2:1:3 w i lt 1 lc rgb "blue" t "Pareto points"
My data file looks like this:
48 15.057599573464184 68 361
93 14.950459657063462 73 361
48 14.065204842090914 69 361
280 13.16320458043516 69 361
120 15.05281009307949 66 361
48 15.133322961840786 59 361
48 16.161631503473544 73 361
470 17.763180586730847 77 361
X axis ranges from 6 to 22.
Y-axis ranges from 0 to 500.
Z-axis ranges from 35 to 85.
I would like to visualize this as having a bounding box around (16,400,65) in a three dimensional way. Anything inside the box is red, anything outside it is grey.
Hope someone can help me here.
P.S : The blue points are printing just fine and though the sample data here does not show some conditions being met, there are points that meet that condition. I did not post the whole file here.

You can reduce the awk effort somewhat and do it in pure gnuplot by defining a simple function:
#!/usr/bin/env gnuplot
set terminal png set output 'test.png'
bigx = 16; bigy = 400; bigz = 65
isbig(x,y,z) = (x > bigx || y > bigy || z > bigz) ? 1 : 0
set palette defined (0 0.5 0.5 0.5, 1 1 0 0) # (grey, red)
unset colorbox
set xrange [0:20]; set yrange [0:500]; set zrange [0:100]
splot 'data.dat' using 2:1:3:(isbig($2,$1,$3)) with points pt 7 palette notitle, \
'' using (1e6):1:1 with points pt 7 lc rgb '#888888' title 'in box', \
'' using (1e6):1:1 with points pt 7 lc rgb 'red' title 'not in box'
(The lines setting the range and unsetting the colorbox, as well as the two extra plot commands, are just to make things pretty in my opinion. It gives a key which describes what the two colors mean without the distracting colorbox.)

Related

Redrawing Excel figures on gnuplot

I was working on excel and drew two histograms shown below, I have been told to redraw them using gnuplot on windows which is very new to me.
The original graph that I want to redraw is this.
Area 1 Area 2
Case 1 Case 2 Case 1 Case 2
Parameter 1 36 66 31 72
Parameter 2 57 91 44 85
Parameter 3 62 90 50 85
My file is a text file and I wrote the above table as follows as I am not sure how to group the different columns together.
Area Area1 Area1 Area2 Area2
Case Case1 Case2 Case1 Case2
Parameter_1 36 66 31 72
Parameter_2 57 91 44 85
Parameter_3 62 90 50 85
I used the following commands and got a histogram that is grouped in the wrong way.
clear
reset
unset key
set style data histogram
set style fill solid border
set style histogram clustered
plot for [COL=2:5] 'date_mins.tsv' using COL:xticlabels(1) title columnheader
Kindly guide me on how to group columns together and also how to add the numbers on top of the bars. {The graph should be same as the one excel generated one.}
To be honest I'm regularly puzzled with histograms in gnuplot, apparently I'm not the only one. In gnuplot console, check help histograms.
Although, there are a few histogram examples on the gnuplot homepage, but of course not all possible variations can be covered.
Apparently, this plotting style is a bit confusing to understand.
This would maybe explain that there are more than 800 questions on SO on histograms with gnuplot.
I'm not sure if or how you can get your desired histogram efficiently, maybe there is an easy way.
I would do it "manually" with the plotting style with boxes.
Check the example below as a starting point. There are a few strange workarounds included, e.g. getting the titles into an array in an earlier plot for later use.
Code:
### special histogram
reset session
$Data <<EOD
Area Area1 Area1 Area2 Area2
Case Case1 Case2 Case1 Case2
"Parameter 1" 36 66 31 72
"Parameter 2" 57 91 44 85
"Parameter 3" 62 90 50 85
EOD
set style fill solid noborder
set boxwidth 0.8
set key noautotitle out center bottom horizontal reverse Left samplen 1 width 2
A=2 # Areas
C=2 # Cases
P=3 # Parameters
g=1 # gap
PosX(a,c,p) = ((a-1)*C*(P+g)) + (c-1)*(P+g) + p
PosY(a,c) = column((a-1)*C+c+1)
PosXArea(a) = (PosX(a,C,P)+PosX(a-1,C,P))*0.5
PosXCase(a,c) = (PosX(a,c,P)+PosX(a,c-1,P))*0.5
myColor(p) = int(word("0x5b9bd5 0xed7d31 0xa5a5a5",int(p)))
myValue(a,c) = strcol((a-1)*C+c+1)
set grid y
set xlabel "\n\n\n" # get empty space below the plot
set format x "" # no xtic labels
set yrange[0:]
array Titles[P] # array for titles
plot for [a=1:A] for [c=1:C] $Data u (PosX(a,c,$0)):(PosY(a,c)):(myColor($0+1)) skip 2 w boxes lc rgb var , \
for [a=1:A] for [c=1:C] '' u (PosX(a,c,$0)):(PosY(a,c)):(Titles[int($0+1)]=strcol(1), myValue(a,c)) skip 2 w labels offset 0,0.7, \
for [a=1:A] for [c=1:C] '' u (PosXCase(a,c)):(0):(myValue(a,c)) every ::1::1 w labels offset 0,-1, \
for [a=1:A] '' u (PosXArea(a)):(0):('\n\n'.myValue(a,1)) every ::0::0 w labels offset 0,-1, \
for [p=1:P] keyentry w boxes lc rgb myColor(p) ti Titles[p]
### end of code
Result:

gnuplot - how to plot invisible points so that the plot is only used to mark x-axis

I have the following data in data file test1.txt:
A 36 1
A 35 1
B 48 2
B 37 2
B 15 2
C 36 3
C 25 3
and test2.txt
A 16 1
A 25 1
B 38 2
B 45 2
C 36 3
the plotting is done as:
dat1="test1.txt"
dat2="test2.txt"
plot dat1 u ($3-0.2):2 w p t 'title 1', \
dat2 u ($3+0.2):2 w p t 'title 2', \
dat1 using 3:(0):xticlabels(1):x2ticlabels(1) notitle, \
dat2 using 3:(0):xticlabels(1):x2ticlabels(1) notitle
The whole point is to have the labels from the first column on the x axis. The issue is that the last two parts of plot
dat1 using 3:(0):xticlabels(1):x2ticlabels(1) notitle, \
dat2 using 3:(0):xticlabels(1):x2ticlabels(1) notitle
produce points at y=0. And because I cannot (or I do not know how to) use
plot dat1 u ($3-0.2):2:xticlabels(1) w p t 'title 1'
(since it plots the label at x coordinate $3-0.2 and not at $3, which i require), I am forced to do two more dummy plots, but they produce points and I do not know how to effectively avoid this other than shifting the outside of the range of the plot by e.g. dat1 using 3:(0):xticlabels(-1):x2ticlabels(-1) in the case of plotting only positive values. Is there any good way of solving this?
I don't really understand what you are trying to do with your data, however if you want to make the points over the x axis invisible you can set the line color to full transparency for the last two plots:
dat1 using 3:(0):xticlabels(1):x2ticlabels(1) linecolor "#FFFF0000" notitle, \
dat2 using 3:(0):xticlabels(1):x2ticlabels(1) linecolor "#FFFF0000" notitle
In recent versions of Gnuplot (link) it is possible to add transparency, in this particular case you want to set full transparency to the line color so that the points are invisible. The color format and transparency can be set using the hexadecimal notation #AARRGGBB where AA (alpha) controls how transparent the color is, for full transparency you want FF which is equivalent to 255, notice how my line color is RED but because is completely transparent we don't see it.
Plot with Full Transparency
My understanding of your question is the following: You have some data which you want to shift in x by +/-0.2 but the corresponding tic shouldn't be shifted.
You've been almost there. Of course, there are points at y=0 because you tell gnuplot to do so.
What you mean with "invisible" could of course be also achieved by fully transparent points, but the easier way is probably to "plot" the points at NaN, i.e. nowhere.
Code:
### plotting data with offset and tic without offset
reset session
set colorsequence classic
$Data1 <<EOD
A 36 1
A 35 1
B 48 2
B 37 2
B 15 2
C 36 3
C 25 3
EOD
$Data2 <<EOD
A 16 1
A 25 1
B 38 2
B 45 2
C 36 3
EOD
set offsets 0.5,0.5,0.5,0.5
set link x2
set x2tics
plot $Data1 u ($3-0.2):2 w p pt 7 t 'title 1', \
$Data2 u ($3+0.2):2 w p pt 7 t 'title 2', \
$Data1 using 3:(NaN):xtic(1):x2tic(1) notitle, \
$Data2 using 3:(NaN):xtic(1):x2tic(1) notitle
### end of code
Result:

Gnuplot filledcurves flip axes

There is a style to fill the space between two functions of x.
Examples of such plots can be found e.g. at http://gnuplot.sourceforge.net/demo/fillbetween.html
Is there any way to make similar plot, but with flipped x and y axes?
Here is the desired shape of a curve (without rotated/mirrored labels, titles and legends, of course)...
It could be done with closed contour (like last example here http://www.gnuplot.info/demo_svg_cvs/fillcrvs.html), but this would require reshuffling the data file. Any other options?
Thank you!
You can't do this directly. From help filledcurves:
The third variant fills the area between two curves sampled at the same set of
x coordinates. It requires three columns of input data (x, y1, y2).
I don't think you can specify (y, x1, x2) directly. As a workaround you can the area between the y axis and the larger function in some color, and then fill the area between the y axis and the smaller function in white:
x1(y) = cos(y)+1
x2(y) = cos(y)+2
xmax(y) = (x1(y) > x2(y) ? x1(y) : x2(y))
xmin(y) = (x1(y) < x2(y) ? x1(y) : x2(y))
plot '+' using (xmax($1)):1 with filledcurve y1, \
'+' using (xmin($1)):1 with filledcurve y1 fillcolor rgb "white"
This probably has to be tweaked a little if one or both of the two functions can be negative.
With gnuplot >=5.2 it could be tweaked even further because it allows arrays.
The following code shows a workaround how filled curves between vertically oriented curves can be realized. You can even use transparency. If you download the attached PNG you will notice that it actually has a transparent background. The basic idea behind this workaround is to make closed areas and fill them. For this, you need to reverse one border, concatenate the borders and plot them filled. Unfortunately, gnuplot has no function to reverse datapoints in a column, so you have to do it in a special procedure yourself.
The code:
### "Vertical" filledcurves
reset session
# create some dummy data
N = 50
set samples N
set xrange [-5:5]
set table $Data
plot '+' u (sin($1)):1:(rand(0)*0.3+1) with table
unset table
# put Borders into arrays
stats $Data nooutput
RowCount = STATS_records
array BorderX1[RowCount]
array BorderX2[RowCount]
array BorderY[RowCount]
set table $Dummy
plot $Data u (BorderX1[$0+1]=$1-$3):(BorderX2[$0+1]=$1+$3):(BorderY[$0+1]=$2) with table
unset table
# reverse BorderX2 and merge borders
set samples RowCount
set table $Border
plot '+' u (BorderX1[$0+1]):(BorderY[$0+1]) with table
plot '+' u (BorderX2[RowCount-$0]):(BorderY[RowCount-$0]) with table
unset table
# make the plot
set object 1 rect at 0,-3 size 10,0.5 fs solid 1.0 fc rgb "black" back
set yrange[-5:5]
plot \
$Border u 1:2 w filledcurves fc rgb "#AA00FF00" not,\
$Border u ($1*1.5):2 w filledcurves fc rgb "#AAFFFF00" not,\
$Data u ($1+2.5):2 w filledcurves y2 fc rgb "brown" not,\
$Data u 1:2 w l lw 8 lc rgb "blue" not,\
'+' u 1:(cos($1)-0.5):(cos($1)+0.5) w filledcurves lc rgb "grey" not,\
'+' u 1:(cos($1)):(1) w l lw 3 dt 2 lc rgb "white" not
### end of code
The result:
Update: These are two alternative and simpler approaches compared to my first answer. One of them works even with gnuplot 5.0.
The plotting style filledcurves (so far) can only fill between two y-curves with identical x-values. However, gnuplot can fill closed curves. So, make the curve closed. Like in my first answer, you can do this if you reverse one curve and add it to the other one.
The assumption for both scripts is that the data has a common y-column, i.e. is organized in 3 columns, e.g. here: y x1 x2
Data: SO50676753.dat (same as OP's data, from silver.dat in the gnuplot demo directory)
# y x1 x2
10 280 16.7332
20 191 13.8203
30 152 12.3288
40 150 12.2474
50 104 10.1980
60 77 8.7750
70 69 8.3066
80 60 7.7460
90 60 7.7460
100 51 7.1414
110 41 6.4031
120 34 5.8310
130 35 5.9161
140 34 5.8310
150 24 4.8990
160 24 4.8990
170 19 4.3589
180 21 4.5826
190 20 4.4721
200 18 4.2426
210 21 4.5826
220 15 3.8730
230 19 4.3589
240 12 3.4641
250 20 4.4721
260 20 4.4721
270 18 4.2426
280 18 4.2426
290 20 4.4721
300 12 3.4641
310 26 5.0990
320 17 4.1231
330 8 2.8284
340 6 2.4495
350 8 2.8284
360 10 3.1623
370 20 4.4721
380 14 3.7417
390 8 2.8284
400 10 3.1623
410 9 3.0000
420 8 2.8284
430 10 3.1623
440 13 3.6056
450 9 3.0000
460 5 2.2361
470 7 2.6458
480 11 3.3166
500 7 2.6458
510 9 3.0000
520 12 3.4641
530 4 2.0000
540 7 2.6458
550 10 3.1623
560 9 3.0000
580 8 2.8284
590 9 3.0000
600 5 2.2361
Script 1: (works with gnuplot>=5.0.0)
Here you assume that you have monotonic and unique y-values. With this you can use the option smooth unique (available at least in gnuplot 4.x versions) to reverse one curve. However, since this solution here uses datablocks and plotting style with table it requires at least gnuplot 5.0.0. Maybe with some workarounds and temporary files you can also get it to work with some 4.6 versions.
### fill between vertical curves
reset session
FILE = "SO50676753.dat"
set table $Temp
plot FILE u 1:2
plot FILE u (-$1):3 smooth unique
set table $Data
plot $Temp u 2:1 index 0 w table, \
'' u 2:(-$1) index 1 w table
unset table
set style fill solid 0.3
set grid x,y
plot $Data u 1:2 w filledcurves
### end of script
Script 2: (works with gnuplot>=5.2.0)
With this solution there are no special assumptions about the data, but since it uses indexing of datablocks it requires gnuplot>=5.2.0.
### fill between vertical curves
reset session
FILE = "SO50676753.dat"
set table $Temp1
plot FILE u 2:1 w table
set table $Temp2
plot FILE u 3:1 w table
unset table
set print $Data
do for [i=1:|$Temp1|] { print $Temp1[i] }
do for [i=|$Temp2|:1:-1] { print $Temp2[i] } # reverse data
set print
set style fill solid 0.3
set grid x,y
plot $Data u 1:2 w filledcurves
### end of script
Result: (same for both scripts):

Gnuplot Plot a Candlesticks plot, but use a line inside the key?

I'm using a C++ program to automate a lot of plots with Gnuplot. I am making boxplots using the candlestick plot style, and I add median and mean by adding modified candlestick plots, based on the example in the manual:
plot ’stat.dat’ using 1:3:2:6:5 with candlesticks title ’Quartiles’, \
’’ using 1:4:4:4:4 with candlesticks lt -1 notitle
This works, but the key looks funny, because the Mean and Median are drawn as rectangles in the key, even though they appear as lines on the plot. Here is an example:
Is there an easy way to make the key display lines instead of rectangles?
Possible solutions could include plotting the mean and median as lines instead of candlesticks, but I would need to calculate the X positions of each start and stop point. Another solution could include drawing the key manaually using labels and lines. But these could be complex and not very flexible, so I'd thought to ask if any simpler solutions exist.
You can fake key entries by plotting "invisible" lines:
set terminal pngcairo
set output "candle_lines.png"
set boxwidth 0.4 relative
set xrange [0:4]
set yrange [0:100]
plot 'stat.dat' using 1:3:2:6:5 with candlesticks title 'Quartiles', \
'' using 1:4:4:4:4 with candlesticks lt -1 notitle, \
'' using 1:7:7:7:7 with candlesticks lt 0 notitle, \
NaN with lines title "Mean" lt -1, \
NaN with lines title "Median" lt 0
My stat.dat:
1 40 50 63 65 70 57
2 50 60 67 75 80 63
3 30 40 53 55 60 47
The result:

Gnuplot: plotting points with variable point types

I have x,y values for points in the first 2 colums and a number that indicates the point type (symbol) in the 3. column, in one data file. How do I plot data points with different symbols?
Unfortunately, there isn't a way (AFAIK) to automatically set the point of the plot from a column value using vanilla GNUPLOT.
However, there is a way to get around that by setting a linestyle for each data series, and then plotting the values based on that defined style:
set style line 1 lc rgb 'red' pt 7 #Circle
set style line 2 lc rgb 'blue' pt 5 #Square
Remember that the number after pt is the point-type.
Then, all you have to do is plot (assuming that the data in "data.txt" is ordered ColX ColY Col3):
plot "data.txt" using 1:2 title 'Y Axis' with points ls 1, \
"data.txt" using 1:3 title 'Y Axis' with points ls 2
Try it here using this data (in the section titled "Data" - also note that column 3 "Symbol" is noted used, it's mainly there for illustrative purposes):
# This file is called force.dat
# Force-Deflection data for a beam and a bar
# Deflection Col-Force Symbol
0.000 0 5
0.001 104 5
0.002 202 7
0.003 298 7
And in the Plot Script Heading:
set key inside bottom right
set xlabel 'Deflection (m)'
set ylabel 'Force (kN)'
set title 'Some Data'
set style line 1 lc rgb 'red' pt 7
set style line 2 lc rgb 'blue' pt 5
plot "data.txt" using 1:2 title 'Col-Force' with points ls 1, \
"data.txt" using 1:3 title 'Beam-Force' with points ls 2
The one caveat is of course that you have have to reconfigure your data input source.
REFERENCES:
http://www.gnuplotting.org/plotting-single-points/
http://www.gnuplotting.org/plotting-data/
Here is a possible solution (which is a simple extrapolation from gnuplot conditional plotting with if), that works as long as you don't have tens of different symbols to handle.
Suppose I want to plot 2D points in a coordinate system. I have only two symbols, that I arbitrarily represented with a 0 and a 1 in the last column of my data file :
0 -0.29450470209121704 1.2279523611068726 1
1 -0.4006965458393097 1.0025811195373535 0
2 -0.7109975814819336 0.9022682905197144 1
3 -0.8540692329406738 1.0190201997756958 1
4 -0.5559651851654053 0.7677079439163208 0
5 -1.1831613779067993 1.5692367553710938 0
6 -0.24254602193832397 0.8055955171585083 0
7 -0.3412654995918274 0.6301406025886536 0
8 -0.25005266070365906 0.7788659334182739 1
9 -0.16853423416614532 0.09659398347139359 1
10 0.169997438788414 0.3473801910877228 0
11 -0.5252010226249695 -0.1398928463459015 0
12 -0.17566296458244324 0.09505800902843475 1
To achieve what I want, I just plot my file using conditionals. Using an undefined value like 1/0 results in no plotting of the given point:
# Set styles
REG_PTS = 'pointtype 7 pointsize 1.5 linecolor rgb "purple"'
NET_PTS = 'pointtype 4 pointsize 1.5 linecolor rgb "blue"'
set grid
# Plot each category with its own style
plot "data_file" u 2:($4 == 0 ? $3 : 1/0) title "regular" #REG_PTS, \
"data_file" u 2:($4 == 1 ? $3 : 1/0) title "network" #NET_PTS
Here is the result :
Hope this helps
Variable pointype (pt variable) was introduced (I guess) not until gnuplot 5.2.0 (Sept 2017) (check help points).
Just in retrospective, another (awkward) solution would be the following for those who are still using such early versions.
Data:
1 1.0 4 # empty square
2 2.0 5 # filled square
3 3.0 6 # empty circle
4 4.0 7 # filled circle
5 5.0 8 # empty triangle up
6 6.0 9 # filled triangle down
7 7.0 15 # filled pentagon (cross in gnuplot 4.6 to 5.0)
Script: (works from gnuplot>=4.6.0, March 2012; but not necessary since 5.2.0)
### variable pointtype for gnuplot>=4.6
reset
FILE = 'SO23707979.dat'
set key noautotitle
set offsets 1,1,1,1
set pointsize 4
stats FILE u 0 nooutput
N = STATS_records # get the number of rows
p0=x1=y1=NaN
plot for [n=0:N-1 ] FILE u (x0=x1, x1=$1, x0):(y0=y1, y1=$2, y0):(p0=$3) \
every ::n::n w p pt p0 lc rgb "red", \
FILE u 1:2 every ::N-1::N-1 w p pt p0 lc rgb "red"
### end of script
Result:

Resources