how to plot a tree graph in gnuplot - gnuplot

I am trying to make a tree like graph in gnuplot, so far I have points with labels arranged into the tree like structure. I would like to connect nodes (points), so each node will be connected to the node on higher level.
gnuplot code:
set term png
set output "tree.png"
set xrange [0:50]
set yrange [0:50]
plot 'data.txt' using 1:2:3 with points pointtype 7 lt 1 title 'title', \
'' using 1:2:3 with labels offset 0,char 1
data:
20 35 1
15 30 1.1
10 25 1.1.1
5 20 1.1.1.1
15 20 1.1.1.2
25 30 1.2
30 25 1.2.1
25 20 1.2.1.1
35 20 1.2.1.2
Thank you

This will most likely require to process the input data file externally in order to generate the list of edges on-the-fly.
If I understood your question correctly, each node (point) in your input is associated with a "tree-path" which is just a string of dot-separated integers expressing the position of the point on each level of the graph (tree). Now, two nodes A and B should be connected iff the path of B is longer than path A by 1 (1 extra level) and the path of A is a prefix of path of B (A is parent of B).
To do this, one could assume that the points on the input are already hierarchically ordered as in your example (i.e., that the coordinates of a parent are defined before any of its children) and proceed as follows:
set term png
set output "tree.png"
set xrange [0:50]
set yrange [0:50]
fName = 'data.txt'
parseEdges = sprintf('< gawk '' \
NF==3{ \
coords = $1 " " $2; \
data[$3] = coords; \
n = split($3, path, "."); \
if(n == 1) next; \
prefix=path[1]; \
for(i=2;i<n;i++){ prefix = prefix "." path[i] } \
if(prefix in data){ \
print data[prefix] "\n" coords "\n"; \
} \
} \
'' %s', fName);
plot \
fName using 1:2:3 with points pointtype 7 lt 1 title 'title', \
'' using 1:2:3 with labels offset 0,char 1, \
parseEdges w l
Here, the gawk script splits the path specification in the third column, extracts its prefix (by stripping the least significant part of the path) and finally checks if the coordinates for this prefix (path of the parent) are already available and if yes, it prints a block of coordinates which is then shown as the connecting edge in the final output. The result is then:

Related

Gnuplot link all points on edges and fill the area

