3

I'm trying to make a stacked bar graph with the bars at full width and symbolic x coords. Here's a minimalish example:

\documentclass{scrartcl}
\usepackage[includeheadfoot,left=15mm,right=15mm,top=-8mm,bottom=10mm,headheight=3cm,headsep=15mm,marginparsep=0mm,marginparwidth=0mm,footskip=0mm]{geometry}
\usepackage{pgfplots}
\pgfplotsset{compat=1.14}

\begin{document}

\pgfplotsset{width=\textwidth}
\begin{tikzpicture}[line cap=rect]
\begin{axis}[
ybar stacked,
bar width=1,
symbolic x coords={a,b,c,d,e,f,g},
]
\addplot coordinates {
(a, 39.000000)
(b, 30.200000)
(c, 39.000000)
(d, 30.200000)
(e, 33.300000)
(f, 30.000000)
(g, 32.900000)
};

\end{axis}
\end{tikzpicture}

\end{document}

However, when I try to complile this with lualatex, I get

! Package pgfplots Error: Sorry, the input coordinate `\pgfplots@loc@TMPa ' has not been defined with 'symbolic x coords={a,b,c,d,e,f,g}... Maybe it has been misspelled? Or did you mean something like [normalized]\pgfplots@loc@TMPa ?.

which I haven't found overly helpful.

What works:

  1. an absolute value for bar width (or no bar width at all)
  2. no symbolic x coords, replace a..g by 1..7.

So now I'm out of things to try. What am I overlooking?

2

The problem starts here:

\def\pgfplots@bar@mathparse@#1#2{%
  \pgfmathparse{\pgfkeysvalueof{/pgf/#2}}%
  \ifpgfmathunitsdeclared
  \else
      \edef\pgfplots@bar@direction@choice@{#1}%
      \if N\pgfplots@bar@direction@choice@%
          \if a\pgfplots@bar@direction@choice
          \else
              \if x\pgfplots@bar@direction@choice
                  \def\pgfplots@bar@direction@choice@{y}%
              \else
                  \if y\pgfplots@bar@direction@choice
                      \def\pgfplots@bar@direction@choice@{x}%
                  \else
                      \pgfplotsthrow{invalid argument}{\pgfplots@bar@direction@choice@}{Sorry, the value of 'bar direction' is invalid}\pgfeov%
                  \fi
              \fi
          \fi
      \fi
      \if N\pgfplots@bar@direction@choice@%
          \pgfplots@bar@mathparse@error{#1}{#2}%
      \else
          \let\pgfplots@loc@TMPa=\pgfmathresult
          % ↓↓↓ notice this line ↓↓↓
          \csname pgfplotstransformdirection\pgfplots@bar@direction@choice@\endcsname{\pgfplots@loc@TMPa}%
          % ↑↑↑ notice this line ↑↑↑
          \let\pgfplots@loc@TMPa=\pgfmathresult
          \if\pgfplots@bar@direction@choice@ x%   
              \pgfqpointxy@orig{\pgfplots@loc@TMPa}{0}%
              \edef\pgfmathresult{\pgf@sys@tonumber\pgf@x}%
          \else
              \pgfqpointxy@orig{0}{\pgfplots@loc@TMPa}%
              \edef\pgfmathresult{\pgf@sys@tonumber\pgf@y}%
          \fi
          %\edef\pgfplots@loc@TMPa{{\pgf@sys@tonumber\pgf@x}{\pgf@sys@tonumber\pgf@y}}%
          %\expandafter\pgfmathveclen@\pgfplots@loc@TMPa
      \fi
  \fi
}%

By using this macro, will calculate the correct width of ybars, especially if the width is given in relative value.

This is why you can see \csname pgfplotstransformdirection ... in the code. This macro is defined by x coord trafo or so. It will translate the input x-coordinate to physical coordinate. Usually the input is a number, (1.2); sometimes it is a date (2017-1-23); in your case it should be symbolic (b).

But your input is 1, which is not a pre-defined symbolic coordinate, so you see the error.

To get over this, one cannot simply pass bar width=b because \pgfmathparse does not know what is b. Some possible solutions include:

  • wait until the package updates; or

  • redefined \pgfplots@bar@mathparse@ by replacing the transform line by

        % ↓↓↓ notice this line ↓↓↓
        \csname pgfplotstransformdirection\pgfplots@bar@direction@choice@\endcsname{[normalized]\pgfplots@loc@TMPa}%  
        % ↑↑↑ notice this line ↑↑↑

And this is even better

        \ifx\pgfplots@symb@magic@prefix\undefined % test if symbolic coordinate
            \csname pgfplotstransformdirection\pgfplots@bar@direction@choice@\endcsname{\pgfplots@loc@TMPa}%
        \else
            \csname pgfplotstransformdirection\pgfplots@bar@direction@choice@\endcsname{[normalized]\pgfplots@loc@TMPa}%
        \fi

An MWE

\documentclass{scrartcl}
\usepackage{pgfplots}
\pgfplotsset{compat=newest}

\begin{document}

\makeatletter

\def\pgfplots@bar@mathparse@#1#2{%
    \pgfmathparse{\pgfkeysvalueof{/pgf/#2}}%
    \ifpgfmathunitsdeclared
    \else
        \edef\pgfplots@bar@direction@choice@{#1}%
        \if N\pgfplots@bar@direction@choice@%
            \if a\pgfplots@bar@direction@choice
            \else
                \if x\pgfplots@bar@direction@choice
                    \def\pgfplots@bar@direction@choice@{y}%
                \else
                    \if y\pgfplots@bar@direction@choice
                        \def\pgfplots@bar@direction@choice@{x}%
                    \else
                        \pgfplotsthrow{invalid argument}{\pgfplots@bar@direction@choice@}{Sorry, the value of 'bar direction' is invalid}\pgfeov%
                    \fi
                \fi
            \fi
        \fi
        \if N\pgfplots@bar@direction@choice@%
            \pgfplots@bar@mathparse@error{#1}{#2}%
        \else
            \let\pgfplots@loc@TMPa=\pgfmathresult
            \ifx\pgfplots@symb@magic@prefix\undefined
                \csname pgfplotstransformdirection\pgfplots@bar@direction@choice@\endcsname{\pgfplots@loc@TMPa}%
            \else
                \csname pgfplotstransformdirection\pgfplots@bar@direction@choice@\endcsname{[normalized]\pgfplots@loc@TMPa}%
            \fi
            \let\pgfplots@loc@TMPa=\pgfmathresult
            \if\pgfplots@bar@direction@choice@ x%   
                \pgfqpointxy@orig{\pgfplots@loc@TMPa}{0}%
                \edef\pgfmathresult{\pgf@sys@tonumber\pgf@x}%
            \else
                \pgfqpointxy@orig{0}{\pgfplots@loc@TMPa}%
                \edef\pgfmathresult{\pgf@sys@tonumber\pgf@y}%
            \fi
        \fi
    \fi
}%

\begin{tikzpicture}
    \begin{axis}[
        ybar stacked,
        bar width=1,
        symbolic x coords={a,b,c,d,e,f,g},
    ]
    \addplot coordinates {
        (a, 39.000000)
        (b, 30.200000)
        (c, 39.000000)
        (d, 30.200000)
        (e, 33.300000)
        (f, 30.000000)
        (g, 32.900000)
    };
    \end{axis}
\end{tikzpicture}

\begin{tikzpicture}
    \begin{axis}[
        ybar stacked,
        bar width=1,
        xticklabels={a,b,c,d,e,f,g},
        xtick=data, % a tick for each bar
        typeset ticklabels with strut % all xticklabels on the same baseline
    ]
    \addplot coordinates {
        (1, 39.000000)
        (2, 30.200000)
        (3, 39.000000)
        (4, 30.200000)
        (5, 33.300000)
        (6, 30.000000)
        (7, 32.900000)
    };
    \end{axis}
\end{tikzpicture}

\end{document}

0

I'm not an expert on pgfplots by any means, but I found a workaround to this issue in cmhughes's answer to a different question: Formatting a pgfplot graph. Thicker bars and total width

Instead of using symbolic y coords={A, B, C}, one can instead specify ytick={0,1,2} and yticklabels={A, B, C} which doesn't lead to the same problem when setting bar width. Of course, all the coordinates in the \addplot lines must be changed to the appropriate numbers instead of the symbols.

Modifying the MWE given in the question appropriately:

\documentclass{scrartcl}
\usepackage[includeheadfoot,left=15mm,right=15mm,top=-8mm,bottom=10mm,headheight=3cm,headsep=15mm,marginparsep=0mm,marginparwidth=0mm,footskip=0mm]{geometry}
\usepackage{pgfplots}
\pgfplotsset{compat=1.16}

\begin{document}

\pgfplotsset{width=\textwidth}
\begin{tikzpicture}[line cap=rect]
\begin{axis}[
ybar stacked,
bar width=0.8,
xtick={0,1,2,3,4,5,6},
xticklabels={a,b,c,d,e,f,g},
]
\addplot coordinates {
(0, 39.000000)
(1, 30.200000)
(2, 39.000000)
(3, 30.200000)
(4, 33.300000)
(5, 30.000000)
(6, 32.900000)
};

\end{axis}
\end{tikzpicture}

\end{document}

output:

enter image description here

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.