Gnuplot: multiple lables on x axis - gnuplot

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

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: How can I add vertical grid line only at midnight every day when using a time xscale?

How can I add vertical grid line only at midnight every day when using a time xscale in gnuplot? I want to be able to produce multiple plots with different time spans from 24-hours to 2-months. I want to put a vertical grid line at midnight every day on the graph so I can easily distinguish individual days on the graph. This is what my gnuplot script looks like now:
set terminal png size 900, 300
set output "images/temps.png"
set xdata time
set timefmt "%m/%d/%y %H:%M"
set datafile separator ","
set ylabel "Temperature \260F"
set xlabel "Time"
set grid ytics
set y2tics mirror
set y2label "Temperature \260F"
set grid xtics lc rgb "#888888" lw 1 lt 0
plot [:][:] 'data.csv' using 1:2 title "" with lines
With this script, I get vertical grids added at automatic intervals. Those intervals are meaningful intervals, but I want to be able to force the spacing.
I found my answer:
set xtics 86400
This is in seconds. 86400 seconds in 24 hours.

Positioning labels on x axis

I am trying to plot a simple graph, x and y coordinates, however how my axis labels are not quite as I wish.
How can I change the '1e+08' and so on to their true value, 100000000
How can I shift the labels of the xtics down so they don't obscure the graph?
Can I print the coordinates in the graph of certian points, for example the dip between 2014-05-10-04-00 and 2014-05-10-08-00?
How can one add more intervals in the labels of the x axis?
Here is the input I'm using:
reset
clear
set output "BytesOverTime.png"
set title "Evolution of Bytes over Time"
set ylabel 'Bytes'
set xlabel 'Time'
set key off
set term png
set xdata time
set timefmt "%Y-%m-%d-%H-%M"
set format x "%Y-%m-%d-%H-%M"
set xtics rotate by 90 nomirror
set datafile separator ' '
set logscale y
plot "timeBytesAverage.out" using 1:2
And the file if its needed to test:
http://pastebin.com/raw.php?i=qqpeJj4V
How can I change the '1e+08' and so on to their true value, 100000000
set format y "%f"
or, as this will give you decimal numbers:
set format y "%.0f"
You may also have a look at
set format y "%.0s%cByte"
which will create MByte, GByte, ... (See right y-axis in my plot)
However, this will be to the base of 1000, not 1024.
How can I shift the labels of the xtics down so they don't obscure the graph?
set xtics rotate by 90 nomirror right
will right-align (left-flush) the tic marks
Can I print the coordinates in the graph of certian points, for example the dip between 2014-05-10-04-00 and 2014-05-10-08-00?
If you know the coordinates, yes:
set xtics add ("high" "2014-05-09-23-30", "low" "2014-05-10-22-30" )
The general syntax is:
set xtics add ( <label1> <position1>, <label2> <position2> , ...)
This will add the list of labels to the automatically generated labels. If you omit the word add, there will be no automatically generated labels, just those in your list.
How can one add more intervals in the labels of the x axis?
set xtics 3600
will generate a label every 3600 seconds, i.e. every hour. This does not work for log scale axes.
set mxtics 2
will cause the gap between two major (labeled) tics being divided into two smaller gaps, i.e. one minor tic mark between two major ones. (However, it seems not to be necessary here, as gnuplot decides to use 2 on it's own)
And here is the result:
Note that I also added
set y2tics
set y2range[1E8:1E12]
set format y2 "%.0s%cByte"
set logscale y2
to demonstrate this special format on the right y-axis.
And by the way: The format of the labels on the y-axis is independent from the format in the data file.
set timefmt "%Y-%m-%d-%H-%M" defines the format inside the file
set format x "%Y-%m-%d-%H-%M defines the format in the plot. So ou may do something like set format x "%Y-%m-%d %H:%M which is more readable.

I have non-contiguous date/time X data and want non-contiguous X scale

I have non-contiguous date/time data (eg weekend data are missing - I don't have rows in data file for them) and I'd like to not to draw them. Graphically, it would be like cutting out a vertical slice of a plot. I'm aware that the X scale would not be linear and am perfectly happy with this.
Here it is what I want to get rid of:
The gnuplot script is auto-generated so it doesn't have to be very neat if it can't be. Currently I'm doing:
set xdata time
set timefmt "%d/%m/%Y-%H:%M:%S"
unset mx2tics
unset mxtics
set xtics border in scale 1,0.5 nomirror rotate font "Times-Roman,12" "$time_min", $xtics, "$time_max"
set xrange ["$time_minb" : "$time_maxb"]
set grid xtics back
Where obviously $var is a proper value of some variable $var. What I'd like to retain: some small (1-2 candles) margin on the left and on the right (between box border and data), labeled ticks every 10 candles.
Ideally all ticks at the borders of time intervals that would be put together in X axis would be marked. Also in the perfect world those labels would be slightly drawn aside to not to overlap each other. But I'm not very picky, I could bear even overlapping of the 2 labels on the joint of 2 intervals if only "empty piece" of a plot is removed.
BTW: I have gnuplot 4.6 but can update to 5.0 if it's necessary.
As I understand the question, it is not about breaking the axis. This would also be possible but might get complicated if you have more than one break.
Actually, there are later questions about the similar topic, e.g.: Remove weekend gaps in gnuplot for candlestick chart
The basic idea is to plot the data against the row index (pseudocolumn 0) instead of time (column 1) in order to make discontinuous data "continuous" and "manually" add the xtic labels.
The accepted solution to the above question, however, is using xticlabels and defines a function which shows, e.g. every 5th xticlabel. This looks OK for the illustrated case. However, although, only every Nth ticlabel will be shown, a tic will be created nevertheless at every data entry which will not look good for data with larger time range.
Hence, another approach would be plotting the data twice: first time for the data and the second time plotting NaN, i.e. nothing but the tics, where you can easily select the spacing via every (check help every). Although the data looks continuous, it might useful to indicate the breaks somehow, e.g. with extra tics or vertical lines. Alternatively, depending on the data, each start of a "continuous" subset could be marked with a date label followed by regular minor tics without labels.
Script: (works with gnuplot>=5.2.0, with some adaptions probably with earlier versions).
### plot dis-continuous time "continuous"
reset session
# create some random test data
set table $Data
myTimeFmt = "%Y-%m-%d"
t0 = time(0)
y0 = 100
f(t) = strftime(myTimeFmt,t1=t0+$0*3600*24)
plot '+' u (f(0)):(y0=y0+rand(0)*2-1) w table
t0 = t1 + (rand(0)*30+30)*3600*24
replot
t0 = t1 + (rand(0)*50+50)*3600*24
replot
unset table
set format x "%Y\n%m-%d" timedate
set grid x,y
set ytics 2
set key noautotitle
set multiplot layout 2,1
plot $Data u (timecolumn(1,myTimeFmt)):2 w l lc "red"
myXTic(col) = strftime("%Y\n%m-%d",timecolumn(col,myTimeFmt))
N = 30
plot $Data u 0:2 w l lc "web-green", \
'' u ($0*N):(NaN):xtic(myXTic(1)) every N
unset multiplot
### end of script
Result:

Plotting some date related records

I'm having some trouble with plotting dataset that looks like this:
2250,2011-07-05 02:00:00.0,null,4,0,0,24,0,626,2250,abc
2250,2011-07-05 04:00:00.0,null,2,0,0,24,0,302,2250,abc
2250,2011-07-05 03:00:00.0,null,9,0,0,24,0,687,2250,abc
2250,2011-07-03 03:00:00.0,null,4,0,0,24,0,423,2250,abc
2250,2011-07-02 05:00:00.0,null,3,0,0,24,0,1525,2250,abc
2250,2011-07-02 04:00:00.0,null,4,0,0,24,0,636,2250,abc
2250,2011-07-11 04:00:00.0,null,1,0,0,24,0,33,2250,abc
2250,2011-07-02 03:00:00.0,null,2,0,0,24,0,495,2250,abc
I'm using this kind of gnuplot script:
set datafile separator ","
set xdata time
set timefmt "%Y-%m-%d %H:%M:%S.0"
set xrange ["2011-06-29 01:00:00.0":"2011-07-11 04:00:00.0"]
set xtics border in scale 1,0.5 nomirror rotate by -45 offset character 0, 0, 0
plot "input.csv" using 1:8 title "total times" with linespoints
I keep getting an error:
all points y value undefined!
which according to docs means that my plot definition did not produce any points. However by analyzing it by hand, it looks unreasonable - the xrange looks ok and the plot columns are also not null.
Any ideas?
With this script, you try to plot the first column as your x-axis and the eighth column as your y-axis. With set xdata time you specify, that the datatype of your x-axis is set to time/date.
Unfortunately your first column is not of type date nor time. Try
plot "input.csv" using 2:8 title "total times" with linespoints
and the script will run perfectly.
(At least it does on my machine ^^).

Resources