Gnuplot: plotting the maximum of two files - max

let's assume I have two files formatted like this:
x --- y
0 --- 2
1 --- 2.4
2 --- 3.6
which differ for the values of y.
is there a way to plot a single graph that is, for every x, the maximum value of y between the two files?
Dunno if explained my self sufficiently well.
I was trying with conditional sentences but I couldn't find any expression that let me search in 2 different files

There is no way to combine two files or more in a single plot with gnuplot only. You must use an external tool to do this, e.g. the command line utility paste:
max(x, y) = (x > y ? x : y)
plot '< paste fileA.txt fileB.txt' using 1:(max($2, $4))
The y values are contained in the second and fourth columns.
This next version uses a python script with numpy to concatenate the files, but any other scripting language would also do:
"""paste.py: merge lines of two files."""
import numpy as np
import sys
if (len(sys.argv) < 3):
raise RuntimeError('Need two files')
A = np.loadtxt(sys.argv[1])
B = np.loadtxt(sys.argv[2])
np.savetxt(sys.stdout, np.c_[A, B], delimiter='\t')
To plot, use:
max(x, y) = (x > y ? x : y)
plot '< python paste.py fileA.txt fileB.txt' using 1:(max($2, $4))

Just for the records, there is a way with gnuplot only to get the maximum out of two files.
For sure, it's probably more efficient to use Linux tools or on Windows install, e.g. CoreUtils from GnuWin, but with gnuplot-only you are surely platform independent without extra installations.
Assumption: both files have same number of lines and identical x-values
Edit: simplified code which works for all gnuplot versions>=4.6.0 and faster version for gnuplot>=5.2.0 using an array.
The simple "trick" is to write the y value of one file into a single string and address them via word(). For small data this is ok, but for larger data (>10'000 lines) it might get slow because apparently it runs with something like O(N^2). Just to get an idea (on my system): 1'000 lines take 0.4 seconds, 10'000 lines take 13 seconds and 20'000 lines already take 45 seconds.
As comparison, the array-solution for gnuplot>=5.2.0 just takes about 3 seconds for 10'000 lines.
Data:
SO19079146_1.dat
1 1.1
2 2.1
4 1.5
6 1.3
7 0.2
8 1.5
9 2.1
SO19079146_2.dat
1 2.1
2 2.5
4 1.5
6 0.3
7 0.7
8 1.0
9 1.4
Script 1: (works for gnuplot>=4.6.0, March 2012)
### plot maximum from two files
reset
FILE1 = 'SO19079146_1.dat'
FILE2 = 'SO19079146_2.dat'
data2 = ''
stats FILE2 u (data2=data2.' '.sprintf("%g",$2)) nooutput
set offset 1,1,1,1
max(col) = (i=int(column(0)+1), y1=column(col), y2=real(word(data2,i)), y1>y2 ? y1 : y2)
plot FILE1 u 1:(max(2)) w lp pt 7 lw 8 lc rgb "grey" ti "Max", \
'' u 1:2 w lp pt 7 lc rgb "red" ti "Data1", \
FILE2 u 1:2 w lp pt 7 lc rgb "blue" ti "Data2"
### end of script
Script 2: (works for gnuplot>=5.2.0, Sept. 2017)
### find the maximum out of two files/datablocks (gnuplot>=5.2.0)
reset session
FILE1 = 'SO/SO19079146_1.dat'
FILE2 = 'SO/SO19079146_2.dat'
stats FILE1 u 0 nooutput
array A[STATS_records]
stats FILE2 u (i=int($0+1), A[i]=$2) nooutput
set offset 1,1,1,1
max(col) = (i=int(column(0)+1), y1=column(col), y2=A[i], y1>y2 ? y1 : y2)
plot FILE1 u 1:(max(2)) w lp pt 7 lw 8 lc "grey" ti "Max", \
'' u 1:2 w lp pt 7 lc "red" ti "Data1", \
FILE2 u 1:2 w lp pt 7 lc "blue" ti "Data2"
### end of script
Result: (identical for all above versions)

Related

How to plot on the same graph with for cycles with Gnuplot?

I want to fit multiple data set and plot the result on the same graph, what I' am doing is:
do for [i=2:500]{
fit f(x) "myData" using 1:i via a,b
plot f(x)
}
The fit works fine, the big problem is that this code produce a different plot at each iteration. I would like to have all the fitted functions in a single graph. Is there any way ?
I guess you cannot fit and plot in the same loop. Well, there would be the multiplot environment (check help multiplot), but I guess this is not your idea.
So, you can fit in a do for loop and store the fitted parameters in an array for later use during plotting.
You didn't specify any function, so I assumed something. Check the following minimized example:
Code:
### fitting in a loop
reset session
$Data <<EOD
1 1 6 4
2 4 10 1
3 9 15 0
4 16 22 1
5 25 31 4
6 36 42 9
7 49 55 16
EOD
f(x,a,b,c) = a*(x-b)**2 + c
colMin = 2
colMax = 4
set fit quiet nolog
array A[colMax]
array B[colMax]
array C[colMax]
do for [col=colMin:colMax] {
a=1; b=1; c=1 # some initial values, sometimes 0 or NaN is not a good start
fit f(x,a,b,c) $Data u 1:col via a,b,c
A[col] = a; B[col] = b; C[col] = c
}
set key top left
plot for [col=colMin:colMax] $Data u 1:col w p pt 7 title sprintf("Column %d",col), \
for [col=colMin:colMax] f(x,A[col],B[col],C[col]) w l \
title sprintf("a=%.2f, b=%.2f, c=%.2f",A[col],B[col],C[col])
### end of code
Result:

gnuplot : setting line style in a for loop

I have to plot several curve on a same graph. I necessarly need to use a for loop to do this. I would like to plot the 2 first curves with lines and the others with points. I am able to plot all the curves with lines or all the curves with points but not to change in the same for loop.
Here is the concerned part of my code:
set style line 1 lw 1 lc rgb "green"
set style line 2 lw 1 lc rgb "purple"
set style line 3 pt 1 ps 1.0 lc rgb "red"
set style line 4 pt 2 ps 1.0 lc rgb "red"
set style line 5 pt 3 ps 1.0 lc rgb "red"
plot for [i=1:words(FILES)] myDataFile(i) u (column(1)):((word(UTAUS_ch,i))) ls i title myTitle(i)
I would like to preface "ls i" with "w l" for the 2 first curves and "ls i" for the others. I tried to use a if statement by replacing "ls i" by "if (i < 2) {w l ls i} else {ls i}" but Gnuplot does not expect to find a if statement at this location.
Can someone help me ?
Thank you,
Martin
As mentioned here you probably cannot switch plotting styles within a plot for loop.
So, either you do two separate loops, one with points and the other with lines or you do one loop with linespoints and define all necessary parameters for points and lines as functions (to keep the plot command readable).
As mentioned here, linewidth 0 is not zero but the thinnest possible line which is typically 1 pixel. To make the line disappear completely you have to use linetype -2.
Code:
### lines and points in the same plot for-loop
reset session
LINECOLORS = "red green blue magenta cyan"
LINEWIDTHS = '1.0 4.0 0.0 0.0 0.0'
POINTTYPES = '0 0 5 7 9'
POINTSIZES = '0 0 1.0 2.0 3.0'
TITLES = 'one two three four five'
myLinecolor(i) = word(LINECOLORS,i)
myLinewidth(i) = real(word(LINEWIDTHS,i))
myPointtype(i) = int(word(POINTTYPES,i))
myPointsize(i) = real(word(POINTSIZES,i))
myLinetype(i) = myLinewidth(i) == 0 ? -2 : 1
myTitle(i) = word(TITLES,i)
set samples 31
set key out
plot for [i=1:words(TITLES)] (sin(0.25*x-i)) w lp pt myPointtype(i) ps myPointsize(i) \
lt myLinetype(i) lw myLinewidth(i) lc rgb myLinecolor(i) title myTitle(i)
### end of code
Result:
Addition:
In order to keep the plot command as short and clear as possible you could also define line styles and use it in the plot for command via ls i, with the same result as above.
...
do for [i=1:words(TITLES)] {
set style line i pt myPointtype(i) ps myPointsize(i) \
lt myLinetype(i) lw myLinewidth(i) lc rgb myLinecolor(i)
}
plot for [i=1:words(TITLES)] (sin(0.25*x-i)) w lp ls i title myTitle(i)
Here a way using a macro:
set style line 1 lw 1 lc rgb "green"
set style line 2 lw 1 lc rgb "purple"
set style line 3 pt 1 ps 1.0 lc rgb "red"
set style line 4 pt 2 ps 1.0 lc rgb "red"
set style line 5 pt 3 ps 1.0 lc rgb "red"
set samp 100
set macro
cmd = ''
do for [i=1:10] {s = i<3? 'w l' : 'ls '.i;
cmd = cmd . '"+" us 1:(sin(x-'.i.'/10.)) '.s.' title "key '.i.'",'}
plot [0:2*pi] #cmd

GNUPLOT 5: conditional plotting with timefmt abscissa

I am having hard time applying conditional plotting to data with timefmt abscissa using gnuplot 5.0 patchlevel 6.
I am trying to plot the content of an ASCII file consisting in two columns:
2016-12-01 12
2017-01-01 1
2017-02-01 2
2017-03-01 3
2017-04-01 4
2017-05-01 5
2017-06-01 6
so I just issue:
set timefmt "%Y-%m-%d"
set xdata time
p 'file.dat' u 1:2 w l, '' u 1:($1>strptime("%Y-%m-%d","2017-03-01")?$2:10) w p
I expect the plot to look like a line following the second column and a series of dots, following the line for the last three abscissas or marking the value 10 at the previous ones.
Actually, all the points are at 10. Do you have any clue about what is happening? Many thanks in advance.
Use timecolumn.
p 'file.dat' u 1:2 w l, '' u 1:(timecolumn(1, "%Y-%m-%d")>strptime("%Y-%m-%d", "2017-03-01") ? column(2) : (10)) w p

Matlab - Algorithm for calculating 1d consecutive line segment edges from midpoints?

So I have a rectilinear grid that can be described with 2 vectors. 1 for the x-coordinates of the cell centres and one for the y-coordinates. These are just points with spacing like x spacing is 50 scaled to 10 scaled to 20 (55..45..30..10,10,10..10,12..20,20,20) and y spacing is 60 scaled to 40 scaled to 60 (60,60,60,55..42,40,40,40..40,42..60,60) and the grid is made like this
e.g. x = 1 2 3, gridx = 1 2 3, y = 10 11 12, gridy = 10 10 10
1 2 3 11 11 11
1 2 3 12 12 12
so then cell centre 1 is 1,10 cc2 is 2,10 etc.
Now Im trying to formulate an algorithm to calculate the positions of the cell edges in the x and y direction. So like my first idea was to first get the first edge using x(1)-[x(2)-x(1)]/2, in the real case x(2)-x(1) is equal to 60 and x(1) = 16348.95 so celledge1 = x(1)-30 = 16318.95. Then after calculating the first one I go through a loop and calculate the rest like this:
for aa = 2:length(x)+1
celledge1(aa) = x(aa-1) + [x(aa-1)-celledge(aa-1)]
end
And I did the same for y. This however does not work and my y vector in the area where the edge spacing should be should be 40 is 35,45,35,45... approx.
Anyone have any idea why this doesnt work and can point me in the right direction. Cheers
Edit: Tried to find a solution using geometric alebra:
We are trying to find the points A,B,C,....H. From basic geometry we know:
c1 (centre 1) = [A+B]/2 and c2 = [B+C]/2 etc. etc.
So we have 7 equations and 8 variables. We also know the the first few distances between centres are equal (60,60,60,60) therefore the first segment is 60 too.
B - A = 60
So now we have 8 equations and 8 variables so I made this algorithm in Matlab:
edgex = zeros(length(DATA2.x)+1,1);
edgey = zeros(length(DATA2.y)+1,1);
edgex(1) = (DATA2.x(1)*2-diffx(1))/2;
edgey(1) = (DATA2.y(1)*2-diffy(1))/2;
for aa = 2:length(DATA2.x)+1
edgex(aa) = DATA2.x(aa-1)*2-edgex(aa-1);
end
for aa = 2:length(DATA2.y)+1
edgey(aa) = DATA2.y(aa-1)*2-edgey(aa-1);
end
And I still got the same answer as before with the y spacing going 35,45,35,45 where it should be 40,40,40... Could it be an accuracy error??
Edit: here are the numbers if ur interested and I did the same computation as above only in excel: http://www.filedropper.com/workoutedges
It seems you're just trying to interpolate your data. You can do this with the built-in interp1
x = [30 24 19 16 8 7 16 22 29 31];
xi = interp1(2:2:numel(x)*2, x, 1:(numel(x)*2+1), 'linear', 'extrap');
This just sets up the original data as the even-indexed elements and interpolates the odd indices, including extrapolation for the two end points.
Results:
xi =
Columns 1 through 11:
33.0000 30.0000 27.0000 24.0000 21.5000 19.0000 17.5000 16.0000 12.0000 8.0000 7.5000
Columns 12 through 21:
7.0000 11.5000 16.0000 19.0000 22.0000 25.5000 29.0000 30.0000 31.0000 32.0000

gnuplot dashed lines in aqua terminal

I am using gnuplot 4.4 patchlevel 4 on Mac OS X v10.6.8. I'm running a gnuplot script, a simplified version of which is this: (file1, file2,...etc are specified in the terminal before running the script)
reset
set term aqua enhanced font "Times-Roman, 18"
set term aqua dashed
plot file1 u 3:10 w lines lt 1 linecolor rgb "#FF0000",\
file2 u 3:10 w lines lt 1 linecolor rgb "#00FF00",\
file3 u 3:10 w lines lt 1 linecolor rgb "#0000FF",\
file4 u 3:10 w lines lt 1 linecolor rgb "#FF00FF",\
file5 u 3:10 w lines lt 1 linecolor rgb "#00FFFF",\
file6 u 3:10 w lines lt 2 linecolor rgb "#FF0000",\
file7 u 3:10 w lines lt 2 linecolor rgb "#00FF00",\
file8 u 3:10 w lines lt 2 linecolor rgb "#0000FF",\
file9 u 3:10 w lines lt 2 linecolor rgb "#FF00FF",\
file10 u 3:10 w lines lt 2 linecolor rgb "#00FFFF"
files 1-5 are one data set and files 6-10 are another. I would like files 1 through 5 to be plotted with solid lines and files 6 through 10 to be plotted with dashed lines. Is there any way to do this in aqua terminal? According to the built-in help, "lines can be drawn either solid or dashed". I've looked at multiple faqs and docs but the consensus seems to be that it is really difficult or impossible to do? Additionally, does anyone know of any comprehensive documentation on the aqua terminal or on gnuplot commands in general?
Edit: To plot files 6-10 I have been using lw 6 to distinguish them from the 1-5 since I couldn't get dashed lines to work. Would the script above as I have it do this correctly? In other words, is the script doing what I think it is doing? (plotting 1-5 solid lines and 6-8 thicker lines?) I ask because in an attempt to make dashed lines, I replace "lw 6" with "lt 2". This however results in file5 being plotted with dashed lines which is just weird.
Edit 2: I attached my terminal test graphic and there doesn't seem to be any mention of dashed lines?
Edit 3: Updated script to reflect changes made.
Edit 4: Graphic is now of set term aqua enhanced font "Times-Roman, 18" dashed; test
It's not too bad at all actually (at least for me on OS-X 10.5.8 with gnuplot 4.2. I stopped building aquaterm in my newer versions of gnuplot as I don't like that terminal) In the aqua terminal, linetype 1 is solid and linetype 2 is dashed.
set term aqua enhanced font "Times-Roman, 18" dashed
plot sin(x) w lines lt 1 lc rgb "blue", cos(x) w lines lt 2 lc rgb "purple"
To see the linetypes that your version of gnuplot will use for a particular terminal, you can use the test command after setting the terminal (and output if the terminal needs it).
A suggestion for how your code should look:
reset
set term aqua enhanced font "Times-Roman, 18" dashed
plot file1 u 3:10 w lines lt 1 linecolor rgb "#FF0000",\
file2 u 3:10 w lines lt 1 linecolor rgb "#00FF00",\
file3 u 3:10 w lines lt 1 linecolor rgb "#0000FF",\
file4 u 3:10 w lines lt 1 linecolor rgb "#FF00FF",\
file5 u 3:10 w lines lt 1 linecolor rgb "#00FFFF",\
file6 u 3:10 w lines lt 2 linecolor rgb "#FF0000",\
file7 u 3:10 w lines lt 2 linecolor rgb "#00FF00",\
file8 u 3:10 w lines lt 2 linecolor rgb "#0000FF",\
file9 u 3:10 w lines lt 2 linecolor rgb "#FF00FF",\
file10 u 3:10 w lines lt 2 linecolor rgb "#00FFFF"
EDIT
I just looked on a friend's computer. for her (gnuplot 4.4.4, os-X 10.6?) linetype 8 was the first dashed linetype (highlighting the usefulness of the test command).

Resources