How do I apply nodes near coords to a single bar / to a single plot?

1,260

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).
Share:
1,260

Related videos on Youtube

Michael S Taylor
Author by

Michael S Taylor

Updated on August 01, 2022

Comments

  • Michael S Taylor
    Michael S Taylor over 1 year

    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

  • Michael S Taylor
    Michael S Taylor over 9 years
    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.