the rate of change of daylight is presently at its greatest.
a few days ago[1], izgi and i were too early for sunrise.
yesterday[2] we witnessed it.
and this morning[3] we missed it.
i know, i know, one should always carpe the diem[4]. but now is really the time to start putting the evenings and mornings to good use.
an example of a thing that does not qualify as a good use of daylight would be writing some code to visualize how much daylight you 're wasting have[5]. that's why i mostly wrote the code for this project over the course of several winters (granted, there were probably some wasted bluebird days).
# the goal
a calendar that lets you know where the sun is relative to a specified location.[6]
# v.1.
the first version was done in matlab at the tail end of 2020. it looked pants. and i can't find a copy of it. last seen on a since deleted student onedrive account.
the detail i wanted to communicate - because it's the thing i find most captivating about the sun's path - is where does the sun rise and set on any given day, and how does that change over the course of a year.
the approach taken was to show each day as a circular mini-map with the specified location at the centre. within each circle, was a sector bound by two radii that point towards where the sun rises and sets. the lengths of these radii scaled with the solar elevation at noon on that day. each circle was coloured according to the number of daylight hours; and the time of sunrise / sunset were placed along each of the sector radii.
this design worked. and i was certainly pleased with it at the time. but...the code was inefficient (if my memory can be trusted: each day's sector was plotted on its own single polar axes instance; and it was very loopy and not very vectorizedy). and it wasn't that much of a looker.
# v.2.
skip forward a year, and i'd moved away from matlab and into python
and the joys of matplotlib
. i replicated the original design, and greatly improved the plotting performance by using patches
and converting each polar plot into cartesian coordinates that were then offset by day of month and month of year. ta-dah. only a single axis required. this looked like this:

i am still quite happy with it. there are additional details such as the font colour changing from white to black and back on the equinoxes. dotted lines around solstices. and the month names and day numbers actually line up with the centre of the circles. which was very much not the case on v.1.
the following year (2022-23) i went a bit abstract:

during the winter that's just finished, i started again. from the ground up.
# v.3.
# rethink
heavily drawing inspiration from sharon lee's tide charts, i wanted something that connected the days together: a way of representing the earth's continuous rotation and orbit, via the sun's (apparent) continuous motion. by using the horizontal coordinate system, the sun's position for an observer at a given location and time can be represented by two angular quantities:
- altitude, which describes how high in the sky the sun is
- 0° : on the horizon
- 90° : directly overhead
- -90° : directly underfoot
- azimuth, which tells you which direction to face to see the sun
- 0°/360° : north
- 90° : east
- 180° : south
- 270° : west
# step 1: altitude
altitude lends itself nicely to plotting, as it can be described by a sine wave[7], the amplitude of which is a function of latitude. every day, the sun crosses the horizon (sunrise), rises to a maximum at solar noon[8], crosses the horizon again (sunset), and then descends to a minimum at the opposite of solar noon.
in summer, the sun spends more time above the horizon. the days are longer. in winter, it spends more time below the horizon (fig 1).

notice how the daily amplitude doesn't change much from month-to-month; instead, the whole wave shifts up and down with the seasons. this allows for plotting each month on its own row, with a consistent scale, but different limits. like so (fig 2).

by plotting each month on its own row, the calendar becomes familiar, and legible (at least, i hope it does). the consistent scale, but differing limits, enables a fair and meaningful comparison to be made. differences between months can be further enhanced by emphasizing the feature that changes - i.e. the horizon - by plotting it in a high contrast colour.
this is the foundation of the calendar done.
# step 2: azimuth
plotting azimuth as a time series is problematic because of the discontinuity at 0°/360°. but that's ok, because circular colour-maps[9] are a thing. and they are masterful. and i love them.

the altitude lines in fig. 2. can be coloured by azimuth, a la fig. 3. so, in addition to going up and down, the lines smoothly change colour as the sun whirls around.
by rotating the colour map, so that the brightest hues align with solar noon, it should (i hope) be reasonably easy, and intuitive, to differentiate day and night (fig. 4.) furthermore, the colour of the altitude line where it crosses the horizon enables the bearing of sunrise / sunset to be roughly ascertained[10]

# step 3: decorations
adding a few other features
# compass rose and solar paths
instead of the using a colour bar (as in fig. 3. & 4.), much better to put wrap it around a compass rose (fig. 5.) that is, after all, the whole point of circular colour maps.

the compass rose permits the inclusion of a little bonus feature: nestled within are polar plots of the solar path. this can be imagined as a map, with the observer at the centre. the edge of the circle represents the horizon. the centre of the circle is directly overhead. here the sunrises ~ne on the summer solstice, and ~se on the winter solstice. the sun stays low in the sky (close to outside of circle) in winter, whereas it rises high (middle of circle) on the summer solstice. i should probably add arrows to show the direction...
# analemma
might as well add an analemma too (fig. 6.). this shows the sun's elevation and azimuth plotted against one another, for a given clock time for every day of the year. this is very closely related (i.e. the same darn thing) as the equation of time, and it goes some way towards explaining why solar noon does not always coincide with midday. add in a few solstice and equinox annotations, and it becomes sort of informative.

# daylight hours
whilst the altitude line (fig. 4.) gives a good sense of how much time per day the sun is above the horizon. it'd be nice to get a clearer idea of just how daylight duration changes over the course of the year. enter fig. 7.

# annotations
on the main plot - add the sunrise and sunset times above the maximum and minimum altitude, respectively. and add a few vertical lines for the solstices, and equinoxes, and daylight saving. add labels for the vertical lines into the margins here and there. and a label telling the reader that the horizon is the horizon.
i can't be bothered to rustle up another plot illustrating just these features.
# styling
here, i've been using the solarized_light2
[11] theme, because i like it. for the actual calendar, i opted for dark.
font - dejavu sans mono. naturally.
frame - alternating black and white - very much borrowing from the tide charts[12].
# the finished thing

which i am reasonably happy with.
things that i would like to improve in v4:
- more empty space - let it breathe
- fill the more empty space with text that explains some of the things that might not be immediately obvious
- another decoration - showing the equation of time - maybe
- ability to handle locations north (south) of the arctic (antarctic) circle - at the moment, my code is a bit[13] wobbly when handling some edge cases[14]
- the same, but for the moon
- get a better grip on UTC offsets
- the ability to change themes
- a black and white version, where, instead of having the altitude line coloured by azimuth, have a marker every other hour that ->↗↘↙↖<- to where the sun is
once the code is a bit cleaner, i'll link to it.
# credits
many a python library creator, and many more astronomers leant a hand
- dr louis strous, whose website was used by vladimir agafonkin to make the
suncalc
javascript library, which kyle barron translated into the python librarysuncalc-py
, which allowed me to ditch the code i wrote based on the esrl spreadsheets - the
pymeeus
library was pretty handy, dittotimezonefinder
matplotlib
, as always. and a healthy dose ofseaborn
- johannes kepler's contribution was essential
- and the rest
# footnotes
last week? ↩︎
which is now the day before yesterday, or maybe even the day before that. grand plans of publishing this at 03:07 on 20th March were thwarted by work. and perfectionist tendencies. ↩︎
which wasn’t also not this morning – although, i probably missed sunrise this morning too. ↩︎
yes, that is a succession reference. ↩︎
or writing about how you wrote some code. ↩︎
on earth’s surface ↩︎
did i just needlessly verify this for myself by mucking about
scipy.optimize.curve_fit
? of course. ↩︎which is a bit different to 12:00. ↩︎
i didn’t use one of fabio crameri’s excellent colour maps, instead i opted for
matplotlib
‘s twilight. but, having just had a look at fabio’s site,roma0
looks fantastic. relatedly: it was this paper by thyng et al., (2016) that first opened my eyes to the thinking behind colour maps. ↩︎a bonus feature in the final version - and perhaps my favourite bonus feature – the line appears to go behind the horizon at sunset, and it comes up above the horizon at sunrise. ↩︎
if wordpress had a solarized light theme, i’d be using it ↩︎
imitation is the sincerest form of flattery etc... ↩︎
very ↩︎
that said, i just tried a few, and it can handle it, but it looks a bit weird. the text labels for sunrise / sunset times stop abruptly. maybe putting a ‘ – ‘ in place of nothing. or a ‘ : ‘. and the sun graph (fig. 7) sometimes struggles when night doesn’t start until the morning (like at Finse, in summer). ↩︎