[Tex/LaTex] How to adapt the color of a label using pgfplots

colorpgfplotstikz-pgf

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?

Best Answer

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.
Related Question