How to Create Beautiful Age Distribution Graphs With Seaborn and Matplotlib (Including Animation) | by Oscar Leo | Jun, 2023


Creating a grid with multiple countries

You can use plt.subplots() to create grids, but in this tutorial, I want to create a grid of images because I think it looks better.

The following function takes a list of images and creates a grid with ncols. It works by creating an empty image with a single background color that’s large enough to fit all figures.

def create_grid(figures, pad, ncols):
nrows = int(len(figures) / ncols)
size = figures[0].size

image = Image.new(
"RGBA",
(ncols * size[0] + (ncols - 1) * pad, nrows * size[1] + (nrows - 1) * pad),
"#ffffff00"
)

for i, figure in enumerate(figures):
col, row = i % ncols, i // ncols
image.paste(figure, (col * (size[0] + pad), row * (size[1] + pad)))

return image

In the following code, I iterate over a list of countries, add the resulting graph to figures, and create a grid by running create_grid() at the end.

figures = []

for country in [
"United States", "China", "Japan", "Brazil", "Canada",
"Germany", "Pakistan", "Russian Federation", "Nigeria",
"Sweden", "Cambodia", "Saudi Arabia", "Iceland",
"Spain", "South Africa", "Morocco"
]:

fig = plt.figure(figsize=(10, 8))

ax = create_age_distribution(
female_df=population_ratio_female,
male_df=population_ratio_male,
country=country,
year="2021"
)

ax.set(xlim=(-10, 10))

# New functions
format_ticks(ax, xformat="percentage")
add_legend(x=0.5, y=1.09)
plt.title("Age Distribution for {} in 2021".format(country), y=1.14, fontsize=20)

image = create_image_from_figure(fig)
image = add_padding_to_chart(image, 20, 20, 20, 5, background_color)

figures.append(image)

grid = create_grid(figures, pad=20, ncols=4)

Note that I use ratios instead of absolute numbers and set xlim=(-10, 10). Otherwise, I won’t be able to compare the countries to each other visually.

Graphs created by the author

Let’s move on to the last part of this tutorial — How to create time-lapse visualizations.

Creating a time-lapse visualization

The static age distribution charts look great, but it’s fascinating to see how they change over time.

Since we have actual values from 1960 to 2021 and predictions to 2050, we can create a time-lapse animation for a relatively long period.

Before we begin, I need to tell you that the font I use, PT Mono, doesn’t have the same height for all characters. To make the visualization look good, I needed to use plt.text() for the year instead of plt.title(). If you use another font, it’s not necessary to do so.

Here’s the code:

images = []
years = list(population_male.columns[4:])

for year in years:
fig = plt.figure(figsize=(10, 8))

ax = create_age_distribution(
female_df=population_female,
male_df=population_male,
country="World",
year=year
)

# New functions
format_ticks(ax, xformat="millions", xlim=(-400000000, 400000000))
add_legend(x=0.5, y=1.09)
plt.title("Age Distribution for the World in ", y=1.14, fontsize=21)
plt.text(x=0.77, y=1.15, s=str(year), fontsize=21, transform=ax.transAxes)

image = create_image_from_figure(fig)
image = add_padding_to_chart(image, 20, 20, 20, 5, background_color)
images.append(image)

I use imageio to create a GIF from the list of images.

# Duplicating the last frames to add a delay 
# before the animation restarts
images = images + [images[-1] for _ in range(20)]
imageio.mimwrite('./time-lapse.gif', images, duration=0.2)

Let’s take a look at the result.

Visualization created by the author

Awesome! That’s all for this tutorial; let me know if you liked it and learned something useful.



Source link

Leave a Comment