gnuplot conditional 'using' causes broken x-axis - gnuplot

Tracking the battery discharge / charge on my phone. Data shaped like a 'V'. Charge percentage and elapsed time in seconds, like this:
100,0
74,8103
51,15304
24,23407
2,30609
23,33286
55,37360
76,40064
100,44132
Here's how I'm processing n files and plotting them together:
plots=""
my_xrange=0
files=system("ls -1B data/*.csv | sort -k2 -t '-'")
do for [ file in files ] {
this="'".file."' ".'using ($2/3600):1 notitle, '
plots=plots.this
}
eval('plot '.plots)
(happy plot elided because of too many links)
Then the boss comes by and says the "uphills" are distracting, can I plot just the "downhills" pretty please? No worries, stats will give me the minima, so I xrange. Woot!
plots=""
my_xrange=0
files=system("ls -1B *.csv | sort -k2 -t '-'")
do for [ file in files ] {
stats file using ($2/3600):1 prefix "STATS" nooutput
if ( STATS_pos_min_y > my_xrange ) { my_xrange = STATS_pos_min_y }
this="'".file."' ".'using ($2/3600):1 notitle, '
plots=plots.this
}
print sprintf( 'stats: plot xrange is %.2f', my_xrange )
set xrange [0:my_xrange]
eval('plot '.plots)
xrange obliterates some uphills
I know there's got to be a way to just not plot the uphills, so I wind up with using conditional.
this="'".file."' ".'using (($2/3600) <= STATS_pos_min_y ? $1 : 1/0) notitle, '
which does effectively kill the uphills, but does two bad things to the plot:
the X axis values don't match the previous plot
the plot lines are merged on top of one-another
broken things
I need to use $2/3600 because I want things to be expressed in terms of hours. Oh, sure, I could write a script to massage the data before it even gets to gnuplot, but that's admitting defeat.
What have I not understood in my use of using?

The plot command for your whole data (purple line) is
plot file using ($2/3600):1 with linespoints
while that for the conditional data (blue line) is
plot file using ((($2/3600) <= STATS_pos_min_y) ? $1 : 1/0) with linespoints
This using statement selects only those data points for which ($2/3600) <= STATS_pos_min_y. However, you do not specify where on the x-axis those data points should be plotted, so gnuplot assumes it's just the line number in the data file (0,1,2,3,4). You have to specify the position on the x axis just like you did in the unconditional plot:
plot file using ($2/3600):((($2/3600) <= STATS_pos_min_y) ? $1 : 1/0) with linespoints
should do it.
By the way, formatting is rather limited in SO comments. To post code it's usually better to edit the question where you have more formatting options.

Related

Getting plot title and caption data from the data file

Consider the following file that I want to plot using gnuplot: Servos20211222_105253.csv
# Date/Time 2021/12/22, 10:52:53
# PonE=0,LsKp=200,LsKi=0,LsKd=250,HsKp=40,HsKi=0,HsKd=130,Sp=800,TDEC=1175137
#
# Rel. Time, currentPos, PosPID, currentSpeed, speedPID, Lag, ServoPos
0.00000,4693184,0,0,0,0,4693184
0.00000,4693184,2300,0,368,0,4693184
0.00391,4693185,2300,12,367,0,4693184
:
:
I would like to:
set the plot title to the date/time from the first comment record.
display the record that starts "# PonE" as a caption.
extract the value for TDEC and plot a horizontal line with the name "Target"
I have some influence over the format of the header records, so if (for example) it would be better that they were not comments but provided in some other way, then that can be done.
It is a common problem to get text values from files using only gnuplot. If you can use OS and shell dependent solutions, I'd suggest to use remove the comments from the file and try something like
set title "`head -1 Servos20211222_105253.csv`"
You can place text anywhere using set label <"label text">, where the label text can be the 2nd line from the file.
You can plot a straight line using plot:
p sin(x), 0.5 title "TDEC"
But instead of 0.5, you need to get the value using shell scripts again, e.g. the cut unix command.
There are ways with gnuplot only, although sometimes a bit cumbersome compared with using tools which you have available on Linux (or comparable tools which you need to install on Windows).
Update: shorter and "simplified" script
One possible gnuplot-only way:
set commentschar to nothing, i.e. ''
assign the columns to variables and/or arrays, e.g. myDate, myTime, P[1..9].
Merge P[1..8] into a multi-line string Params by "mis"-using sum (check help sum)
Convert P[9] into a floating point number TDEC for plotting
Script: (modified the data a bit just for illustration)
### extract values from headers with gnuplot only
reset session
$Data <<EOD
# Date/Time 2021/12/22, 10:52:53
# PonE=0,LsKp=200,LsKi=0,LsKd=250,HsKp=40,HsKi=0,HsKd=130,Sp=800,TDEC=1175137
#
# Rel. Time, currentPos, PosPID, currentSpeed, speedPID, Lag, ServoPos
0.00000,1300000,0,0,0,0,4693184
0.00200,1200000,2300,0,368,0,4693184
0.00391,1100000,2300,12,367,0,4693184
EOD
set datafile separator comma commentschar ''
array P[9] # array to store parameters
stats $Data u ($0==0 ? (myDate=strcol(1)[3:], myTime=strcol(2)) : \
sum [_i=1:9] (P[_i] = _i==1 ? strcol(_i)[3:] : strcol(_i) ,0 )) \
every ::0::1 nooutput
set datafile commentschar # set back to default
Params = P[1]
Params = (sum [_i=2:8] (Params=Params.sprintf("\n%s",P[_i]),0),Params)
set title sprintf("%s %s", myDate, myTime)
TDEC = real(P[9][6:]) # convert to real number
set label 1 at graph 0.02, first TDEC P[9] offset 0,-0.7
set label 2 at graph 0.02, graph 0.85 Params
plot $Data u 1:2 w lp pt 7 title "Data", \
TDEC w l lc "red" title "Target"
### end of script
Result:

Iteratively generate datablocks in gnuplot

Is it possible to iteratively generate datablocks, where the name of the datablock is build up inside the loop?
Let's assume I have three fruits (in reality there are more):
array namelist[3] = ['apple', 'banana', 'pineapple']
I want to create three datablocks with the names $apple_data, $banana_data and $pineapple_data, so I tried the following:
do for [i=1:|namelist|] {
set table '$'.namelist[i]."_data"
plot ...
unset table
}
Unfortunately, instead of datablocks gnuplot created files with these names in the working directory. I guess gnuplot is checking whether the first character after set table is a $?
My second attempt was to remove the apostrophes around $:
set table $.namelist[i]."_data"
But this raised the weird error "Column number or datablock line expected", pointing at the period right after $.
Any ideas on how to achieve that?
The reason for all this is that I read in the banana/apple data files with a lengthy path, apply some lengthy calculations within using, and reuse these for lots of successive stats and plot commands. I would like to avoid having to hard-code and copy-paste the same long path and the cumbersome using command over and over again.
Not sure if I fully understood your detailed intention.
If you only want to avoid typing (or copy pasting) a lengthy path again and again, simply use variables:
FILE1 = 'C:/Dir1/SubDir1/SubSubDir1/SubSubSubDir1/File1'
FILE2 = 'C:/Dir2/SubDir2/SubSubDir2/SubSubSubDir2/File2'
plot FILE1 u 1:2, FILE2 u 1:2
Anyway, you asked for dynamically generated datablocks. One way which comes to my mind is using evaluate, check help evaluate. Check the example below as a starting point, which can probably be simplified.
Code: (simplified thanks to #Eldrad's comment)
### dynamically generate some datablocks
reset session
myNames = 'apple banana pineapple'
myName(i) = word(myNames,i)
N = words(myNames)
set samples 11
do for [i=1:N] {
eval sprintf('set table $%s_data',myName(i))
plot '+' u 1:(rand(0)) w table
unset table
}
plot for [i=1:N] sprintf('$%s_data',myName(i)) w lp pt 7 ti myName(i)
### end of code
Result:

Separate data from text file and plot the graph using gnuplot

I have the data in the following format
+CMT: "+944434556","","17/06/20,13:51:21+22" Level 255mm
And I want to plot a graphic between time on x axis and 255 on y axis. Can you please let me know the code for the above?
This is what I think you want :
plot "<awk -F'[, +m\"]' '{print $5, $16, $12}' datafile.dat" u 1:2:xtic(3) notitle
where datafile.dat contains your data.
In order to find the location on the x-axis, I assumed that 944434556 also represent the time. So the point is in reality set at (944434556,255) but the plot displays 13:51:21. Of course, you could also do :
plot "<awk -F'[, +m\"]' '{print $16, $12}' datafile.dat" u 1:xtic(2) notitle

gnuplot filling color between upper and lower bound

I have three columns data.txt file. I would like to fill the area with color between upper and lower bound. How can I do that? My data.txt file goes as follows,
#Time Force SD
0.000 42.155 1.974
4.890 48.548 3.773
16.102 53.244 4.959
24.215 58.864 5.677
37.698 72.483 4.828
69.354 78.334 3.557
85.586 83.071 7.040
101.155 84.780 5.411
plot "data.txt" u 1:($2+$3) and u 1:($2-$3) w filledcurve (Is there any thing like this?)
Many thanks!
Just use three columns in the using statement (see also help filledcurves):
plot 'data.txt' using 1:($2-$3):($2+$3) with filledcurves

Gnuplot pm3d plotting from file

I'm having a problem with pm3d. I have data in the format x y # # # #, and I want to add the four #'s and plot their sum versus x,y with something like this:
set pm3d map
splot 'data' 1:2:($3 + $4 + $5+ $6)
I've made sure that my data has lines wherever the first number changes, but I'm getting the error:
';' expected
after data. If I get rid of everything after data then gnuplot is able to plot, but of course the plot is not what I want.
You're missing the keyword using.
splot 'data' using 1:2:($3+$4+$5+$6)
I suppose it's an easy one to miss because in the examples it is often abbreviated u:
splot 'data' u 1:2:...

Resources