GNUPLOT 5: conditional plotting with timefmt abscissa - time

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

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

plotting multi bar graph (like clustered column in Excel)

I have the data in the following format
Type Sub-type Value
A A_1 10
A A_1 20
A A_1 30
A A_1 40
A A_2 25
A A_2 35
A A_3 45
B B_1 10
B B_1 20
B B_2 30
C C_1 10
C C_1 20
C C_2 10
C C_2 20
I want to plot multi bar plot in such a way that the bars of same sub-type will be same color. The different sub-types should have different column. The types should be separated by some spaces.
[Edited]
I used the http://bl.ocks.org/mbostock/3887051 with data.csv file but with some more rows
CA,2704659,4499890,2159981,3853788,10604510,8819342,4114496
CA,3704659,4499890,2659981,3853788,10604510,8819342,4114496
CA,6704659,4499890,2159981,3853788,10604510,8819342,4114496
TX,2027307,3277946,1420518,2454721,7017731,5656528,2472223
NY,1208495,2141490,1058031,1999120,5355235,5120254,2607672
NY,1008495,2671490,1058031,1999120,5355235,5120254,2607672
NY,1208495,2141490,1058031,1999120,5355235,5120254,2607672
FL,1140516,1938695,925060,1607297,4782119,4746856,3187797
IL,894368,1558919,725973,1311479,3596343,3239173,1575308
PA,737462,1345341,679201,1203944,3157759,3414001,1910571
PA,737462,1345341,679201,1203944,3157759,3414001,1910571
PA,37462,345341,79201,3944,31579,34101,1910571
This is too broad a question and the problem is not clearly stated. In order to get you started, here a very basic gnuplot solution (so.dat is the file with the data you have provided):
set datafile separator ","
set style fill solid
set style histogram
set style data histograms
set boxwidth .9
set yrange [0:11000000]
plot "so.dat" u 2:xtic(1), "so.dat" u 3:xtic(1), "so.dat" u 4:xtic(1), "so.dat" u 5:xtic(1), "so.dat" u 6:xtic(1), "so.dat" u 7:xtic(1), "so.dat" u 8:xtic(1)
which produces
You could customize from here, if that is close enough to what you want.

gnuplot with .6 second

I have a dataset with timestamps and values. The timestamp has 6 digit milli seconds. I tried to use this set format x "%H:%M:%.6S" with gnuplot. However, gnuplot cannot recognize this and just groups the values together for each second in the plot:
set format x "%H:%M:%.6S"
The dataset looks like this:
16:28:11.690076 1
16:28:11.690198 12
16:28:11.710519 14
16:28:11.730769 53
16:28:11.770280 18
16:28:11.791748 12
16:28:11.893583 15
The first column is the timestamp and the second column is the value. I want to plot the time on the x axis and the value on the y axis.
Now, gnuplot only gives me a plot up to seconds, but not millisecond. Is there something I should have set?
To read in time data you must use set timefmt ... to specify the format to use. Here, you must not specify the number of digits to use for the seconds, using %S reads the milliseconds as you specified them.
For the output you can set the number of digits:
set timefmt '%H:%M:%S'
set xdata time
set format x '%H:%M:%.3S'
plot 'test.txt' using 1:2 w lp pt 7 notitle

Gnuplot: plotting the maximum of two files

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)

Resources