I have x-y data like this:
133.322 1073
399.966 1073
799.932 1073
1333.22 1073
133.322 1078
399.966 1078
799.932 1078
1333.22 1078
133.322 1083
399.966 1083
799.932 1083
1333.22 1083
133.322 1088
399.966 1088
799.932 1088
1333.22 1088
133.322 1093
399.966 1093
799.932 1093
1333.22 1093
133.322 1098
399.966 1098
799.932 1098
1333.22 1098
133.322 1103
399.966 1103
799.932 1103
1333.22 1103
1333.22 1108
What I what to get is like this:
or
How can I do it with Gnuplot? I need to plot many other data in this way. So a common solution would be great. Thank you very much.
The following is an attempt to draw an outline around random points.
Mathematicians probably might have ideas for a better procedure.
The procedure:
determine the bounding box for the datapoints, i.e. the extremal points for left,top,right,bottom which typically define a tetragon, but could also be a trigon or 2-gon
for each "quadrant", i.e. left/top, top/right, right/bottom, bottom/left, check whether the other points are outside of this polygon via determining the curvature (or orientation) between the two extreme points and a given point.
sort the outside points with ascending or descending x depending on the quadrant, basically sort the outline path "clockwise". Problem: gnuplot has no sort function. You could use an external program, but I generally prefer a gnuplot-only solution which makes it a bit longer.
remove all points which lead to a concave outline, this might need several iterations.
I would be happy to see simpler solutions. Suggestions for improvements are welcome.
Code:
### find and fill outline of random distributed points
reset session
# create some random test data
set samples 50
set table $Data
plot '+' u (invnorm(rand(0))*100):(invnorm(rand(0))*100) w table
unset table
# if you have a file, skip the above test data section
# and uncomment the following 3 lines and put your filename
#set table $Data
# plot "myData.dat" u 1:2 w table
#unset table
# get the coordinates of the leftmost, topmost, rightmost, and bottommost points
# in case of multiple points with leftmost x-value take the one with the topmost y-value
# similar of the other extreme points
#
# function to initialize extreme point cordinates
Init(x,y) = (Lx=column(x),Ly=column(y), \
Tx=column(x),Ty=column(y), \
Rx=column(x),Ry=column(y), \
Bx=column(x),By=column(y) )
# find extreme point coordinates
GetExtremes(x,y) = (Lx>column(x) ? (Lx=column(x),Ly=column(y)) : \
(Lx==column(x) && Ly<column(y) ? Ly=column(y) : NaN), \
Ty<column(y) ? (Tx=column(x),Ty=column(y)) : \
(Ty==column(y) && Tx<column(x) ? Tx=column(x) : NaN), \
Rx<column(x) ? (Rx=column(x),Ry=column(y)) : \
(Rx==column(x) && Ry>column(y) ? Ry=column(y) : NaN), \
By>column(y) ? (Bx=column(x),By=column(y)) : \
(By==column(y) && Bx>column(x) ? Bx=column(x) : NaN))
set table $Dummy
plot n=0 $Data u (n==0?(Init(1,2),n=n+1):GetExtremes(1,2)) w table
unset table
# put extremal points into array 1=left,2=top,3=right,4=bottom
# and 5=left again for closed line of the extremal polygon
array EPx[5] = [Lx,Tx,Rx,Bx,Lx]
array EPy[5] = [Ly,Ty,Ry,By,Ly]
# (re-)define sgn() function such that sgn(NaN) gives NaN (gnuplot would give 0)
mysgn(x) = x==x ? sgn(x) : NaN
# function to determine orientation of the curves through 3 points A,B,C
# output: -1=clockwise; +1=counterclockwise (mathematical positive); NaN if one point is NaN
Orientation(xa,ya,xb,yb,xc,yc) = mysgn((xb-xa)*(yc-ya)-(xc-xa)*(yb-ya))
# determine outside points for all 4 "quadrants"
# a point is outside
set datafile missing NaN # important for removing points from outline
array SinglePoint[1] # dummy array for plotting a single point
array EmptyLines[2] # dummy array for plotting two emtpy lines
array OutsidePoints[4] # number of outside points for each "quadrant"
set table $OutsidePoints
do for [n=1:4] {
i=0
plot SinglePoint u (EPx[n]):(EPy[n]) w table
plot $Data u 1:(Orientation(EPx[n],EPy[n],$1,$2,EPx[n%4+1],EPy[n%4+1]) < 0 ? (i=i+1,$2):NaN) w table
plot SinglePoint u (EPx[n%4+1]):(EPy[n%4+1]) w table
plot EmptyLines u ("") w table
OutsidePoints[n] = i+2
}
unset table
# sort the outside points of the 4 "quadrants" by in- or decreasing x
# since gnuplot has no built-in sort function it's a bit lengthy
AllOutsidePoints = (sum [i=1:4] OutsidePoints[i])-3 # reduce by 3 double extremal points
array Xall[AllOutsidePoints]
array Yall[AllOutsidePoints]
idx = 0
do for [n=1:4] {
array X[OutsidePoints[n]] # initialize array
array Y[OutsidePoints[n]] # initialize array
set table $Dummy
plot $OutsidePoints u (X[$0+1]=$1, Y[$0+1]=$2) index n-1 w table
unset table
# Bubblesort, inefficient but simple
SortDirection = n<3 ? +1 : -1 # n=1,2: +1=ascending, n=3,4: -1=descending
do for [j=OutsidePoints[n]:2:-1] {
do for [i=1:j-1] {
if ( X[i]*SortDirection > X[i+1]*SortDirection) {
tmp=X[i]; X[i]=X[i+1]; X[i+1]=tmp;
tmp=Y[i]; Y[i]=Y[i+1]; Y[i+1]=tmp;
}
}
}
# append array to datablock
set print $Outline append
do for [i=1:|X|-(n==4?0:1)] { print sprintf("%g %g",X[i],Y[i]) }
set print
# create an array for all sorted outside datapoints
last = |X|-(n==4?0:1)
do for [i=1:last] {
Xall[idx+i]=X[i]
Yall[idx+i]=Y[i]
}
idx=idx+last
}
# function checks convexity: result: >0: concave, 1=convex
# Orientation: -1=clockwise, 0=straight, +1=counterclockwise, NaN=undefined point
# function actually doesn't depend on n, just to shorten the function call later
CheckConvexity(n) = (Convex=1,sum [i=2:|Xall|-1] ( idx0=i-1, idx1=i, idx2=i+1, Convex=Convex && \
(Orientation(Xall[idx0],Yall[idx0],Xall[idx1],Yall[idx1],Xall[idx2],Yall[idx2])<0)),Convex)
# put array to datablock
set table $Convex
plot Xall u (Xall[$0+1]):(Yall[$0+1]) w table
unset table
# remove concave points (could take several iterations)
Count=0
while (!CheckConvexity(0)) {
Count = Count+1
print sprintf("Iteration %d ...",Count)
# set concave points to NaN
do for [i=2:|Xall|-1] {
idx0=i-1; idx1=i; idx2=i+1
if (Orientation(Xall[idx0],Yall[idx0],Xall[idx1],Yall[idx1],Xall[idx2],Yall[idx2])>=0) {
Yall[idx1] = NaN
}
}
# remove NaN points by plotting it to datablock
set table $Convex
plot Xall u (Xall[$0+1]):(Yall[$0+1]) w table
unset table
# create new X,Y array with reduced size
array Xall[|$Convex|]
array Yall[|$Convex|]
# put datablock into array again for next iteration if necessary
set table $Dummy
plot $Convex u (Xall[$0+1]=$1):(Yall[$0+1]=$2) w table
unset table
}
print sprintf("Convex after %d iterations.",Count)
set object 1 rect from Lx,By to Rx,Ty dt 3
set offsets graph 0.01, graph 0.01, graph 0.01, graph 0.01
set key out top center horizontal
plot \
keyentry w l ls 0 ti "Bounding box", \
$Outline u 1:2 w filledcurves closed lc rgb "green" fs solid 0.1 not noautoscale, \
EPx u (EPx[$0+1]):(EPy[$0+1]) w l lc rgb "black" ti "Extremal polygon", \
$Data u 1:2 w p pt 7 lc rgb "blue" ti "Points inside polygon", \
$OutsidePoints u 1:2 w p pt 7 lc rgb "red" ti "Points outside polygon", \
Xall u (Xall[$0+1]):(Yall[$0+1]) w l lw 1 lc rgb "green" ti "Concave outline", \
$Convex u 1:2 w lp pt 7 lw 2 lc rgb "orange" ti "Convex outline", \
### end of code
Result:
Addition: (second procedure)
I agree with #Christoph that gnuplot is probably not the optimal tool for doing this but nevertheless you can do it :-). Here is a shorter procedure.
The procedure:
search for the bottommost point and if there are several points with bottommost y-value take the one with the rightmost x-coordinate.
from this point calculate the angles a to all other points. Find the point with the smallest difference to a target angle, which at the beginning is aTar=0. If there are several points with the same smallest difference angle take the point with the largest distance dMax. Add this point to the outline.
set the new target angle to the angle of the line between the previous and the new found point.
go again to 2 until you will end up with the first point BxStart,ByStart.
I hope my description is somehow understandable. Although the code is shorter than the first version it might be less efficient because it hast to go multiple times (i.e. number of outline points) through all points. Worst case would be points which are already aligned on a circle.
Code:
### fill outline of random points
reset session
# create some test data
set samples 50
set table $Data
plot '+' u (invnorm(rand(0))*100):(invnorm(rand(0))*100) w table
unset table
### if you have a file, uncomment the following lines and put your filename
#set table $Data
# plot "myData.dat" u 1:2 w table
#unset table
# Angle by dx,dy (range: -90°<= angle < 270°), NaN if dx==dy==0
set angle degrees
Angle(dx,dy) = dx==dx && dy==dy ? dx==0 ? dy==0 ? NaN : sgn(dy)*90 : dx<0 ? 180+atan(dy/dx) : atan(dy/dx) : NaN
# Angle by dx,dy (range: 0°<= angle < 360°), NaN if dx==dy==0
Angle360(dx,dy) = (a_tmp=Angle(dx,dy), a_tmp==a_tmp) ? a_tmp-360*floor(a_tmp/360.) : NaN
# get the coordinates of the bottommost point
# in case of multiple points with bottommost y-coordinate take the one with the rightmost x-coordinate
Init(x,y) = (Bx=column(x),By=column(y))
GetExtremes(x,y) = (By>column(y) ? (Bx=column(x),By=column(y)) : \
(By==column(y) && Bx>column(x) ? Bx=column(x) : NaN))
set table $Dummy
plot $Data u ($0==0?Init(1,2):GetExtremes(1,2)) w table
unset table
print sprintf("Bottommost point: %g,%g:", Bx,By)
# Distance
Dist(x0,y0,x1,y1) = sqrt((x1-x0)**2 + (y1-y0)**2)
# function for getting the next outline point
GetNext(x,y) = (a=Angle360(column(x)-Bx,column(y)-By), aDiff=(a<aTar?a+360-aTar:a-aTar),\
d=Dist(Bx,column(x),By,column(y)), \
aMin>aDiff ? (aNext=a, aMin=aDiff,dMax=d,xNext=column(x),yNext=column(y)) : \
aMin==aDiff ? dMax<d ? (dMax=d, xNext=column(x),yNext=column(y)) : NaN : NaN)
BxStart=Bx; ByStart=By
set print $Outline append
print sprintf("% 9g % 9g",BxStart,ByStart) # add starting point to outline
aTar=0
while 1 { # endless loop
aMin=360; dMax=0
set table $Dummy
plot $Data u (GetNext(1,2)) w table
unset table
print sprintf("% 9g % 9g",xNext,yNext)
Bx=xNext; By=yNext; aTar=aNext
if (xNext==BxStart && yNext==ByStart) { break } # exit loop
}
set print
plot $Data u 1:2 w p pt 7 ti "Datapoints",\
$Outline u 1:2 w l lc rgb "red" ti "Convex Outline"
### end of code
Result:

