[Tex/LaTex] using bar chart to compare two groups of data, how to draw one node (showing the ratio) per two bars

bar chartnodesnodes-near-coordspgfplots

I have two groups of data, you can think of them as one control group and one treatment group, and each data point shows the system's performance under certain parameter x.

Now for each value of parameter x, I want to draw two bars (one for the control group and the other for the treatment group) that stays closely together, to compare their performance. This is already done.

Furthermore, I want to draw one node per two bars, on top of the two bars, to indicate the ratio of the treatment group's performance to control group's.

enter image description here

Note that the red text above each pair of bars are the effect I want. Is this doable in pgfplots?

I have looked at bar shift and bar near coords but still does not get a succinct way to do what I want.

Specifically, the ideal case is that I provide the two groups of data to pgfplots, like

\addplot coordinates { (1,x1) (2,x2) ... (9,x9) };
\addplots coordinates { (1,y1) (2,y2) ... (9,y9) };

and some command automatically generates the nodes (y1/x1) (y2/x2) … (y9/x9) on top of each pair of bars.

Thanks in advance!

The minimal code generating the diagram similar to that in the question is shown below. I have removed minor things like legend and patterns.

\documentclass{article}
\usepackage{pgfplots}
\begin{document}
\begin{tikzpicture}
\begin{semilogyaxis}[
        xtick = data,
        symbolic x coords={1,2,4,8,16,32,64,128,256,512,1024,2048},
        x tick label style={rotate=45,anchor=east,xshift=0.5em},
        ybar=0pt,
        bar width=5pt,
]
\addplot 
        coordinates {
(1, 12224822.47615195) (2, 30575568.537983067) (4, 56065152.09279688) (8, 119050256.55456343) (16, 261199511.2399962) (32, 539436878.3711921) (64, 884494633.5530908) (128, 1458149738.5198479) (256, 1504651025.9424655) (512, 3690489159.8036933) (1024, 4002894124.741196) (2048, 5886439904.74722)
        };

\addplot
        coordinates {
(1, 12120350.197539225) (2, 30647908.833372578) (4, 56033201.34011042) (8, 118156559.2107797) (16, 258243240.89016733) (32, 538593063.3199656) (64, 853738697.5167842) (128, 1323350550.6813228) (256, 1364824842.2256825) (512, 3354827274.6800394) (1024, 4111728131.806063) (2048, 6950375713.147153)
        };

\end{semilogyaxis}
\end{tikzpicture}
\end{document}

Best Answer

As already stated in the comments below the question, you can use the nodes near coords feature to plot the numbers above the bars. Here a complete solution. For more details on how it works, please have a look at the comments in the code.

% used PGFplots v1.14
\documentclass[border=5pt]{standalone}
\usepackage{pgfplots}
\usepackage{pgfplotstable}  % <-- needed to draw the "inline" table
\begin{document}
    \begin{tikzpicture}
            % first provide your data as table, so later the data can
            % easily be accessed for various stuff
            \pgfplotstableread{
                x       y                   z
                1       12224822.47615195   12120350.197539225
                2       30575568.537983067  30647908.833372578
                4       56065152.09279688   56033201.34011042
                8       119050256.55456343  118156559.2107797
                16      261199511.2399962   258243240.89016733
                32      539436878.3711921   538593063.3199656
                64      884494633.5530908   853738697.5167842
                128     1458149738.5198479  1323350550.6813228
                256     1504651025.9424655  1364824842.2256825
                512     3690489159.8036933  3354827274.6800394
                1024    4002894124.741196   4111728131.806063
                2048    5886439904.74722    6950375713.147153
            }{\data}
        \begin{semilogyaxis}[
            xtick=data,
            symbolic x coords={1,2,4,8,16,32,64,128,256,512,1024,2048},
            x tick label style={
                rotate=45,
                anchor=east,
                xshift=0.5em,
                yshift=-0.5em,
            },
            ybar=0pt,
            bar width=5pt,
            axis on top,
        ]
            % then your `\addplot commands change to
            \addplot table [x=x,y=y] {\data};
            \addplot table [x=x,y=z] {\data};
        \end{semilogyaxis}
    % so far so simple.
    % Now to the "challenging" part, where you want to add nodes
    % "above the bars".
        % because the labels should be centered above the bars the easiest
        % way to achieve that is to draw a normal line plot, but cannot be done
        % in a bar plot, why we have to draw another axis exactly on top of
        % the above axis
        \begin{semilogyaxis}[
            % here we don't need to show any axis, ticks and labels,
            % so we hide them
            hide axis,
            % of course the x axis should be the same as before, so the
            % values are repeated here
            xtick=data,
            symbolic x coords={1,2,4,8,16,32,64,128,256,512,1024,2048},
            % now comes the `nodes near coords' feature
            nodes near coords,
            % because the bars are quite narrow we reduce the font size of
            % the `nodes near coords'
            nodes near coords style={
                font=\scriptsize,
            },
        ]
            % and here the mentioned line plot, which we hide of course
            \addplot [
                % (comment the next line to see what the `\addplot' actually
                % is doing but hidden except for the labels)
                draw=none,
                % with the following key-value we state *how* we want to
                % provide the data which should be shown in the `nodes near coords'
                point meta=explicit,
                nodes near coords,
            ] table [
                x=x,
                % because we want to draw the `nodes near coords' above the
                % higher of the both bars, we choose the `max' value of both
                % bars
                y={create col/expr={max(\thisrow{y},\thisrow{z})}},
                % and here we provide *what* should be shown in the `nodes near coords'
                meta expr={\thisrow{z}/\thisrow{y}},
            ] {\data};
        \end{semilogyaxis}
    \end{tikzpicture}
\end{document}

image showing the result of above code

Related Question