Skip to content

CO2 Emissions in Europe

The lines of code where ninejs is used are highlighted (only three, including the import); everything else is part of the original code.

import geopandas as gp
import pandas as pd
import plotnine as gg
from pyfonts import load_google_font, set_default_font
from pypalettes import load_palette

from ninejs import interactive, save


set_default_font(load_google_font("Fira Sans"))
cmap_colors = load_palette("BrwnYl")


def good_centroid(geometry):
    projected = geometry.to_crs(epsg=3035)
    centroids = projected.geometry.centroid
    return gp.GeoSeries(centroids, crs=projected.crs).to_crs(geometry.crs)


world = gp.read_file(
    "https://raw.githubusercontent.com/holtzy/the-python-graph-gallery/master/static/data/europe.geojson"
)
co2 = pd.read_csv(
    "https://raw.githubusercontent.com/holtzy/the-python-graph-gallery/master/static/data/co2PerCapita.csv"
)

data = world.merge(co2, how="left", left_on="name", right_on="Country")
data = data[data["continent"] == "Europe"]
data = data[~data["name"].isin(["Russia", "Iceland"])]
data = data[data["Year"] == 2021]
data = data[["name", "Total", "geometry"]].dropna()
data["tooltip"] = data.apply(lambda row: f"{row['name']}: {row['Total']:.2f} t", axis=1)

centroids = good_centroid(data)
data["center_lon"] = centroids.x
data["center_lat"] = centroids.y

countries_to_annotate = [
    "France",
    "Italy",
    "Romania",
    "Poland",
    "Finland",
    "Ukraine",
    "Spain",
    "Germany",
    "Sweden",
    "United Kingdom",
    "Belarus",
    "Norway",
]

labels = data[data["name"].isin(countries_to_annotate)].copy()
adjustments = {
    "France": (10, 3),
    "Italy": (-2.4, 2.5),
    "Finland": (0, -2),
    "Belarus": (0, -0.4),
    "Ireland": (0, -1),
    "Germany": (-0.2, 0),
    "Poland": (0, 0.2),
    "Sweden": (-1.2, -2.8),
    "United Kingdom": (1, -1.5),
    "Norway": (-4, -5.5),
}

for country, (x_adjust, y_adjust) in adjustments.items():
    country_rows = labels["name"] == country
    labels.loc[country_rows, "center_lon"] += x_adjust
    labels.loc[country_rows, "center_lat"] += y_adjust

labels["country_label"] = labels["name"].replace({"United Kingdom": "UK"}).str.upper()
labels["label"] = [
    f"{country}: {total:.2f}"
    for country, total in zip(labels["country_label"], labels["Total"])
]
labels["label_color"] = labels["Total"].map(
    lambda value: "#ffffff" if value > 7 else "#000000"
)

plot = (
    gg.ggplot(data)
    + gg.geom_map(
        gg.aes(fill="Total", tooltip="tooltip", data_id="name"),
        color="black",
        size=0.25,
    )
    + gg.geom_text(
        data=labels,
        mapping=gg.aes(
            x="center_lon",
            y="center_lat",
            label="label",
            color="label_color",
            tooltip="tooltip",
        ),
        size=7,
        fontweight="bold",
        show_legend=False,
    )
    + gg.annotate(
        "text",
        x=15,
        y=32,
        label="CO2 emissions per capita in Europe (2021)",
        size=16,
        fontweight="bold",
        ha="center",
    )
    + gg.annotate(
        "text",
        x=15,
        y=30.5,
        label="Unit: metric tons | Data: zenodo.org | Viz: barbierjoseph.com",
        size=10,
        ha="center",
    )
    + gg.scale_fill_gradientn(colors=cmap_colors, limits=(0, 15))
    + gg.scale_color_identity()
    + gg.coord_cartesian(xlim=(-11, 41), ylim=(24, 73), expand=False)
    + gg.theme_void(base_size=8)
    + gg.theme(
        figure_size=(8.2, 10),
        legend_position="none",
        plot_background=gg.element_rect(fill="white", color="white"),
        panel_background=gg.element_rect(fill="white", color="white"),
        plot_margin=0.01,
    )
)

interactive(plot) + save("docs/iframes/europe-co2.html")