store commented value from data file in gnuplot - gnuplot

I have multiple data files output_k, where k is a number. The files look like
#a=1.00 b = 0.01
# mass mean std
0.2 0.0163 0.0000125
0.4 0.0275 0.0001256
Now I need to retrieve the values of a and b and to store them in a variable, so I can use them for the title or function input etc. The looping over the files in the folder works. But I need some help with reading out the the parameters a and b. This is what i have so far.
# specify the number of plots
plot_number = 100
# loop over all data files
do for [i=0:plot_number] {
a = TODO
b = TODO
#set terminal
set terminal postscript eps size 6.4,4.8 enhanced color font 'Helvetica,20' linewidth 2
set title "Measurement \n{/*0.8 A = a, B = b}"
outFile=sprintf("plot_%d.eps", i)
dataFile=sprintf("output_%d.data", i)
set output outFile
plot dataFile using 1:2:3 with errorbars lt 1 linecolor "red", f(a,b)
unset output
}
EDIT:
I am working with gnuplot for windows.

If you are on a Unixoid system, you can use system to get the output of standard command line tools, namely head and sed, which again allow to extract said values form the files:
a = system(sprintf("head -n 1 output_%i.data | sed \"s/#a=//;s/ b .*//\"", i))
b = system(sprintf("head -n 1 output_%i.data | sed \"s/.*b = //\"", i))
This assumes that the leading spaces to all lines in your question are actually a formatting mistake.

A late answer, but since you are working under Windows you either install the comparable utilities or you might be interested in a gnuplot-only solution (hence platform-independent).
you can use stats to extract information from the datablock (or file) to variables. Check help stats.
the extraction of your a and b depends on the exact structure of that line. You can split a line at spaces via word(), check help word and get substrings via substr() or indexing, check help substr.
Script: (works with gnuplot>=5.0.0)
### extract information from commented header without external tools
reset session
$Data <<EOD
#a=1.00 b = 0.01
# mass mean std
0.2 0.0163 0.0000125
0.4 0.0275 0.0001256
EOD
set datafile commentschar ''
set datafile separator "\t"
stats $Data u (myHeader=strcol(1)[2:]) every ::0::0 nooutput
set datafile commentschar # reset to default
set datafile separator # reset to default
a = real(word(myHeader,1)[3:])
b = real(word(myHeader,4))
set label 1 at graph 0.1,0.9 sprintf("a=%g\nb=%g",a,b)
plot $Data u 1:2 w lp pt 7 lc "red"
### end of script
Result:

Related

using gnuplot to read in - not output - a png image, or many, in one session - as an "overlay"

