gnuplot: errorbars with pointtype variable - gnuplot

I want to plot data with error bars and variable point type. I know, I could do it with two commands:
array data = [7, 2, 5, 6]
pl [0.7:4.3] data us 1:2:(0.8) w e pt -1, "" us 1:2:(7-($1==3)) pt var lc 1
I would expect that something like pl [0.7:4.3] data us 1:2:(0.8):(6) w e pt var would work, but it doesn't. It seems gnuplot interprets it as 4 columns: x y xlow xhigh.
It does not happen with variable linecolor (lc var).
So can I plot variable pointtype with one command instead of two?
Drawbacks of two commands: more typing, more difficult to read and maintain, two legend entries (could be hidden with t "", but then it can't be toggled with mouse click).

If you use with yerrobars instead of with errorlines it seem to work for gnuplot 5.4.4 and 5.4.5, however, not for gnuplot<=5.4.0 and not for the gnuplot5.5.0 binary which I have. Pretty strange...
Script: (seems to work only for gnuplot 5.4.4 and 5.4.5)
### yerrorbars with variable pointtype
reset session
array data = [7, 2, 5, 6]
plot [0.7:4.3] data u 1:2:($2-0.8):($2+0.8):(7-($1==3)) w yerrorbars \
pt var ps 3 lw 2 lc "red"
### end of script
Result:

Known bug. Fixed recently, not yet in distributed release. Description below is from the commit log.
fix variable pointtype, pointsize in plot styles yerrorlines and yerrorbars
Despite what the documentation said, these two plot styles did not
correctly track variable point properties, with the exception of
using x:y:ylow:yhigh:(varprop) with yerrorbars
and even there the variable pointsize was lost unless pointintervalbox
was set to 0.
Now both plot styles work for either x:y:ydelta or x:y:ylow:yhigh
and either or both of pointstyle variable and pointtype variable.
It remains a limitation that "pt variable" cannot load character
point types. This is due to field overloading in struct coordinate.

Related

Place tics at values stored in variables

I have used the stats command to store the x-postion of absolute maxima in my plot of seven datasets in seven variables, grN_pos_max_y with N that goes from 1 to 7. Can I place the tics in the x-axis at the positions specified by these variables?
I tried using
$maxima << EOD
gr1_pos_max_y
gr2_pos_max_y
gr3_pos_max_y
gr4_pos_max_y
gr5_pos_max_y
gr6_pos_max_y
gr7_pos_max_y
EOD
and then
plot ..., \
$maxima u 1:(NaN):xticlabel(1) notitle
but I don't know how to read variables into a data block (if I replace the variable names by their values, however, it works).
Edit: This is what I want (I plotted it using Ethan's answer)
I'm not entirely sure I understand what you want, but this may get you partway there:
set xtics add (gr1_pos_max_y, gr2_pos_max_y, gr3_pos_max_y, gr4_pos_max_y, gr5_pos_max_y, gr6_pos_max_y, gr7_pos_max_y)
plot 'whatever'
That will get you plain (unlabeled) tic marks in addition to whatever tic marks and labels are being generated automatically.
If you want only these marks and no auto-generated marks, remove the keyword add.
If you want to place labels to go with these new tics, change it to:
set xtics add ( "Max 1" gr1_pos_maxy, "Max 2" gr2_pos_maxy, ...
This is all assuming you want these tics to label a plot that contains something other than the tics themselves. If you want only a plot of these y values, perhaps as impulses?, please re-phrase the question or show a sketch of what you want it to look like.
There is no need for awk, you can do it all in gnuplot.
put stats into a loop and write the STATS values into a datablock $Maxima
plot your data and $Maxima as Ethan suggested with impulses
you can also plot the maxima y-value as labels in the graph
The script needs to be adapted depending on your file naming scheme.
Script:
### extract maxima from several files
reset session
N = 7
myFile(n) = sprintf("SO72750257_%d.dat",n)
# create some "random" test data
do for [n=1:N] {
set table myFile(n)
f(x) = -a*(x-x0)**2 +y0
x0 = (n-1)*10./N + rand(0)*10./N
a = rand(0)*50+10
y0 = rand(0)*80+20
plot [0:10] '+' u 1:(f(x))
unset table
}
# extract maxima
set print $Maxima
do for [n=1:N] {
stats myFile(n) u 1:2 nooutput
print sprintf("%.1f %.1f", STATS_pos_max_y, STATS_max_y)
}
set print
set yrange[0:]
set offsets graph 0.05, graph 0.05, graph 0.1, 0
set xtics () # remove all xtics
set key out noautotitle
plot for [i=1:N] myFile(i) u 1:2 w l ti sprintf("Set %d",i), \
$Maxima u 1:2:($0+1):xtic(1) w impulses lc var dt 2, \
$Maxima u 1:2:2 w labels offset 0, char 1
### end of script
Result:

Weird behavior on plotting parametric functions (or their corresponding datablock) when using lines

I have some weird behavior on plotting parametric functions and/or their corresponding datablock when using lines.
The plot seem don't obey the linestyle (row 1), at the same time the default linetype applied seems reversed when comparing plots come from functions or datablock (row 2).
Curiously the plot seems to inherit the linewidth from linestyle (row 3).
Only when using linecolor (row 4) the plots looks like correct.
Here are the code, tested under 5.2.8 and 5.4 rc1 versions:
reset
set terminal pngcairo size 750,9.0 font ",10"
set output "parametric.png"
unset tics
unset border
set view equal xyz
set view ,,2
set view 100,30
set xyplane 0
set hidden3d
set parametric
set urange [0:2*pi]
set vrange [0:pi/2]
set style line 1 lc "red" lw 2
f(u,v) = cos(u)*cos(v)
g(u,v) = sin(u)*cos(v)
h(v) = sin(v)
set table $hemisphere
splot f(u,v), g(u,v), h(v)
unset table
set multiplot layout 4,2 columnsfirst
splot f(u,v), g(u,v), h(v) w l ls -1 t "Using functions (with ls -1 )"
splot f(u,v), g(u,v), h(v) w l lt 3 t "Using functions (with lt 3)"
splot f(u,v), g(u,v), h(v) w l ls 1 t "Using functions (with custom ls 1)"
splot f(u,v), g(u,v), h(v) w l lc "red" t "Using functions (with lc 'red')"
splot $hemisphere w l ls -1 t "Using datablock (with ls -1)"
splot $hemisphere w l lt 3 t "Using datablock (with lt 3)"
splot $hemisphere w l ls 1 t "Using datablock (with custom ls 1)"
splot $hemisphere w l lc "red" t "Using datablock (with lc 'red')"
unset multiplot
Additionally, if you taken a close look on surface it has a reversed line segment.
What is happen here? Am I missing something?
Basic reason:
From the docs (selected text from help hidden3d)
Syntax:
set hidden3d {defaults} |
{{offset <offset>} | {nooffset}}
[...]
The first option, `offset`, influences the linetype used for lines on the
'back' side. Normally, they are drawn in a linetype one index number higher
than the one used for the front, to make the two sides of the surface
distinguishable. You can specify a different linetype offset to add
instead of the default 1, by `offset <offset>`. Option `nooffset` stands for
`offset 0`, making the two sides of the surface use the same linetype.
Notice that there is no mention of linestyles, as opposed to linetypes. The hidden3d algorithm carries out a complicated process of assigning colors to individual line segments that is explicitly based on the numerical linetype. Generation of the line sample in the key is more generic. It apparently fails to duplicate exactly what happens if hidden3d is active, so let's call that much a bug.
Wrong color for one line segment: I think this must be due to round-off error somewhere. Minute changes to the view angle or even to the terminal size cause the artifact to go away.
Doesn't really help anything but explains why it is the way you see it: In gnuplot 5 the use of linetypes pretty much supplemented the older mechanism of linestyles. There is partial backwards compatibility via the command set style increment user, which triggers in many places where the program has to pick a color for the "next thing" whatever that might be. But it doesn't catch all the places where the multiple colors are involved, and hidden3d is one of those places.

How to draw a filledcurve graph with GNUPlot by using 2 csv files

If I have 2 csv files ("CSV1.csv" dataname_1 and "CSV2.csv" dataname_2), how can I draw filled curve graph from the data of 2 csv files. The formats of these CSV files are identical, where 2 is timestamps and 5 is the value thus the using 2:5
I am trying this:
plot dataname_2 using 2:5 title "Above" with filledcurves above lc rgb 'blue',\
dataname_1 using 2:5 title "Below" with filledcurves below lc rgb 'red',\
dataname_2 using 2:5 title "Engine Starts" with lines lc rgb "#1E90FF",\
dataname_1 using 2:5 title "Engine Hours" with lines lc rgb "#FF1493"
I need to modify the code above so that the output is:
A solution which will probably always work is to prepare the data with whatever external tool in such a way that gnuplot can handle and plot it. I'm aware that the philosophy of gnuplot is to concentrate on plotting and not necessarily on data preparation for plotting. However, it is always good to have a minimum set of features to do some basic data preparation.
In your case you have several problems, well, let's call it challenges ;-)
with filledcurves requires data within the same file or datablock
however, gnuplot cannot easily merge datafiles line by line (it can with some workaround, see: https://stackoverflow.com/a/61559658/7295599). Simply appending would be no problem with gnuplot.
the latter doesn't help you since with filledcurves needs identical x for upper and lower curve, i.e. x,y1,y2 and your data has x1,y1 and x2,y2
however, gnuplot cannot easily resample data (it can with some workaround, see: Resampling data with gnuplot)
with filledcurves cannot directly fill curves with non-monotonic increasing x (not the case with your data. Here just for illustration purposes) (it can with some workaround see: https://stackoverflow.com/a/53769446/7295599 or https://stackoverflow.com/a/56176717/7295599)
So a workaround for all this could be the following (works with gnuplot 5.2, maybe can be tweaked to work with earlier versions):
Assumptions:
Data x1,y1 and x2,y2 in two files or datablocks
Data has not necessarily identical x, i.e. x1,y1 and x2,y2
Data may contain non-monotonic x
the two curves have only one intersection (well, the workaround below will just take the first one)
Procedure:
if not already, get the data into a datablock.
Find the intersection of the curves.
Create new datablocks: Filled1 using Data1 from the beginning to the intersection point and using Data2 backwards from the intersection point to the beginning. Filled2 using Data1 from the end backwards to the intersection point and using Data2 from the intersection point to the end.
Plot $Data1 and $Data2 with lines and $Filled1 and $Filled2 with filledcurves
Steps 2 and 3, probably will not be much shorter in another programming language unless there are dedicated functions.
Get files to datablock: (see also here gnuplot: load datafile 1:1 into datablock)
# get files to datablocks
set table $Data1
plot 'myFile1.dat' u 1:2 w table
set table $Data2
plot 'myFile2.dat' u 1:2 w table
unset table`
Code: (copy&paste for gnuplot >=5.2)
### fill intersecting curves from two files not having identical x
reset session
$Data1 <<EOD
1 1
2 0
4 1
3 3
5 5
6 6
8 8
9 9
EOD
$Data2 <<EOD
1 3
3.5 5
7.5 1
9 7
EOD
# orientation of 3 points a,b,c: -1=clockwise, +1=counterclockwise
Orientation(a,b,c) = sgn((word(b,1)-word(a,1))*(word(c,2)-word(a,2)) - \
(word(c,1)-word(a,1))*(word(b,2)-word(a,2)))
# check for intersection of segment a-b with segment c-d,
# 0=no intersection, 1=intersection
IntersectionCheck(a,b,c,d) = \
Orientation(a,c,b) == Orientation(a,d,b) || \
Orientation(c,a,d) == Orientation(c,b,d) ? 0 : 1
# coordinate of intersection
M(a,b) = real(word(a,1)*word(b,2) - word(a,2)*word(b,1))
N(a,b,c,d) = (word(a,1)-word(b,1))*(word(c,2)-word(d,2)) - \
(word(a,2)-word(b,2))*(word(c,1)-word(d,1))
Px(a,b,c,d) = (M(a,b)*(word(c,1)-word(d,1)) - (word(a,1)-word(b,1))*M(c,d))/N(a,b,c,d)
Py(a,b,c,d) = (M(a,b)*(word(c,2)-word(d,2)) - (word(a,2)-word(b,2))*M(c,d))/N(a,b,c,d)
Intersection(a,b,c,d) = sprintf("%g %g", Px(a,b,c,d), Py(a,b,c,d))
stop = 0
do for [i=1:|$Data1|-1] {
a = $Data1[i]
b = $Data1[i+1]
do for [j=1:|$Data2|-1] {
c = $Data2[j]
d = $Data2[j+1]
if (IntersectionCheck(a,b,c,d)) {
i0 = i; j0 = j
stop=1; break }
}
if (stop) { break }
}
# create the datablocks for the outline to be filled
set print $Filled1
do for [k=1:i0] { print $Data1[k] }
print Intersection(a,b,c,d)
do for [k=j0:1:-1] { print $Data2[k] }
set print $Filled2
do for [k=|$Data1|:i0+1:-1] { print $Data1[k] }
print Intersection(a,b,c,d)
do for [k=j0+1:|$Data2|] { print $Data2[k] }
set print
set key top left
plot $Filled1 u 1:2 w filledcurves lc rgb 0x3f48cc, \
$Filled2 u 1:2 w filledcurves lc rgb 0xed1c24, \
$Data1 u 1:2 w lp pt 7 lw 5 lc rgb 0x99d9ea, \
$Data2 u 1:2 w lp pt 7 lw 5 lc rgb 0xff80c0
### end of code
Result:

Fitting graph and draw lines by selecting ranges in horizontal axis

I am trying to plot a graph and fitting it using a linear line.
f1(x)=a1+b1*x
fit [0:80] f1(x) 'diff-xy-bcmLyo25perS.dat' via a1,b1
f2(x)=a2+b2*x
fit [100:220] f2(x) 'diff-xy-bcmLyo25perS.dat' via a2,b2
And I tried to plot both the plots into the same graph using command:
f(x) = x < 60 ? f1(x) : f2(x)
plot 'diff-xy-bcmLyo25perS.dat' using 1:2 with lines linestyle 1 title "{/Symbol b}BCMal-C_{12}C_{8}", f(x) lw 3.0 lc rgb 'black'
I get a plot as above.
In that plot one could see that there are two lines intersecting at 80 (horizontal scale) and it makes shape like 'v'.
I wish to eliminate that 'v' shape intersection and I would like to get two separate lines, one from 0 to 80 and the other one from 100 to 220.
How I could get this?
Appreciate any help.
Thanks in advance.
You could exploit that gnuplot doesn't plot infinity and NaN values (as 1.0/0)
Using
plot_if_in_range(y,x,lower,upper) = (x>=lower && x<=upper)?(y):(1.0/0)
You could easily plot any function in given domain:
plot plot_if_in_range(exp(x) , x, -5, 2), \
plot_if_in_range(sin(x)+x, x, -2, 5)
With gnuplot 5.0 you can specify different range for different functions:
set style data lines
plot 'diff-xy-bcmLyo25perS.dat' using 1:2 ls 1, \
[0:80] f1(x) lw 3.0 lc rgb 'black',\
[100:220] f2(x) lw 3.0 lc rgb 'black'
Note, that this works only, because you first plot the data file. Plotting only
plot [0:80] f1(x), [100:220] f2(x)
wouldn't work, since the first range settings are equivalent to a global set xrange [0:80] (it has always been), so that the second function wouldn't be visible at all.
However, in your case it should work fine.
Edit:
Sorry, this is basically the same idea as Sergei Izmailov's answer which I missed.
Answer:
Use the special file "+", which provides x values for your plot that you can then sample using a function of your choice, including one that ignores input if it's outside of range. Then you can use your f1(x) and f2(x) directly:
plot "+" using ($1):(0 < $1 && $1 < 80 ? f1($1) : 1/0), \
"+" using ($1):(100 < $1 && $1 < 220 ? f2($1) : 1/0)

Conditional execution of the plot command

I'm using gnuplot to create graphs of a rather simply structured file. In particular, the file contains 8 columns, the first 4 columns describe "measured" values, the second 4 "predicted" values. I want to create two plots, one comprising only measured values, one comprising both.
Since my gnuplot script is rather long, I would like to introduce a variable to set the flag whether predicted values should be contained or not. I want to use different line types, axis and labels, and hence, cannot use the "using" approach.
Here is what I use so far:
plot 'file.txt' using 2:xticlabels(1) title "Val1 (Measured)" with
lines axes x1y1, '' using 3:xticlabels(1) title "Val2 (Measured)"
with linespoints axes x1y2;
if (settingCompareToAggretagion == 1)
plot 'file.txt' using 4:xticlabels(1) title "Val1 (Aggregated)" with lines
axes x1y1, '' using 5:xticlabels(1) title "Val2" with linespoints axes x1y2;
There is obviously the problem that I get two plots but one. I also tried to "attach" the second set of plots to the command with an inline if condition (bool.exrp. ? x : y) but this is not working.
Thank you!
That can be done with the replot command:
plot x, x**2
replot x+5, x**2 + 5
That plots a single graph with four plots.
In your case the following should work:
plot 'file.txt' u 2:xtic(1) t "Val1 (Measured)" w l,\
'' u 3 t "Val2 (Measured)" w lp axes x1y2
if (settingCompareToAggregation == 1) {
replot 'file.txt' u 4 t "Val1 (Aggregated)" w l,\
'' u 5 t "Val2 (Aggregated)" w lp axes x1y2
}

Resources