8

I have the problem that in the following plot the right node near coords text of A is missing. The source of the problem is a rounding error in the data: They should sum up to 100 but in A it is a bit more. What would be the best way to avoid this? Simply rounding A down is not an option. I have tons of such plots, with more columns, and in almost everyone there is a row with a sum a bit too large.

\documentclass[]{article}
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}

\usepackage{pgfplots}
\pgfplotsset{compat=1.13}
\usepackage{pgfplotstable}

\pgfplotsset{
 my stackbar plot/.style={
             xbar stacked,
             xmin=0,xmax=100,
             symbolic y coords={A,B},
             ytick=data,
             nodes near coords={xxx},}}

\begin{document}


\begin{tikzpicture}
\pgfplotstableread[col sep=space]{
text   --    -   
B      50    50
A      50.01  50
 }\data


\begin{axis}[my stackbar plot,]
 \addplot table [x expr = \thisrow{--},y=text] {\data};
 \addplot table [x expr = \thisrow{-}, y=text] {\data};
\end{axis}
\end{tikzpicture}

\end{document} 

enter image description here

  • 1
    Depending on whether your other plots need clipping, you could set clip=false to fix the problem with the disappearing nodes. – Jake Feb 18 '16 at 9:54
  • how about setting xmax a little bigger, e.g xmax=101? – cmhughes Feb 18 '16 at 11:30
  • @Jake: The problem with clip=false is that the stack bar can overshot the axis. With the value in the example it can not be seen, but with e.g. 50.1 is already visible. I think I will have to process the values to scale them. – Ulrike Fischer Feb 18 '16 at 12:16
  • @cmhughes: This would move the right axis, but I need a clean 0-100 box (the numbers are percents.) – Ulrike Fischer Feb 18 '16 at 12:17
  • @UlrikeFischer If you operate on percentages, how can they add up to more than a hundred? Perhaps, it is better to review the rounding errors in your input data, rather than adjusting the visualization. If you cannot correct the input, how about rounding and displaying the residual as error bar? – Henri Menke Feb 18 '16 at 15:07
2

I decided that the sanest solution is to normalize the values. Here a simplified version of the code I used at the end:

\documentclass[]{article}
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}

\usepackage{pgfplots}
\pgfplotsset{compat=1.13}
\usepackage{pgfplotstable}

\pgfplotsset{
 my stackbar plot/.style={
             xbar stacked,
             xmin=0,xmax=100,
             symbolic y coords={A,B},
             ytick=data,
             nodes near coords={xxx},}}

\begin{document}


\begin{tikzpicture}
\pgfplotstableread[col sep=space]{
text   --    -
B      50    50
A      50.01  50
 }\data

\pgfplotstablecreatecol[create col/expr={\thisrow{--}+\thisrow{-}}]{sum}\data
\pgfplotstablecreatecol[create col/expr={\thisrow{--}/\thisrow{sum}*100}]{--}\data
\pgfplotstablecreatecol[create col/expr={\thisrow{-}/\thisrow{sum}*100}]{-}\data

\begin{axis}[my stackbar plot,]
 \addplot table [x expr = \thisrow{--},y=text] {\data};
 \addplot table [x expr = \thisrow{-}, y=text] {\data};
\end{axis}
\end{tikzpicture}

\end{document}

enter image description here

Edit

Further test revealed that normalizing is not enough. The total can still be a bit larger than 100 and so the mark could get lost. It is necessary to trunc the values, see pgfplots: correct rounding problems.

1

It is also possible to normalize only values in rows that not add up to 100:

\documentclass[]{article}
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}

\usepackage{pgfplots}
\pgfplotsset{compat=1.13}
\usepackage{pgfplotstable}

\pgfplotsset{
 my stackbar plot/.style={
             xbar stacked,
             xmin=0,xmax=100,
             symbolic y coords={A,B},
             ytick=data,
             nodes near coords={xxx},}}

\begin{document}


\begin{tikzpicture}
\pgfplotstableread[col sep=space]{
text   --    -
B      50    50
A      50.01  50
 }\data

\pgfplotstablecreatecol[create col/expr={\thisrow{--}+\thisrow{-}}]{sum}\data

% normalize only if the sum is not 100
\pgfplotsinvokeforeach{--,-}{%
  \pgfplotstablemodifyeachcolumnelement{#1}\of\data\as\wert{%
    \pgfplotstablegetelem{\pgfplotstablerow}{sum}\of\data%
    \pgfmathparse{\pgfplotsretval==100?\wert:\wert*100/\pgfplotsretval}%
    \edef\wert{\pgfmathresult}
  }%
}

\begin{axis}[my stackbar plot,]
 \addplot table [x expr = \thisrow{--},y=text] {\data};
 \addplot table [x expr = \thisrow{-}, y=text] {\data};
\end{axis}
\end{tikzpicture}

\end{document}

enter image description here

In the same way it is possible to change only the values in rows whitch adds up to more than 100 using

% normalize only if the sum is >100
\pgfplotsinvokeforeach{--,-}{%
  \pgfplotstablemodifyeachcolumnelement{#1}\of\data\as\wert{%
    \pgfplotstablegetelem{\pgfplotstablerow}{sum}\of\data%
    \pgfmathparse{\pgfplotsretval<=100?\wert:\wert*100/\pgfplotsretval}%
    \edef\wert{\pgfmathresult}
  }%
}
  • Good idea, But normalizing is not enough, the total can still be a (small) bit to large, see tex.stackexchange.com/questions/295628/…. – Ulrike Fischer Feb 24 '16 at 21:29
  • @UlrikeFischer Yes, I know. I saw the question. But I thougt that the suggestion using xintexpr is better than something like floor(10000/\pgfplotsretval*\wert)/100. – esdd Feb 24 '16 at 22:16

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.