gnuplot: connecting last to first point in polar plot - gnuplot

I have a data file like
0 8.4
60 7.5
120 8.9
180 9.2
240 8.3
300 6.9
My gnuplot script looks this way:
unset xtics
unset ytics
set polar
set angle degrees
set rrange [0:10]
set rtics 2
set grid polar
set size square
p 'data.txt' u 1:2 w lp
My problem is that I want the first and last data point to be connected by the line. I get the expected result if I repeat the first point in my data file again at the end of the file like:
0 8.4
60 7.5
120 8.9
180 9.2
240 8.3
300 6.9
0 8.4
Ist this the only way to get the expected result? I'm asking because my real file has a lot of data-sets which I reference by the gnuplot index command like p 'data.txt' index 1276 u 1:2 w lp and always duplicating the first data point again at the end at each block is quite annoying.

A solution is to connect the first and last point by doing a second plot with only those two points.
Using the syntax every (check help plot every), you can plot only the first point (number 0) and last point (number N)
with :
every N::0::N
In the example you gave, the line 9 should be modified as follow :
p 'data.txt' u 1:2 w lp ls 1, 'data.txt' u 1:2 ev 5::0::5 w lp ls 1 noti
A first flaw in this solution is you have to specify the style of the second line to ensure it looks like the first one, and does not appear in the keys (hence the ls 1 and noti).
The second flaw is you need to know the number of points in your block. It can be obtained in gnuplot using the stats syntax, as shown here. For your example, I would use it on the column 0 (for the points numbers) as follows :
stats 'data.txt' u 0
N = STATS_max

Related

How to sprintf() last data value in Gnuplot key?

I'm working on a temperature graph and would like to put the last data point in the title. I can use column(2) to kind of do this but I'd like to add some descriptive text as well. I'm trying the code below to concatentate some text with the data value but getting this error: line 0: f_sprintf: attempt to print numeric value with string format
plot "/tmp/data.txt" using 1:2 with lines ls 2 title sprintf('Current :%sF', column(2))
I've tried changing the sprintf modifer to %d along with various flavors of concatenation with the dot character and haven't found the right combination.
Most probably there are various solutions. The first possibility which comes to my mind (I guess requiring gnuplot >5.2) is using keyentry, check help keyentry. While plotting you are asigning column 2 to a variable. After plotting, this variable holds the last value of column 2, which you use later in keyentry, which is a keyentry without plotting anything. There would also be workarounds for older gnuplot versions.
Code:
### last value into key
reset session
$Data <<EOD
1 7.1
2 6.2
3 5.3
4 4.4
5 3.5
6 2.6
7 1.7
8 0.8
EOD
plot $Data u 1:(a=$2) w lp pt 7 lc 1 notitle, \
keyentry w lp pt 7 lc 1 ti sprintf("Last y value: %g",a)
### end of code
Result:
The problem here is that the title string is evaluated by gnuplot before the data is parsed and plot is performed.
A trick is to store the last value of temperature, and plot it afterwards.
T=0
plot "/tmp/data.txt" using 1:(T=column(2)) w l ls 2 notitle, \
1/0 w l ls 2 title sprintf('Current: %.1fF', T)

Plotting Condition Lines

Suppose I have the following data:
"1,5"
"2,10"
""
"3,4"
"4,2"
""
"5,6"
"6,10"
I want to graph this using gnuplot with a line between each condition, similar to this display:
How might this be accomplished? I have looked into gridlines, but that does not seem to suit my need. I am also looking for a solution that will automatically draw condition / phase lines between each break in the data set.
As mentioned in the comments and explained in the linked question and its answers, you can draw arbitrary lines manually via set arrow ... (check help arrow).
However, if possible I don't want to adjust the lines manually every time I change the data or if I have many different plots.
But, hey, you are using gnuplot, so, make it automated!
To be honest, within the time figuring out how it can be done I could have changed a "few" lines and labels manually ;-). But now, this might be helpful for others.
The script below is written in such a way that it doesn't matter whether you have zero, one or two or more empty lines between the different blocks.
Comments:
the function valid(1) returns 0 and 1 if column(1) contains a valid number (check help valid).
the vertical lines are plotted with vectors (check help vectors). The x-position is taken as average of the x-value before the label line and the x-value after the label line. The y-value LevelY is determined beforehand via stats (check help stats).
the labels are plotted with labels (check help labels) and positioned at the first x-value after each label line and at an y-value of LevelY with an offset.
Script:
### automatic vertical lines and labels
reset session
$Data <<EOD
Baseline
1 10.0
2 12.0
3 10.5
4 11.0 # zero empty lines follow
Treatment
5 45.0
6 35.0
7 32.5
8 31.0 # one empty line follows
Baseline
9 14.0
10 12.8
11 12.0
12 11.3 # two empty lines follow
Treatment
13 35.0
14 45.0
15 45.0
16 37.0
EOD
set offset 1,1,1,1
set border 3
set title "Student Performance" font ",14"
set xlabel "Sessions"
set xtics 1 out nomirror
set ylabel "Number of Responses"
set yrange [0:]
set ytics out nomirror
set key noautotitle
set grid x,y
stats $Data u 2 nooutput
LevelY = STATS_max # get the max y-level
getLinePosX(col) = (v0=v1,(v1=valid(col))?(x0=x1,x1=column(1)):0, v0==0?(x0+x1)/2:NaN)
getLabel(col) = (v0=v1,(v1=valid(col))?0:(h1=strcol(1),h0=h1),column(1))
plot x1=NaN $Data u (y0=(valid(1)?$2:NaN),$1):(y0) w lp pt 13 ps 2 lw 2 lc "red", \
x1=v1=NaN '' u (getLinePosX(1)):(0):(0):(LevelY) w vec nohead lc "black" lw 1.5 dt 2, \
v1=NaN '' u (getLabel(1)):(LevelY):(sprintf("%s",v0==0?h0:'')) w labels left offset 0,1.5 font ",12"
### end of script
Result:

How to remove line between "jumping" values, in gnuplot?

I would like to draw a line with plots that contain "jumping" values.
Here is an example: when we have plots of sin(x) for several cycles and plot it, unrealistic line will appear that go across from right to left (as shown in following figure).
One idea to avoid this might be using with linespoints (link), but I want to draw it without revising the original data file.
Do we have simple and robust solution for this problem?
Assuming that you are plotting a function, that is, for each x value there exists one and only one corresponding y value, the easiest way to achieve what you want is to use the smooth unique option. This smoothing routine will make the data monotonic in x, then plot it. When several y values exist for the same x value, the average will be used.
Example:
Data file:
0.5 0.5
1.0 1.5
1.5 0.5
0.5 0.5
Plotting without smoothing:
set xrange [0:2]
set yrange [0:2]
plot "data" w l
With smoothing:
plot "data" smooth unique
Edit: points are lost if this solution is used, so I suggest to improve my answer.
Here can be applied "conditional plotting". Suppose we have a file like this:
1 2
2 5
3 3
1 2
2 5
3 3
i.e. there is a backline between 3rd and 4th point.
plot "tmp.dat" u 1:2
Find minimum x value:
stats "tmp.dat" u 1:2
prev=STATS_min_x
Or find first x value:
prev=system("awk 'FNR == 1 {print $1}' tmp.dat")
Plot the line if current x value is greater than previous, or don't plot if it's less:
plot "tmp.dat" u ($0==0? prev:($1>prev? $1:1/0), prev=$1):2 w l
OK, it's not impossible, but the following is a ghastly hack. I really advise you add an empty line in your dataset at the breaks.
$dat << EOD
1 1
2 2
3 3
1 5
2 6
3 7
1 8
2 9
3 10
EOD
plot for [i=0:3] $dat us \
($0==0?j=0:j=j,llx=lx,lx=$1,llx>lx?j=j+1:j=j,i==j?$1:NaN):2 w lp notit
This plots your dataset three times (acually four, there is a small error in there. I guess i have to initialise all variables), counts how often the abscissa values "jump", and only plots datapoints if this counter j is equal to the plot counter i.
Check the help on the serial evaluation operator "a, b" and the ternary operator "a?b:c"
If you have data in a repetitive x-range where the corresponding y-values do not change, then #Miguel's smooth unique solution is certainly the easiest.
In a more general case, what if the x-range is repetitive but y-values are changing, e.g. like a noisy sin(x)?
Then compare two consecutive x-values x0 and x1, if x0>x1 then you have a "jump" and make the linecolor fully transparent, i.e. invisible, e.g. 0xff123456 (scheme 0xaarrggbb, check help colorspec). The same "trick" can be used when you want to interrupt a dataline which has a certain forward "jump" (see https://stackoverflow.com/a/72535613/7295599).
Minimal solution:
plot x1=NaN $Data u 1:2:(x0=x1,x1=$1,x0>x1?0xff123456:0x0000ff) w l lc rgb var
Script:
### plot "folded" data without connecting lines
reset session
# create some test data
set table $Data
plot [0:2*pi] for [i=1:4] '+' u 1:(sin(x)+rand(0)*0.5) w table
unset table
set xrange[0:2*pi]
set key noautotitle
set multiplot layout 1,2
plot $Data u 1:2 w l lc "red" ti "data as is"
plot x1=NaN $Data u 1:2:(x0=x1,x1=$1,x0>x1?0xff123456:0x0000ff) \
w l lc rgb var ti "\n\n\"Jumps\" removed\nwithout changing\ninput data"
unset multiplot
### end of script
Result:

Gnuplot: draw error bars of data points outside plotting range

If I set a specific yrange and plot in a pdf terminal with this plot command:
plot "data.dat" u 1:4:5:6 w yerrorbars pt 6 ps 0.5 t "R_t"
errorbars that belong to data points outside the yrange, but end inside the yrange are not shown.
How do I force gnuplot to draw those. I already tried "set clip one/two"
The only workaround I found is to plot the data 3 times, once for the central point and once for each side of the error bar.
Use "-" as symbol for the errorbars and use their own "errorbars" to draw a line to the central point.
You could use multiplot to achieve this.
Set your plot to have zero margins, so the axes are on the border of the canvas, and switch of all tics and borders for the first plot.
Switch on the axes, tics etc. again, and do an empty plot that you set at the correct position using set size and set origin. You'll have to do some math to calculate the exact position.
#MaVo159, you can reduce it to plotting only twice by using with yerrorbars and with vectors (check help vectors). You need to set the proper arrow style, check help arrowstyle.
However, this works only for gnuplot>=5.2.3, for earlier versions there seems to be a bug which plots the arrowhead at the wrong side for some of the vectors extending the graph.
You nevertheless have to plot once with yerrorbars in order to get the proper legend.
Script: (works for gnuplot>=5.2.3, May 2018)
### plot errorbars from points outside the range
reset
$Data <<EOD
1 9 5.11 8.32
2 8 6.20 9.22
3 6 5.31 6.31
4 5 4.41 5.51
5 4 3.31 4.71
6 2.9 2.81 3.71
7 2 1.11 3.41
EOD
set yrange[3:7]
set offsets 1,1,0,0
set style arrow 1 heads size 0.05,90 lw 2 lc 1
set multiplot layout 2,1
plot $Data u 1:2:3:4 w yerrorbars pt 6 ps 2 lw 2
plot $Data u 1:2:3:4 w yerrorbars pt 6 ps 2 lw 2, \
'' u 1:3:(0):($4-$3) w vec as 1 notitle
unset multiplot
### end of script
Result:
You could modify your data file: Because the central value of the data point is outside the plot range you could set it equal to the errorbar's end point that would be still visible in your plot.
Example:
plot range: set yrange[-2:2]
data point: 1, -3, -1, -4 (x, y, ylow, yhigh)
set data point to: 1, -1, -1, -4
Attention: Since you have to edit your data file you should
Make a copy of the original data file
Be very careful when editing the file
Keep in mind, that when changing the plot range such that the central
value of the data point becomes visible you have to use the original data point. Otherwise you will see the correct error bar but there will be no central value plotted. (this is equivalent to setting 'point type' to 0)

Displaying markers on specific values in Gnuplot's line plot

I have data for a CDF in a file which looks like the following:
0.033 0.0010718113612
0.034 0.0016077170418
0.038 0.0021436227224
... ...
... ...
0.847 0.999464094319
0.862 1.0
First column is the X-axis value and the second column is the CDF value on Y-axis. I set the line style as follows:
set style line 1 lc rgb 'blue' lt 1 lw 2 pt 7 ps 0.75 # --- blue
and subsequently plot the line with the following:
plot file1 using 1:2 title 'Test Line CDF' with linespoints ls 1
This all works fine, the problem seems to be that my CDF file is pretty big (about 250 rows) and Gnuplot would plot the marker/point (a circle in this case) for every data point. This results in a very "dense" line because of the over-concentration of markers such that the underlying line is almost not visible as I show in an example image below:
How can I selectively draw the markers so that instead of having them on all data points, I plot them after every 50 data points, without having to decrease the number of data points (which I believe is what "every n" in the plot command would do) in my data file or decrease the marker size?
There is no need to use two plots commands, just use the pointinterval option:
plot 'data' pointinterval 5 with linespoints
That plots every line segment, but only every fifth point symbol.
The big advantage is, that you can control the behaviour with set style line:
set style line 1 lc rgb 'blue' lt 1 lw 2 pt 7 ps 0.75 pi 5
plot 'data' w lp ls 1
You can plot the same function twice, once with lines only, and then with points every n points. This will draw less points without decreasing the amount of segments. I think this is what you want to achieve. For this example I have done set table "data" ; plot sin(x) to generate numerical sampling of the sin(x) function.
What you have at the moment is:
plot "data" with linespoints pt 7
which gives
Now you can do the following:
plot "data" with lines, "data" every 10 with points pt 7 lc 1
which gives what you want:
You can change the styling to meet your needs.
Although #Miguel beat me to it, but I'm also posting my solution below:
The idea is to once draw the line and then draw the points with the "every n" specifier. I changed my own Gnuplot script in the following manner. A kind of hack but works:
set style line 1 lc rgb 'blue' lt 1 lw 2 pt 7 ps 0 # --- blue
plot file1 using 1:2 title '' with linespoints ls 1, "" using 1:2 every 20 title 'Test Line CDF' with points ls 1 ps 0.75
This retains the nice curve, without quantizing it too coarsely while also keeping the points much better spaced.

Resources