Plotting arrows with start and end from two different files - gnuplot

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:

Related

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 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.

Plotting horizontal lines in gnuplot on an existing graph, using the same coloured lines

The starting point is that I have a graph with 4 lines on it. They are the results of my simulation, plotted over an x-axis of iteration, at 4 different locations. I also have experimental values at each of those locations. I want to plot those 4 experimental values as horizontal lines on the same graph. I would also like the line colours of the simulation and experiment results at each location to be the same.
With #Tom's help, below, I have got the following script to do this:
unset bars
max = 1e6
set xrange[7000:24000]
set yrange[-0.5:1.5]
plot for [i=2:5] 'sim' using 1:(column(i)) ls i, \
for [i=1:4] 'expt' using (1):1:(max) every ::(i-1)::(i-1) with xerror ls i ps 0
The problem is that I want the values in xrange[x_min:x_max] and yrange[y_min:y_max] to be taken from sim and expt as follows:
x_min = min(sim[:1]) # where min(sim[:1]) means "min value in file 'sim' col 1"
x_max = max(sim[:1])
y_min = min(sim[:2],sim[:3],sim[:4],sim[:5],expt[:1])
y_max = max(sim[:2],sim[:3],sim[:4],sim[:5],expt[:1])
My OS is Scientific Linux: Release 6.3, Kernel Linux 2.6.32-358.2.1.el6.x86_64, GNOME 2.28.2
sim and expt are .txt files
A representative sample of sim is:
7520 0.282511 0.0756715 -0.222863 -0.0898819
7521 0.315944 0.201687 -0.321723 -0.106345
7522 0.230956 0.102217 -0.34196 -0.061009
7523 1.460043 -0.00118292 -0.045077 0.673926
A representative sample of expt is:
1.112
0.123
-0.45
0.862
Thank you for your help.
I think that this is a way to solve your problem:
unset bars
max = 1e6
set xrange[0:8]
plot for [i=1:4] 2*i+sin(x) ls i, \
for [i=1:4] 'expt' using (1):1:(max) every ::(i-1)::(i-1) with xerror ls i ps 0
Based on some information I found on Gnuplot tricks, I have (ab)used error bars to produce horizontal lines based on the points in this data file:
2
4
6
8
The (1):1:(max) specifies that a point should be plotted at the coordinate (1, y), where y is read from the data file. The max is the value of xdelta, which determines the size of the x error bar. This is one way of achieving a horizontal line in your plot, as a suitably large value of max will result in an error bar across the entire xrange of your plot.
Here's what the output looks like:
Considering, that you have a data file with five columns, one with the x-values and four with y-values. Now you have additional file where a number path_to_expt comes from. In order to plot the columns and one horizontal line having the y-value path_to_expt you can use
plot for [i=2:5] path_to_file using 1:(column(i))
This plot col 2 against 1, 3 vs 1, 4 vs 1 and 5 vs 1. To get different styles, just use set linetype to redefine the automatically assigned line types:
set linetype 1 lc rgb 'orange'
# ... other lt definitions
plot for [i=2:5] path_to_file using 1:(column(i))
If you don't want to overwrite exising linetype 1..4, use e.g. 11..14:
set linetype 11 lc rgb 'orange'
# ...
plot for [i=2:5] path_to_file using 1:(column(i)) lt (9 + i)
Finally, in order to plot a horizontal line, using the same x-values as in the data file, use
mynumber = 27
plot path_to_file using 1:(mynumber)
If you don't put a number in parentheses, it is interpreted as column number (like the 1 here), whereas put inside parentheses, it is treated as number.
Another option would be to set arrows:
set arrow from graph 0, first mynumber to graph 1, first mynumber lt 1
plot for [i=2:5] path_to_file using 1:(column(i))

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 pm3d gets white lines

I draw a spectrogram with gnuplot version 4.6.
I ensured it is the newest version here:
http://www.gnuplot.info/download.html
Gnuplot is installed from Debian repository.
The plot area and the scale on the right includes strange white lines. They seem to separate the data. On plot area with dense data they look like checkered pattern:
Lines are less visible on the scale but also they are there. There are only horizontal lines on the scale.
I thought it's the case of monitor gamut or something but lines occur also with pdf monochrome.
My code is:
#!/usr/bin/gnuplot
set term pdf
# set style fill noborder # checked with and without this line
set output "../results1/fft.pdf"
set pm3d map
splot "../results1/fft.dat"
As you can read there I tried using option noborder but both with and without the lines exist.
Example data can be:
0 1 3
0 2 3
0 3 4
0 4 2
0 5 2
0 6 3
0 7 4
0 8 3
1 1 3
1 2 2
1 3 4
1 4 2
1 5 2
1 6 3
1 7 4
1 8 4
2 1 2
2 2 4
2 3 4
2 4 3
2 5 2
2 6 4
2 7 2
2 8 2
3 1 2
3 2 3
3 3 3
3 4 4
3 5 2
3 6 2
3 7 2
3 8 2
Do you have any idea how to get rid of this lines?
This has plagued me for some time as well. The best workaround I have is inspired by this post. Basically you can use
plot "datafile" with image
instead of the splot command. There are some subtle differences in how the data is plotted, but this creates a .pdf without those nasty gaps between the colored areas, and a much smaller file.
Note this only really works for data which forms a rectangular grid! If the datafile is in a matrix format (no x or y data except for the number of data points) which for your example would be
3 3 2 2
3 2 4 3
...
(z-value from first row of each block makes the first row, etc.) you can use the command
plot 'datafile' ($1*xincr - x0):($2*yincr - y0):3 matrix with image
The stuff in parens is optional, but allows you to scale the resulting plot to the correct x and y values. (xincr is a gnuplot variable you would have to set for the x-increment in the data, x0 is the x offset, etc.)
If this results in a white gap around the plot, use the plot command once, rescale the axes, and plot again, e.g.
set terminal unknown
plot 'datafile' ($1*xincr - x0):($2*yincr - y0):3 matrix with image
set xr[GPVAL_DATA_X_MIN:GPVAL_DATA_X_MAX]
set yr[GPVAL_DATA_Y_MIN:GPVAL_DATA_Y_MAX]
set output "fft.pdf"
replot
Second answer
I find that this effect is pdf-viewer-dependent. For instance, it shows up in evince under linux but not okular. Depending on your application you could just use a different viewer.
For me, replacing
set pm3d map
with
unset surface; set pm3d at b; set view map
corrects this problem. Tested on gnuplot 4.6 patchlevel 2 and gnuplot 5.4 patchlevel 1.
I can't give much insight as to why, but the manual reveals that
set pm3d map
is a shortcut for
set pm3d at b; set view map; set style data pm3d; set style func pm3d
Simple testing reveals that the problem occurs if either of the "set style" instructions are included. Their removal corrects the problem, but leaves the surface visible - hence "unset surface".

Resources