2

This is a follow up question to: PGFPLOTS: Drawings inside a bar of a barplot

I created a stack bar plot with coordinates at the bars such that I can draw arrows and other stuff inside the bar arranged at this coordinates. The following solution works fine as long as I only have one row:

\documentclass[border=5pt]{standalone}
\usepackage{pgfplots}
    \usetikzlibrary{arrows.meta}
    \pgfplotsset{
        compat=1.16,
        % define a style to use for the connecting lines
        /tikz/my line style/.style={
            black,
            thick,
            ->,
        },
    }
\begin{document}
\begin{tikzpicture}
    \begin{axis}[
        xbar stacked,
        width=8cm,
        height=2cm,
        symbolic y coords={naive},
        ytick=data,
        yticklabels={Naive},
        xlabel={Runtime [s]},
        legend columns=3,
        legend style={
            at={(0.5,1.05)},
            anchor=south,
            legend cell align=left,
            align=left,
            legend plot pos=left,
            draw=black,
            font=\footnotesize,
        },
        % !!! this is the critical point !!!
        % to make that solution work you have set the following option due to
        % technical reasons which is roughly:
        % normally the markers are first collected and are drawn *after*
        % `\end{axis}', in contrast to the `\draw' command. Said that, the
        % named `nodes near coords' are not available during the execution of
        % the `\draw' command
        clip marker paths=true,
    ]
        % draw the connecting lines using the predefined style
        \draw [my line style] (b-1-0) edge (a-0-1)
                                      edge (a-1-1)
        ;

        \addplot+[green] coordinates {(100,naive)}
            coordinate (a-\plotnum-\coordindex)
        ;
            \addlegendentry{Pre computations}

        \addplot+[
            yellow,
            nodes near coords,
            node near coords style={
                black,
                font=\small\bfseries,
                % also add names to the `nodes near coords`
                name=b-\plotnum-\coordindex,
            },
        ] coordinates {(900,naive)}
            % add coordinates to the points/bars
            coordinate (a-\plotnum-\coordindex)
        ;
            \addlegendentry{Iteration}

        \addplot+[red] coordinates {(150,naive)};
            \addlegendentry{Post computations}
    \end{axis}
\end{tikzpicture}
\end{document}

This results in: enter image description here

Now I want to add more rows. Therefore, I added more symbolic y coordinates:

symbolic y coords={naive, opt1, opt2}

to the axis options and then tried:

           \addplot+[green] coordinates {
                         (100,naive) (120,opt1) (125,opt2)
                }
                coordinate (a-\plotnum-\coordindex)
            ;
                \addlegendentry{Pre computations}

            \addplot+[
                yellow,
                nodes near coords,
                node near coords style={
                    black,
                    font=\small\bfseries,
                    % also add names to the `nodes near coords`
                    name=b-\plotnum-\coordindex,
                },
            ] coordinates {(900,naive)(800,opt1) (725,opt2)}
                % add coordinates to the points/bars
                coordinate (a-\plotnum-\coordindex)
            ;
                \addlegendentry{Iteration}

            \addplot+[red] coordinates {(150,naive)(120,opt1) (90,opt2)};
                \addlegendentry{Post computations}

This fails with the error that my (a-0-1) so no longer found. How can I automatically define a tikz coordinate for each key-value pair in the coordinates-list?

1 Answer 1

5

Here the modified code. To find out, how it works, please have a look at the comments in the code.

% used PGFPlots v1.16
\documentclass[border=5pt]{standalone}
\usepackage{pgfplotstable}
    \usetikzlibrary{arrows.meta}
    \pgfplotsset{
        compat=1.16,
        % define a style to use for the connecting lines
        /tikz/my line style/.style={
            black,
            thick,
            ->,
        },
    }
\begin{document}
\begin{tikzpicture}
        % moved data to a table
        \pgfplotstableread{
            y       x1  x2  x3
            naive   100 900 150
            opt1    120 800 120
            opt2    125 725 90
        }{\loadedtable}
            % store number of rows in the table
            \pgfplotstablegetrowsof{\loadedtable}
            \pgfmathtruncatemacro{\N}{\pgfplotsretval-1}
    \begin{axis}[
        xbar stacked,
        width=8cm,
        % ---------------------------------------------------------------------
        % adjusted or added stuff
        % ---------------------------------------------------------------------
        % so the bars don't overlap
        height=4cm,
        % so there is no free negative space
        xmin=0,
        % so there is some free space left above and below the bars
        % (otherwise it could be that some parts of the upper and lower bar
        %  are clipped at the axis limits)
        enlarge y limits={abs=0.5},
        % (just use the coordinate index as y position ...
        table/y expr={\coordindex},
        % ... use as labels the `y` column of the data table ...
        yticklabels from table={\loadedtable}{y},
        % ---------------------------------------------------------------------
        % (and state them at the data points (of the first `\addplot` command)
        ytick=data,
        xlabel={Runtime [s]},
        legend columns=3,
        legend style={
            at={(0.5,1.05)},
            anchor=south,
            legend cell align=left,
            align=left,
            legend plot pos=left,
            draw=black,
            font=\footnotesize,
        },
        % !!! this is the critical point !!!
        % to make that solution work you have set the following option due to
        % technical reasons which is roughly:
        % normally the markers are first collected and are drawn *after*
        % `\end{axis}', in contrast to the `\draw' command. Said that, the
        % named `nodes near coords' are not available during the execution of
        % the `\draw' command
        clip marker paths=true,
    ]
        % draw the connecting lines using the predefined style
        \pgfplotsinvokeforeach {0,...,\N} {
            \draw [my line style] (bb#1) edge (a#1)
                                         edge (b#1)
            ;
        }

        \addplot+[green] table [x=x1] {\loadedtable}
            \foreach \i in {0,...,\N} {
                coordinate [pos=\i/\N] (a\i)
            }
        ;
        \addlegendentry{Pre computations}

        \addplot+[
            yellow,
            nodes near coords,
            node near coords style={
                blue,
                font=\small\bfseries,
                % also add names to the `nodes near coords`
                name=bb\coordindex,
            },
        ] table [x=x2] {\loadedtable}
            % add coordinates to the points/bars
            \foreach \i in {0,...,\N} {
                coordinate [pos=\i/\N] (b\i)
            }
        ;
        \addlegendentry{Iteration}

        \addplot+[red] table [x=x3] {\loadedtable};
        \addlegendentry{Post computations}
    \end{axis}
\end{tikzpicture}
\end{document}

image showing the result of above code

1
  • Thanks alot. This is what I was looking for :-) Commented Apr 1, 2020 at 12:35

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .