Show time based xtics at midday / noon - gnuplot

I have some csv data I'm trying to plot in gnuplot.
example:
1,2014-11-07T17:01
2,2014-11-08T11:53
3,2014-11-08T18:50
4,2014-11-09T09:42
5,2014-11-10T11:40
6,2014-11-11T12:34
I'm using
set xtics format "%a"
to show a short day name of the week (Mon, Tue, Wed) which is shown once per day at midnight.
How can I get gnuplot to show the xtics at midday/noon/12pm rather than at midnight?

This is a bit similar to the question mixing date and time on gnuplot xaxis. It's basically about extracting the timestamp for the first noon based on the first date in your data file. Then you can use this timestamp as start for setting the xtics.
The extraction of the first noon is done with stats, strptime and some other time functions:
reset
fmt = "%Y-%m-%dT%H:%M"
set datafile separator ','
stats 'test.txt' using (strptime(fmt, strcol(2))) every ::::0 nooutput
t = int(STATS_min)
t_start_midnight = t - tm_hour(t)*60*60 - tm_min(t)*60 - tm_sec(t)
t_start_noon = t_start_midnight - 12*60*60
Then you can plot your data with
set xdata time
set timefmt fmt
set xtics t_start_noon, 24*60*60
set format x '%a'
plot 'test.txt' using 2:1 with lp pt 7 ps 2 notitle
Note, that stats doesn't work in time mode, and must be invoked before set xdata time.

Related

Labeling Points with a date/time x axis in GNUPLOT

I have a simple dataset consisting of a date/time field (YYYY-MM-DD HH:MM) and a temperature field, taken at 1 minute intervals. I am trying to learn how to label points on a plot such than I can label the max and min temperatures.
The data is coming from an SQL server in a node.js app and the commands / data are being piped to gnuplot via STDIN with the output being a PNG. I can successfully plot the data, but now I am just trying to label the max and min temperature points on the plot, with the "coordinates" coming from an SQL query such that a min or max point would look like (x,y) = (2021-02-11 18:34, 72.57). Every command I try that should label points on the plot have no effect. And the examples that I find usually don't involve a date/time x-axis.
What is the magic ju-ju needed to be able to take an arbitrary data point and label it on the plot with a time/date x-axis? FWIW, since the data is being retrieved from an SQL server, I can format the data in whatever way makes it the easiest method needed to plot the data and more importantly, label the points that I want.
Thanks in advance for any advice!!
Justin
EDIT (per the first comment):
Here is what I am using in terms of gnuplot commands:
set term png size 1280,600
unset output
set datafile separator ","
set xdata time
set timefmt "%Y-%m-%d %H:%M"
set format x "%H:%M"
set ylabel "Temperature ˚F
set xlabel "Time
set style line 100 lt 1 lc rgb "grey" lw 0.5
set grid ls 100
set xtics border
set xtics rotate
set key off
$mydata << EOD
// this is where my code "prints" the SQL data to STDIN of gnuplot
// data is formatted: 2021-02-11 22:48,74.42
EOD
plot $mydata using 1:2 with lines
Note, I can format the data in whatever way that makes it easiest for gnuplot to process. I have found that sending YYYY-MM-DD HH:MM,TEMP has worked without issue.
I am tring to use the 'set label' command using a time/date as the x value and the temperature as the y value:
set label 1 'Maximum' at 2021-02-11 19:10,72.50
which does not produce any labels.
Here is an example plot where I want to label the max and min points:
When the x axis is time, the units are seconds. You are looking for the functions that convert between seconds (a floating point value) and a formatted time/date string.
strptime("timeformat",s) reads the time from the string s using the
timeformat specifiers and converts it into seconds since the year 1970.
strftime("timeformat",t) produces a string by applying the timeformat
specifiers to the time t
given in seconds since the year 1970.
In the case you show, this would correspond to:
myformat = "%Y-%m-%d %H:%M"
set label 1 'Maximum' at strptime(myformat, "2021-02-11 19:10"), 72.50

Gnuplot: multiple lables on x axis

