How to plot two columns with different index in Gnuplot? - gnuplot

I have a data set that has two groups of data each one with 3 columns. I know that I use plot "dataset.dat" i 0 u 1:2 to plot the second column versus the first column in the first set of data (index starts with zero), or plot "dataset.dat" i 1 u 2:3 to plot the third column versus the second column in the second set of data. But what if I want to plot the second column of index 1 versus the second column of index 0?, is that possible? or do I have to put them contiguously in the same index. I have search in the documentation but isn't mentioned there. Thanks for your help.

This is basically a data (re-)arrangement challenge. You could rearrange your data with whatever external tool, but in principle you can also do it somehow with gnuplot.
One possible solution would be to place your y-values (from index 1) in a separate datablock (here; $myY) and in the final plot command address it by datablock line-index, which starts from 1 and requires a integer number, that's why it is $myY[int($0+1)]. Furthermore, you need to convert it into a (floating point) number via real(), check help real. The assumption is that the subblocks have the same length.
Code:
### plot x and y from different indices
reset session
$Data <<EOD
11 12 13
21 22 23
31 32 33
111 112 113
121 122 123
131 132 133
EOD
set table $myY
plot $Data u 2 index 1 w table
unset table
unset key
plot $Data u 2:(real($myY[int($0)+1])) index 0 w lp pt 7
### end of code
Result:

Related

Iterate over all datasets AND all columns in gnuplot

I have a datafile with an arbitrary number of datasets, each with an arbitrary number of columns. Every column starts with a header that I would like to use as a title. This is an example datafile, "gp.dat":
a b
2 3
4 9
16 27
c
4
16
64
I would like to generate a plot using gnuplot (gnuplot 5.4 patchlevel 2) that interprets every column in every dataset as an independent line, each labeled with its column header. For the above dataset, this would do the trick:
plot for [d=0:*] for [i=1:2] "gp.dat" index d using i title columnheader with linespoints
Resulting in the following plot:
However, when I try to specify ALL datasets AND ALL columns, the "c" line vanishes:
plot for [d=0:*] for [i=1:*] "gp.dat" index d using i title columnheader with linespoints
This seems to hold for any index I supply for the column number above 2, so this produces the same bad plot:
plot for [d=0:*] for [i=1:3] "gp.dat" index d using i title columnheader with linespoints
How can I specify ALL datasets and ALL columns and guarantee that everything will be plotted?
In the past, I made other strange observations using the * in such "self (de-/non-)terminating loops". I guess gnuplot determines the number of columns from the last block, but is probably not prepared to have variable number of columns.
Here is a somewhat awkward but straightforward procedure to plot all blocks and all columns. This example works as long as your column separator is whitespace.
determine the number of blocks using stats (check help stats)
set the column separator temporarily to "\n", i.e. strcol(1) will be the whole line
extract the number of columns from the first row of each block using words (check help words) and write it to a datablock $ColMax (check help table).
reset the column separator to whitespace again
use the variable number of columns for each block
Maybe there are shorter and smarter solutions.
Script:
### plot all blocks and all columns (variable number of columns in blocks)
reset session
$Data <<EOD
a b
2 3
4 9
16 27
c
4
16
64
d e f
5 6 7
33 44 55
77 88 99
EOD
stats $Data u 0 nooutput
set datafile separator "\n"
set table $ColMax
plot for [b=0:STATS_blocks-1] $Data u (words(strcol(1))) index b every ::::0 w table
unset table
set datafile separator whitespace
set key top center
plot for [b=0:STATS_blocks-1] for [c=1:$ColMax[b+1]] $Data u 0:c index b w lp pt 7 ti columnhead
### end of script
Result:
Addition:
Here is a bit shorter solution which does not use reading from or plotting to a table/datablock (which works only for gnuplot>5.0).
The following should also work for later versions of 4.x if you read the data from a file.
Script:
### plot all blocks and all columns (variable number of columns in blocks)
reset
FILE = 'myFile.dat'
set datafile separator "\n" # or any character which is not in the data
B = 0
Cols = ''
stats FILE u (column(-2)==B ? (B=B+1, Cols=Cols.' '.words(strcol(1))):0) every ::1::1 nooutput
set datafile separator whitespace
set key top center
plot for [b=0:B-1] for [c=1:word(Cols,b+1)] FILE u 0:c index b w lp pt 7 ti columnhead
### end of script

Gnuplot Stacked Filledcurves from various indexes

I have a file where my data are separated into several indexes. I would like to plot some or all of the indexes as stacked filledcurves by adding the values of selected previous indexes to the values of the current index. I could not find a way to use the sum function as in the case of data arranged as columns in a single index (as in this question), even using the pseudocolumn(-2) as the index number.
Important note: every index as strictly identical sets of x values, only the y values differ.
Is there a way to do something like
p 'data.dat' index (sum(ind=1,3,4,5) ind) u 1:2 w filledcurve x1 t 'Sum(1,3,4,5)', '' index (sum(ind=1,2,5) ind) u 1:2 w filledcurve x1 t 'Sum(1,2,5)'
within gnuplot or do I have to resort to a script (maybe a variation of the one in this answer)?
You can do this with some help outside gnuplot (invoked within gnuplot). Imagine you have the following data file with 4 indices (0 to 3):
1 2
2 3
1 5
2 5
1 0
2 3
1 4
2 3
Now say that we want to sum 1 and 2 and 0 and 3. The first sum should return:
1 5
2 8
while the second sum should return
1 6
2 6
We can select the blocks we want using set table:
set table "sum1"
plot for [i in "1 2"] "data3" index 0+i pt 7 not
set table "sum2"
plot for [i in "0 3"] "data3" index 0+i pt 7 not
unset table
Now use sed piping to remove the empty lines and smooth freq to sum for equal x values:
plot "< sed '/^\s*$/d' sum1" smooth freq t "sum1", \
"< sed '/^\s*$/d' sum2" smooth freq t "sum2"
Although you may be able to do it using functions and variables of gnuplot 4.4+, this won't be very efficient as you want to perform an operation on several distant lines in your file, which is in fact an operation on arrays. Gnuplot is not meant for this, the datafiles should have a structure reasonably close to what you want to plot. I advise that you try to produce a file with such a structure, e.g. have the values you want to sum on the same line in different columns.

gnuplot: min and max values for arbitrary number of columns

I'm trying to plot an arbitrary number of lines in a same plot. My data file is like the following:
1 10 15 20
2 20 25 30
3 30 35 40
4 40 45 50
5 50 55 60
I'm using multiplot to do this:
set multiplot
do for [i=1:ny] {
plot 'data.dat' u 1:i+1 with lines lc i title word(names,i)
}
unset multiplot
where ny=3 in this example. As expected, the yrange of each plot is different, so the graph looks very messy. I'm trying to add
set yrange [ymin:ymax]
where ymin=min(col2,col3,col4,...,coln) is the minimum value among all the columns 2-n and ymax is the maximum value. However, I still don't know how to get ymin and ymax. The function stats allow me to get minimums and maximums for one or two columns at the same time, but no more. Even if I do this column by column, I still don't know how to get the maximum among n scalars.
Any idea?
You can use if statement, here is the code:
ymin=1000 #set ymin to a very large value
ymax=0 #set ymax to a very small value
do for [i=1:ny] {
stats "data.dat" u i+1
if (STATS_min < ymin) {ymin=STATS_min}
if (STATS_max > ymax) {ymax=STATS_max}
}
Usually, multiplot isn't for drawing multiple plots in one graph, but to draw several beneath each other. I guess you want to iterate inside the plot command:
plot for [i=1:ny] 'data.dat' u 1:i+1 with lines lc i title word(names, i)
This uses ranges which cover the values of all sub-plots. And it gets the key right.

gnuplot label using other values than the ones used for the plot

I'd like to plot a label for my axis x that is not related to the values used for the plot.
Let's say my data is in a file.txt looking like :
toto 0 1 23 56
tutu 0 2 45 67
tata 0 3 67 23
tete 1 4 12 56
and what I want is a display of column 4 and 5 values using column 3 as the x axis :
plot "file.txt" u 3:4 title "colum4_values",\
"" u 3:5 title "colum5_values"
but I'd like to have the values of the column 1 displayed along the bottom X axis (xlabel) and the values of the column 2 displayed along the top X axis (x2label).
Is it possible?
In order to use the values of a column as tic labels, you can use xticlabels (short hand is xtic) or x2tic:
set x2tics
set xtics nomirror
plot 'file.txt' using 3:4:xtic(1) title 'column4_values',\
'' using 3:5:x2tic(2) title 'column5_values'
Usually, to plot on the x2-axis, you need to use axes x2y1, but when using x2tic this seems not to be necessary. You only need to enable the tics on the second axis with set x2tics.

gnuplot: 3D plot of a matrix of data

How can I plot (a 3D plot) a matrix in Gnuplot having such data structure,
using the first row and column as a x and y ticks (the first number of the first row is the number of columns) ?
4 0.5 0.6 0.7 0.8
1 -6.20 -6.35 -6.59 -6.02
2 -6.39 -6.52 -6.31 -6.00
3 -6.36 -6.48 -6.15 -5.90
4 -5.79 -5.91 -5.87 -5.46
Exactly this data format can be read in with matrix nonuniform:
set view 50,20
set ticslevel 0
splot 'data.txt' matrix nonuniform with lines t ''
This generates the correct tics, like specified in the data file:
To plot a 4D plot, using colour as the 4th dimension, you can use
splot '1.txt' using 2:3:4:5 every ::1 palette
# | |
# | |
# used for 3d plots skip the header line
Or do you want to draw a different picture, with x and y being the first column and line, and the numbers in the matrix just represinting z? Then use the following:
splot '1.txt' every ::1:1 matrix
To add some effects, you can change it to
set dgrid3d 4,4
splot '1.txt' every ::1:1 matrix with lines

Resources