1

I produce the following chart:

enter image description here

If you look in the table \hchartone, you'll see that I created two separate series (yoy and yoy2) in order to be able to plot the last bar in a different colour.

However, this causes the x-tick label for 1Q20 to be absent.

How do I fix this?


Code to produce the above:

\documentclass[border=5pt]{standalone}
\usepackage{pgfplots}
\usepackage{pgfplotstable}
\pgfplotsset{compat=1.17}

%colors
\usepackage{color} % colors
\usepackage{xcolor} 
\definecolor{c1}{HTML}{122084}
\definecolor{c6}{HTML}{ff8091}
\definecolor{c6d}{HTML}{db4d60}

\begin{document}

%\pagecolor{gray!20!white}

\pgfplotstableread[col sep=comma]{
    date, yoy, yoy2
    1Q19, 4.5, 
    2Q19, 4.9, 
    3Q19, 4.4, 
    4Q19, 3.6, 
    1Q20, , -0.3
}\hchartone

\begin{tikzpicture}
\small
\begin{axis}[
width = 6.5cm,
height = 6cm,
axis lines=left,
enlarge x limits={0.1},
enlarge y limits={0.1, upper},
%
% y ticks style and label
ymin = -1.1,
ylabel={Annual change (\%)},
ylabel shift = 0pt,
ytick distance = 1,
y tick label style={/pgf/number format/.cd, fixed, fixed zerofill, precision=1, /tikz/.cd, font=\scriptsize},
%
% x axis ticks and style
xtick=data,
xticklabels from table={\hchartone}{date}, 
axis x line shift={\pgfkeysvalueof{/pgfplots/ymin}},       
xticklabel shift={-\pgfkeysvalueof{/pgfplots/axis x line shift}},
table/x expr = \coordindex,     
%
% nodes near coords
nodes near coords,
nodes near coords style = { /pgf/number format/.cd,
    fixed, fixed zerofill, precision=1, /tikz/.cd, font=\scriptsize,
},
]
%
% done with the axis, now the plots
\addplot [c1, fill, ybar, nodes near coords, draw opacity = 0]
table [y=yoy]  {\hchartone};
\addplot [c6, fill, ybar, nodes near coords style = {color = c6d}, draw opacity = 0]
table [y=yoy2]  {\hchartone};
\end{axis}
\end{tikzpicture}

\end{document}
Thev
  • 1,568
  • If you remove xtick=data, then you get the last tick in, however, every other tick is missing. If you then add xtick distance=1, the last one goes missing again. –  May 09 '20 at 23:31
  • Sorry, I am confused - did the above work for you or were you pointing out more anomalies? (apologies for my confusion!) – Thev May 09 '20 at 23:42
  • Your code is fine. I just wanted to mention that if you drop xtick=data, the last tick appears but this solution seems to be useless since it has a bad side effect. –  May 09 '20 at 23:44
  • I've added a comment with a hacky solution. Still trying to find an elegant one. – Thev May 09 '20 at 23:51
  • Replace xtick=data with xtick={0,...,4}. – Torbjørn T. May 10 '20 at 07:26

2 Answers2

2

Here is a very simple hack of the plot handler, which uses the undocumented key at end bar, and which allows you to color the bars in one go. I cannot guarantee that this will always be safe, but at least here it seems to work fine.

\documentclass[border=5pt]{standalone}
\usepackage{pgfplots}
\usepackage{pgfplotstable}
\pgfplotsset{compat=1.17}

%colors
\usepackage{color} % colors
\usepackage{xcolor} 
\definecolor{c1}{HTML}{122084}
\definecolor{c6}{HTML}{ff8091}
\definecolor{c6d}{HTML}{db4d60}


\begin{document}

%\pagecolor{gray!20!white}

\pgfplotstableread[col sep=comma]{
    date, yoy
    1Q19, 4.5
    2Q19, 4.9
    3Q19, 4.4
    4Q19, 3.6
    1Q20, -0.3
}\hchartone

\begin{tikzpicture}
\small
\begin{axis}[
width = 6.5cm,
height = 6cm,
axis lines=left,
enlarge x limits={0.1},
enlarge y limits={0.1, upper},
%
% y ticks style and label
ymin = -1.1,
ylabel={Annual change (\%)},
ylabel shift = 0pt,
ytick distance = 1,
y tick label style={/pgf/number format/.cd, fixed, fixed zerofill, precision=1, /tikz/.cd, font=\scriptsize},
%
% x axis ticks and style
xtick=data,
xticklabels from table={\hchartone}{date}, 
axis x line shift={\pgfkeysvalueof{/pgfplots/ymin}},       
xticklabel shift={-\pgfkeysvalueof{/pgfplots/axis x line shift}},
table/x expr = \coordindex,     
%
% nodes near coords
nodes near coords,
nodes near coords style = { /pgf/number format/.cd,
    fixed, fixed zerofill, precision=1, /tikz/.cd, font=\scriptsize,
},
]
%
% done with the axis, now the plots
%
% hack the plot handler
\pgfkeys{/pgf/at end bar={\ifnum\coordindex=4
\pgfsetfillcolor{c6}
\else
\pgfsetfillcolor{c1}
\fi
\pgfusepath{stroke, fill}
}}
\addplot [c1, fill, ybar, nodes near coords, draw opacity = 0]
table [y=yoy]  {\hchartone};
\end{axis}
\end{tikzpicture}

\end{document}

enter image description here

There are many ways in which one can generalize this. For instance, this one colors all negative values differently from the positive values.

\documentclass[border=5pt]{standalone}
\usepackage{pgfplots}
\usepackage{pgfplotstable}
\pgfplotsset{compat=1.17}