I'm trying to plot the following data
29.07.2012 18:45:04;23.6;54
29.07.2012 18:50:04;22.7;56
29.07.2012 18:55:04;22.2;56
29.07.2012 19:00:04;22.0;56
29.07.2012 19:05:04;21.9;57
29.07.2012 19:10:04;21.8;56
29.07.2012 19:15:04;21.8;54
29.07.2012 19:20:04;21.7;53
29.07.2012 19:25:04;21.7;53
(Date, time, temperature, humidity) in the following style (cropped at the top):
The labels on the x axis are the hour from the time of day and below are the weekdays and the date. I don't have the weekdays in my data file, but I'd like to have the date below the hours.
My plotfile:
set datafile separator ";"
set terminal png size 5280,1024
set output '~/tfd.png'
set xdata time
set timefmt "%d.%m.%Y %H:%M:%S"
set format x "%H"
plot "data.csv" using 1:2 title 'temperatur'
I can think of three method to do this. If you don't have to have those dates on the same axis, the second method is probably the most stable. Both the first and third methods have their advantages and disadvantages. Between those two, the third is possibly the better approach, but it requires more work.
For these examples, in order to make sure that the data would span more than 1 day, I used your same data but added one extra line
31.07.2012 19:30:04;22.7;53
All three methods work with version 5.0.
Method 1 does not line up correctly in version 4.6, but can be made to with one extra command.
Method 2 should work in any reasonably recent version.
Method 3 will not place all date labels in version 4.6 due to an overflow bug in iteration (see here for some explanation), but can be made to work by changing the iteration to place the labels.
Method 1 - Multiplot
We can do this by superimposing the same plot over itself using multiplot and doing the x-axis different each time.
set datafile separator ";"
set xdata time
set timefmt "%d.%m.%Y %H:%M:%S"
# Increase bottom margin to allow room for dates
set bmargin at screen 0.1
set multiplot layout 1,1
# tics starting at 0 every 6 hours showing hour
set xtics 0,60*60*6 format "%H"
plot "data.csv" using 1:2 with lines t "Temperature"
# Tics starting at 0 every 24 hours showing day.month
# moved down by 1 character to be under hours
set xtics 0,60*60*24 format "%d.%m" offset 0,-1
set origin 0,0 # This is not needed in version 5.0
replot
unset multiplot
Other than the difference in the axis labels, the plots must be identical to avoid them not lining up, and it does cause the y-axis labels to be slightly bolded as they are written over themselves.
In version 5.0 the set origin command is not needed, but is needed in version 4.6.
Method 2 - Secondary Axis
If using the secondary axis is acceptable, you could also approach it that way. For example, if the day is shown on the x2 axis and the hour on the x1 axis, we could do
set datafile separator ";"
set xdata time
set x2data time
set timefmt "%d.%m.%Y %H:%M:%S"
set xtics 0,60*60*6 format "%H"
set x2tics 0,60*60*24 format "%d.%m"
plot "data.csv" using 1:2 with lines t "Temperature"
This eliminates some of the problems of the multiplot method, but results in the two data labels being on different axes.
Method 3 - Setting Manual Labels
Finally we can manually set the labels. Fortunately, we can use a loop in the most recent version of gnuplot, so we don't have to issue a separate command for it, but we do have to compute the labels ourselves.
We can use the stats command to compute the labels. The stats command will complain if we give it time data, so we must use it before setting the time mode on, and we must do a little bit of work for computing the day boundaries. To make sure that we are working with the start of each day and not sometime in the middle, we parse the dates into an internal representation (seconds since the Unix Epoch), and round down to the nearest multiple of 86400 (the number of seconds in a day).
Altogether we can do
# in-large margin for date labels
set bmargin at screen 0.1
set datafile separator ";"
# Get first and last day in data file as STATS_min and STATS_max
stats "data.csv" u (floor(strptime("%d.%m.%Y %H:%M:%S",stringcolumn(1))/86400)*86400) nooutput
set xdata time
set timefmt "%d.%m.%Y %H:%M:%S"
set for [i=STATS_min:(STATS_max+86400):86400] label strftime("%d.%m",i) at i,graph 0 center offset 0,char -2
# set xtics every 6 hours
set xtics 0,60*60*6 format "%H"
plot "data.csv" using 1:2 with lines t "Temperature"
We can improve this by numbering the labels if we need to later remove them ((i-STATS_min)/86400+1 will number them 1, 2, 3, etc). Note that like the first method we needed to increase the margin size on the bottom. I added one extra day to the labels to cover the possible rounding up that gnuplot will do on the x-axis.
There is a bug dealing with iteration and integer overflow in version 4.6. To use this solution in 4.6, change
set for [i=STATS_min:(STATS_max+86400):86400] label strftime("%d.%m",i) at i,graph 0 center offset 0,char -2
to
days = (STATS_max-STATS_min)/86400+1
set for [i=0:days] label strftime("%d.%m",i*86400+STATS_min) at (i*86400+STATS_min),graph 0 center offset 0,char -2

Plot same TimePeriod from Multiple Days

