I have a file in the form
# Line 1
# x y z
x11 y11 z11
x12 y12 z12
....
x1n y1n z1n
( blank row )
.....
# Line N
# x y z
xN1 y11 z11
xN2 y12 z12
....
xNk yNk zNk
If I try to splot such file, gnuplot intended it as a surface, and the result is very awful (because the endpoint of a line is close to the endpoint of next line, not to the first point). How can I plot them as different lines (as every line was in a different file)?
Each contiguous part of coordinates is called a block. Two blocks are separated by a single blank row. (Note, that two blank rows separate two data sets which can be accessed with index).
You can select a certain row for plotting using the every option:
block = 4
splot 'file.dat' every :::block::block
This selects the fifth block (the numbering starts at 0).
To iterate over all available blocks, you can estimate the number of blocks with the stats command:
stats 'file.dat'
splot for [i=0:int(STATS_blank)] 'file.dat'
Note, that some blanks at the end of the file, which do not separate blocks, are also counted, but that is no problem for the iteration.
You can of course also use the iteration variable i to select a certain linetype or linestyle.
Related
I have a file that looks like this:
0 0.000000
1 0.357625
2 0.424783
3 0.413295
4 0.417723
5 0.343336
6 0.354370
7 0.349152
8 0.619159
9 0.871003
0.415044
The last line is the mean of the N entries listed right above it. What I want to do is to plot a chart that has each point listed and a line with the mean value. I know it involves replot in some way but I can't read the last value separately.
You can make two passes using the stats command to get the necessary data
stats datafile u 1 nooutput
stats datafile u ($0==(STATS_records-1)?$1:1/0) nooutput
The first pass of stats will summarize the data file. What we are actually interested in is the number of records in the file, which will be saved in the variable STATS_records.
The second pass will compute a column to analyze. If the line number (the value of $0) is equal to one less than the number of records (lines are numbered from 0, so this is the last line), than we get this value, otherwise we get an invalid value. This causes the stats command to only look at this last line. Now the value of the last line is stored in STATS_max (or STATS_min and several other variables).
Now we can create the plot using
plot datafile u 1:2, STATS_max
where we explicitly state columns 1 and 2 to make the first plot specification ignore that last line (actually, if we just do plot datafile it should default to this column selection and automatically ignore that last line, but this makes certain). This produces
An alternative way is to use external programs to filter the data. For example, if we have the linux command tail available, we could do1
ave = system("tail -1 datafile")
plot datafile u 1:2, ave+0
Here, ave will contain the last row of the file as a string. In the plot command we add 0 to it to force it to change to a number (otherwise gnuplot will think it is a filename).
Other external programs can be used to read that last line as well. For example, the following call to python3 (using Windows style shell quotes) does the same:
ave = system('python -c "print(open(datafile,\"r\").readlines()[-1])"')
or the following using AWK (again with Windows style shell quotes) has the same result:
ave = system('awk "END{print}"')
or even using Perl (again with Windows shell quotes):
ave = system('perl -lne "END{print $last} $last=$_" datafile')
1 This use of tail uses a now obsolete (according to the GNU manuals) command line option. Using tail -n 1 datafile is the recommended way. However, this shorter way is less to type, and if forward compatibility is not needed (ie you are using this script once), there is no reason not to use it.
Gnuplot ignores those lines with missing data (for example, the last line of your datafile has no column 2). Then, you can simply do the following:
stats datafile using 2 nooutput
plot datafile using 1:2, STATS_mean
The result:
There is no need for using external tools or using stats (unless the value hasn't been calculated already, but in your example it has).
During plotting of the data points you can assign the value of the first column, e.g. to the variable mean.
Since the last row doesn't contain a second column, no datapoint will be plotted, but this last value will be hold in the variable mean.
If you replace reset session with reset and read the data from a file instead of a datablock, this will work with gnuplot 4.6.0 or even earlier versions.
Minimal solution:
plot FILE u (mean=$1):2, mean
Script: (nicer plot and including data for copy & paste & run)
### plot values as points and last value from column 1 as line
reset session
$Data <<EOD
0 0.000000
1 0.357625
2 0.424783
3 0.413295
4 0.417723
5 0.343336
6 0.354370
7 0.349152
8 0.619159
9 0.871003
0.415044
EOD
set key top center
plot $Data u (mean=$1):2 w p pt 7 lc rgb "blue" ti "Data", \
mean w l lw 2 lc rgb "red"
### end of script
Result:
This question is related to this one:
store commented value from data file in gnuplot
I formatted now every single data file that it looks like:
1.0 0.01
0.2 0.0163 0.0000125
0.4 0.0275 0.0001256
Then I tried to read the first line and store it into variables in this way:
set term push
set term unknown
plot dataFile every ::0::0 using (a=$0):(b=$1)
set term pop
But this is not working as it should, why? The rest of the file I plot as follows:
plot dataFile every ::1 using 1:2:3 with errorbars lt 1 linecolor "red",f(a,b)
Column counting starts at 1, the zeroth column is the row number. And you must also restrict to the first block (note the three colons). Try
plot dataFile every :::0::0 using (a=$1):(b=$2)
Alternatively you can use stats in a similar way:
stats dataFile every :::0::0 using 1:2
a = STATS_min_x
b = STATS_min_y
I have a data file with 3 column and I want to plot with 2 of them. But I want to use the third with a condition to exclude or not the line from the plot (For example, if $3 < 10 the data line isn't valid). I know there is set datafile missing but this case is somewhat peculiar and I don't know how to do that. Any help is appreciated...
You can use conditional logic in the using expression in the plot command:
plot 'data.dat' u 1:($3 < 10 ? 1/0 : $2)
This command plots 1/0 (it skips that data point) if the value in the third column is < 10, and otherwise plots the value in the second column.
I have several data files produced from a Fortran code. All the data files are following the same style regarding their names, that is: data###.out, where ### starts from 001 and ends to 500. I know that in order to read and plot several data files in gnuplot I must use
plot for [i=1:500] sprintf('data00%i.out', i) u 1:2 w d lc rgb 'black'
However, this only works until data009.out. For 010 to 099 it should skip one zero and from 100 to 999 two zeros. How can I obtain this?
To pad with zeroes an integer printed with three digits, the correct format is %03i. Try:
plot for [i=1:500] sprintf('data%03i.out', i) u 1:2 w d lc rgb 'black'
I'd like to plot a histogram data already created, stored in hist.dat as:
#hist1
100
1
9
10
30
30
10
9
1
Where the (zeroth line is a comment), first line contains the summation of the y value of the histogram, and x values are 1, 2, ... (the line number). So without normation, I could use
plot "hist.dat" every::1 using 0:1
and with normation I could use
plot "hist.dat" every::1 using 0:($1/100)
The question is how can I refer the summated value (100)? Because I don't want to pre-read the file just to create a correct gnuplot code, so I dont't want to write down the value implicit. I already tried
plot "hist.dat" using 0:($1/(columnhead+0))
but columnhead cannot called within using (it is a string, that's why I tried to add 0 to make it int).
I don't want to modify the file or create a new one based on this one, I want to just use the appropriate gnuplot command. I would like to avoid neglecting the summated value and recalculating it again with gnuplot.
Solution: according to andyras who give the correct answer, a bit improved method is
first(x) = ($0 == 0) ? (first = column(x), 1/0) : first
plot "hist.dat" using 0:($1/first(1))
So you can use this to plot histograms if you have multiple columns as if the hist.dat were
#hist1 hist2
10000 8000
1000 50
9000 70
1000 1100
3000 4500
3000 1200
1000 700
9000 380
1000
How can I refer the summated value (100)? (without pre-reading the file)
Yes, using a gnuplot function:
first(x) = ($0 == 0) ? (first = $1, 1/0) : first
plot "hist.dat" using 0:($1/first($1))
If it is reading the first line, the function assigns the value from that line to the variable first and returns 1/0 (gnuplot treats it as missing data and won't extend the x range to include that point). Otherwise the function returns the value of first.
This way you don't even have to use every ::1.
If you didn't mind rereading the file you could use the stats command to find out the largest value in the file.