Gnuplot Stacked Filledcurves from various indexes - gnuplot

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.

Related

Plotting arrows with start and end from two different files

I have two different .txt files with x and y coordinates of equal number of samples in both.
File 1
x y
1 2
5 4
4 6
File 2
x y
5 6
3 4
2 3
I want to connect each of these points inFile 1 with the corresponding points in File 2. I know to draw an arrow between two points it is
set arrow from (x,y) to (c,d)
But how do I get the coordinates of these points from two different files to draw connecting lines/ arrows?
Something like this:
plot "< paste file1.data file2.data" with vectors
Edit: I came across this old answer and was amazed (actually shocked) how inefficient and complicated solutions I suggested.
A much better approach: Since gnuplot 5.2.0 you can index datablocks. Prerequisite is that your data is in a datablock already. See here: gnuplot: load datafile 1:1 into datablock.
If you can be sure that your data files have identical number of lines, you can "mimic" the Linux paste command using a gnuplot-only, hence, platform-independent solution.
Basically, you join the two lines having the corresponding index after removing the last character (newline) of each line.
Script: (works with gnuplot>=5.2.0, Sept. 2017)
### plot arrows across two files, i.e. merge lines with gnuplot only
reset session
$Data1 <<EOD
File 1
x y
1 2
5 4
4 6
EOD
$Data2 <<EOD
File 2
x y
5 6
3 4
2 3
EOD
set print $Combined
do for [i=1:|$Data1|] {
print $Data1[i][1:strlen($Data1[i])-1].' '.$Data2[i][1:strlen($Data2[i])-1]
}
set print
plot $Combined u 1:2:($3-$1):($4-$2) w vec lc rgb "red"
### end of script
Result:

Multiple datasets in the same data file in gnuplot

I have a following kind of file:
<string1> <x1> <y1>
<string2> <x2> <y2>
...
I want to draw a scatter plot from the (x,y) values, having the different strings in the first column in different data sets, which will be drawn with different colors (I have many different x,y values but only a few different strings). I tried this:
plot "DATAFILE" using 2:3 title column(1)
Unfortunately, this one picks the first column for the first row and uses that as a title for all entries.
You could use awk to pick only rows where the first column matches your strings:
plot "<awk '$1~/string1/' DATAFILE" using 2:3 title column(1),\
"<awk '$1~/string2/' DATAFILE" using 2:3 title column(1)
and so on. For a built-in gnuplot solution, you can do:
plot "DATAFILE" u 2:(stringcolumn(1) eq "string1" ? $3:1/0),\
"DATAFILE" u 2:(stringcolumn(1) eq "string2" ? $3:1/0)
if you want to do something more automatic that would generate plots for every unique entry in column 1, this solution worked for me:
input file (test.dat - separated, otherwise need to change cut statement below):
one 1 3
two 2 4
ten 3 5
ten 4 3
two 5 4
one 6 5
one 7 3
ten 8 4
two 9 5
ten 10 3
two 11 4
one 12 5
the following line creates a plotting statement for gnuplot, and saves in a file:
cut -f1 test.dat | sort -u | awk '
BEGIN {print "plot\\"}
{print "\"test.dat\" u 2:(stringcolumn(1) eq \""$1"\" ?\$3:1/0),\\"}' > plot.gp
and the contents are:
plot\
"test.dat" u 2:(stringcolumn(1) eq "one" ?$3:1/0),\
"test.dat" u 2:(stringcolumn(1) eq "ten" ?$3:1/0),\
"test.dat" u 2:(stringcolumn(1) eq "two" ?$3:1/0),\
then you'd do:
gnuplot plot.gp
or add the line load "plot.gp" to your script.
I am pretty sure there must be a "gnuplot-only" solution, but that goes beyond my knowledge. Hope this helps.
You have just one plot, so just one title.
If you want to plot separately all datasets (separated by two consecutive blank lines), you (just) need to say so:
N_datasets=3
plot for [i=0:N_datasets-1] "file.dat" using 2:3 index i with title columnhead(1)
But the formatting of your datafile is not what gnuplot expects, and using title columnhead will also skip first line (assumed to contain headers only). The standard gnuplot format for this would be:
string1
x1_1 y1_1
x1_2 y1_2
...
string2
x2_1 y2_1
x2_2 y2_2
...