My Data Looks like this:
File_A
2015-08-01 00:00 424.9563018750976
2015-08-01 00:01 785.7380434263472
....
2015-08-01 23:59
File_B
2015-08-02 00:01 1.4625096463725384
2015-08-02 00:02 6.0047607076482485
....
2015-08-02 23:59
So the Date Format is: %Y-%m-%d %H:%M
I'd like to plot a series for the whole month but for each day only the timeperiod fom e.g. 09:00 - 15:00.
Here's what I tried:
clear
reset
cd 'C:\Users\SammerP\Desktop\Desktop Calc\AIT ALL\CatchAllDataAIT\data'
set title 'Data of Month' font 'bold verdana,08'
set xdata time
set timefmt '%Y-%m-%d %H:%M'
set format x '%Y-%m-%d %H:%M'
set ylabel 'Value'
set yrange [550:700]
set ytics (550,560,570,580,590,600,610,620,630,640,650,660,670,680,690,700,710,720,730,740,750,760,770,780,790,800)
set xtics rotate by 45 offset -1.5,-1.2
set xrange ['2014-08-01 09:00':'2014-08-31 15:00']
set xtics ('08-01' '2014-08-01 13:00','08-02' '2014-08-02 13:00','08-03' '2014-08-03 13:00','08-04' '2014-08-04 13:00','08-05' '2014-08-05 13:00',\
'08-06' '2014-08-06 13:00','08-07' '2014-08-07 13:00','08-08' '2014-08-08 13:00','08-09' '2014-08-09 13:00','08-10' '2014-08-10 13:00','08-11' '2014-08-11 13:00',\
'08-12' '2014-08-12 13:00','08-13' '2014-08-13 13:00','08-14' '2014-08-14 13:00','08-15' '2014-08-15 13:00','08-16' '2014-08-16 13:00',\
'08-17' '2014-08-17 13:00','08-18' '2014-08-18 13:00','08-19' '2014-08-19 13:00','08-20' '2014-08-20 13:00','08-21' '2014-08-21 13:00',\
'08-22' '2014-08-22 13:00','08-23' '2014-08-23 13:00','08-24' '2014-08-24 13:00','08-25' '2014-08-25 13:00','08-26' '2014-08-26 13:00',\
'08-27' '2014-08-27 13:00','08-28' '2014-08-28 13:00','08-29' '2014-08-29 13:00','08-30' '2014-08-30 13:00','08-31' '2014-08-31 13:00')
set grid
set nokey
plot'File_A.csv' using 1:2 axes x1y1 linewidth 1 lc rgb 'red' w l,\
'File_B' using 1:2 axes x1y1 linewidth 1 lc rgb 'red' w l,
..........
I tried it by plotting only the certain line from each file but than I end up with hole between the days.
I thought that maybe the problem was the xrange setting so I deleted that but the Problem was the same
Is there a way to set the xrange so that Gnuplot plots From Day 1 to 31, every Day from 09:00 from 15:00 and without the empty spaces between the days.
Here's an example of how it looks like now:
That cannot be done automatically with gnuplot. In my opinion, your best option is to not use a time-axis, but a normal numerical axis and provide your own mapping to label the xtics properly and to adjust the gap between the days like you want.
Here is a possible solution, but without having proper data for testing I couldn't verify if I got all steps correct:
gapBetweenDaysInSeconds = 1000
startHour = 9.0
endHour = 15.0
set xtics ("01-08" (13-startHour)*60*60)
set for [i=2:31] xtics add (sprintf("08-%02d", i) ((i-1)*(endHour-startHour) + 13 - startHour)*60*60 + (i-1)*gapBetweenDaysInSeconds)
# for gnuplot 5.0
# gettime(col) = timecolumn(col, '%Y-%m-%d %H:%M')
# for all gnuplot version.
gettime(col) = strptime('%Y-%m-%d %H:%M', strcol(col).' '.strcol(col+1))
files="File_A.csv File_B.csv File_C.csv" # ... to be continued
plot for [file in files] file using (t=gettime(1), tm_hour(t) < startHour || tm_hour(t) >= endHour ? 1/0 : (((tm_mday(t)-1)*(endHour-startHour) + (tm_hour(t)-startHour))*60 + tm_min(t))*60 + tm_sec(t) + (tm_mday(t)-1)*gapBetweenDaysInSeconds):2 lt 1
That assumes, that you have one file per day, and those files are listed, separated by white spaces, in the variable files.
The first call to set xtics sets only a single xtic and deletes all other. Then I use set xtics add to add all following tics in a loop.
For each row, the time stamp is parsed using the gettime user-defined function and assigned to the variable t. In a second step I extract only the day of the mont, hour, minutes and seconds using the tm_* functions and calculate a position on the xaxis given in seconds since the first of the respective month. The gap between two days can be given using the variable gapBetweenDaysInSeconds.
At the moment the month is hardcoded to 08.
That should be a reasonable starting point.

