Plotting with Makie.jl

SolarPosition.jl provides a plotting extension for Makie.jl.

The main plotting function is analemmas!.

To use it, simply import both the SolarPosition and Makie packages:

using SolarPosition
using CairoMakie

# supporting packages
using Dates
using TimeZones

This example notebook is based on the pvlib sun path example.

Basic Sun Path Plotting

The plotting functions generate analemmas (figure-8 patterns showing the sun's position at each hour of the day throughout the year). You simply provide an observer location and the year you want to visualize:

# Define observer location (New Delhi, India)
# Parameters: latitude, longitude, altitude in meters
obs = Observer(28.6, 77.2, 0.0)
tz = TimeZone("Asia/Kolkata")
year = 2019
2019

Simple Sun Path Plot in Cartesian Coordinates

We can visualize solar positions in cartesian coordinates using the analemmas! function. The function automatically generates analemmas for all 24 hours of the day:

fig = Figure(backgroundcolor = (:white, 0.0), textcolor= "#f5ab35")
ax = Axis(fig[1, 1], backgroundcolor = (:white, 0.0))
analemmas!(ax, obs, year, hour_labels = false)
fig
Example block output

Polar Coordinates with Hour Labels

Plotting in polar coordinates with analemmas! may yield a more intuitive representation of the solar path. Here, we enable hourly labels for better readability:

fig2 = Figure(backgroundcolor = :transparent, textcolor= "#f5ab35", size = (800, 600))
ax2 = PolarAxis(fig2[1, 1], backgroundcolor = "#1f2424")
analemmas!(ax2, obs, year, hour_labels = true)
fig2
Example block output

Now let's manually plot the full solar path for specific dates March 21, June 21, and December 21. Also known as the vernal equinox, summer solstice, and winter solstice, respectively:

line_objects = []
for (date, label) in [(Date("2019-03-21"), "Mar 21"),
                      (Date("2019-06-21"), "Jun 21"),
                      (Date("2019-12-21"), "Dec 21")]
    times = collect(ZonedDateTime(DateTime(date), tz):Minute(5):ZonedDateTime(DateTime(date) + Day(1), tz))
    solpos = solar_position(obs, times)
    above_horizon = solpos.elevation .> 0
    day_filtered = solpos[above_horizon]
    line_obj = lines!(ax2, deg2rad.(day_filtered.azimuth), day_filtered.zenith,
                      linewidth = 2, label = label)
    push!(line_objects, line_obj)
end

# Add legend below the plot
fig2[2, 1] = Legend(fig2, line_objects, ["Mar 21", "Jun 21", "Dec 21"],
                    orientation = :horizontal, tellheight = true, backgroundcolor = :transparent)
fig2
Example block output

The figure-8 patterns are known as analemmas, which represent the sun's position at the same time of day throughout the year.

Note that in polar coordinates, the radial distance from the center represents the zenith angle (90° - elevation). Thus, points closer to the center indicate higher elevations. Conversely, a zenith angle of more than 90° (negative elevation) indicates that the sun is below the horizon. Tracing a path from right to left corresponds to the sun's movement from east to west.

It tells us when the sun rises, reaches its highest point, and sets. And hence also the length of the day. From the figure we can also read that in June the days are longest, while in December they are shortest.

Custom Color Schemes

You can customize the color scheme used for the analemmas by passing a colorscheme argument. Here's an example using the :balance colorscheme.

Info

More colorschemes are available in the Makie documentation.

fig = Figure(backgroundcolor = (:white, 0.0), textcolor= "#f5ab35")
ax = Axis(fig[1, 1], backgroundcolor = (:white, 0.0))
analemmas!(ax, obs, year, hour_labels = false, colorscheme = :balance)
fig
Example block output

Docstrings

SolarPosition.analemmas!Function

Plot analemmas (figure-8 patterns showing the sun's position at each hour throughout the year) for a given observer location and year.

Arguments

  • ax: A Makie Axis or PolarAxis to plot on
  • observer::Observer: Observer location (latitude, longitude, altitude)
  • year::Int: Year for which to generate the analemmas
  • hour_labels::Bool=true: Whether to add hour labels to the plot
  • colorscheme::Symbol=:twilight: Color scheme for the analemma points (any Makie colormap)

Description

This function automatically generates solar position data for all 24 hours of each day throughout the specified year and plots them as analemmas. The plot specializes to either PolarAxis or regular Axis and adjusts the plot accordingly:

  • PolarAxis: Plots in polar coordinates with azimuth as the angle and zenith as the radius
  • Axis: Plots in cartesian coordinates with azimuth on the x-axis and elevation on the y-axis

The analemmas are colored by day of year. The default colorscheme is :twilight, but this can be customized using the colorscheme keyword argument.

Examples

using SolarPosition
using CairoMakie

# Define observer location (New Delhi, India)
obs = Observer(28.6, 77.2, 0.0)
year = 2019

# Plot in cartesian coordinates
fig = Figure()
ax = Axis(fig[1, 1], title="Sun Path - Cartesian")
analemmas!(ax, obs, year)
fig

# Plot in polar coordinates
fig2 = Figure()
ax2 = PolarAxis(fig2[1, 1], title="Sun Path - Polar")
analemmas!(ax2, obs, year, hour_labels=true)
fig2

# Use a custom colorscheme
fig3 = Figure()
ax3 = Axis(fig3[1, 1], title="Sun Path - Custom Colors")
analemmas!(ax3, obs, year, colorscheme=:viridis)
fig3

See also: Observer, solar_position

source