full_range_monthly.gnuplot: fix sampling when drawing boxes
authorAntonio Ospite <ao2@ao2.it>
Fri, 30 Nov 2018 10:29:09 +0000 (11:29 +0100)
committerAntonio Ospite <ao2@ao2.it>
Fri, 30 Nov 2018 14:44:30 +0000 (15:44 +0100)
Instead of working around the problem by doubling the sample rate, fix
the actual problem and prevent different samples to refer to the same
box, resulting in holes in the background.

The solution is to have samples fall in the middle of months instead of
their boundaries, this compensates for the fact that different months
having a slightly different number of days.

Now two different samples are always in two different months.

full_range_monthly.gnuplot

index 98c6578..e5c6b57 100755 (executable)
@@ -72,6 +72,9 @@ start_of_month(x) = strptime("%Y-%m-%d", "" . int(tm_year(x)) . "-". int(tm_mon(
 # strptime() seems to adjust the year automatically when passing a month > 12
 start_of_next_month(x) = strptime("%Y-%m-%d", "" . int(tm_year(x)) . "-" . (int(tm_mon(x)) + 2) . "-01")
 
+# Calculate the difference between two dates.
+months_between_dates(a, b) = int((tm_year(b) - tm_year(a)) * 12 + tm_mon(b) - tm_mon(a))
+
 # Dummy plot to gather some stats from the dataset
 set terminal unknown
 plot 'data.dat' using 1:2
@@ -85,16 +88,8 @@ set xrange [xmin:xmax]
 set yrange [ymin:ymax]
 
 # Calculate the x sampling rate for the '+' plot below.
-#
-# The sample rate below is two times the strictly needed one because in this
-# way the month spacing error is reduced: "set samples" assumes evenly
-# distributed data, but starts of months are not, so it may happen that
-# a month gets skipped or repeated.
-#
-# With this workaround most of the tiles of the background gradient will be
-# drawn twice but there will be less chance of missing intervals because of
-# accumulation of errors.
-x_samples = int((xmax - xmin) / one_month) * 2
+# Have one sample per month, the +1 is to include the month of xmax.
+x_samples = months_between_dates(xmin, xmax) + 1
 set samples x_samples, 100
 
 set xtics three_months
@@ -103,8 +98,28 @@ set terminal qt 0
 #set terminal png notransparent nocrop truecolor rounded enhanced font "arial,8" fontscale 1.0
 #set output 'full_range_monthly.png'
 
-# Use the boxxyerrorbars style to draw the background choosing the color
-# according to the month.
+# The plot is done in three steps:
+#
+# 1. Plot an undefined function to force gnuplot to use the specified xrange
+#    and yrange without rescaling them, this makes sure that changing the
+#    sampling interval later does not affect the displayed xrange.
+#
+# 2. Use the boxxyerrorbars style to draw the background choosing the color
+#    according to the month.
+#    
+#    When doing this, shift samples to make them fall in the middle of months.
+#
+#    This is needed to avoid "holes" between the boxes because samples are
+#    evenly spaced while months lengths are not, so it may happen that
+#    a sample crosses the month boundary even when it's not supposed to,
+#    resulting in two different samples to draw the same box because of
+#    start_of_month() and start_of_next_month().
+#
+#    Having some "buffering days"  can compensate  for the varying months
+#    lengths.
+#
+# 3. Finally plot the actual data
 plot \
-  '+' using ($1):(0):(start_of_month($1)):(start_of_next_month($1)):(ymin):(ymax):(tm_mon($1)) with boxxy fc palette fs solid notitle, \
+  NaN notitle, \
+  [xmin - one_month/2 : xmax - one_month/2] '+' using ($1):(0):(start_of_month($1)):(start_of_next_month($1)):(ymin):(ymax):(tm_mon($1)) with boxxy fc palette fs solid notitle, \
   'data.dat' using 1:2 w l lc rgb "black" title "data"