%colors
\usepackage{color} % colors
\usepackage{xcolor} 
\definecolor{c1}{HTML}{122084}
\definecolor{c6}{HTML}{ff8091}
\definecolor{c6d}{HTML}{db4d60}


\begin{document}

%\pagecolor{gray!20!white}

\pgfplotstableread[col sep=comma]{
    date, yoy
    1Q19, 4.5
    2Q19, 4.9
    3Q19, 4.4
    4Q19, 3.6
    1Q20, -0.3
}\hchartone

\begin{tikzpicture}
\small
\begin{axis}[
width = 6.5cm,
height = 6cm,
axis lines=left,
enlarge x limits={0.1},
enlarge y limits={0.1, upper},
%
% y ticks style and label
ymin = -1.1,
ylabel={Annual change (\%)},
ylabel shift = 0pt,
ytick distance = 1,
y tick label style={/pgf/number format/.cd, fixed, fixed zerofill, precision=1, /tikz/.cd, font=\scriptsize},
%
% x axis ticks and style
xtick=data,
xticklabels from table={\hchartone}{date}, 
axis x line shift={\pgfkeysvalueof{/pgfplots/ymin}},       
xticklabel shift={-\pgfkeysvalueof{/pgfplots/axis x line shift}},
table/x expr = \coordindex,     
%
% nodes near coords
visualization depends on={int(sign(\thisrow{yoy}))\as\mysign},
nodes near coords,
nodes near coords style = {/utils/exec={\ifdim\mysign pt>0pt
\tikzset{text=c1}
\else
\tikzset{text=c6}
\fi},
 /pgf/number format/.cd,
    fixed, fixed zerofill, precision=1, /tikz/.cd, font=\scriptsize,
},
%       nodes near coords style={anchor=\myanchor}
]
%
% done with the axis, now the plots
%
% hack the plot handler
\makeatletter
\pgfkeys{/pgf/at end bar={\ifdim\the\pgf@ya<0pt
\pgfsetfillcolor{c6}
\else
\pgfsetfillcolor{c1}
\fi
\pgfusepath{stroke, fill}
}}
\makeatother
\addplot [c1, fill, ybar, nodes near coords, draw opacity = 0]
table [y=yoy]  {\hchartone};
\end{axis}
\end{tikzpicture}
\end{document}

enter image description here

  • Cool! Thank you for the new technique. Is there a similar technique to handle the node near coord? – Thev May 10 '20 at 08:26
  • 1
    @TheveshTheva For this problem the old techniques are more than sufficient, please see the code at the end of the answer. –  May 10 '20 at 08:34
1

One very hacky solution is this:

  1. Add a 0 entry to the yoy column for 1Q20 - this causes the missing label to show, but now creates a problem with nodes near coords - there is an extra one from the first series at 0.0 for 1Q20.
  2. To fix the above, manually paint over it with a white rectangle. (haha)

This is fine with a small data series but would be untenable for large ones. However, I can get this:

enter image description here

With this code:

\documentclass[border=5pt]{standalone}
\usepackage{pgfplots}
\usepackage{pgfplotstable}
\pgfplotsset{compat=1.17}

%colors
\usepackage{color} % colors
\usepackage{xcolor} 
\definecolor{c1}{HTML}{122084}
\definecolor{c6}{HTML}{ff8091}
\definecolor{c6d}{HTML}{db4d60}

\begin{document}

%\pagecolor{gray!20!white}

\pgfplotstableread[col sep=comma]{
    date, yoy, yoy2
    1Q19, 4.5, 
    2Q19, 4.9, 
    3Q19, 4.4, 
    4Q19, 3.6, 
    1Q20, 0, -0.3
}\hchartone

\begin{tikzpicture}
\small
\begin{axis}[
width = 6.5cm,
height = 6cm,
axis lines=left,
enlarge x limits={0.1},
enlarge y limits={0.1, upper},
%
% y ticks style and label
ymin = -1.1,
ylabel={Annual change (\%)},
ylabel shift = 0pt,
ytick distance = 1,
y tick label style={/pgf/number format/.cd, fixed, fixed zerofill, precision=1, /tikz/.cd, font=\scriptsize},
%
% x axis ticks and style
xtick = data,
xticklabels from table={\hchartone}{date}, 
xtick distance = 1,
axis x line shift={\pgfkeysvalueof{/pgfplots/ymin}},       
xticklabel shift={-\pgfkeysvalueof{/pgfplots/axis x line shift}},
table/x expr = \coordindex,     
%
% nodes near coords
nodes near coords,
nodes near coords style = { /pgf/number format/.cd,
    fixed, fixed zerofill, precision=1, /tikz/.cd, font=\scriptsize,
},
]
%
% done with the axis, now the plots
\addplot [c1, fill, ybar, nodes near coords, draw opacity = 0]
table [y=yoy]  {\hchartone};
\addplot [c6, fill, ybar, nodes near coords style = {color = c6d}, draw opacity = 0]
table [y=yoy2]  {\hchartone};
\end{axis}
\draw[white, fill] (4,0.8) rectangle (4.8,1.02);
\end{tikzpicture}

\end{document}
Thev
  • 1,568
  • Generally, I think it is very surprising that there is no inbuilt feature to either (1) simply change the color of a single data point; (2) ensure that all x-axis ticks are shown; (3) allow selective removal of a node. These are all standard in MSExcel. – Thev May 09 '20 at 23:57
  • While there is no built in solution, there are solutions on the market like this one. I would agree that something of that sort is a worthy addition to pgfplots but of course someone would have to really do it. –  May 10 '20 at 00:08