Gnuplot: connecting two data with line at a certain point from different data files

This question is an extension of a previously answered one.
I want a graph using gnuplot with two data in mixed scheme. This is a data consisting of 3 columns:
#x y1 y2
1 0 1
2 0 1
3 0 1
4 0 1
5 0 1
6 0 1
7 0 1
8 0 1
9 0.1 1.2
10 0.1 1.23
What I want is that one line draws without seam. e.g.
From x=1 to x=5, use y1 value, then from x=6 to x=10 use y2 value.
And, all the points are connected with one single line. Does any body know how to make it with simple gnuplot command?
One more related question is there. If the data in 3rd column is separated to other file, say sheme2.dat, how can i draw a same graph with pure gnuplot commands?
If you absolutely want to use pure Gnuplot you can cheat a little with variables(, but I suggest you to rethink the problem):
set term unknown
plot 'sheme.dat' u 1:2 every ::::4
x0=GPVAL_DATA_X_MAX
y0=GPVAL_DATA_Y_MAX
plot 'sheme2.dat' u 1:2 every ::5
x1=GPVAL_DATA_X_MIN
y1=GPVAL_DATA_Y_MIN
set term wxt
# or png or qt or...
set arrow 1 from x0,y0 to x1,y1 nohead lc 1
plot 'sheme.dat' u 1:2 every ::::4 w l lc 1
replot 'sheme2.dat' u 1:2 every ::5 w l lc 1
This is a tricky way to connect the last and first data points with an arrow, but the conditions of this problem are so specific.
For a file with columns 1/2 and a second file with column 3 you can use paste as well:
plot "<paste -d ' ' data1.dat data2.dat" using 1:($1<=5?$2:$3) with lines
With the -d ' ' meaning that data1.dat and data2.dat will be separated by a single space.
For three columns in one file (as answered before)
plot "data.dat" using 1:($1<=5?$2:$3) with lines

Gnuplot: fence plot from data

I'm trying to figure out how to do fence plots in gnuplot, but I'm having a hard time understanding what's going on in the examples I find on the internet.
I have a (varying) number of data sets from different points in time in my simulation, in a datafile organized as a matrix of values1:
t1 x11 y11 // indices here indicate that (x1,y1) are a data point which
t1 x21 y21 // I'd plot on a regular 2D plot for this timestep, with the
... // additional index noting which time step the values are for.
t1 xN1 yN1
[blank line]
t2 x12 y12
t2 x22 y22
...
t2 xN2 yN2
[etc...]
tM xNM yNM
I want to plot this with one fence for each time value. I can plot do simply splot 'data.txt' and get something which is quite similar to what I want - + markers along the "top edges" of the fences, with time on x axis, x-data on y axis and y-data on z axis. However, if I add something like w lines to the splot command I just get a surface with all the data series connected.
I've tried to adapt the examples from the demo script collection (about halfway down), but they both rely on a dummy variable, and I can't figure out how to combine that with my data series. I've found some other exampels as well, but they are all quite elaborate and I don't understand what they do at all.
What is a good way to create fence plots from data using gnuplot?
1 If it's necessary, it is possible to change this - I am in control of the code that generates the data. It's a hassle, though...
This does require a bit of a change to the data unfortunately. The change is pretty minor though and could probably be handled with a simple awk1,2 script:
Here's a copy/paste of my interactive gnuplot session:
gnuplot> !cat test.dat
1 2 3
1 2 0
1 3 4
1 3 0
1 4 5
1 4 0
2 2 3
2 2 0
2 3 4
2 3 0
2 4 5
2 4 0
3 2 3
3 2 0
3 3 4
3 3 0
3 4 5
3 4 0
!
gnuplot> splot 'test.dat' u 1:2:3 w lines
The thing to note here is that there are 2 blank lines between "fences" and each x,y data point appears twice with a blank line afterward. The second time it appears, the z-coordinate is 0.
To get each fence to have a different color:
gnuplot> splot for [i=0:3] 'test.dat' index i u 1:2:3 w lines
The awk script can even be done inline:
splot "< awk {...} datafile"
But that can get a little tricky with quoting (to include a single quote in a single quoted string, you double it) ...
AWKCMD='awk ''{if(!NF){print ""}else if(index($0,"#")!=1){printf "%s %s %s\n%s %s 0\n\n", $1,$2,$3,$1,$2}}'' '
splot '<'.AWKCMD.'datafile.dat' u 1:2:3 w lines
As far as efficiency is concerned, I'm believe that the iteration I used above will call the awk command for each time it iterates. The workaround here is to pull the color from the index number:
splot '<'.AWKCMD.' test.dat' u 1:2:3:(column(-2)) w l lc variable
I believe that this will only do the awk command once as desired so with only a million entries it should still respond relatively quickly.
1awk '{if(!NF){print ""}else{printf "%s %s %s\n%s %s 0\n\n", $1,$2,$3,$1,$2}}' test.dat
2awk '{if(!NF){print ""}else if(index($0,"#")!=1){printf "%s %s %s\n%s %s 0\n\n", $1,$2,$3,$1,$2}}' test.dat (version which ignores comments)

