9

I created this style that shifts the labels and put them on the bottom of the ybars.

However, I have a problem with the bars that have too short length (for example, see the 8.7 and 5.1 in the example below). I want to check if the values are less than some threshold, or the length of the bar is shorter than the label (number) then change its color.

How can I overlay another label on top of the one in white when the bar is shorter? or maybe change the color of the label to a gradient color? or just overlay the part that is outside of the bar?

error image

\documentclass{standalone}

\usepackage{tikz}
\usepackage{pgfplots}
\usepackage{pgfplotstable}
\usetikzlibrary{calc}

\begin{document}
\makeatletter
\begin{tikzpicture}
\begin{axis}[
ybar,
every node near coord/.style={
  check for zero/.code={ % If meta=0, make the node a coordinate (which doesn't have text)
    \pgfmathfloatifflags{\pgfplotspointmeta}{0}{
        \pgfkeys{/tikz/coordinate}
    }{}
  },
  check for zero, color=white, text opacity=1, font=\footnotesize, inner ysep=0.5pt,
},%
% Bottom nodes 
calculate full offset/.code={
    \pgfkeys{/pgf/fpu=true,/pgf/fpu/output format=fixed}
    \pgfmathsetmacro\testmacro{((\pgfplotspointmeta-\pgfkeysvalueof{/pgfplots/ymin})*10^\pgfplots@data@scale@trafo@EXPONENT@y)*\pgfplots@y@veclength}
    \pgfkeys{/pgf/fpu=false}
},%
nodes near coords bottom/.style={
    every node near coord/.append style={
        /pgfplots/calculate full offset,
        yshift=-\testmacro,
        rotate=90, anchor=west,%I need the rotate text here and not in the 
        %general style, as the ybar redefines the style
    }
},%
ymin=0,
nodes near coords={\pgfmathprintnumber[fixed zerofill,precision=1]{\pgfplotspointmeta}},
nodes near coords bottom,
]
\pgfplotstableread{
% set real imag mag
1 8.7
2 5.1
3 91.8367

}\mydata
\addplot table[x index=0,y index=1,header=false] {\mydata};
\end{axis}
\end{tikzpicture}
\makeatother
\end{document}

* EDIT *

I need to create some special gradient on each label that is below the bar height. For example, I need to adapt something like How to put color gradient to "Desired Text Only" to each label that is not showing. However, I cannot find a way to put the macro in the style section of the codes. Or is there any equivalent solution?

13

Here is a way to evaluate a conditional in a small TeX script:

enter image description here

\documentclass{standalone}

\usepackage{tikz}
\usepackage{pgfplots}
\usepackage{pgfplotstable}
\usetikzlibrary{calc}

\begin{document}
\makeatletter
\begin{tikzpicture}
\begin{axis}[
ybar,
% Bottom nodes 
% #1: the THRESHOLD after which we switch to a special display.
nodes near coords bottom/.style={
    % a new feature since 1.9: allows to place markers absolutely:
    scatter/position=absolute,
    close to zero/.style={
        at={(axis cs:\pgfkeysvalueof{/data point/x},\pgfkeysvalueof{/data point/y})},
    },
    big value/.style={
        at={(axis cs:\pgfkeysvalueof{/data point/x},0)},
        color=white, text opacity=1, 
        inner ysep=0.5pt,
    },
    every node near coord/.style={
      check for zero/.code={%
        \pgfmathfloatifflags{\pgfplotspointmeta}{0}{%
            % If meta=0, make the node a coordinate (which doesn't have text)
            \pgfkeys{/tikz/coordinate}%
        }{%
            \begingroup
            % this group is merely to switch to FPU locally. Might be
            % unnecessary, but who knows.
            \pgfkeys{/pgf/fpu}%
            \pgfmathparse{\pgfplotspointmeta<#1}%
            \global\let\result=\pgfmathresult
            \endgroup
            %
            % simplifies debugging:
            %\show\result
            %
            \pgfmathfloatcreate{1}{1.0}{0}%
            \let\ONE=\pgfmathresult
            \ifx\result\ONE
                % AH : our condition 'y < #1' is met.
                \pgfkeysalso{/pgfplots/close to zero}%
            \else
                % ok, proceed as usual.
                \pgfkeysalso{/pgfplots/big value}%
            \fi
        }
      },
      check for zero, 
      font=\footnotesize, 
      rotate=90, anchor=west,
    },%
},%
ymin=0,
nodes near coords={\pgfmathprintnumber[fixed zerofill,precision=1]{\pgfplotspointmeta}},
nodes near coords bottom=10,
]
\pgfplotstableread{
% set real imag mag
1 8.7
2 5.1
3 91.8367

}\mydata
\addplot table[x index=0,y index=1,header=false] {\mydata};
\end{axis}
\end{tikzpicture}
\makeatother
\end{document}

Here is an explanation:

  • I employed a new feature since pgfplots 1.9: scatter/position=absolute. It allows to places markers using at=<coordinate expression> which is precisely what you want here.
  • I employed the new feature that /data point/x will always evaluate to the current points x coordinate in the context of nodes near coords (similarly for y).
  • I moved everything which is closely related to the style nodes near coords bottom into its definition.
  • I defined styles close to zero and big value. My intention is that everything below a predefined absolute threshold (which is an argument to nodes near coords bottom) will be placed using close to zero, everything else with big value.
  • your existing check for zero routine now checks for zero, then it also checks for the threshold and applies exactly one of close to zero or big value.
  • I reorganized your styles such that close to zero keeps the plot's current color and moves the node outside of the bar.
  • There is one complicated item and that is ... math expression parsing. Somehow, this is not very nice in PGF; the different math libraries do not talk well with each other. :-(
  • I assigned a threshold of 10 as argument to nodes near coords bottom.
5
  • Thanks for your explanation. I didn't know there was a better way of doing the bottom labels. I understand your solution. However, I was trying to keep all the labels to the bottom to have consistency. Is there a way to put something like a gradient in the label color by checking the length of the bar? or am I stuck with having some labels in top of the bar and others below? – adn Oct 28 '13 at 12:39
  • 1
    @adn In principle, you can assign any tikz option to the node. If you find one which has a suitable color gradient, you would be fine. I guess that could be formulated as separate question (I do not know the answer currently). Perhaps it would be sufficient to simply fill the background of the node? – Christian Feuersänger Oct 28 '13 at 18:30
  • The issue is that half node is on the bar, and the other half on the white background. My question was aiming to change the half that is white font on white background, to other color, while maintaining the white part on the bar. Like in my figure, that you can't see the .1 part of the 5.1 – adn Oct 28 '13 at 18:35
  • perhaps that is feasible using scopes and clip paths... but are you sure that two colors for one character will increase the readability? Have you tried something like fill=white, draw=black instead? – Christian Feuersänger Oct 28 '13 at 18:42
  • I'm not sure if it will increase it. On one hand, I want to keep the consistency of all the bar plots, having the numbers at the bottom. On the other one, I want to make the numbers visible. So, I want to test it. But I cannot figure a way on how to do what I want. – adn Oct 28 '13 at 18:52

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.