5
$\begingroup$

I would like to mark the periods of day versus night on a DateListPlot (and associated plots) by light gray regions for the night. Here's a minimal example that gives the appearance of what I seek:

DateListPlot[
 {{DateObject[{2022, 1, 1}], 80},
  {DateObject[{2022, 1, 5}], 85},
  {DateObject[{2022, 1, 10}], 82}},
 GridLines -> {Automatic, Automatic},
 GridLinesStyle -> {{LightGray, Thickness[0.1]}, Automatic}]

DateListPlot with nights marked

(Note that the nights are not properly marked for each day.)

There are three problems with this kludgy approach:

  • The Thickness in GridLineStyle must change as I add more dates to the plot. I'd rather it be automatic.
  • The specification Automatic for GridLines sometimes puts grid lines every day (as I need), but other times every other day, or every week. That of course defeats the approach.
  • The harder problem is the following: The beginning and end of nighttime (and hence the duration of night) changes throughout the year, of course... longer in winter, shorter in summer. I'd like that subtlety included as well.

This third component problem suggests that basing the shading on GridLines is not the proper approach.

Any suggestions?

$\endgroup$

2 Answers 2

5
$\begingroup$
data = {{DateObject[{2022, 1, 1}], 80}, {DateObject[{2022, 1, 5}], 85}, 
    {DateObject[{2022, 1, 10}], 82}};

sunrisesandsunsets = Transpose @ Map[Map[AbsoluteTime]@#["Values"] &]@
    Through[{Sunrise, Sunset}[DateRange @@ MinMax[data[[All, 1]]]]];

{min, max} = MinMax@data[[All, 2]];

DateListPlot[data, GridLines -> {Join @@ sunrisesandsunsets, Automatic}, 
 GridLinesStyle -> {{LightGray, Thin}, Automatic}, 
 Epilog -> {Opacity[.3, Gray], 
   Rectangle[Scaled[{0, -1}, {#, min}], Scaled[{0, 1}, {#2, max}]] & @@@ 
    Partition[Prepend[.99 AbsoluteTime @ Min @ data[[All, 1]]] @
      Flatten @ sunrisesandsunsets, 2]}]

enter image description here

$\endgroup$
1
  • 1
    $\begingroup$ Once again, the extraordinary @kglr finds an elegant solution ($+1, \checkmark$). $\endgroup$ Commented Feb 26, 2022 at 20:16
1
$\begingroup$

Here is almost the same approach as @kglr but a little simpler.

(*pick a location*)
location = 
  Entity["City", {"London", "GreaterLondon", "UnitedKingdom"}];

(*find maximum value which determine the height of the highlight \
boxes*)
{{startDate, endDate}, {minValue, maxValue}} = 
  MinMax /@ Transpose@data;

(* fix sub-day granularity issue *)
startDate = DayRound[startDate, "Day", "Previous"];
endDate = DayRound[endDate, "Day", "Next"];

(*find sunset for the day before given dates and sunrise for that \
date,also,reap the outputs to use in GridLines*)
{prologValues, borders} = 
  Reap[Rectangle[{Sow@Sunset[DatePlus[#, -1]], 
       minValue*.8}, {Sow@Sunrise[#], maxValue*1.2}] & /@ 
    DateRange[startDate, endDate]];

DateListPlot[data, Prolog -> {LightGray, prologValues}, 
 GridLines -> {First@borders, None}, 
 GridLinesStyle -> Directive[Thick, Dashed]]

Output:

enter image description here

Notes:

  • if you remove the location, you'll gain around 2x speedup
  • The code assumed the values are positive (.8, 1.2)
$\endgroup$
2
  • $\begingroup$ Very nice ($+1$). Indeed, I had some problems with starting times and time resolution of an hour. $\endgroup$ Commented Feb 26, 2022 at 21:03
  • 1
    $\begingroup$ @DavidG.Stork The issue was fixed with DayRound. $\endgroup$
    – Ben Izd
    Commented Mar 4, 2022 at 7:28

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.