gnuplot, plotting time on x-axis

I have data in the following format in a text file. I want to print the time (hours, mins and secs) on the x-axis. Each timestamp is on a separate line
00:00:05,1
00:00:15,0
01:05:23,1
07:45:00,0
23:21:22,1
Trying the following commands with gnuplot but time isn't printed on x-axis. I would like the time displayed in hours.
set datafile separator ","
set xdata time
set xrange["00:00:00":"24:00:00"]
set timefmt '%H:%M:%S
plot 'data.txt' using 1:2 with boxes
Any help greatly appreciated.
The set timefmt settings are used only for reading the data file. If you don't provide an explicit output format, timedate is assumed automatically. Use set xtics format '%H:%M:%S' to set an explicit output format. Also, parsing of the set xrange strings can be done properly only after you have set the time format:
set datafile separator ","
set xdata time
set timefmt '%H:%M:%S
set xrange["00:00:00":"24:00:00"]
set xtics format '%H:%M:%S'
plot 'data.txt' using 1:2 with boxes

Make gnuplot's x axis start at 0 instead of the first date

I'm plotting some [date, value] formatted data (cpu use over time) and want the xtics to start at 0 or 1 instead of the first date.
So for 10 hours it should look like: 0:01:00, 0:02:00, .., 0:10:00 insead of 9:23:00 ... (since the first day in the data is the 9th at 11pm).
My current datetime settings:
set xdata time
set timefmt "%Y-%m-%d %H:%M:%S"
set xtics format "%d:%H:%M" font ",25"
Edit: If there's a way to just count hours starting from 0 on the x axis without day info that'd be awesome too. Either way. I just want to start counting from 0 to make the "time taken" very clear.
I couldn't get it to work with set xdata time, because for the output only the day of the month is available, which is in the range [1:31], so the 0-position would start with 1. The same happens for total number of hours, because that value is limited to [0:23], so that number over 23 are wrapped back.
Here is a solution without time data. I use the strptime function to convert the date string to a time stamp (in seconds), which is then divided by 3600 to get the hour (as float number):
The test data file is:
2013-08-25 18:45:11 100
2013-08-25 19:11:23 200
2013-08-25 20:00:32 400
2013-08-25 21:00:32 300
2013-08-26 20:11:12 500
And the example script:
reset
file='data.txt'
fmt="%Y-%m-%d %H:%M:%S"
start=system('head -1 '.file)
start_stamp = strptime(fmt, start)
plot 'data.txt' using ((strptime(fmt, stringcolumn(1).' '.stringcolumn(2))-start_stamp)/3600.0):3 with lines t ''
The first column is extracted with an external tool.
The result is:
And here is another variant, which uses a more comfortable data format, using commas as separators, and the first column is extracted with gnuplot:
The data file:
2013-08-25 18:45:11,100
2013-08-25 19:11:23,200
2013-08-25 20:00:32,400
2013-08-25 21:00:32,300
2013-08-26 20:11:12,500
The script file:
reset
file='data.txt'
fmt="%Y-%m-%d %H:%M:%S"
set datafile separator ','
plot 'data.txt' using ($0 == 0 ? start_stamp = strptime(fmt, stringcolumn(1)) : 0, \
(strptime(fmt, stringcolumn(1))-start_stamp)/3600.0):2 with lines t ''
The results are equivalent.
EDIT: One last variant, which is a mixture #andyras's and my answer. You can use set timefmt with an explicit call to timecolumn to parse the input as time. The output is then handled like a conventional double number. I use $0, i.e. the number of the current sample, to set the offset value:
reset
set timefmt "%Y-%m-%d %H:%M:%S"
offset = 0
t0(x)=(offset=($0==0) ? x : offset, x - offset)
plot 'data.txt' u (t0(timecolumn(1))/3600.0):3 notitle w l
This is not quite an answer, but close enough that I am posting it as such.
I have a way that you can start the time file at time zero (inspired by this answer to an old question of mine):
set xdata time
set timefmt "%Y-%m-%d %H:%M:%S"
set xtics format "%d:%H:%M" font ",6"
first = 0
offset = 0
# returns data offset by first value
t0(x)=(offset=(first==0)?x:offset,first=1,x-offset)
plot 'data.dat' u (t0(timecolumn(1))):3 notitle
Here are some sample data
2013-09-16 00:14:00 1
2013-09-26 00:15:00 3
2013-10-04 00:16:00 2
2013-10-19 00:17:00 4
and the output:
This strategy has the problem that once the data go above 31 days the date counter resets.
I could not figure out how to get the xtics format to manipulate data columns.

Resources