Indicating weekends in timeseries plot and setting xrange in timeseries gnuplot

Viewed 59

Using the excellent answer gnuplot - Read Double Quoted datetime stamp I have been able to plot my time series data.

I now trying to indicate weekends (or interesting timeblocks) my plot and set visible xrange to be 31/1 to 28/2

Weekends in Feb this year were 2/5/22 to 2/6/22 and 2/12/22 to 2/13/22 etc - how could I draw a vertical column and shade to indicate weekend or other interesting timeseries blocks? I looked at trying to plot a rectangle using timeseries points, ie weekend1, but I was unable to fill that shape. Then I tried to draw a rectangle, but could not work out how to specify the corners in the timeseries format to display it.

Since my x axis is a timeseries

  • How could I indicate all weekends in the diagram - kind of like in a calendar or timesheet?
  • How do I define the xrange to be 1/31/22 to 2/28/22?
reset session
set datafile separator comma
myTimeFmt = "%m/%d/%y, %H:%M %p"
set format x "%d" time
#
# Gives error all points y value undefined!
#
# set xrange ["1/31/22, 12:01 AM":"2/28/22, 11:59 PM"]  # 

#
#  Trying to draw a series to fill to indicate a weekend range - vertically
#
$weekend1 <<EOD
"2/5/22, 12:01 AM",0
"2/5/22, 12:01 AM",600
"2/6/22, 11:59 PM",600
"2/6/22, 11:59 PM",0
EOD

$account <<EOD
"1/31/22, 5:07 PM",1
"1/31/22, 8:01 PM",100
"2/1/22, 11:10 AM",200
"2/6/22, 12:25 PM",300
"2/9/22, 2:02 PM",400
"2/24/22, 4:22 PM",500
EOD

set object 1 rect from 1,1 to 2,2 
plot $account u (timecolumn(1,myTimeFmt)):2 w lp pt 1 ps 1 lc "red" lw 1 ti "Account"
#plot $weekend1 u (timecolumn(1,myTimeFmt)):2 w lp pt 1 ps 1 lc "grey"
1 Answers

Here is what I've understood from your question: plot some time series data and highlight the weekends by coloring the background. One possible way to get this would be to create datablock with all days within your time range and draw boxes (check help boxxyerror) which are colored (check help lc variable) depending of the weekday (check help tm_wday).

  • first you have to plot the boxes in the background and then the data
  • the background color should span the whole vertical graph size. For this you need to know the y-range of the data. You can get STATS_min and STATS_max from stats (check help stats).
  • in order to span the whole graph you can extend the y-range of the boxes (by adding the range again on top and on bottom) but do not apply autoscale for the boxes (check help noautoscale). Autoscale will be only used for the data.
  • Maybe you have a fixed known y-range, then you can simply set it via set yrange and suitable size of the boxes.

I hope you can adapt the following example to your needs.

Code:

### highlight weekends
reset session

myTimeFmt  = "%d.%m.%Y"
DateStart  = "01.01.2022"
DateEnd    = "28.02.2022"
SecsPerDay = 24*3600

# create some random test data
set print $Data
    y=50
    do for [t=strptime(myTimeFmt,DateStart):strptime(myTimeFmt,DateEnd):SecsPerDay] {
        print sprintf('"%s", %g', strftime(myTimeFmt,t),y=y+rand(0)*10-5)
    }
set print

# datablock with every day between start and end date
set print $Days
    do for [t=strptime(myTimeFmt,DateStart):strptime(myTimeFmt,DateEnd):SecsPerDay] {
        print strftime(myTimeFmt,t)
    }
set print

set datafile separator comma
set key noautotitle
set style fill solid 0.4 border
set format x "%d %b\n%Y" timedate
set xtics out scale 2, 1

DayColor(t) = tm_wday(t)==0 ? 0xff0000 : tm_wday(t)==6 ? 0xffdd00 : 0xdddddd

stats $Data u 2 nooutput   # get min and max from column 2

plot $Days u (t=timecolumn(1,myTimeFmt)):(0):(t):(t+SecsPerDay):\
          (2*STATS_min-STATS_max):(2*STATS_max+STATS_min):(DayColor(t)) w boxxy lc rgb var noautoscale, \
     $Data u (timecolumn(1,myTimeFmt)):2 w lp pt 7 lc "black"
### end of code

Result:

enter image description here

NB: first I thought you wanted to plot a calendar highlighting the weekends, but this was not your question. Since I already had the following code (which will plot a calendar in two different versions), I will post it nevertheless. Maybe it is useful to you or others for further adaptions and optimizations.

Code:

### plot a calendar
reset session

myTimeFmt  = "%d.%m.%Y"
DateStart  = "01.01.2022"
DateEnd    = "31.12.2022"
SecsPerDay = 24*3600

set print $Data
    do for [t=strptime(myTimeFmt,DateStart):strptime(myTimeFmt,DateEnd):SecsPerDay] {
        print strftime(myTimeFmt,t)
    }
set print

set xrange[0.5:31.5]
set xtics 1 scale 0 offset 0,0.5 font ",8"
set link x2 via x inverse x
set x2tics 1 out scale 0 offset 0,-0.5 font ",8"
set yrange [:] reverse noextend
set ytics 1 scale 0
set key noautotitle
set style fill solid 0.4 border lc "black"

WeekDay(t)    = word("S M T W T F S",int(tm_wday(t))+1)
DayColor(t)   = tm_wday(t) == 0 ? 0xff0000 : tm_wday(t) == 6 ? 0xffdd00 : 0xdddddd
MonthFirst(t) = int(strptime("%Y%m%d",sprintf("%04d%02d01",tm_year(t),tm_mon(t)+1)))
Month(t)      = int(tm_year(t)*12 + tm_mon(t))
MonthName(n)  = word("January February March April May June July August September October November December",n)
MonthLabel(t) = sprintf("%s",MonthName(Month(t)%12+1))                   # without year
MonthLabel(t) = sprintf("%s %04d",MonthName(Month(t)%12+1),tm_year(t))   # alternatively with year

plot $Data u (t=timecolumn(1,myTimeFmt), tm_mday(t)):(Month(t)):(0.5):(0.5):(DayColor(t)): \
             xtic(tm_mday(t)):ytic(MonthLabel(t)) w boxxy lc rgb var, \
        '' u (t=timecolumn(1,myTimeFmt), tm_mday(t)):(Month(t)):(WeekDay(t)) w labels

pause -1

MonthOffset(t) = tm_wday(MonthFirst(t))==0 ? 7 : tm_wday(MonthFirst(t))
set xrange[1.5:*]

plot $Data u (t=timecolumn(1,myTimeFmt), tm_mday(t)+MonthOffset(t)):(Month(t)):(0.5):(0.5):(DayColor(t)): \
             xtic(WeekDay(t)):x2tic(WeekDay(t)):ytic(MonthLabel(t)) w boxxy lc rgb var, \
        '' u (t=timecolumn(1,myTimeFmt), tm_mday(t)+MonthOffset(t)):(Month(t)):(sprintf("%d",tm_mday(t))) w labels font ",8"
### end of code

Result:

enter image description here

enter image description here

Related