Gnuplot script, for loop within or adding to existing plot - gnuplot

I would like to plot a series of vertical lines in gnuplot at a set interval.
Some information about the plot.
The plot is mainly some data from a .dat file. The gnuplot script is called by a bash scripts which alters the gnu plot script using sed. This is a snipit of the an old bash script (ugly I'm sure).
sed -i 's/C = CONCEHOLD/C = '${$CO}'/g' $GNUPLOTROOT/plotviscosity.plt
gnuplot $GNUPLOTROOT/plotviscosity.plt
mv my-plot.ps $VISCPLOTNAME
sed -i 's/C = '${$CO}'/C = CONCEHOLD/g' $GNUPLOTROOT/plotviscosity.plt
with the . plt file looking like this.
set title "Viscosity vs Time, C = CONCEHOLD, beta = RATHOLD, zeta = ZETAHOLD"
set xlabel "Time"
set ylabel "Viscosity"
plot "viscout.dat" using 3:2 title 'Viscosity'
# Saving to my-plot.ps
load save.plt
#
I would like to add to this plot a series of vertical lines at a set repeating interval. I have found how to plot vertical lines via http://t16web.lanl.gov/Kawano/gnuplot/parametric-e.html
set parametric
const=3
set trange [1:4]
set xrange [0:5]
set yrange [0:5]
plot const,t
I would like to have
const=repititionperiod*i
where i is an integer belonging to (1,calculateduppedlimit].
I could input repititionperiod via sed again and in a similar vain calculateduppedlimit but need some sort of for loop either within gnuplot or a separate gnuplot script that adds a vertical line to the already created plot within a for loop in my bash script.
I can't find any information on loops within gnu plot or adding to a previously created plot.
Any advice gratefully received.

EDIT: Gnuplot does now in fact now support a for loop, you can read about it here
As I understand gnuplot doesn't have a for loop, although you can generate one of sorts as follows:
Make a file "loop.gp" containing
const = const + 1
#... some gnuplot commands ...
if(const<100) reread
then in a gnuplot terminal, or script write,
const = 3; load "loop.gp";
This will give you a simple loop.
(this example is taken from the misc. section of http://t16web.lanl.gov/Kawano/gnuplot/index-e.html)
For your particular answer you might try adding arrows rather than paremetric lines,
eg.
set arrow from const,1 to const,4 nohead
will do much the same thing.
In this case you loop.gp could be
const = const + repititionperiod
#... some gnuplot commands ...
set arrow from const,1 to const,4 nohead
if(const<calculatedupperlimit) reread
and you would run you loop with
const = 1; repititionperiod=2;calculatedupperlimit = 10; load "loop.gp"; replot;
The replot plots the arrows.
If you "just" want the lines and nothing else - then you will need to feed a graph to actually plot (a set of arrows doesn't count). The example you gave could then be used to plot the first vertical line.
hope this helps.
Tom

Related

Putting a value from an input data file into 'Set Label'

I'm plotting an animated surface in gnuplot and want to read in an average or sum of the mapped z values and include this in a label to be printed in the plot, so that I get a running total updated as the GIF progresses. It's probably straightforward, but I'm a "gnu"bie, so to speak, and find this system pretty confusing!
I've tried putting the running sum and average numbers in additional columns ...
splot 'output3.dat' index i:i using 1:2:(column(3), TD1 = strcol(4), TD2 = strcol(5)) with pm3d
but this doesn't plot, and the string variables TD1, TD2 don't seem to exist outside the splot command.
The command you show would indeed set variables TD1 and TD2 globally if you change the order of clauses in the serial evaluation expression (the comma-separated sub-expressions):
splot 'output3.dat' index i:i using 1:2:(TD1 = strcol(4), TD2 = strcol(5), column(3)) with pm3d
However, if the idea is to create a label using set label that will appear as part of the resulting graph, this won't work. The set label command would have to be executed before the splot command, so TD1 and TD2 will not have the correct values yet.
There is an alternative that might serve you better. Instead of trying to put this dynamically evaluate information in a label, put it in the plot title. Unlike a label, the plot title is evaluated after the corresponding plot is generated, so any variables set or updated by that plot will be current. [caveat: this is true for current gnuplot (version 5.4) but was not always true. If you have an older gnuplot version the title is evaluated before the plot rather than after].
Since current gnuplot also allows you to place the individual plot titles somewhere other than in the key proper, you have the same freedom that you would with a label to position the text anywhere on the output page. For example, if you want to sum the values in column 3 of the data file and print the total as part of a title above the resulting plot:
SUM = 0
splot 'foo.dat' using 1:2:(SUM = SUM+column(3), column(3)) with linespoints title 'foo.dat', \
keyentry title = sprintf("Points sum to %g", SUM) at screen 0.5 0.9
I used a separate keyentry clause because this allows to omit the sample line segment that would otherwise be generated, but it would also be possible to make this the title of the plot itself if you want that sample line.

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:

Passing a Command as a Variable to another Program?

I'm creating an interactive script that allows me to plot specific parts of a data file using Gnuplot. These files contain multiple channels of instrumentation data and I'd like to plot specified channels together on the plot. At the moment I can only plot each channel independently with a script.
for ycolumn in $ycolumns; do
gnuplot -p << EOF
set datafile separator ","
set autoscale
set grid
set xlabel "Time"
set ylabel "Data"
set title "$graphTitle"
plot "$FILE" using $xcolumn:$ycolumn lt rgb "red" with lines t " "
EOF
This is the code that plots each channel independently. To plot them together I need the the plot line to look like this
plot "$FILE" using $xcolumn:$ycolumn1 lt with lines t " ","$FILE" using $xcolumn:$ycolumn2 lt with lines t " ", etc...
My question is how, if possible, could I have a for loop outside gnuplot that appends each column command ("$FILE" using $xcolumn:$ycolumn1 lt with lines t " ") to a variable, and then that variable gets passed to the plot command inside Gnuplot?
I was thinking about using expect but I can't figure out a way to implement that in the way I'm trying to automate this script.
Probably the most straightforward approach is to first assemble the entire plot command (as mentioned in the comments by 'that other guy') and then use it in the here document:
plotCmd=""
plotCmdDelim="plot"
for ycolumn in $ycolumns
do
plotCmd="${plotCmd}${plotCmdDelim} '${FILE}' using $xcolumn:$ycolumn lt rgb 'red' with lines t ' '"
plotCmdDelim=","
done
gnuplot -p << EOF
set datafile separator ","
set autoscale
set grid
set xlabel "Time"
set ylabel "Data"
set title "$graphTitle"
${plotCmd}
EOF

in a gnuplot script how to go access the range

I call a function in a gnuplot session, and would like to know the ranges and also if a logscale is used inside this function. How to do that ?
Thank you
gnuplot> load 'myfunction.gnu'
the file myfunction.gnu:
if "logscale" {do this};else {do that}
Partial solution could be as follows. Let's say that the main script looks like:
set logscale x
set xr [10:100]
load 'my_function.gpl'
Then in my_function.gpl, you could do:
set terminal push
set terminal unknown
plot 1
isLogScale = (GPVAL_X_LOG > 0)?1:0
xMin = GPVAL_X_MIN
xMax = GPVAL_X_MAX
set terminal pop
if(isLogScale){
print "logscale"
}else{
print "..."
}
The idea is to:
save the current terminal with set terminal push
set a "fake" terminal with set terminal unknown
generate a plot into this terminal (nothing is plotted) in order to force Gnuplot to initialize its internal variables used in the lines below
check the log scaling using GPVAL_X_LOG (equal to zero if logscale hasn't been set) and ranges with GPVAL_X_MIN, GPVAL_X_MAX.
revert the terminal settings with set terminal pop
perform some action using this information
However, the catch is that although set logscale x sets GPVAL_X_LOG by default to 10, unset logscale does not revert it back to zero, so if one used set logscale x;unset logscale, the code snippet above would not handle this correctly...
In my opinion, a better solution would be to introduce a custom variable in the main script as:
useLogScale = 1
if(useLogScale){
set logscale x
}
set xr [10:100]
load 'my_function.gpl'
then the variable useLogScale is also directly available in my_function.gpl.

Junk in the terminal when trying to export .png

I have a file (called print_1012720.txt) that looks like the text shown below.
1133254688 5698771509078629376
1150031904 5698771509371165696
1150031904 5698771510035551232
4170258464 5698771510036082688
2895583264 5698771510036715520
1620908064 5698771510037202176
346232864 5698771510037665280 <----
3366459424 5698771510038193664
2091784224 5698771510332259072
817109024 5698771510332816128 <-----
3837335584 5698771510333344512
2562660384 5698771510339882240
1287985184 5698771510340411392
13309984 5698771510340939776 <-------
3033536544 5698771510348048896
1758861344 5698771510348577280
484186144 5698771510349228800
3504412704 5698771510632804864
2229737504 5698771510633441792
955062304 5698771510634390272
3975288864 5698771510638858496
2700613664 5698771510639347712
1425938464 5698771510642663168
134486304 5698771510643387136
3154712864 5698771510643808768
I am running the following commands in bash.
gnuplot
reset
set terminal png
set xdata time
set timefmt "%d/%m/%Y %H:%M:%S"
set format x "%H:%M"
set xlabel "time"
set ylabel "highest seq number"
set yrange [0:65535]
set title "seq number over time"
set key reverse Left outside
set grid
set style data linespoints
plot "print_1012720" using 1:2 title "Flow 1"
It gives garbage in my shell. I suspect that it is the spacing between the columns that is causing this. However if I correct the spacing then the file is correctly plotted. Any clue how this can be rectified?
I suspect your main problem is that you are not setting an output. After your set terminal command you should set an output file, otherwise gnuplot will spit out the .png to your terminal, which looks like gibberish. Try putting the following in a file (saved as 'plot.plt' for instance) and then run gnuplot plot.plt at the bash command line.
set terminal png
set output 'output.png'
set xdata time
set timefmt "%s"
set format x "%H:%M"
set xlabel "time"
set ylabel "highest seq number"
set title "seq number over time"
set key reverse Left outside
set grid
set style data linespoints
plot "print_1012720.txt" using 1:2 title "Flow 1"
Creating a plot file this way will save you a lot of time typing at the gnuplot command line.
A couple of other comments:
1) You set your yrange to be 0:65535 when your y values from the datafile are much larger.
2) It looks like you are trying to extract a time in UNIX format from the first column in your datafile. For this you would want the line set timefmt '%s' as I have above. However, the time data in the data file appear to be all over the place, as do the y data.
3) You do not need the reset command at the beginning, since running gnuplot this way will create a new instance of gnuplot, so there will be nothing to reset.
4) You also had 'print_1012720' without the '.txt' extension; I'm not sure this was an error on your part.

Resources