I want to read multiple png files - which themselves were created with gnuplot (terminal png) - in order to achieve an "overlay" - that is, a number of functions plotted together one on top of the other, with no background. This apparently could be done with gnuplot in one session.
I found this idea from the Linux Gazette article "Plotting the spirograph equations with 'gnuplot' ", from 2006 :
https://linuxgazette.net/133/luana.html
I am stuck on a number of error messages (vide infra) :
line 0: Bad data on line 1 of file [...]
line 0: warning: using default binary record/array structure
line 0: Too many using specs for this style
Looking for solutions, I read in the help pages ( http://gnuplot.info/docs_5.5/loc7742.html ) that gnuplot can read png images :
plot 'file.png' binary filetype=png
... and I have looked into using pngcairo instead of png itself. I am using eog to view the .png images. Here is sample code which generates the error above, and more if adjusted :
set size ratio -1
set nokey
set noxtics
set noytics
set noborder
set parametric
i2p = {0,1}*2*pi
set terminal png
t0 = 0
t1 = 1
#---------------------------------------------
# plot first function in the gnuplot session :
#---------------------------------------------
test01(t) = exp(i2p*(2*t))
set output "solve_png_problem_15nov22a.png"
plot [t=t0:t1] 1*real(test01(t)),1*imag(test01(t)) lc 1
#---------------------------------------------------
# plot second function in the same gnuplot session :
#---------------------------------------------------
test02(t) = + 3*1.0**20 * exp(i2p*(-3*t+20/200. )) + 3*1.0**19 * exp(i2p* (2*t+20/200.))
set output "solve_png_problem_15nov22b.png"
plot [t=t0:t1] 1*real(test02(t)),1*imag(test02(t)) lc 2
#------------------------------------------------------------
# last plotting to apparently "overlay" the two plots above :
#------------------------------------------------------------
set terminal png size 600,600
set output "solve_png_problem_15nov22_overlay.png"
set noparametric
plot "solve_png_problem_15nov22a.png", "solve_png_problem_15nov22b.png"
.... the reduced sample code is generated from the awk script supplement to the article - see it for detail :
https://linuxgazette.net/133/misc/luana/spirolang.awk.txt
The functions are nontrivial so they were kept in tact, as the associated settings might be causing the problem. The individual images look ok, so I think the problem is in the last plot command.
I read in the help pages that gnuplot can read png images :
plot 'file.png' binary filetype=png
... and also filetype=auto, and I have looked into using pngcairo instead of png itself, with no progress ; I have read the results of Google searches for the error messages. I have read the help pages on terminal, png, image, binary, and so on. I was expecting gnuplot to simply recognize the file was a png image that gnuplot itself generated, using the png terminal. What actually results is the error"Too many using specs for this style". For this, I have tried moving the position of the "binary filetype=png" in the code, which give the error "line 0: Bad data on line 1 of file [...]". I have also tried using programs outside gnuplot, such as montage and composite (ImageMagick).
gnuplot version 5.4 patchlevel 2
Ubuntu 22.04
post-answer update:
TL;DR : use svg terminal.
I saved a lot of grief by simply using the svg terminal. The original work must have been published before gnuplot got the svg terminal. I still need to work svg into the original script - but svg will make it a lot easier.
Try this in GNUPLOT.
gnuplot<<EOF
set terminal png medium size 600,600 background rgb "white"
set size ratio -1
set nokey
set noxtics
set noytics
set noborder
set parametric
i2p = {0,1}*2*pi
t0 = 0
t1 = 1
#---------------------------------------------
# plot first function in the gnuplot session :
#---------------------------------------------
test01(t) = exp(i2p*(2*t))
set output "solve_png_problem_15nov22a.png"
plot [t=t0:t1] 1*real(test01(t)),1*imag(test01(t)) lc 1
#---------------------------------------------------
# plot second function in the same gnuplot session :
#---------------------------------------------------
test02(t) = + 3*1.0**20 * exp(i2p*(-3*t+20/200. )) + 3*1.0**19 * exp(i2p* (2*t+20/200.))
set output "solve_png_problem_15nov22b.png"
plot [t=t0:t1] 1*real(test02(t)),1*imag(test02(t)) lc 2
#------------------------------------------------------------
# last plotting to "overlay" the two plots above :
#------------------------------------------------------------
set output "solve_png_problem_15nov22_overlay.png"
plot \
[t=t0:t1] 1*real(test01(t)),1*imag(test01(t)) lc 1, \
[t=t0:t1] 1*real(test02(t)),1*imag(test02(t)) lc 2
EOF
First Result:
Second Result:
Combined Result:

gnuplot: histogram of events: issue with timecolumn()

I would like to see the number of events per timeperiod.
My rows look like this
"2020-11-11 09:15:50",field2,field3
This is what I have tried
binwidth = 3600 # 1h in seconds
bin(t) = (t - (int(t) % binwidth) + binwidth/2)
set datafile separator ","
#set xdata time
set timefmt '"%Y-%m-%d %H:%M:%S"'
set boxwidth binwidth
plot 'Statistics.log' using (bin(timecolumn(1, '"%Y-%m-%d %H:%M:%S"'))):(1) smooth freq with boxes
I'm getting
unknown type in magnitude()
How would I debug errors like these? (How do I dump what gnuplot "sees" for timecolumn() etc.?)
(gnuplot 4.6)
At first, The timecolumn() in gnuplot 4.6 is a single-argument function, and only the argument for the column number is allowed. Therefore, the plot command can be rewritten as,
plot "test.dat" using (bin(timecolumn(1))):(1) smooth freq with boxes
Secondly, do not include leading and trailing double quotes in your timefmt formatting.
set timefmt '%Y-%m-%d %H:%M:%S'
For more information about this, please refer to the "help data" section.
...
However, whitespace inside a pair of double quotes is ignored when
counting columns, so the following datafile line has three columns:
1.0 "second column" 3.0
Finally, your code can be modified as follows (for gnuplot 4.6)
binwidth = 3600 # 1h in seconds
bin(t) = (t - (int(t) % binwidth) + binwidth/2)
set datafile separator ","
set xdata time
set timefmt '%Y-%m-%d %H:%M:%S'
set boxwidth binwidth
plot 'Statistics.log' using (bin(timecolumn(1))):(1) smooth freq with boxes
A few minutes too late... while testing... #binzo basically already answered.
The only difference: if your data uses double quotes for the date
"2020-11-11 09:15:50",field2,field3`
and you don't want to change your existing data, you have to specify it in set timefmt. For some strange reason which I cannot explain right now, if you set datafile separator "," it will mess up the graph, but it seems to work without.
Code: (tested with gnuplot 4.6.0)
### timedata in histogram (gnuplot 4.6)
reset
FILE = 'Statistics.log'
myTimeFmt = '"%Y-%m-%d %H:%M:%S"'
# create some test data
myDate = strptime(myTimeFmt, '"2020-11-11 11:11:11"')
myRandomDate(n) = myDate + 3*3600*invnorm(rand(0))
set print FILE
do for [i=1:500] {
print sprintf("%s,%g,%g",strftime(myTimeFmt,myRandomDate(0)),rand(0),rand(0))
}
set print
# set datafile separator "," # if uncommented this will messup the plot, don't know why
set xdata time
set format x "%Y-%m-%d\n%H:%M"
set timefmt '"%Y-%m-%d %H:%M:%S"'
binwidth = 3600 # 1 h in seconds
bin(t) = (t - (int(t) % binwidth) + binwidth/2)
set boxwidth binwidth
set style fill solid 0.5
set xtics 4*3600 # 4 h in seconds
plot FILE u (bin(timecolumn(1))):(1) smooth freq w boxes notitle
### end of code
Result:

How plot graph with missing data lines?

I have data recorded in time. But some data lines are missing and gnuplot replace them with long lines in these intervals.
How can i set gnuplot to draw nothing instead of draw lines in these intervals?
PS. I don't have free cells in these lines, I dont have these lines at all.
lines:
column 1 ... col 195
13:30:20.8 0.78061899
13:30:21.8 5.969546498
13:32:19.8 17.21257881
13:32:20.8 6.922475345
If you don't want to draw a line between two points you must insert an empty line in the data file between the two point entries, so that effectively you have
13:30:20.8 0.78061899
13:30:21.8 5.969546498
13:32:19.8 17.21257881
13:32:20.8 6.922475345
This cannot be done with gnuplot directly, but you can use e.g. awk to do the processing on-the-fly:
set timefmt '%H:%M:%S'
set xdata time
filename = 'data.txt'
plot 'awk ''{split($1,d,":"); t_prev = t; t = (d[1] * 60 + d[2])*60 + d[3]; if (t_prev && (t - t_prev > 10)) print ""; print }'' '.filename with lines
Here, the gap threshold is 10 seconds.
I suppose your miss data identifier is "NaN", then you can use the following command
plot "data" using 1:($2) with linespoints
instead of
plot "data" using 1:2 with linespoints
The former one will ignore the missing data and treat it as blank line and therefore not draw a connecting line across the gap while the latter one will draw continuous, unbroken line.
Just for the records: there are later questions about the same/similar issue.
Avoid connection of points when there is empty data
How to remove line between "jumping" values, in gnuplot?
Removing vertical lines due to sudden jumps in gnuplot
However, my solutions there require transparent color, which was not available in at the time of OP's question (gnuplot 4.6.5, Feb 2014). Nevertheless, there is a solution without external tools like awk or changing the data.
First solution for gnuplot 4.6.: Instead of a transparent line you use a white line which, however, will cover the grid lines, although it will be hardly visible.
Second solution for gnuplot 4.6 is using vectors. This really interrupts the line and will work for gnuplot 5.x as well.
Data:
00:00:00 0.406406
00:00:44 0.339779
00:01:28 0.986602
00:02:13 0.17746
00:02:57 0.0580277
00:03:42 0.586614
00:04:26 0.84247
00:05:11 0.597502
00:05:55 0.0394846
00:06:40 0.369416
00:13:20 0.527109
00:13:42 0.371411
00:14:04 0.851465
00:14:26 0.980312
00:14:48 0.431391
00:15:11 0.545491
00:15:33 0.708445
00:15:55 0.861669
00:16:17 0.277122
00:16:40 0.787273
Script:
### avoid showing a line across larger time gaps
reset
FILE = "SO26510245.dat"
myFmt = "%H:%M:%S"
tGap = 60 # 60 seconds
set format x "%H:%M"
set timefmt "%H:%M:%S"
set xdata time
set ytics 0.5
set key top center noautotitle
set grid x,y
set multiplot layout 3,1
plot FILE u 1:2 w l lc rgb "red" ti "data as is"
myColor(col) = (t0=t1, t1=timecolumn(1), t1-t0>tGap ? 0xffffff : 0x0000ff)
plot t1=NaN FILE u 1:2:(myColor(1)) w l lc rgb var ti "white line"
myGap(col) = (t1-t0>tGap ? NaN : y0)
plot t1=y1=NaN FILE u (t0=t1,t1=timecolumn(1),t0):(y0=y1,y1=$2,myGap(0)):(t1-t0):(y1-y0) \
w vec lc rgb "web-green" nohead ti "with vectors"
unset multiplot
### end of script
Result: (created with gnuplot 4.6.0, from March 2012)

How to print input file next to graph in gnuplot?

Is it possible with gnuplot to print the data that I plotted next to the graph?
If I have a text file input.txt:
#x y
1 2
2 5
3 6
4 7
And I do plot 'input.txt' I'd like to have it plotted as usual and next to the plot I'd like to have the table printed. Is this possible?
Note: I'm on Windows and I'd like to format the output.
A bit late, but the OP asked for Windows... so, in short:
data = system('type yourfile.dat') # Windows
In Windows, if you give a path, you need to pay attentention about \, spaces and doublequotes ".
Data: SO22225051.dat
#x y
1 2
2 5
3 6
4 7
Script:
Solution working for both Linux and Windows. Version 1 for gnuplot>=5.2.0, Version 2 for gnuplot>=4.6.0.
### place data as table/text in graph
reset
FILE = 'SO22225051.dat'
set rmargin 15
set label 1 at screen 0.9,0.7 font "Courier New,12"
# Version 1: Windows & Linux using system() command;
# GPVAL_SYSNAME only available for gnuplot>=5.2.0
getData(f) = GPVAL_SYSNAME[1:7] eq "Windows" ? \
system(sprintf('type "%s"',f)) : \
system(sprintf('cat "%s"',f)) # Linux/MacOS
Data = getData(FILE)
set label 1 Data
plot FILE u 1:2 w lp pt 7 lc rgb "red"
pause -1
# Version 2: gnuplot-only, platform-independent, working at least with gnuplot>=4.6.0
Data = ''
set datafile commentschar ''
set datafile separator "\t"
stats FILE u (Data=Data.strcol(1)."\n") nooutput
set datafile commentschar # restore default
set datafile separator # restore default
set label 1 Data
plot FILE u 1:2 w lp pt 7 lc rgb "red"
### end of script
Result:
The only difference between version 1 and 2 is that in version 2 gnuplot will remove leading spaces for each data line.
Sure you can. The simplest way to do this in gnuplot is read in the file by calling an external command (cat on *nix, not sure on Windows) and storing the output as a variable, then setting a label on the graph. Here is how I do it:
set rmargin 8
datas = system('cat data.dat')
print datas
set label datas at graph 1.1,0.7
plot 'data.dat' notitle
This puts the data file off to the side, in place of a key.

Plotting arrows with gnuplot

I have data generated in a simulation. The generated data file looks something like this:
1990/01/01 99
1990/01/02 92.7
1990/01/03 100.3
1990/01/04 44.2
1990/01/05 71.23
...
2100/01/01 98.25
I can create a chart (trivially), by simply issuing the (long versioned) command:
plot "simulation.dat" using 1:2 with line
I want to add a third column which will add arrow information. The encoding for the third column would be as follows:
0 => no arrow to be drawn for that x axis value
1 => an UPWARD pointing arrow to be drawn for the x axis value
2 => a DOWNWARD arrow to be drawn for the x axis value
I am just starting to learn gnuplot, and will appreciate help in how I can use gnuplot to create the arrows on the first plot?
I dont think there is an automatic way to create all your arrows at the same time based on the third column. You will have to execute the following for each arrow that you want:
set arrow xval1,yval1 to xval2,yval2
You can also use relative arrows
set arrow xval1,yval1 rto 1,0
This will draw a horizontal arrow from xval1,yval1 to (xval1+1),yval1
There are plenty of options associated with the set arrow command:
If you didn't want the arrow head then you might try the impulses style (with impulses rather than with lines)
(If you still want the lines on top then you can plot twice).
If you really want the arrow heads then the following might help: It uses a for loop (or sorts) to add vertical arrows to a plot.
Gnuplot script, for loop within or adding to existing plot
Specifically:
create a file simloop.gp which looks like the following:
count = count+1
#save the count to count.gp
system 'echo '.count.' > count.gp'
#load the simloop shell
system "./simloop.sh"
#draw the arrow
load 'draw_arrow.gp'
if(count<max) reread
Then create a simloop.sh file that looks something like so
#!/bin/bash
#read the count
count=$(awk -F, '{print $1}' count.gp)
#read the file
xcoord=$(awk -v count=$count -F, 'BEGIN{FS=" ";}{ if(NR==count) print $1}' simulation.dat)
ycoord=$(awk -v count=$count -F, 'BEGIN{FS=" "}{ if(NR==count) print $2}' simulation.dat)
dir=$(awk -v count=$count -F, 'BEGIN{FS=" "}{ if(NR==count) print $3}' simulation.dat)
#choose the direction of the arrow
if [ \"$dir\" == \"0\" ]; then
echo '' > draw_arrow.gp
fi
if [ \"$dir\" == \"1\" ]; then
echo 'set arrow from ' $xcoord' ,0 to '$xcoord','$ycoord' head' > draw_arrow.gp
fi
if [ \"$dir\" == \"2\" ]; then
echo 'set arrow from '$xcoord',0 to '$xcoord','$ycoord' backhead' > draw_arrow.gp
fi
Then create a simulation.gp file that looks something like so:
count = 0;
max = 5;
load "simloop.gp"
set yrange[0:*]
plot "simulation.dat" u 1:2 w l
Make sure the shell file has executable permissions (chmod +wrx simloop.sh), load up gnuplot and type
load "./simulation.gp"
This worked for me with the data file
1 99 0
2 92.7 1
3 100.3 2
4 44.2 0
5 71.23 1
(For testing I got rid of the time formatting You should be able to put it back without too much trouble.)
Then I got this graph:
Which I think is more or less what you want.
Although the question is quite old, here is my answer.
One can use the vectors plotting style, which can use variable arrowstyles based on a column's value:
set style arrow 1 backhead
set style arrow 2 head
set yrange[0:*]
set xdata time
set timefmt "%Y/%m/%d"
plot "simulation.dat" using 1:2 with line,\
"" using 1:2:(0):(-$2):($3 == 0 ? 1/0 : $3) with vectors arrowstyle variable
It the value of a column is 1/0, the point is considered as undefined and is skipped.

Resources