Gnuplot - How to place y-values above bars when using Histogram style?

I am currently using a script to generate histogram plots, e.g., by doing:
set style histogram cluster gap 4
plot for [COL=2:10] 'example.dat' u COL:xticlabels(1) title columnheader(COL)
Now I wish to add the y-values (numbers) above the bars in the histogram but adding w labels gives the 'Not enough columns for this style' error.
plot for [COL=2:10] 'example.dat' u COL:xticlabels(1) title columnheader(COL), \
for [COL=2:10] 'example.dat' u COL title '' w labels
Is it possible to add y-labels using the histogram style?
Note: I know that there are examples for plotting with boxes. I wish to make this work with the histogram style if possible.
Here's a test datafile I came up with:
example.dat
hi world foo bar baz qux
1 2 3 4 5 6
4 5 7 3 6 5
Here's the script I used to plot it:
set yrange [0:*]
GAPSIZE=4
set style histogram cluster gap 4
STARTCOL=2 #Start plotting data in this column (2 for your example)
ENDCOL=6 #Last column of data to plot (10 for your example)
NCOL=ENDCOL-STARTCOL+1 #Number of columns we're plotting
BOXWIDTH=1./(GAPSIZE+NCOL) #Width of each box.
plot for [COL=STARTCOL:ENDCOL] 'example.dat' u COL:xtic(1) w histogram title columnheader(COL), \
for [COL=STARTCOL:ENDCOL] 'example.dat' u (column(0)-1+BOXWIDTH*(COL-STARTCOL+GAPSIZE/2+1)-0.5):COL:COL notitle w labels
Each cluster of histograms takes a total width of 1 unit on the x axis. We know how many widths we need (the number of boxes +4 since that is the gapsize). We can calculate the width of each box (1/(N+4)). We then plot the histograms as normal. (Note that I added with histogram to the plot command).
According to the builtin help, labels require 3 columns of data (x y label). In this case, the y position and the label are the same and can be read directly from the column COL. The x position of the first block is centered 0 (and has a total width of 1). So, the first block is going to be located at x=-0.5+2*BOXWIDTH. The 2 here is because the gap is 4 boxwidths -- two on the left and 2 on the right. The next block is going to be located at -0.5+3*BOXWIDTH, etc. In general, (as a function of COL) we can write this as
-0.5+BOXSIZE*(COL-STARTCOL+1+GAPSIZE/2)
We need to shift this to the right by 1 unit for each additional block we read. Since each block corresponds to 1 line in the data file, we can use pseudo-column 0 (i.e. column(0) or $0) for this since it gets incremented for each "record/line" gnuplot reads. The 0th record holds the titles, the first record holds the first block. Since we want a function which returns 0 for the first record, we use column(0)-1. Putting it all together, we find that the x-position is:
(column(0)-1-0.5+BOXSIZE*(COL-STARTCOL+1+GAPSIZE/2))
which is equivalent to what I have above.

Resources