Gnuplot ellipsoids with Text file center

I have a text file with 3 columns defining 3D points.
I want to paint every point in 3D and an ellipsoid centered in every point. I discard using the
set parametric
way because I need to iterate my text file.
So i think in doing something like this:
gnuplot
reset
set xrange [-5:5]
set yrange [-5:5]
set zrange [-5:5]
Rx = 1
Ry = 1
Rz = 1
fx(u,v) = column(2) + Rx*cos(u)*cos(v)
fy(u,v) = column(1) + Ry*sin(u)*cos(v)
fz(u,v) = column(3) + Rz*sin(v)
iMax = 200
splot "file.txt" using ($2):($1):($3) title "Input " with points ps 2 pt 7,\
for [i=0:iMax] "file.txt" u (fx(2*pi*i/iMax, pi*i/iMax)):(fy(2*pi*i/iMax, pi*i/iMax)):(fz(2*pi*i/iMax, pi*i/iMax)) notitle with points ps 2 pt 7
But the only think I can get is this strange and heavy (I know that they are a lot of iterations per row, but maybe there is another approach) pattern
Any help? Thank you.
There is something wrong for the mathematic point of view? Using something like this Im perfectly able to plot spheres, but without parsing data:
set parametric
R = 1
set urange [-pi/2:pi/2]
set vrange [0:2*pi]
splot R*cos(u)*cos(v),R*cos(u)*sin(v),R*sin(u) w l lc rgb "yellow"
I assume you want to plot the 2D surfaces of 3D ellipsoids. But the plot command has only a loop over i which is only 1D. This can not give a 2D surface. It might be possible to nest another 1D loop to get this approach to work.
I would suggest something else. Before plotting, you can store the center coordinates into a gnuplot array. Then you loop over this array and plot a sphere/ellipsoid using parametric mode.
This might be a starting point:
# This is the file with the center coordinates.
datafile = "ellipses.dat"
# The "stats" command stores the number of rows in the STATS_records variable.
stats datafile nooutput
num_rows = STATS_records
# Generate arrays which will contain the center coordinates of the ellipsoids.
array centers_x[num_rows]
array centers_y[num_rows]
array centers_z[num_rows]
# Read the center coordinates into the prepared arrays.
# I "misuse" the stats command. The "using" expression in parenthesis executes
# the respective commands and returns the value after the last comma: row + 1.
# This return value is not needed anywhere.
row = 1
stats datafile using (centers_x[row]=$1, \
centers_y[row]=$2, \
centers_z[row]=$3, \
row = row + 1) nooutput
# Output into an image file.
set terminal pngcairo
set output "ellipsoids.png"
# Set parameters for ellipsoids.
Rx = 0.1
Ry = 0.1
Rz = 0.7
# Use parametric mode for plotting.
set parametric
set urange [-pi/2:pi/2]
set vrange [0:2*pi]
# Finally plot:
splot datafile using 1:2:3 title "Input " with points ps 2 pt 7, \
for [i=1:num_rows] centers_x[i] + Rx*cos(u)*cos(v), \
centers_y[i] + Ry*cos(u)*sin(v), \
centers_z[i] + Rz*sin(u) notitle
Please doublecheck x, y, and z: I was not that careful. This is the result:
I have used this example data:
1 2 3
2 2 4
2 3 4
3 3 3
3 4 5
Arrays are available starting with gnuplot 5.2. For older versions, please search the internet for workarounds.

