# How can I draw a pretty population pyramid graph with pgfplots?

I'm trying to plot a graph population pyramid.

I wrote this MWE.

\documentclass{article}

\usepackage{pgfplots}
\usepackage{pgfplotstable}

\begin{document}
age,man,woman
+100 years,0,4
95 - 99 years,3,6
90 - 94 years,10,16
85 - 89 years,43,57
80 - 84 years,103,111
75 - 79 years,175,224
70 - 74 years,274,322
65 - 69 years,421,427
60 - 64 years,514,524
55 - 59 years,578,606
50 - 54 years,732,785
45 - 49 years,885,911
40 - 44 years,1044,1120
35 - 39 years,1192,1289
30 - 34 years,1315,1306
25 - 29 years,1214,1362
20 - 24 years,1360,1336
15 - 19 years,1471,1406
10 - 14 years,1495,1446
5 - 9 years,1375,1351
0 - 4 years,1325,1257

\begin{tikzpicture}
\begin{axis}[
width =\textwidth,
height = 0.6*\textheight,
enlarge x limits=0.6,
xbar = 0pt,
xmin = -5,
xmax = 5,
y dir = reverse,
nodes near coords,
bar width=8pt,
bar shift=0pt,
axis x line= left,
nodes near coords = {\pgfmathprintnumber\pgfplotspointmeta\%},
every node near coord/.append style={font=\scriptsize, color=black},
xticklabel= {\pgfmathprintnumber\tick\%},
symbolic y coords={+100 years,95 - 99 years,90 - 94 years,85 - 89 years,80 - 84 years,75 - 79 years,70 - 74 years,65 - 69 years,60 - 64 years,55 - 59 years,50 - 54 years,45 - 49 years,40 - 44 years,35 - 39 years,30 - 34 years,25 - 29 years,20 - 24 years,15 - 19 years,10 - 14 years,5 - 9 years,0 - 4 years},
ytick={+100 years,95 - 99 years,90 - 94 years,85 - 89 years,80 - 84 years,75 - 79 years,70 - 74 years,65 - 69 years,60 - 64 years,55 - 59 years,50 - 54 years,45 - 49 years,40 - 44 years,35 - 39 years,30 - 34 years,25 - 29 years,20 - 24 years,15 - 19 years,10 - 14 years,5 - 9 years,0 - 4 years}
]
\end{axis}
\end{tikzpicture}
\end{document}


But the result is an ugly graph:

How can I improve it to obtain something like this?

• It might be easier in this case to use straight Tikz instead of pgfplots. Start by stacking and naming all the nodes of the far left. Or perhaps the faint color bars. – John Kormylo Jun 27 '14 at 2:59
• Instead of a graph you could try with a tabular with pgfplotstable help. – Ignasi Jun 27 '14 at 8:45
• I'am almost there!! = ) – leonardo cesar Jun 27 '14 at 12:39
• Waiting for answer!!! – MYaseen208 Jun 27 '14 at 12:54
• @leonardocesar: Just out of interest: Which country is it? – Martin Thoma Jul 2 '14 at 19:45

It takes a lot of work to be pretty!

\documentclass{standalone}
\usepackage[svgnames]{xcolor}
\usepackage{tikz}
\usepackage{pgfplotstable}
\usepackage{wasysym}

\begin{document}
age,man,woman
+100 years,0,4
95 - 99 years,3,6
90 - 94 years,10,16
85 - 89 years,43,57
80 - 84 years,103,111
75 - 79 years,175,224
70 - 74 years,274,322
65 - 69 years,421,427
60 - 64 years,514,524
55 - 59 years,578,606
50 - 54 years,732,785
45 - 49 years,885,911
40 - 44 years,1044,1120
35 - 39 years,1192,1289
30 - 34 years,1315,1306
25 - 29 years,1214,1362
20 - 24 years,1360,1336
15 - 19 years,1471,1406
10 - 14 years,1495,1446
5 - 9 years,1375,1351
0 - 4 years,1325,1257

\newlength{\dy}\setlength{\dy}{\baselineskip}
\newlength{\dx}\setlength{\dx}{0.007em}
\newlength{\temp}

\pgfmathparse{\pgfplotsretval-1}
\edef\rows{\pgfmathresult}
% compute total for percentages
\setlength{\temp}{0pt}
\foreach \y in {0,1,...,\rows}{%
}
\pgfmathparse{0.01\temp}
\edef\total{\pgfmathresult}

\noindent\begin{tikzpicture}

\node at (0,2\dy) {Population Pyramid - 2010};
\node[below,text=Navy] at (-8em,0) {\huge\mars};
\node[below,text=HotPink] at (8em,0) {\huge\venus};

\foreach \y in {0,1,...,\rows}{%
\node[left] at (-19em,-\y\dy) {\strut\pgfplotsretval};
\node[left] at (-15em,-\y\dy) {\strut\pgfplotsretval};
\node[left,fill=Navy,text width=\pgfplotsretval\dx,text height=.8\dy,inner sep=0]
at (0,-\y\dy+0.1\dy) {};
\pgfmathparse{\pgfplotsretval/\total}
\pgfmathprintnumberto[fixed,precision=2]{\pgfmathresult}{\per}
\node[left] at (-\pgfplotsretval\dx,-\y\dy) {\small\strut\per\%};
\node[left] at (17em,-\y\dy) {\strut\pgfplotsretval};
\node[right,fill=HotPink,text width=\pgfplotsretval\dx,text height=.8\dy,inner sep=0]
at (0,-\y\dy+0.1\dy) {};
\pgfmathparse{\pgfplotsretval/\total}
\pgfmathprintnumberto[fixed,precision=2]{\pgfmathresult}{\per}
\node[right] at (\pgfplotsretval\dx,-\y\dy) {\small\strut\per\%};
}
\node[left] at (-3em,-\rows\dy-.9\dy) {Man};
\node[left,fill=Navy,text width=2em,text height=.8\dy,inner sep=0]
at (-1mm,-\rows\dy-.9\dy) {};
\node[right,fill=HotPink,text width=2em,text height=.8\dy,inner sep=0]
at (+1mm,-\rows\dy-.9\dy) {};
\node[right] at (3em,-\rows\dy-.9\dy) {Woman};

\end{tikzpicture}
\end{document}


You can adjust the size by adjusting the font, or with more precision using \resizebox.

• I should mention that I stole the symbols from leonardo cesar's solution. – John Kormylo Jun 29 '14 at 1:10
• wow! amazing solution!!! but there is a little problem with logic! you must to divide each group age by total population. thanks!!! – leonardo cesar Jun 29 '14 at 15:30
• Okay, change made. – John Kormylo Jun 29 '14 at 18:24
• This solution is nice, but the age ranges use a hyphen with spaces, which is typographically poor. Correct would be an en dash without spaces. – lblb May 13 '17 at 14:05

this look better = )

\documentclass[10pt]{article}
\usepackage{pgfplots}\pgfplotsset{compat=1.10}
\usepackage{pgfplotstable}
\usepackage{lmodern}
\usepackage{wasysym}
\begin{document}

age,man,woman
+100 years,0,4
95 - 99 years,3,6
90 - 94 years,10,16
85 - 89 years,43,57
80 - 84 years,103,111
75 - 79 years,175,224
70 - 74 years,274,322
65 - 69 years,421,427
60 - 64 years,514,524
55 - 59 years,578,606
50 - 54 years,732,785
45 - 49 years,885,911
40 - 44 years,1044,1120
35 - 39 years,1192,1289
30 - 34 years,1315,1306
25 - 29 years,1214,1362
20 - 24 years,1360,1336
15 - 19 years,1471,1406
10 - 14 years,1495,1446
5 - 9 years,1375,1351
0 - 4 years,1325,1257

\begin{tikzpicture}
\begin{axis}[
name=popaxis,
scale only axis,
xbar,
xmin=0,
xmax=5,
%xbar=2pt,
%xlabel={\%},
width=0.5*\textwidth, height= 0.5*\textheight,
y dir = reverse,
nodes near coords = {\pgfmathprintnumber\pgfplotspointmeta\%},
every node near coord/.append style={font=\scriptsize, color=black},
xticklabel= {\pgfmathprintnumber\tick\%},
y tick label style={text width=3cm,align=center},
axis x line=left,
axis y line=none,
%
enlarge x limits = {value=0.15,upper},
axis line style={-},
clip=false
]
%
\pgfmathsetmacro{\lastrow}{\pgfplotsretval-1}
\node[xshift=-1.5cm,yshift=-0.5cm,align=center] at (axis cs:0,\lastrow) {\textcolor{cyan}{\huge\mars} Man};
\node[xshift= 1.5cm,yshift=-0.5cm,align=center] at (axis cs:0,\lastrow) {\textcolor{magenta}{\huge\venus} Woman};
\node[xshift= 0.0cm,yshift=-2.0cm,align=center] at (axis cs:0,\lastrow) {\%};
%
\end{axis}
\begin{axis}[
at={(popaxis.north west)},anchor=north east, %xshift=-3cm,
scale only axis,
xbar = 0,
xmin = 0,
xmax = 5,
width=0.5*\textwidth,
height= 0.5*\textheight,
x dir=reverse,
y dir=reverse,
nodes near coords = {\pgfmathprintnumber\pgfplotspointmeta\%},
every node near coord/.append style={rotate = 0, anchor = east, font=\scriptsize, color=black},
xticklabel= {\pgfmathprintnumber\tick\%},
axis x line=left,
axis y line*=left,
%
ytick = data,