2

Yesterday, I asked how to add numbers to the top of clustered bars in a bar graph with pgfplots in a MWE from the pgfplots manual, and got great answers. However, I've been unable to modify the solution to work for my graph; I get the error, "Missing number, treated as zero" right after width = 0.8\textwidth]. How can I fix this?

Code:

\documentclass{article}
\usepackage{pgfplots,pgfplotstable}
\begin{document}
  \begin{tikzpicture}
    \begin{axis}[
      ymin=0,
      symbolic x coords={float,small int,int,latin string,string,heterogeneous},
      xtick=data]
      ylabel=CPU Cycles,
      legend style={at={(0.5,-0.15)},
        anchor=north,legend columns=-1},
      ybar=5pt,% configures `bar shift'
      bar width=9pt,
      width = 0.8\textwidth
      ]
      \addplot[y1,fill=blue] coordinates {
        (float,42)
        (small int,50)
        (int,80)
        (latin string,80)
        (string,40)
        (heterogeneous,50)
      };
      \addplot[y2,fill=blue] coordinates {
        (float,42)
        (small int,50)
        (int,80)
        (latin string,80)
        (string,40)
        (heterogeneous,50)
      };

      \addplot [
      only marks,
      point meta=explicit,
      nodes near coords={\pgfmathprintnumber[precision=1]{\pgfplotspointmeta}\%},
      nodes near coords style={above}
      ]
      table[
      x=x,
      y expr={max(\thisrow{y1},\thisrow{y2})},
      % meta expr={(1-\thisrow{y2}/\thisrow{y1}) * 100}] {\mydata};
       meta expr={100*(1-\thisrow{y1}/\thisrow{y2})}] {\mydata};

      \legend{Far,Near}
    \end{axis}
  \end{tikzpicture}
\end{document}

The working version, which I'm trying to modify, is the following:

\documentclass{article}
\usepackage{pgfplots,pgfplotstable}
\pgfplotsset{compat=1.14}

\pgfplotstableread{
x y1 y2
1930 50e6 38e6
1940 33e6 42e6
1950 40e6 43e6
1960 50e6 45e6
1970 70e6 65e6
}\mydata

\begin{document}
\begin{tikzpicture}
\begin{axis}[
    ymin=0,
    x tick label style={
        /pgf/number format/1000 sep=},
    ylabel=Population,
    enlarge x limits=0.15,
    legend style={at={(0.5,-0.15)},
        anchor=north,legend columns=-1},
    ybar=5pt,% configures `bar shift'
    bar width=9pt,
]
\addplot table[x=x,y=y1] {\mydata};
\addplot table[x=x,y=y2] {\mydata};

\addplot [
  only marks,
  point meta=explicit,
  nodes near coords={\pgfmathprintnumber[precision=1,showpos]{\pgfplotspointmeta}\%},
  nodes near coords style={above}
  ]
  table[
    x=x,
    y expr={max(\thisrow{y1},\thisrow{y2})},
    meta expr={(\thisrow{y2}-\thisrow{y1})/\thisrow{y1} * 100}] {\mydata};

\legend{Far,Near}
\end{axis}
\end{tikzpicture}
\end{document}
  • The y1 and y2 keys doesn't exist, and the final \addplot cannot work because you have no \mydata table. – Torbjørn T. Feb 27 '17 at 20:34
  • @TorbjørnT. Thanks. I added the working code that I'm trying to modify, which defines those keys etc. Do you have any idea how I can correctly port it over? – Elliot Gorokhovsky Feb 27 '17 at 20:37
4

There are a few problems with your code.

  • First of all, there's an extra ] after xtick=data in the axis options. This means that the following options will not be read, so that must be removed.

  • The code in my answer to your other question relies on storing the data in a pgfplotstable table. For example,

    \pgpflotstableread{
    A B C
    1 2 3
    2 3 4
    }\mydata
    

    This saves that table of data to the \mydata macro. The first row gives names to the columns. You can then plot one column versus another with e.g.

    \addplot table[x=A,y=B] {\myadata};
    

    So this means that the values in the A column is used as the x-coordinates, and those in the B column are used as y-coordinates.

    In your code, you've gone from \addplot table[x=x,y=y1] {\mydata };, to \addplot [y1,...] coordinates {..};, so you specify the coordinates manually instead of reading them from the table, but you've kept the y1 argument, which actually referred to a specific column in the table. A table which you haven't defined.

  • And because the table is not defined, the third \addplot doesn't work.

    Explanation of the code adding the numbers

    The numbers above the bars are added with the third \addplot:

    \addplot [
      only marks,
      point meta=explicit,
      nodes near coords={\pgfmathprintnumber[precision=1,showpos]{\pgfplotspointmeta}\%},
      nodes near coords style={above}
      ]
      table[
        x=x,
        y expr={max(\thisrow{y1},\thisrow{y2})},
        meta expr={(\thisrow{y2}-\thisrow{y1})/\thisrow{y1} * 100}] {\mydata};
    
    • only marks: ybar is specified in the axis, but this shouldn't plot a bar.
    • point meta=explicit: The point meta defines what should be printed by nodes near coords, explicit means that the value is an explicit coordinate.
    • nodes near coords={\pgfmathprintnumber[precision=1,showpos]{\pgfplotspointmeta}\%}: The nodes near coords option prints something next to the plot marker/bar. The part after = defines the formatting of the number fed to these nodes, represented by \pgfplotspointmeta. The \pgfmathprintnumber macro is for pretty-printing numbers, the precision determines the number of decimals, while showpos means that a plus sign is printed before positive numbers.
    • nodes near coords style={above}: positions the nodes near coords above the coordinate.

    • table[<options>] {\mydata} is explained above, but the <options> are a bit different:

      • x=x: use the column named x as x-coordinates
      • y expr={max(\thisrow{y1},\thisrow{y2})}: for y-coordinates, use not a specific value from the table, but the result of the expression given. \thisrow{y1} returns the value from the given column, here y1, so max(\thisrow{y1},\thisrow{y2}) is the maximum of y1 and y2.
      • meta expr={(\thisrow{y2}-\thisrow{y1})/\thisrow{y1} * 100}: Similar to y expr, meta expr sets the meta value, which in the end defines the content of the nodes near coords, to the result of the given expression. So this is the explicit value of the point meta.

A working version of your code is the following. Note that I made up the values in the y2 column, so you should edit those. Note also that because some of the x-values had spaces in them, I used a comma as a column separator, instead of the default space.

\documentclass{article}
\usepackage{pgfplots,pgfplotstable}
\begin{document}
\begin{tikzpicture}
\pgfplotstableread[col sep=comma]{
x,y1,y2
float,42,23
small int,50,60
int,80,30
latin string,80,90
string,40,45
heterogeneous,50,37
}\mydata

\begin{axis}[
      ymin=0,
      symbolic x coords={float,small int,int,latin string,string,heterogeneous},
      xtick=data,
      ylabel=CPU Cycles,
      legend style={at={(0.5,-0.15)},
        anchor=north,legend columns=-1},
      ybar=5pt,% configures `bar shift'
      bar width=9pt,
      width = \textwidth,
      height= 0.6\textwidth
      ]

      \addplot[fill=blue] table[x=x,y=y1] {\mydata};
      \addplot[fill=red] table[x=x,y=y2] {\mydata};

      \addplot [
      only marks,
      point meta=explicit,
      nodes near coords={\pgfmathprintnumber[precision=1]{\pgfplotspointmeta}\%},
      nodes near coords style={above}
      ]
      table[
      x=x,
      y expr={max(\thisrow{y1},\thisrow{y2})},
      meta expr={(1-\thisrow{y1}/\thisrow{y2}) * 100}] {\mydata};


      \legend{Far,Near}
  \end{axis}
  \end{tikzpicture}
\end{document}

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.