5

I have two questions regarding the pgfplots package. I have attached the source code I worked on. There are two features I am not able to realize:

  1. I would like to put the total value (sum of the whole stacked bar) on top of the bar, rotated by 90°. For me, it was only possible yet to get the value of each part of the stacked bar by using the nodes near coords command.

  2. Additionally, the percentage of each part of the stacked bar as relative to the whole stacked bar should be displayed in the bar, also rotated by 90° (addition equals 100%)

If it is somehow possible, percentages should have only one significant digit, and those below 5% should not be displayed in the bar. I know this is a pretty complex example, but maybe there is one who can solve it.

\documentclass{article}
 \usepackage{pgfplots,pgfplotstable}
  \usetikzlibrary{pgfplots.groupplots}
   \pgfplotsset{compat=1.8}

 \pgfplotstableread{
 Criterion  ddd     ccc     vvv 
 (0)    700         750         750 
 (a)    700         750         750 
 (b)        1200        750         750     
 (c)    33      345     345
 (d)    34      333     345
 (e)    234     344     344
  }\Rob

 \pgfplotstableread{
 Criterion  ddd     ccc     vvv 
 0      70          75          75  
 a      70          75          75  
 b          120         75      75      
 c      3       34      34
 d      3       33      34
 e      23      34      34
 }\Gab


\begin{document}
 \begin{tikzpicture}
\begin{groupplot}[group style= {
    columns=2,xlabels at=edge bottom,
    ylabels at=edge left,
    horizontal sep=1cm,group name=plots,
},
ymin=0, enlarge x limits={abs=.5}, enlarge y limits={upper,value=0.4}, 
ylabel=Mon, ylabel style={text height=0.02\textwidth,inner ysep=0pt}, 
ybar,ybar stacked,
major x tick style = transparent, 
/pgf/bar shift=0pt, /pgf/bar width=9pt,
x tick label style={text height=2ex},   
xlabel style={yshift=-2ex}, 
xticklabels from table={\Rob}{Criterion}, 
xtick=data,legend columns=-1, legend style={draw=none, /tikz/every even column/.append   style={column sep=5pt}}]

\nextgroupplot[xlabel=Rob, xlabel shift = -7.5cm, legend to name=grouplegend]
\pgfplotstableforeachcolumn\Rob\as\col{
    \ifnum\pgfplotstablecol=0 
    \else
      \edef\tmp{
        \noexpand\addplot table [x expr=\noexpand\coordindex,y=\col] {\noexpand\Rob};
        \noexpand\addlegendentry {\col}
    }
    \tmp
    \fi
}

\nextgroupplot[xlabel=Gab, xlabel shift = -7.5cm]
\pgfplotstableforeachcolumn\Gab\as\col{
    \ifnum\pgfplotstablecol=0 
    \else
    \edef\tmp{
        \noexpand\addplot table [x expr=\noexpand\coordindex,y=\col] {\noexpand\Gab};
    }
    \tmp
    \fi

 }
  \end{groupplot}
 \draw[dashed] (plots c1r1.south west) -- ++(0,-1.5);
  \draw[dashed] (plots c1r1.south east) -- ++(0,-1.5);
 \draw[dashed] (plots c2r1.south west) -- ++(0,-1.5);
 \draw[dashed] (plots c2r1.south east) -- ++(0,-1.5);
 \node at (plots c1r1.south) [inner sep=0pt,anchor=north, yshift=-12ex]     {\ref{grouplegend}};
 \end{tikzpicture}
 \end{document}
  • This would in principle be possible using visualization depends on keys, but at the moment they're broken for stacked plots, unfortunately. See tex.stackexchange.com/questions/86369/…. – Jake Jun 12 '13 at 3:24
  • @Jake I believe the bug you mention is fixed: any chance of an answer here (to get it off the 'unanswered' list)? – Joseph Wright Aug 3 '14 at 19:13
  • @Jake Any chance of an answer? :) – Sean Allred Aug 1 '15 at 21:45
4

Here is a solution that works without visualization depends on.

Please note that I have truncated the given code to just one plot, because there is nothing new in the second one and only would make the code even longer. I also removed a lot of styles etc. which almost didn't change the output and weren't related to the questions, so would also just "disturb" or distract.

(I also didn't apply the "show only one significant digit" requirement -- I think OP meant "one decimal digit" --, because that doesn't look good. But I think with the given solution it should be pretty easy to adapt it if this should really be necessary.)

For details on how the solution works, please have a look at the comments in the code.

\documentclass[border=5pt]{standalone}
\usepackage{pgfplots}
\usepackage{pgfplotstable}
    \usetikzlibrary{
        pgfplots.groupplots,
    }
    \pgfplotsset{
        % so that the new feature of centering the `nodes near coords' text is applied
        compat=1.9,
        %
        % create a style which will be used to show the sum values
        % (borrowed from <http://tex.stackexchange.com/a/162389/95441>)
        show sum on top/.style={
            /pgfplots/scatter/@post marker code/.append code={
                \node [
                    black,
                    rotate=90,
                    anchor=west,
                    at={(normalized axis cs:
                            \pgfkeysvalueof{/data point/x},
                            \pgfkeysvalueof{/data point/y})
                    },
                ] {\pgfmathprintnumber{\pgfkeysvalueof{/data point/y}}};
            },
        },
    }
    \pgfplotstableread{
        Criterion   ddd     ccc     vvv
        (0)         700     750     750
        (a)         700     750     750
        (b)         1200    750     750
        (c)         33      345     345
        (d)         34      333     345
        (e)         234     344     344
    }\Rob
    % get number of columns in the table
    \pgfplotstablegetcolsof{\Rob}
        \pgfmathtruncatemacro{\NoOfCols}{\pgfmathresult - 1}
    % we also need this value again on a "zero basis" for a style
        \pgfmathtruncatemacro{\NoOfColsZeroBased}{\NoOfCols-1}
    % add column of the sum of the values in each row
    % (because you did the rest also with loops, so here is the loop solution for it)
    % (inspired by <http://tex.stackexchange.com/a/281436/95441>)
    \pgfplotstablecreatecol[
        create col/assign/.code={
                % create and initialize a variable that stores the sum values
                \pgfmathsetmacro\RowSum{0}
            % cycle through the columns
            \pgfplotsforeachungrouped \i in {1,...,\NoOfCols} {
                \pgfmathsetmacro\RowSum{\RowSum+\thisrowno{\i}}
            }
            % set the calculated value to the corresponding cell
            \pgfkeyslet{/pgfplots/table/create col/next content}{\RowSum}
        }
    ]{Sum}{\Rob}
\begin{document}
    \begin{tikzpicture}
        \begin{groupplot}[
            group style={
                columns=2,
                xlabels at=edge bottom,
                ylabels at=edge left,
                horizontal sep=1cm,
                group name=plots,
            },
            ymin=0,
            enlarge y limits={upper,value=0.4},
            ylabel=Mon,
            ybar stacked,
            % instead of making the ticks invisible, just set the length to zero
            major tick length=0pt,
            xtick=data,
            xticklabels from table={\Rob}{Criterion},
            legend columns=-1,
            % -----
            % define the number style for the `nodes near coords' where
            % only values greater than 5 should be shown
            % (adapted from <http://tex.stackexchange.com/a/59961/95441>
            nodes near coords={
                \pgfkeys{/pgf/fpu=true}
                \pgfmathparse{\pgfplotspointmeta-5}
                \pgfmathfloatifflags{\pgfmathresult}{+}{%
                    \pgfmathprintnumber[
                        precision=0,
                    ]{\pgfplotspointmeta}\%
                }{}
                \pgfkeys{/pgf/fpu=false}
            },
%            % because rotating the values would cause them to overlap
%            % I just provide the solution to that in commented form
%            nodes near coords style={
%                rotate=90,
%                font=\footnotesize,
%            },
            % to the last plot the sum value should be added as a node
            % for which we use the created style
            every axis plot no \NoOfColsZeroBased/.append style={
                show sum on top,
            },
        ]
        \nextgroupplot[
            % instead of shifting the `xlabel' just provide a title
            title=Rob,
            legend to name=grouplegend,
        ]
            % add all data columns to the axis
            \foreach \i in {1,...,\NoOfCols} {
                \addplot+ [
                    % this has to be given because we want to use a different
                    % value than the default `y' value
                    point meta=explicit,
                ] table [
                    x expr=\coordindex,
                    y index=\i,
                    % here we calculate the number which we want to be plotted
                    meta expr=\thisrowno{\i}/\thisrow{Sum}*100,
                ] {\Rob};
                        % extract the corresponding column header name from the table
                        \pgfplotstablegetcolumnnamebyindex{\i}\of{\Rob}\to{\colname}
                    % use it as legend entry
                    \addlegendentryexpanded{\colname}
            }
%        % I removed the second plot because there is nothing different here
%        \nextgroupplot
        \end{groupplot}

        \draw [dashed] (plots c1r1.south west) -- ++(0,-1.5);
        \draw [dashed] (plots c1r1.south east) -- ++(0,-1.5);

        \node [inner sep=0pt,anchor=north, yshift=-12ex]
            at (plots c1r1.south) {\ref{grouplegend}};

    \end{tikzpicture}
\end{document}

image showing the result of above code

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.