🎨 Transform Figma mockups into production-ready Dash apps. Join us November 10. Save your spot.

Chris Parmer

Chris Parmer

October 27, 2026

Population Pyramids - A Complete Guide

TL;DR

  • A population pyramid is two horizontal bar charts back to back, men on the left and women on the right, with one row per age and the youngest at the bottom.
  • Population pyramids are also known as age pyramids, age-sex pyramids and age structure diagrams, and are similar to butterfly charts and histograms.
  • Its shape tells the story: a wide base means many children, bulges are baby booms, dents are wars or birth-control policies, and a longer side means more men or more women at that age.
  • The same construction, called a butterfly chart, works for any two quantities in one unit, such as exports and imports.
  • You can make a population pyramid with Plotly from two go.Bar traces, one side negated, with barmode="relative".

What is a population pyramid?

Population pyramids look like this:

Population pyramid of Japan in 2023 by single year of age: the widest rows are age 50 (2.04 million, the 1971-74 baby boom) and age 75 (1.96 million, the 1947-49 boom), with a dent at age 78 (1.18 million, born 1945) and 0.77 million aged 0

Data: UN World Population Prospects 2024.

How do you read a population pyramid? In the example above, notice these things:

  • Each row is one year of age in Japan, with the youngest at the bottom and the oldest at the top. The blue bar to the left of the center line is the number of men of that age, and the orange bar to the right is the number of women.
  • The width of a row is how many people of that age live in Japan, and everyone in a row was born in about the same year, so you can read history down the chart. The two bulges are Japan's baby booms, and the widest rows are the second boom, born in 1971-74.
  • The dents line up with events in the country's history. The notch just above the first boom, on both the men's and the women's side, is the small cohort born in 1945, the last year of the war.
  • Demographers classify pyramids by their overall shape. Japan's base is narrower than its middle, with 0.77 million babies aged 0, which they call a constrictive shape.
  • Compare the two sides near the top before reading anything else into the shape. In the oldest rows the orange bars are much wider than the blue ones, with 2.8 women for every man aged 90 or older, so the top of the pyramid leans toward the women's side.

It's often used for charts like these:

Two population pyramids in percent: Centre County, Pennsylvania (157,393 people, median age 34.0) with 21.1% aged 20-24, and Sumter County, Florida (157,772 people, median age 68.3) with 15.7% aged 75-79

Comparing places. Centre County, Pennsylvania, home of Penn State, and Sumter County, Florida, home of most of The Villages, each have about 157,000 people, but 21.1% of the first are aged 20-24 and 58% of the second are 65 or older. Data: US Census Bureau, Vintage 2025 county estimates.

Three workforce pyramids from the 2024 American Community Survey: registered nurses (3.7 million, 87% women, 23% aged 55+), software developers (2.3 million, 19% women) and construction laborers (2.0 million, 4% women)

A workforce. Women are 87% of 3.7 million US registered nurses, 19% of software developers and 4% of construction laborers. Data: US Census Bureau, American Community Survey 2024 PUMS.

Butterfly chart of US goods exports and imports with its 15 largest trading partners in 2025, sorted by total trade, with the balance on the right: deficits with 13, the largest with China (-$221 billion), and surpluses with the Netherlands (+$60 billion) and the United Kingdom (+$31 billion)

Any two quantities in one unit, as a butterfly chart. In 2025 the US bought more than it sold with 13 of its 15 largest trading partners, the most with China ($221 billion). Data: UN Comtrade (US Census Bureau figures).

A short history

The first population pyramid is credited to the Statistical Atlas of the United States that Francis A. Walker published in 1874 from the 1870 census (the plate in the David Rumsey Map Collection). Its plate is titled "Charts showing the distribution by age and sex of the population of the United States". The 1870 age tables are only published as scanned pages (1870 census publications), so we haven't redrawn it here.

Alternatives to a population pyramid

Here's the same US population drawn six ways. Some are better for the question, some worse, some just different:

The US population in 2025 by age and sex drawn six ways: a population pyramid, two lines of men and women against age, men per 100 women by age falling below 100 from age 35, grouped vertical bars by 5-year group, a dumbbell chart of men and women per age group, and 100% stacked bars of the share of women in each group
  • Two lines against age (better for comparing years or places). Men and women on one axis start from the same baseline, which people read more accurately than bars growing out from a center line (Cleveland and McGill, 1984), and you can overlay several years without clutter. You lose the familiar shape.
  • Men per 100 women (better when the balance is the question). One line shows that US women outnumber men at every age from 35, which the pyramid only hints at. It drops the sizes.
  • Grouped bars (worse). Thirty-six vertical bars show the same numbers, but the silhouette that makes a pyramid readable at a glance is gone.
  • Dumbbell chart (different). It puts both values for each age group on one axis, so the gap is easy to see, and it works well when the gap is the story. See our dumbbell chart guide.
  • 100% stacked bars (different). They show the share of women in each age group and nothing about how many people there are.

How to make a population pyramid

With AI

ChatGPT, Claude Code, GitHub Copilot, Cursor and other AI tools are excellent at writing Plotly code. Name Plotly in the prompt, say which group goes on which side, and list the checks you want:

Make a plotly population pyramid from population.csv (columns: age_group, age, male, female).
- Use two go.Bar traces with orientation="h",
the men's values negated, and barmode="relative".
- Youngest at the bottom: fix the row order with yaxis.categoryarray.
- A symmetric x range, with tickvals/ticktext so the labels show no minus signs.
- Write "Men" and "Women" above the top row instead of a legend.
- A title that states the main takeaway.
- Assert there is one row per age group and the total matches the source.
- Save it as pyramid.html and as a PNG at 2x scale.

With Plotly Studio

Plotly Studio is a desktop app where you point an AI at a dataset and it builds charts and a Dash app around your questions. Ask for a population pyramid the same way:

Show a population pyramid of this country by single year of age, men on the left and women on the right, with no minus signs on the axis. Add a slider for the year and draw 1990 as a black outline for comparison.

Make a population pyramid in Python or JavaScript

This is the code AI tools write under the hood. In Python, a small helper builds a pyramid from two horizontal bar traces:

import plotly.graph_objects as go
def make_pyramid(df, y, left, right, names=("Men", "Women"), colors=("#2a78d6", "#eb6834")):
top = max(df[left].max(), df[right].max())
step = float(f"{top / 2:.1g}") # a round tick step
ticks = [-2 * step, -step, 0, step, 2 * step]
fig = go.Figure([
go.Bar(y=df[y], x=-df[left], orientation="h", name=names[0], marker_color=colors[0]),
go.Bar(y=df[y], x=df[right], orientation="h", name=names[1], marker_color=colors[1]),
])
fig.update_layout(barmode="relative", bargap=0.08, showlegend=False,
xaxis=dict(range=[-top * 1.1, top * 1.1], tickvals=ticks,
ticktext=[f"{abs(t):,g}" for t in ticks]),
yaxis=dict(categoryorder="array", categoryarray=list(df[y])))
for x, text, color in [(-top / 2, names[0], colors[0]), (top / 2, names[1], colors[1])]:
fig.add_annotation(x=x, y=df[y].iloc[-1], yshift=22, text=f"<b>{text}</b>",
showarrow=False, font=dict(color=color))
return fig
import pandas as pd
# World population in 2023, billions (UN World Population Prospects 2024)
world = pd.DataFrame({"age_group": ["0-19", "20-39", "40-59", "60-79", "80+"],
"male": [1.37, 1.23, 0.94, 0.46, 0.06],
"female": [1.29, 1.17, 0.93, 0.52, 0.10]})
make_pyramid(world, "age_group", "male", "female").show()

In JavaScript, plotly.js builds the same thing from two bar traces:

<div id="chart"></div>
<script src="https://cdn.plot.ly/plotly-4.1.1.min.js"></script>
<script>
// World population in 2023, billions (UN World Population Prospects 2024)
const ages = ["0-19", "20-39", "40-59", "60-79", "80+"];
const men = [1.37, 1.23, 0.94, 0.46, 0.06];
const women = [1.29, 1.17, 0.93, 0.52, 0.10];
Plotly.newPlot("chart", [
{type: "bar", orientation: "h", y: ages, x: men.map(v => -v), name: "Men",
customdata: men, hovertemplate: "Men %{y}: %{customdata}B<extra></extra>"},
{type: "bar", orientation: "h", y: ages, x: women, name: "Women"}
], {
barmode: "relative",
xaxis: {tickvals: [-1, -0.5, 0, 0.5, 1], ticktext: ["1B", "0.5B", "0", "0.5B", "1B"]}
});
</script>

Without barmode="relative" (or "overlay"), Plotly groups the two traces and draws each row's bars side by side, half a row apart.

Share it

Every Plotly chart has a Share chart button (the cloud icon in its toolbar) that uploads it to Plotly Cloud and gives you a link. Only you can see it until you change its visibility.

For a live app, put the chart in a Dash app and publish it with the Plotly Cloud CLI. Coding agents can run these commands for you:

pip install "dash[cloud]"
plotly user login
plotly app publish

If your data has to stay in your own cloud or data center, publish to Dash Enterprise instead.

Dos and don'ts

Most published pyramids that are hard to read share the same few mistakes, and none of them is about color. Here is the US population in 2025 both ways, with the same blue and orange.

Don't leave the bars in the default grouped mode (each age's two bars sit half a row apart), print minus signs on the men's side, put a legend over the data or label every one of 101 ages:

A US population pyramid by single year of age with each age's two bars offset vertically, -2M and -1M on the men's side of the axis, a male and female legend over the bars and 101 tiny age labels

Do put both bars on one row with barmode="relative", drop the minus signs, label ages every 10 years and write "Men" and "Women" on the chart:

The same US population pyramid with aligned bars, a white line between the sides, axis labels 2M, 1M, 0, 1M, 2M, ages every 10 years and Men and Women written above the bars

Four ways to style the same pyramid

Here is Japan's population in 2023 four ways. Pick the one that fits the question.

Single years, in counts. With bargap=0 the 101 bars form one silhouette and every cohort shows, including both baby booms.

Japan's 2023 population pyramid by single year of age in counts, a continuous blue and orange silhouette with bulges at ages 50 and 75

5-year groups, in percent. Fewer, wider rows read faster, and percent of the total compares with any other country.

Japan's 2023 population pyramid in 5-year groups as percent of the total, with separate bars for each group from 0-4 to 85+

Outline only. A step line per side leaves room to overlay a second year or a projection in another color.

Japan's 2023 population pyramid drawn only as a blue and an orange step outline, with no fill

Highlight one story. Gray bars with the two baby-boom cohorts in purple tell the reader exactly where to look.

Japan's 2023 population pyramid in gray with the 1947-49 and 1971-74 birth cohorts highlighted in purple

Checklist

Do

  • Write a title that states the takeaway.
  • Use barmode="relative" and a symmetric axis range.
  • Drop the minus signs with tickvals and ticktext.
  • Name the two sides on the chart, above the top row.
  • Use percent of the total when you compare populations of different sizes.
  • Label projections as projections.

Don't

  • Fit each side's axis separately.
  • Mix age-group widths (16-19 next to 20-24) without saying so.
  • Read the open-ended top group (85+, 100+) as one more 5-year row.
  • Use a log axis on negated values; it can't show them.

Options to customize

These are the go.Bar and layout options that matter most for a pyramid. The full list is in the Plotly bar trace reference.

  1. orientation="h" with negated x: draws one side to the left of zero.
  2. barmode="relative" (layout): puts both sides on one row and stacks extra traces outward, for stacked pyramids.
  3. barmode="overlay" (layout): draws traces on top of each other, for an outlined reference population over filled bars.
  4. xaxis.tickvals, xaxis.ticktext: custom tick labels that drop the minus signs.
  5. xaxis.range: keep it symmetric, and fixed in animations.
  6. bargap: 0 for single years of age.
  7. customdata, hovertemplate: show positive values in the hover for the negated side.
  8. marker.color as a list: one color per bar, for generations, life stages or a highlighted cohort.
  9. marker.pattern.shape: hatching, to mark a projection.
  10. go.Scatter(line_shape="hvh"): a step line along the bar edges, to outline a second year.
  11. go.Scatter(mode="text"): a column of ratios or balances beside the bars.
  12. make_subplots(shared_yaxes=True): small multiples, mirrored log axes, or labels in a middle column.
  13. xaxis.type="log", xaxis.autorange="reversed": a log scale on each side of mirrored subplots.
  14. yaxis.type="category", yaxis.categoryarray: fix the row order, and stop Plotly reading labels like "2000-04" as dates.

More population pyramid examples

Ten more pyramids and butterfly charts built from real public data, each with its source, the technique that makes it work and a prompt to rebuild it.

1. China in 1990 and 2023

Population pyramid of China in 2023 by single year of age with the 1990 pyramid as a black outline: 26.7 million children aged 0 in 1990 against 9.1 million in 2023, and 117 boys per 100 girls at age 17

China had 26.7 million children aged 0 in 1990 and 9.1 million in 2023. The 1990 base, drawn as an outline, has moved up to the 30s, and boys outnumber girls 117 to 100 at age 17, the imbalance the one-child era produced (Zhu, Lu and Hesketh, 2009). Data: UN World Population Prospects 2024.

Tip: draw the earlier year as go.Scatter(mode="lines", line_shape="hvh") on both sides so it traces the bar edges.

Get the data from the UN World Population Prospects 2024 CSV "Population by single age and sex"
(1950-2023), location China, years 1990 and 2023
(columns: year, age, male, female, in thousands).
Build a plotly population pyramid of 2023 with bargap=0, and draw 1990 as a black step outline
(go.Scatter, line_shape="hvh") on each side.
- Annotate the age-0 counts for both years and the age where boys per 100 girls peaks.

2. South Korea today and in 2050 (projection)

Two population pyramids of South Korea colored by life stage: 2023 with 18.3% aged 65+ of 51.7 million, and the UN's 2050 projection, hatched, with 39.7% aged 65+ of 45.1 million

The UN projects South Korea's share aged 65+ to more than double, from 18.3% in 2023 to 39.7% in 2050, while the population falls from 51.7 million to 45.1 million. Coloring by life stage shows the working-age block shrinking. Data: UN World Population Prospects 2024 (2050 is the medium-variant projection).

Tip: give a projection its own panel, a hatched fill (marker.pattern.shape="/") and the word "projection" in its title.

Get the data from the UN World Population Prospects 2024 CSV "Population by 5-year age groups
and sex", location Republic of Korea, years 2023 and 2050 (medium variant)
(columns: year, age_group, age, male, female, in thousands).
Build two plotly population pyramids side by side, 2023 and 2050.
- Color bars by life stage: under 15, 15-64, 65+.
- Mark 2050 as a projection: lighter hatched fill and "(UN projection)" in its title.
- Panel titles with the share aged 65+ and the total.

3. Russia's missing men

Population pyramid of Russia in 2023 by single year of age, each bar split into the part matched by the other sex and the surplus: 10.4 million more women than men, women outnumbering men at every age from 37, and 1.96 women per man at 65 and older

Russia has 10.4 million more women than men. Splitting each bar into the matched part and the surplus shows where they are: from age 37 up women outnumber men at every age, and at 65 and older there are 1.96 women per man. Data: UN World Population Prospects 2024.

Tip: stack a light "matched" trace and a dark "surplus" trace on each side so the gap becomes its own shape.

Get the data from the UN World Population Prospects 2024 CSV "Population by single age and sex"
(1950-2023), location Russian Federation, year 2023 (columns: age, male, female, in thousands).
Build a plotly population pyramid with four traces: min(male, female) in a light tint on each
side, and the surplus (male - min, female - min) in full color stacked outside it.
- Annotate the first age with more women than men and the ratio at 65+.

4. Four countries, four shapes

Four population pyramids in percent of each country's total, 2023: Niger with 47.0% under 15, India 25.1%, the United States 17.6% and 17.4% aged 65+, and Japan with 11.6% under 15 and 29.6% aged 65+

These are the four textbook shapes: expansive Niger (47.0% under 15), early-transition India, stationary United States and constrictive Japan (29.6% aged 65+). Percent of each total puts Niger's 26 million people and India's 1.4 billion on one scale. Data: UN World Population Prospects 2024.

Tip: use make_subplots(shared_yaxes=True) and one shared percent axis so the shapes compare.

Get the data from the UN World Population Prospects 2024 CSV "Population by 5-year age groups
and sex", year 2023, for Niger, India, United States of America and Japan
(columns: location, age_group, age, male, female; add male_pct and female_pct as percent
of each country's total).
Build four plotly population pyramids side by side with make_subplots(cols=4, shared_yaxes=True).
- Same x range on every panel, in percent, no minus signs.
- Panel titles with the share under 15 and 65+.

5. The US pyramid colored by generation

Population pyramid of the US in 2025 by single year of age colored by generation: Millennials 73.1 million, Gen Z 72.2 million, Boomers 66.6 million, Gen X 64.4 million, Gen Alpha 50.6 million and Silent 14.7 million

Coloring single years by birth cohort turns the pyramid into a map of generations. In 2025 Millennials (73.1 million) and Gen Z (72.2 million) are the largest, ahead of Boomers (66.6 million). Data: US Census Bureau, Vintage 2025 population estimates.

Tip: color by a category instead of by sex, and separate the sides with fig.add_vline(x=0, line_color="white").

Get the data from the US Census Bureau Vintage 2025 national population estimates,
file nc-est2025-agesex-res.csv (single year of age by sex, POPESTIMATE2025)
(columns: age, birth_year = 2025 - age, generation from Pew's birth-year boundaries, male, female).
Build a plotly population pyramid by single year of age, one color per generation on both sides.
- Label each generation on the right with its birth years and total.

6. New cancer cases by age, sex and site

Stacked population pyramid of 1.94 million new US cancer cases in 2023 by age, sex and site: breast, prostate, lung, colorectal and other. Women aged 35-49 had 109,486 cases and men 56,414, and breast cancer is 41% of the women's cases

US women aged 35-49 are diagnosed with cancer 1.9 times as often as men of the same age, and breast cancer is 41% of their cases. Prostate cancer drives the men's side from the 50s. Stacking sites inside each bar shows why the shape is what it is. Data: CDC and NCI, U.S. Cancer Statistics, 2023.

Tip: put the sex-specific sites next to the axis and "other" in light gray on the outside.

Get the data from CDC and NCI U.S. Cancer Statistics public use data (USCS-1999-2023-ASCII.zip,
BYAGE.TXT): incidence, All Races, 2023, by age group and sex for breast, prostate, lung and bronchus,
colon and rectum, and all sites (columns: age_group, age, sex, site, cases).
Build a stacked plotly population pyramid: one trace per site and side, barmode="relative",
"Other sites" = all sites minus the four.
- Annotate the 35-49 totals for women and men.

7. Semaglutide adverse event reports against the population

Population pyramid of 30,477 FDA adverse event reports listing semaglutide, 2020-2025, as filled bars, with the US adult population as black outlined bars: women aged 45-69 are 37.4% of reports and 19.4% of adults

Comparing a sample with the population it comes from is everyday work in pharma. Women file 63% of the 30,477 semaglutide adverse event reports with an age and sex, and women aged 45-69 make up 37.4% of reports against 19.4% of US adults. Data: FDA FAERS via openFDA (2020-2025); US Census Bureau.

Tip: draw the reference population as empty bars with a black edge and barmode="overlay".

Get the data from the FDA Adverse Event Reporting System through the openFDA drug event API:
reports received 2020-2025 listing semaglutide, counted by patient.patientonsetage (years) for
each patientsex; and the US Census Bureau Vintage 2025 national estimates for ages 18+
(columns: age_group, male_reports, female_reports, male_pop, female_pop, each also as percent of its total).
Build a plotly population pyramid in percent: reports as filled bars, the population as
transparent bars with a black outline, barmode="overlay".

Another way to see it: dividing each group's share of reports by its share of adults gives one number per group, 2.6 for women aged 70-74.

Line chart on a log scale of the share of semaglutide reports divided by the share of US adults, by age, for men and women, from 0.03 for men aged 18-24 to 2.6 for women aged 70-74

8. COVID-19 death rates on mirrored log axes

Butterfly chart of US COVID-19 deaths per 100,000 people by age and sex, January 2020 to September 2023, on mirrored log axes: men's rates were 1.4 to 1.8 times women's in every age group from 15 up, reaching 5,831 per 100,000 men aged 85+

Men died of COVID-19 at 1.4 to 1.8 times the rate of women in every age group from 15 up. Rates matter here: in counts, more women than men died at 85+ because far more women live that long. Data: CDC NCHS provisional death counts; US Census Bureau population estimates.

Tip: a log axis can't take negative values, so use two subplots and reverse the left axis.

Get the data from the CDC NCHS "Provisional COVID-19 Deaths by Sex and Age" dataset
(data.cdc.gov 9bhg-hcku), group By Total, United States, plus the US Census Bureau Vintage 2025
national estimates for 2022 (columns: age_group, male_deaths, female_deaths, male_pop,
female_pop, male_rate, female_rate per 100,000).
Build a plotly butterfly chart with make_subplots(cols=3, shared_yaxes=True): men's rates on
the left with a reversed log axis, the men-to-women ratio as text in the middle, women's rates
on the right with a log axis.

9. An age pyramid of the US power grid

Butterfly chart of operating US generating capacity by period online, coal, gas and oil on the left and solar, wind and batteries on the right, newest at the bottom: 319 GW of solar, wind and batteries since 2015 against 90 GW of gas, and 189 GW of gas from 2000-04 still operating

A fleet of power plants has an age structure too. Since 2015, 319 GW of solar, wind and batteries came online in the US against 90 GW of gas and almost no coal, while 84% of operating coal capacity predates 1990. Data: US EIA, EIA-860M, September 2026.

Tip: put the newest period at the bottom, like age 0, so it reads as an age pyramid.

Get the data from the US EIA's EIA-860M monthly generator inventory (latest month), sheet
Operating: net summer capacity by operating year and technology, grouped into coal, natural gas,
oil, solar, wind and batteries and binned into 5-year periods (columns: period, start, group, gw).
Build a plotly butterfly chart: coal, gas and oil stacked on the left, solar, wind and batteries
on the right, barmode="relative", newest period at the bottom (yaxis type="category").

10. The age pyramid of the US Congress

Butterfly chart of the 533 members of the US Congress by age and party, Democrats on the left and Republicans on the right, House and Senate stacked, with a line at 70: 133 members are 70 or older, 29% of Democrats and 21% of Republicans

Any institution has a pyramid. 133 of the 533 members of Congress are 70 or older: 29% of Democrats and 21% of Republicans. Stacking the Senate in a lighter tint shows it is older: 37 of 100 senators are 70 or older, against 96 of 433 representatives. Data: @unitedstates congress-legislators dataset, ages on 24 October 2026.

Tip: add a reference line at the age that matters with fig.add_hline.

Get the data from the @unitedstates congress-legislators dataset (legislators-current.csv),
voting members only, with age on today's date (columns: age_group, age, chamber, party, members).
Build a plotly butterfly chart: Democrats left, Republicans right, House and Senate stacked
in two tints of each party color, counts at the end of each bar, a dotted line at 70.

FAQ

bluesly
x
instagram
youtube
medium
fcaebook

Product

© 2026
Plotly. All rights reserved.
Cookie Preferences
aicpa/soc2