Temperature over the Year

ridgeline
density plot
Author

Hassan Kibirige

import datetime
import numpy as np
import pandas as pd
from mizani.labels import label_custom
from plotnine import (
    ggplot,
    aes,
    geom_violin,
    geom_sina,
    labs,
    coord_flip,
    scale_x_discrete,
    scale_y_continuous,
    scale_fill_gradient,
    element_text,
    element_line,
    element_rect,
    element_blank,
    theme
)

Create the data

np.random.seed(1234)
averages = [10, 11, 14, 18, 23, 26, 29, 32, 25 ,18, 14, 6]
sd = [3, 3, 4, 6, 7, 8, 5, 5, 4, 7, 4, 3]
date = [datetime.date(2022, 1, 1) + datetime.timedelta(days=i) for i in range(365)]

data = pd.DataFrame({
    "date": date,
    "month": [f"{d:%B}" for d in date],
    "temperature": [
        round(np.random.normal(averages[d.month-1], sd[d.month-1]))
        for d in date
    ]
})
months = data["month"].unique().tolist()[::-1]
data["month"] = data["month"].astype(pd.CategoricalDtype(categories=months))
data["mean_temperature"] = data.groupby("month", observed=True)["temperature"].transform("mean")

data.head()
date month temperature mean_temperature
0 2022-01-01 January 11 9.967742
1 2022-01-02 January 6 9.967742
2 2022-01-03 January 14 9.967742
3 2022-01-04 January 9 9.967742
4 2022-01-05 January 8 9.967742

To achieve the ridgeline effect, we create right sided violin and sina plots, with both geoms set to an equivalent width / maxwidth. We then flip the coordinate system for a vertical layout and theme the plot for a better look.

line_color = "#D2D2D2"
line_size = 0.25

(
    ggplot(data, aes("month", "temperature", fill="mean_temperature"))
    + geom_violin(
        position="identity",
        style="right",
        width=2,
        color="none",
        size=line_size,
        trim=False,
        alpha=.85,
    )
    + geom_sina(
        position="identity",
        style="right",
        fill="#AAAAAA",
        size=1,
        stroke=0,
        maxwidth=2,
        random_state=123
    )
    + labs(title="Temperature over the Year")
    + scale_y_continuous(
        expand=(0, 0.5),
        labels=label_custom("{:.0f}°C")
    )
    + scale_x_discrete(expand=(0, -.95, 0, 0))
    + scale_fill_gradient("#2222BB", "#AA2222")
    + coord_flip()
    + theme(
        figure_size=(6, 6),
        legend_position="none",
        text=element_text(color="#222222"),
        line=element_line(size=line_size, color=line_color),
        axis_line=element_blank(),
        panel_grid_major_x=element_line(linetype=(0, (20, 20))),
        panel_grid_minor=element_blank(),
        axis_ticks_minor=element_blank(),
        axis_ticks_length_major_y=50,
        axis_title=element_blank(),
        axis_text_y=element_text(va="bottom", ha="left", margin={"t": 5, "r": -45}),
        axis_text_x=element_text(ha="left", margin={"t": -7}),
        axis_ticks_length=12,
        panel_background=element_rect(fill="#FAFAFA"),
        panel_border=element_blank(),
    )
)