Skip to content

Instantly share code, notes, and snippets.

@Digma
Last active February 5, 2024 16:56
Show Gist options
  • Save Digma/b91db287f8f577fae41c406892d46b15 to your computer and use it in GitHub Desktop.
Save Digma/b91db287f8f577fae41c406892d46b15 to your computer and use it in GitHub Desktop.
Matplotlib Line Chart in the style of OurWorldInData
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
# Data from Our World in Data (https://ourworldindata.org/grapher/ghg-emissions-by-sector)
df = pd.read_csv('data/ghg-emissions-by-sector.csv')
df_grouped = (
df
.drop(columns=["Entity", "Code"])
.groupby('Year')
.sum()
.rename(columns={
"Fugitive emissions of greenhouse gases from energy production": "Fugitive emissions",
"Greenhouse gas emissions from bunker fuels": "Aviation and shipping",
})
/ 1e9 / 4 # Billion tons
)
df_grouped = df_grouped
# Rename columns
columns = df_grouped.columns
columns_short_names = [name.replace("Greenhouse gas emissions from ", "") for name in columns]
columns_short_names = [name[0].upper() + name[1:] for name in columns_short_names]
df_grouped.columns = columns_short_names
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
# Data from Our World in Data (https://ourworldindata.org/grapher/ghg-emissions-by-sector)
df = pd.read_csv('data/ghg-emissions-by-sector.csv')
df_grouped = (
df
.drop(columns=["Entity", "Code"])
.groupby('Year')
.sum()
.rename(columns={
"Fugitive emissions of greenhouse gases from energy production": "Fugitive emissions",
"Greenhouse gas emissions from bunker fuels": "Aviation and shipping",
})
/ 1e9 / 4 # Billion tons
)
df_grouped = df_grouped
# Rename columns
columns = df_grouped.columns
columns_short_names = [name.replace("Greenhouse gas emissions from ", "") for name in columns]
columns_short_names = [name[0].upper() + name[1:] for name in columns_short_names]
df_grouped.columns = columns_short_names
# Shades of gray
GREY10 = "#1a1a1a"
GREY30 = "#4d4d4d"
GREY40 = "#666666"
GREY50 = "#7f7f7f"
GREY60 = "#999999"
GREY75 = "#bfbfbf"
GREY85 = "#5b5b5b"
GREY91 = "#e8e8e8"
GREY98 = "#fafafa"
# OurWorldInData color palette
COLOR_SCALE = [
"#6D3E91", "#C05917", "#58AC8C", "#286BBB", "#883039", "#BC8E5A", "#00295B", "#C15065",
"#18470F", "#9A5129", "#E56E5A", "#A2559C", "#38AABA", "#578145", "#970046", "#00847E",
"#B13507", "#4C6A9C", "#CF0A66", "#00875E", "#B16214", "#8C4569", "#3B8E1D", "#D73C50"
]
# Vertical lines every 2 million tons
HLINES = np.arange(0, 16, 2)
ax = df_grouped.plot(figsize = (10, 8.5))
fig = ax.get_figure()
fig.text(
0.015, 0.93, # (x,y) coordinates
"Greenhouse gas emissions by sector, World",
color=GREY40, fontname="Georgia", # Serif font
fontsize=24, weight="bold"
)
# Subtitle
fig.text(
0.015, 0.90, # (x,y) coordinates
"Greenhouse gas emissions are measured in tonnes of carbon"
" dioxide-equivalents over a 100-year timescale.",
color=GREY30, fontsize=12,
)
# Legend
fig.text(
0.015, 0.04, # (x,y) coordinates
"Data source: Climate Watch (2023)\n"
"OurWorldInData.org/co2-and-greenhouse-gas-emissions | CC BY",
fontsize=10, color=GREY30
)
# Manually set axes range
ax.set_xlabel("")
ax.set_xlim(1990, 2020)
ax.set_ylim(0, 16)
# Keep only the bottom axis
ax.spines["left"].set_color("none")
ax.spines["right"].set_color("none")
ax.spines["top"].set_color("none")
# X-axis: Change colors axis and label
ax.spines['bottom'].set_color(GREY40)
ax.tick_params(axis='x', colors=GREY40)
ax.xaxis.label.set_color(GREY40)
# X-Axis: Position ticks center, except for first and last
for tick in ax.xaxis.get_major_ticks():
tick.label1.set_horizontalalignment('center')
ax.xaxis.majorTicks[0].label1.set_horizontalalignment('left')
ax.xaxis.majorTicks[6].label1.set_horizontalalignment('right')
# Y-axis: Add vertical gridlines every 2 billion tons
for h in HLINES:
ax.axhline(h, color=GREY91, lw=1, zorder=0, linestyle="--")
# Y-Axis: Remove y ticks
ax.yaxis.set_tick_params(width=0)
# Y-axis: Change y axis labels to have Unit#
ax.set_yticklabels(
[f"{y} billion t" if y!=0 else "0 t" for y in np.arange(0, 16, 2)],
fontsize=12,
weight=500,
color=GREY40
)
# Remove existing legend
ax.legend().remove()
# Define margin around annotation
PAD = 0.1
y_offsets = [-0.1, 0.05, 0.3, -0.4, 0, 0, +0.1, 0, +0.4, -0.2, -0.1 ]
# For each timeserie
for idx, column in enumerate(df_grouped.columns):
# 1. Pick a Color from OurWorldInData palette
color = COLOR_SCALE[idx]
# 2. Plot each line with some round markers
ax.plot(
df_grouped.index, df_grouped[column],
color = color, label=column, marker="o",
markersize=2.5, lw=1.2, clip_on=False
)
# 3. Add annotation with name of each serie
y_end_value = df_grouped[column].iloc[-1]
y_offset = y_offsets[idx]
annotation_x = 2021
annotation_y = y_end_value + y_offset
ax.text(
annotation_x, annotation_y + y_offset, column,
color=color, fontsize=12, va="center"
)
# 4. Add arrow between line to annotation
line_chart_x_end = 2020 + PAD
line_chart_y_end = y_end_value
ax.arrow(
line_chart_x_end,line_chart_y_end,
1-2*PAD, y_offset,
clip_on = False, color=GREY75
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment