0

After reading the pretty population pyramid question, I was inspired to "Tufte-ify" the graph to remove redunancy and clutter (and to become more familiar with pgfplots).

I modified the code from leonardo cedar's answer to the population pyramid question. For learning purposes, I decided to highlight one data point that I thought was interesting. With one exception, the proportion of females is larger than males beginning with the 25-29 year age group. Using an idea taken from here. I highlighted the male and female bars and added the percentage of each gender. The result is shown below; overall, I'm pleased with the result but not with the way I obtained it.

I have four questions. If I should split them into separate posts, please let me know.

1) How can I automatically associate the precentage with the chosen bar? In my MWE, the position of the two percentages at the of each red bar is hard coded, using

\node [color=white] at (\xcenter+3.8cm,-6.05cm) {\scriptsize 4.34\%};  % Females
\node [color=white] at (\xcenter-3.65cm,-6.05cm) {\scriptsize 3.87\%}; % Males

Leonardo's code had:

nodes near coords = {\pgfmathprintnumber\pgfplotspointmeta\%},
every node near coord/.append style={rotate = 0, anchor = east, font=\scriptsize, color=black},

which placed the percentage for every bar (for the males, in this case). I know I can change the anchor to west to get the percentages plotted inside the bar. Can I change this to plot the precent for just one bar? Or is there another way?

2) Is there a way to automatically determine the height of the graph area occupied by the bars? I hard coded a thin black line at 0% on the x-axis to provide a visual center dividing males and females. I played around with the coordinates to position it. I would like to determine the height programmatically. (In this case, the black line does not extend all the way to the top because it would cover the uppermost data point. I'm not worried about that overall.)

3) Is it possible to bold the y tick label for just the chosen data point, in this case the 25-29 year olds? I have no idea where to begin.

4) How can I shift the x- and y-axes closer to the bars? I have no idea where to begin.

MWE. Other suggestions for improvement are welcome:

\documentclass[10pt]{article}
\usepackage{pgfplots}
\usepackage{pgfplotstable}
\usepackage{filecontents}

\pgfplotsset{%
    discard if not/.style 2 args={
        x filter/.code={
            \edef\tempa{\thisrow{#1}}
            \edef\tempb{#2}
            \ifx\tempa\tempb
            \else
                \def\pgfmathresult{inf}
            \fi
        }
    }
}    

\begin{document}

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

\pgfplotstableread[col sep=comma, header=true]{data.csv}{\datatable}

\begin{center}
\begin{tikzpicture}
\edef\xcenter{0cm}% from John Kormylo's answer 

\pgfplotsset{major grid style={thin, white}} 

\begin{axis}[ %Female
    name=popaxis,
    scale only axis,
    xbar,
    /pgf/bar shift=0pt,
    xmin=0,
    xmax=5,
    width=0.5*\textwidth, 
    height= 0.5*\textheight,
    y dir = reverse,
    xticklabel= {\pgfmathprintnumber\tick\%},
    axis x line=left,
    axis y line=none,
    enlarge x limits = {value=0.15,upper},
    axis line style={white},
    clip=false,
    xmajorticks=true,
    every x tick/.style={color={white}},
    grid=major,
    axis on top
]
\addplot[white,fill=black!30] table[y expr =\coordindex, x expr={\thisrow{female}/31395*100}, col sep=comma] {data.csv};%total pop = 31395 
\addplot[white,fill=red!50!black, discard if not ={male}{1214}] table[y expr =\coordindex, x expr={\thisrow{female}/31395*100}, col sep=comma] {data.csv}; 

\pgfplotstablegetrowsof{\datatable}
\pgfmathsetmacro{\lastrow}{\pgfplotsretval}  
\node[xshift=-3cm,yshift=7cm,align=center] at (axis cs:0,\lastrow) {Male}; 
\node[xshift= 3cm,yshift=7cm,align=center] at (axis cs:0,\lastrow) {Female}; 
\node[xshift= -8.5cm,yshift=7cm,align=left] at (axis cs:0,\lastrow) {Age Group\\(years)}; 

% hard-coded precentage for females 25-29.
\node [color=white] at (\xcenter+3.8cm,-6.05cm) {\scriptsize 4.34\%};
\end{axis}
%
\begin{axis}[ % Male
at={(popaxis.north west)},anchor=north east, 
    scale only axis,
    xbar,
    /pgf/bar shift=0pt,
    xmin = 0,
    xmax = 5,
    width=0.5*\textwidth,
    height= 0.5*\textheight,
    x dir=reverse,
    y dir=reverse,
%    Leonardo's code that print's all precentages for males. I just want one.
%    nodes near coords = {\pgfmathprintnumber\pgfplotspointmeta\%},
%    every node near coord/.append style={rotate = 0, anchor = west, font=\scriptsize, color=black},
    xticklabel= {\pgfmathprintnumber\tick\%},
    axis x line=left,
    axis y line*=left,
    ytick = data,
    yticklabels from table = {\datatable}{age},
    ytick align=center,
    ytick pos=left,
    enlarge x limits = {value=0.15,upper},
    axis line style={white},
    every x tick/.style={color=white},
    every y tick/.style={color=white},
    xmajorgrids=true,
    axis on top
]
\addplot[white,fill=black!30] table[y expr =\coordindex, x expr={\thisrow{male}/31395*100}, col sep=comma] {data.csv};
\addplot+[white,fill=red!50!black, discard if not = {male}{1214}] table[y expr =\coordindex, x expr={\thisrow{male}/31395*100}, col sep=comma] {data.csv}; 
% Hard coded precentage for males, 25-29.
\node [color=white] at (\xcenter-3.65cm,-6.05cm) {\scriptsize 3.87\%};
\end{axis}

% Hard-coded center axis
\draw [color=black, line width=0.1pt] (0,0.63) -- (0,8.6cm);
\end{tikzpicture}
\end{center}
\end{document}

Here is the resulting graph:

Population Pyramid Plot

3

That's a lot of questions in a single post. This site works best if you ask about a single issue per post, preferably in such a way that other people with similar problems have a chance of finding the question. I would suggest that for each question in your post, you open a new issue where you try to generalise and whittle down the problem in such a way that it is "googleable". For example, your first question could be phrased as "How do I apply nodes near coords to a single bar / to a single plot?".

That said, here are quick answers for your four questions:

  1. You can specify the nodes near coords in the \addplot [...] options instead of in the \begin{axis}[...] options. That way, it will only apply for that plot.
  2. See How can I add a zero line to a plot?
  3. You can change the relevant entry in the table from 25--29 to \bfseries 25--29.
  4. Set enlarge y limits={abs=1}, enlarge x limits=false (or similar).
  • Is it too late to remove some of my questions? I ask because if I only include the first question, then the helpful answers supplied by @Jake for 2-4 won't have context. – Michael S Taylor Jun 30 '14 at 16:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.