Is there a way to plot an arc with given start, centre, end point in gnuplot?

The final goal is to plot a contour path in Cartesian space existing of simple element types (only lines + arcs/circles). The parameter of the circular element is presented by a start, centre and end point. I have no influence, whether the arc is fully closed (=ellipsis or circle) or only a quarter, half a circle or something in between. It's given by a file.
I found already the circle command, but there is only a begin/end angle provided.
I know, that's possible to calculate the angles out of the 3 points, but
i'm looking for a smart command like CAD-applications do with start, centre, end.
Thanks for you thoughts.
Two ways come to my mind for plotting arcs between 3 given points where one of them is the center point.
You explicitely asked for ellipses, so the second approach might be the one for you. Nevertheless, because of its simplicity I will show the simple rotating vector approach as well.
Both approaches work easiest if you have your data in a datablock (check this: gnuplot: load datafile 1:1 into datablock) in order to extract the point coordinates from a certain data line.
1. Rotating & scaling vectors:
a simple way which will always work (but will not necessarily give ellipses): rotate the first vector towards the second vector in the given rotation direction and linearly scale its length. This will result in circle arcs when the two vectors have identical length. Depending on the angles and lengths of the two vectors, it might result in ellipses or spirals.
2. Calculate suitable ellipses:
a bit more complicated is plotting ellipses. I'm not sure, but I guess with the above 3 given points you can draw an infinite number of ellipses through these points. The restriction in the example below is that the longer vector will be taken as the larger elliptic axis. The ellipse will be scaled and rotated such that the endpoint of the smaller vector will be on the ellipse. If the angle difference of the vectors is 0 degrees it will be interpreted as 360 degrees. However, it will be impossible to find an ellipse if the two vectors have an angle difference of 0, 180 or 360 degrees and at the same time different lengths. The code below will nevertheless draw some arcs.
I hope there is no bug in the code and maybe it can be simplified. Suggestions are welcome.
Data: SO57408781_Arcs.dat
File without headerline. Columns: x0 y0 x1 y1 x2 y2 rotation_direction
-7 7 -5 7 -5 7 +1
0 7 2 7 0 9 +1
7 7 9 7 5 7 +1
-4 0 0 4 -2 -2 +1
5 0 8 0 5 5 +1
9 -2 0 -5 7 -7 +1
-7 -7 -5 -7 -4 -9 +1
Code:
### draw ars/ellipses with center point and startpoint to endpoint
reset session
set size square
set angle degrees
FileToDatablock(f,d) = GPVAL_SYSNAME[1:7] eq "Windows" ? \
sprintf('< echo %s ^<^<EOD & type "%s"',d,f) : \
sprintf('< echo "\%s <<EOD" & cat "%s"',d,f) # Linux/MacOS
FILE = 'SO57408781_Arcs.dat'
# file structure
# x0 y0 x1 y1 x2 y2 rotation_direction
load FileToDatablock(FILE,'$Arcs')
# value extraction from datablock
x(i,n) = word($Arcs[i],2*n+1)
y(i,n) = word($Arcs[i],2*n+2)
Direction(i) = word($Arcs[i],7) # rotation direction +1=CCW, -1=CW
# length and angles
L(dx,dy) = sqrt(dx**2 + dy**2)
Angle(x0,y0,x1,y1) = (_dx=x1-x0, _dy=y1-y0, _L=sqrt(_dx**2 + _dy**2), _L==0 ? NaN : \
(_dy>=0 ? acos(_dx/_L) : 360-acos(_dx/_L) ))
# get x,y vector lengths, angles and rotation direction
getXYVAD(n) = (x0=x(n,0), y0=y(n,0), x1=x(n,1), y1=y(n,1), x2=x(n,2), y2=y(n,2), \
v1=L(x1-x0,y1-y0), v2=L(x2-x0,y2-y0), \
a1=Angle(x0,y0,x1,y1), a2=Angle(x0,y0,x2,y2), rd=Direction(n) )
# calculate parameters for the arc
getParamsA(i) = (ca=a2>a1, cd=rd>0, a12=(360*(cd && ca ? 0 : 1) + (a2-a1)*(cd?1:-1))*(cd?1:-1) )
xPosA(i,t) = x0 + (v1*(1-t) + v2*t)*cos(a1+a12*t)
yPosA(i,t) = y0 + (v1*(1-t) + v2*t)*sin(a1+a12*t)
# calculate parameters for the ellipse
getParamsE(n) = (v1>=v2 ? (va=v1, vb=v2, aa=a1, ab=a2) : (va=v2, vb=v1, aa=a2, ab=a1), \
ca = a2>=a1, cd = rd>0, cv = v1>=v2, \
a12 = 360*(a1-a2!=0 && ca==cd ? 0 : cd==cv?1:-1) + (cv?1:-1)*(a2-a1), \
a3 = asin(sqrt(va**2 - (vb*cos(a12))**2) / va), \
a = (abs(a12)<90 ? a3 : abs(a12)<180 ? 180-a3 : abs(a12)<270 ? 180+a3 : 360-a3)*sgn(a12), \
Ra=va, Rb = (abs(a12)==180 || abs(a12)==360) ? Ra : va*vb*abs(sin(a12))/sqrt(va**2 - (vb*cos(a12))**2))
xPosE(i,t) = x0+Ra*cos(a*t)*cos(aa)-Rb*sin(a*t)*sin(aa)
yPosE(i,t) = y0+Ra*cos(a*t)*sin(aa)+Rb*sin(a*t)*cos(aa)
set xrange[-11:11]
set yrange[-11:11]
set key out center top noautotitle
set multiplot layout 1,2
set key title 'Rotating \& scaling vectors'
plot for [i=1:|$Arcs|] [t=0:1] '+' u (getXYVAD(i), getParamsA(i), xPosA(i,t)):(yPosA(i,t)) w l lc "web-green",\
$Arcs u 1:2:($3-$1):($4-$2) w vec lc "blue", \
'' u 1:2:($5-$1):($6-$2) w vec lc "red", \
'' u 1:2 w p pt 7 lc "black" ti "Center point", \
'' u 3:4 w p pt 7 lc "blue" ti "Start point", \
'' u 5:6 w p pt 7 lc "red" ti "End point", \
'' u 1:2:($0+1) w labels offset -0.7,-0.7
set key title 'Drawing ellipses'
plot for [i=1:|$Arcs|] [t=0:1] '+' u (getXYVAD(i), getParamsE(i), xPosE(i,t)):(yPosE(i,t)) w l lc "web-green",\
$Arcs u 1:2:($3-$1):($4-$2) w vec lc "blue", \
'' u 1:2:($5-$1):($6-$2) w vec lc "red", \
'' u 1:2 w p pt 7 lc "black" ti "Center point", \
'' u 3:4 w p pt 7 lc "blue" ti "Start point", \
'' u 5:6 w p pt 7 lc "red" ti "End point", \
'' u 1:2:($0+1) w labels offset -0.7,-0.7
unset multiplot
### end of code
Result:

How to draw a filledcurve graph with GNUPlot by using 2 csv files

If I have 2 csv files ("CSV1.csv" dataname_1 and "CSV2.csv" dataname_2), how can I draw filled curve graph from the data of 2 csv files. The formats of these CSV files are identical, where 2 is timestamps and 5 is the value thus the using 2:5
I am trying this:
plot dataname_2 using 2:5 title "Above" with filledcurves above lc rgb 'blue',\
dataname_1 using 2:5 title "Below" with filledcurves below lc rgb 'red',\
dataname_2 using 2:5 title "Engine Starts" with lines lc rgb "#1E90FF",\
dataname_1 using 2:5 title "Engine Hours" with lines lc rgb "#FF1493"
I need to modify the code above so that the output is:
A solution which will probably always work is to prepare the data with whatever external tool in such a way that gnuplot can handle and plot it. I'm aware that the philosophy of gnuplot is to concentrate on plotting and not necessarily on data preparation for plotting. However, it is always good to have a minimum set of features to do some basic data preparation.
In your case you have several problems, well, let's call it challenges ;-)
with filledcurves requires data within the same file or datablock
however, gnuplot cannot easily merge datafiles line by line (it can with some workaround, see: https://stackoverflow.com/a/61559658/7295599). Simply appending would be no problem with gnuplot.
the latter doesn't help you since with filledcurves needs identical x for upper and lower curve, i.e. x,y1,y2 and your data has x1,y1 and x2,y2
however, gnuplot cannot easily resample data (it can with some workaround, see: Resampling data with gnuplot)
with filledcurves cannot directly fill curves with non-monotonic increasing x (not the case with your data. Here just for illustration purposes) (it can with some workaround see: https://stackoverflow.com/a/53769446/7295599 or https://stackoverflow.com/a/56176717/7295599)
So a workaround for all this could be the following (works with gnuplot 5.2, maybe can be tweaked to work with earlier versions):
Assumptions:
Data x1,y1 and x2,y2 in two files or datablocks
Data has not necessarily identical x, i.e. x1,y1 and x2,y2
Data may contain non-monotonic x
the two curves have only one intersection (well, the workaround below will just take the first one)
Procedure:
if not already, get the data into a datablock.
Find the intersection of the curves.
Create new datablocks: Filled1 using Data1 from the beginning to the intersection point and using Data2 backwards from the intersection point to the beginning. Filled2 using Data1 from the end backwards to the intersection point and using Data2 from the intersection point to the end.
Plot $Data1 and $Data2 with lines and $Filled1 and $Filled2 with filledcurves
Steps 2 and 3, probably will not be much shorter in another programming language unless there are dedicated functions.
Get files to datablock: (see also here gnuplot: load datafile 1:1 into datablock)
# get files to datablocks
set table $Data1
plot 'myFile1.dat' u 1:2 w table
set table $Data2
plot 'myFile2.dat' u 1:2 w table
unset table`
Code: (copy&paste for gnuplot >=5.2)
### fill intersecting curves from two files not having identical x
reset session
$Data1 <<EOD
1 1
2 0
4 1
3 3
5 5
6 6
8 8
9 9
EOD
$Data2 <<EOD
1 3
3.5 5
7.5 1
9 7
EOD
# orientation of 3 points a,b,c: -1=clockwise, +1=counterclockwise
Orientation(a,b,c) = sgn((word(b,1)-word(a,1))*(word(c,2)-word(a,2)) - \
(word(c,1)-word(a,1))*(word(b,2)-word(a,2)))
# check for intersection of segment a-b with segment c-d,
# 0=no intersection, 1=intersection
IntersectionCheck(a,b,c,d) = \
Orientation(a,c,b) == Orientation(a,d,b) || \
Orientation(c,a,d) == Orientation(c,b,d) ? 0 : 1
# coordinate of intersection
M(a,b) = real(word(a,1)*word(b,2) - word(a,2)*word(b,1))
N(a,b,c,d) = (word(a,1)-word(b,1))*(word(c,2)-word(d,2)) - \
(word(a,2)-word(b,2))*(word(c,1)-word(d,1))
Px(a,b,c,d) = (M(a,b)*(word(c,1)-word(d,1)) - (word(a,1)-word(b,1))*M(c,d))/N(a,b,c,d)
Py(a,b,c,d) = (M(a,b)*(word(c,2)-word(d,2)) - (word(a,2)-word(b,2))*M(c,d))/N(a,b,c,d)
Intersection(a,b,c,d) = sprintf("%g %g", Px(a,b,c,d), Py(a,b,c,d))
stop = 0
do for [i=1:|$Data1|-1] {
a = $Data1[i]
b = $Data1[i+1]
do for [j=1:|$Data2|-1] {
c = $Data2[j]
d = $Data2[j+1]
if (IntersectionCheck(a,b,c,d)) {
i0 = i; j0 = j
stop=1; break }
}
if (stop) { break }
}
# create the datablocks for the outline to be filled
set print $Filled1
do for [k=1:i0] { print $Data1[k] }
print Intersection(a,b,c,d)
do for [k=j0:1:-1] { print $Data2[k] }
set print $Filled2
do for [k=|$Data1|:i0+1:-1] { print $Data1[k] }
print Intersection(a,b,c,d)
do for [k=j0+1:|$Data2|] { print $Data2[k] }
set print
set key top left
plot $Filled1 u 1:2 w filledcurves lc rgb 0x3f48cc, \
$Filled2 u 1:2 w filledcurves lc rgb 0xed1c24, \
$Data1 u 1:2 w lp pt 7 lw 5 lc rgb 0x99d9ea, \
$Data2 u 1:2 w lp pt 7 lw 5 lc rgb 0xff80c0
### end of code
Result:

Gnuplot last point in line

I have some values of an experiment I want to plot in the xyz coordinate system. the values are somewhat limited to a certain amount and have thus a beginning and an end. Furthermore I want to plot them and the last point of them should be visible in a special way. Like a unique point with a special color or a special dot. How can I create such a line where the end is visible as a dot or something similar?
In case that it is the last point, you can use every to select it. Unfortunately, there is no 'magic' value to get the last point. You must count the number of entries and use that value:
stats 'file.dat' nooutput
last_index = int(STATS_records - 1)
splot 'file.dat' with lines, '' every ::last_index with points
Alternatively, you could use the using statement, to add some filtering which is true only for this single point which you want to select.
In the most general case, you would have
f(i, x, y, z) = ...
splot 'file.dat' with lines, '' using (f($0, $1, $2, $3) ? $1 : 1/0):2:3 with points
This skips all points, for which f returns 0. $0 is the shorthand for column(0), which gives the row index, $1 gives the numerical value of the first column and so on.
Now it is up to you to define an appropriate filtering function f.
If the end point is given e.g. by the point with the maximum x-value, you could use:
stats 'file.dat' using 1 nooutput
f(x) = (x == STATS_max ? 1 : 0)
splot 'file.dat' with lines, '' using (f($1) ? $1 : 1/0):2:3 with points
If you have an other criterium, you must define your function f accordingly.
To add a label to this point, you can use the label plotting style:
splot 'file.dat' with lines, \
'' using (f($1) ? $1 : 1/0):2:3:(sprintf('(%.1f,%.1f,%.1f)', $1, $2, $3)) \
offset char 1,1 point notitle
Here is a solution without stats which works even with gnuplot 4.4.0 (I guess stats was only available in gnuplot 4.6.0).
use the pseudocolumn 0 (check help pseudocolumns), if $0==0 (i.e. first row) you assign the values to x0,y0,z0.
assign x1=$1, y1=$2, and z1=$3. So after the first plot command the variables x1,y1,z1 hold the last point's coordinates.
use the special filename '+' (check special filenames) for plotting a single datapoint.
Script: (works with gnuplot>=4.4.0, March 2010)
### mark startpoint and endpoint of a path
reset
FILE = "SO19426060.dat"
# create some random test data
a = rand(0)
b = rand(0)
c = rand(0)
set table FILE
splot '+' u (a=a+rand(0)-0.5):(b=b+rand(0)-0.5):(c=c+rand(0)-0.5)
unset table
set grid x
set grid y
set xyplane relative 0
splot FILE u ($0==0?x0=$1:0,x1=$1):($0==0?y0=$2:0,y1=$2):($0==0?z0=$3:0,z1=$3) \
w l lc rgb "black" notitle, \
'+' u (x0):(y0):(z0) every ::0::0 w p pt 7 lc rgb "blue" ti "start", \
'+' u (x1):(y1):(z1) every ::0::0 w p pt 7 lc rgb "red" ti "end"
### end of script
Result:

Resources