How to plot month numbers in gnuplot 5.4?

Viewed 102

I am trying to get the month of a date in gnuplot 5.4.

Consider the following data:

2019/01/01
2019/02/01
2019/03/01
2019/04/01
2019/05/01
2019/06/01
2019/07/01
2019/08/01
2019/09/01
2019/10/01
2019/11/01
2019/12/01
2020/01/01
2020/02/01
2020/03/01
2020/04/01
2020/05/01
2020/06/01
2020/07/01
2020/08/01
2020/09/01
2020/10/01
2020/11/01
2020/12/01

For each data point, I want to show the full date on the x axis and the month number (0-11) on the y axis.

The gnuplot documentation recommends using the tm_mon function for such a task, which should return the month number for a given date.

As far as I understand, the following gnuplot script should do what I want:

#!/bin/gnuplot
set timefmt '%Y/%m/%d'
set xdata time
set format x '%m/%y'
set datafile separator ','

plot "data.csv" using 1:(tm_mon($1)) title 'data'

But that is not the case. This gnuplot script correctly shows dates on the x axis but has a constant 0 on the y axis.

What am I doing wrong? Why is tm_mon($1) constantly returning 0?

2 Answers

I'm not sure whether I fully got your intention. I understand you want column 1 as xtic labels. However, there is a difference between just taking the column 1 as xtic labels or interpreting column 1 as date/time and scaling the x-axis accordingly and gnuplot would take care automatically about the xtic labels. For the first case, the width of the graph might not be wide enough to show all labels without overlap, so, I reformatted date. Check help strptime and help strftime. By the way, help tm_mon says it needs input in seconds, not in your date format as it is in $1, there for use strptime().

I understand you want the yrange ranging from 1 to 12 for the months of a year. But where is the data you want to plot? Maybe the following examples is a starting point to better find out what you really want.

Code:

### plotting dates...
reset session

$Data <<EOD
2019/01/01
2019/02/01
2019/03/01
2019/04/01
2019/05/01
2019/06/01
2019/07/01
2019/08/01
2019/09/01
2019/10/01
2019/11/01
2019/12/01
2020/01/01
2020/02/01
2020/03/01
2020/04/01
2020/05/01
2020/06/01
2020/07/01
2020/08/01
2020/09/01
2020/10/01
2020/11/01
2020/12/01
EOD

myTimeInputFmt = "%Y/%m/%d"
myTimeOutputXFmt = "%Y\n%m\n%d"
set xlabel "Date"
set format x myTimeOutputXFmt   # to get enough space for the 3 lines of the label

set ylabel "Month"
set yrange [0.5:12.5]
set ytics 1

plot $Data u 0:(tm_mon(strptime(myTimeInputFmt,strcol(1)))+1): \
             xtic(strftime(myTimeOutputXFmt,strptime(myTimeInputFmt,strcol(1)))) \
             with points pt 7 lc "red" title 'data'
### end of code

Result:

enter image description here

Another way to read data properly

There is also the function 'timecolumn(N, "timeformat")' in gnuplot, although it can only be used in using. This is the function for reading the Nth column of input data as a datetime. The second argument of this function is optional if you use the format given by set timefmt. With it, your script will work by the following script.

#!/bin/gnuplot
set timefmt '%Y/%m/%d'
set xdata time
set format x '%m/%y'
set datafile separator ','

plot "data.csv" using 1:(tm_mon(timecolumn(1))) title 'data'

Why is tm_mon($1) constantly returning 0?

In your script, tm_mon($1) is interpreted as tm_mon("2019/01/01") when reading first line from 'data.csv'. tm_mon basically accepts the real value that represents an UNIX time as the argument. But, if a string value is given, tm_mon try to convert it into the real value and interpret as an UNIX time. So, tm_mon doesn't constantly returning 0. You would understand this behavior by trying the following commands.

gnuplot> print tm_mon(1607698800)    ### 2020-12-12 in UNIX time
11.0
gnuplot> print tm_mon("1607698800")
11.0
gnuplot> print tm_mon("1607698800/05/06")
11.0
Related