0

I'm reading data that is structured as an outer group (the x indices/rows) with different inner categories (multiple columns) that are composed of multiple values themselves again. The goal is to create a stacked barplot that reflects this and displays the categories as separate bars under one x tick.

The separation of categories is achieved by shifting the x value in relation to the current category. However, this seems to be an issue with the stacked barplot as consecutive bars with the same original x value start where the previous barplot ended. erroneous stacking

How I would want it to look like without modifying the file or the table in this case (the real file has some dozen columns and rows):

desired result

\documentclass[11pt]{book}
\usepackage{pgfplots}
\usetikzlibrary{patterns}
\usepackage{pgfplotstable}
\pgfplotscreateplotcyclelist{mycyclelist}{
    black,  postaction={pattern color=blue,     pattern=vertical lines}\\%
    black,  postaction={pattern color=orange,   pattern=horizontal lines}\\%
    black,  postaction={pattern color=green,    pattern=grid}\\%
    black,  postaction={pattern color=red,      pattern=north east lines}\\%
    black,  postaction={pattern color=purple,   pattern=crosshatch dots}\\%
}

\begin{document}
\begin{figure}[!htbp]
\begin{tikzpicture}
    \pgfplotstableread{
    x   As  Aa  A1  A2  A3  A4  A5  Bs  Ba  B1  B2  B3  B4  B5
    1   0   244415  0.3011  0   99.6072 0   0.0925  0   4142970 0.034   0   99.9496 0.0002  0.0162
    2   0   514279  5.4288  0   93.9848 0.0016  0.5855  0   8376969 1.7197  0   98.3238 0.0001  0.0402
    }\datatable

    \begin{axis}[
                    ybar stacked, 
                    bar width=8pt, 
                    cycle list name = mycyclelist, 
                    ymin=0, 
                    xtick=data, 
                    legend entries={1, 2, 3, 4, 5}, 
                    legend columns=5, 
            ]

        \foreach \y/\plotlabel in {0/A, 1/B} { % categories A and B
            \foreach \i in {0,...,4} { % composing values inside a category
                \edef\temp{\noexpand
                    \addplot%
                        \ifnum\i<1% label only the first plot
                        +[nodes near coords=\plotlabel]
                        \fi
                }\temp
                    plot table [
                            header = true, 
                            x expr={\thisrowno{0}*2 + \y}, 
                            y expr={\thisrowno{\the\numexpr 3 + \y * 7 + \i}}, % offset + category * sizeof(category bundle) + value-index
                        ]
                        {\datatable};
            }
        }
    \end{axis}
\end{tikzpicture}
\end{figure}
\end{document}

Does pgfplots use the original x index instead of the modified one to stack the bars or is there something wrong with my code?

2
+50

I don't know for sure, but it looks like stacking is handled row-by-row. Neither do I know if this can be customized. I circumvented the issue by using multiple axis environments: Output of example code

\documentclass[11pt]{book}
\usepackage{pgfplots}
\usetikzlibrary{patterns}
\usepackage{pgfplotstable}
\pgfplotscreateplotcyclelist{mycyclelist}{
    black,  postaction={pattern color=blue,     pattern=vertical lines}\\%
    black,  postaction={pattern color=orange,   pattern=horizontal lines}\\%
    black,  postaction={pattern color=green,    pattern=grid}\\%
    black,  postaction={pattern color=red,      pattern=north east lines}\\%
    black,  postaction={pattern color=purple,   pattern=crosshatch dots}\\%
}
\pgfplotsset{compat=1.7}
\begin{document}
\begin{figure}[!htbp]
\begin{tikzpicture}
    \pgfplotstableread{
    x   As  Aa  A1  A2  A3  A4  A5  Bs  Ba  B1  B2  B3  B4  B5
    1   0   244415  0.3011  0   99.6072 0   0.0925  0   4142970 0.034   0   99.9496 0.0002  0.0162
    2   0   514279  5.4288  0   93.9848 0.0016  0.5855  0   8376969 1.7197  0   98.3238 0.0001  0.0402
    }\datatable
    \pgfplotstablegetrowsof{\datatable}
    \pgfmathsetmacro{\datatablerows}{\pgfplotsretval}

    % Axis limits
    \pgfmathsetmacro{\xmin}{0.5}
    \pgfmathsetmacro{\xmax}{\datatablerows + 0.5}
    \pgfmathsetmacro{\ymin}{0}
    \pgfmathsetmacro{\ymax}{120}

    % Categories
    \def\categories{0/A, 1/B}
    \pgfmathsetmacro{\ncategories}{2}

    % Width of a bar group (0 -- 1)
    \pgfmathsetmacro{\contentwidth}{0.5}

    % Gap between bars in the same group, proportional to bar width
    \pgfmathsetmacro{\innergap}{0.75}

    \pgfmathsetmacro{\barwidth}{\contentwidth /
      (\ncategories + (\ncategories-1)*\innergap)}
    \pgfmathsetmacro{\innerskip}{(\innergap + 1) * \barwidth}
    \pgfmathsetmacro{\groupstart}{-0.5*\contentwidth + 0.5*\barwidth}

    \pgfplotsset{set layers}
    % Axes and legend
    \begin{axis}[
      scale only axis,
      ybar stacked,
      bar width=1pt, 
      cycle list name = mycyclelist, 
      xmin=\xmin,xmax=\xmax,
      ymin=\ymin,ymax=\ymax,
      xtick={1,...,\datatablerows},
      ytick={0,50,100}, 
      legend entries={1, 2, 3, 4, 5}, 
      legend columns=5, 
      ]
      % Dummy bar outside visible area
      \foreach \k in {1, 2, 3, 4, 5} {
        \addplot coordinates {
          (-5, 1)
        };
      }
    \end{axis}

    \foreach \y/\plotlabel in \categories {
      % Each category gets its own axis
      \begin{axis}[
        scale only axis,
        ybar stacked, 
        bar width=\barwidth,
        cycle list name = mycyclelist, 
        xmin=\xmin,xmax=\xmax,
        ymin=\ymin,ymax=\ymax,
        axis lines=none,
        ]

        \foreach \i in {0,...,4} { % composing values inside a category
          \edef\temp{\noexpand
            \addplot%
            \ifnum\i<1% label only the first plot
            +[nodes near coords=\plotlabel]
            \fi
          }\temp
          plot table [
          header = true, 
          x expr={\thisrowno{0} + \groupstart + \y * \innerskip}, 
          y expr={\thisrowno{\the\numexpr 3 + \y * 7 + \i}},
          ]
          {\datatable};
        }
      \end{axis}
    }
\end{tikzpicture}
\end{figure}
\end{document}
  • This works great! Although a semilogxaxis seems to destroy the mechanism, any idea what could go wrong there? – mschrimpf Jun 27 '14 at 4:30
  • @Mash I think you would need to transform the x coordinates of the bars. A linear coordinate system is assumed in my example code. The code also specifies the width of a bar in axis units (vs physical units). This doesn't really make sense when using a log axis. – mvkorpel Jun 27 '14 at 6:13

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.