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?

1 Answer 1

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}
2
  • This works great! Although a semilogxaxis seems to destroy the mechanism, any idea what could go wrong there?
    – mschrimpf
    Commented Jun 27, 2014 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
    Commented Jun 27, 2014 at 6:13

You must log in to answer this question.

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