2

I'm trying to select the color of a stacked bar plot based on the value of a cell in the line.

\documentclass{article}
\usepackage{pgfplots, pgfplotstable}
\usepackage[utf8]{inputenc}

\begin{document}

\pgfplotstableread[col sep=comma]{
label,startyear,endyear,color  
Washington, 1789, 1797, black!50
Adams, 1797, 1801, red!30
Jefferson, 1801, 1809, green!50
Madison, 1801, 1809, green!50
}\loadedtable
% sort by startyear
\pgfplotstablesort[sort key=startyear]\sortedtable\loadedtable

\begin{tikzpicture}
\begin{axis}[
  xbar stacked,
  xmin=1785,
  bar width=0.2cm,
  axis lines=left,
  width=\textwidth, height=4cm,
  enlarge y limits={abs=0.5},
  ytick=\empty,
]

\addplot [draw=none, forget plot] table [col sep=comma,x=startyear, y expr=-\coordindex]{\sortedtable};
\addplot +[
   nodes near coords,
   nodes near coords align={anchor=west},
   point meta=explicit symbolic, every node near coord/.append style={black}] table[col sep=comma,x expr=\thisrow{endyear}-\thisrow{startyear}, y expr=-\coordindex,meta=label]{\sortedtable};
\end{axis}
\end{tikzpicture}
\end{document}

I have not however found a way to get each row to be filled with the selected color.

1
  • I don't think that this is possible. Usually you need to add one \addplot command per color as shown in https://tex.stackexchange.com/a/128040/95441. Then the remaining task would be to create a cycle list from the given values in the table. Would that be an option? – Stefan Pinnow Jun 3 '19 at 18:11
4

It is not too difficult to draw these bars in different colors. Instead of drawing bars this draws rectangles that of course look like bars. The definition of the corresponding plot marks is from here. (I do not understand why you need to sort the table.)

\documentclass{article}
\usepackage{pgfplots, pgfplotstable}
\pgfplotsset{compat=1.16}
\usetikzlibrary{calc}
\usepackage[utf8]{inputenc}
\pgfkeys{/pgf/shapes/xbar/height/.initial=10cm,/pgf/shapes/xbar/width/.initial=6pt}
\pgfdeclareplotmark{xbar}{%
    \pgfpathrectangle{\pgfpoint{0pt}{-.5*\pgfkeysvalueof{/pgf/shapes/xbar/width}}{0pt}}{%
    \pgfpoint{-\pgfkeysvalueof{/pgf/shapes/xbar/height}}{\pgfkeysvalueof{/pgf/shapes/xbar/width}}}
    \pgfusepath{stroke,fill}}
\begin{document}

\pgfplotstableread[col sep=comma]{
label,startyear,endyear,color  
Washington, 1789, 1797, black!50
Adams, 1797, 1801, red!30
Jefferson, 1801, 1809, green!50
Madison, 1801, 1809, green!50
}\loadedtable
% sort by startyear
\pgfplotstablesort[sort key=startyear]\sortedtable\loadedtable

\begin{tikzpicture}
\begin{axis}[xmin=1785,xmax=1810,height=4cm,
  /pgf/shapes/xbar/width=0.2cm,
  axis lines=left,
  width=\textwidth, 
  enlarge y limits={abs=0.5},
  ytick=\empty,
  scatter/@pre marker code/.code={
  \pgfplotstablegetelem{\coordindex}{color}\of{\sortedtable}
  \edef\mycolor{\pgfplotsretval}
  \pgfplotstablegetelem{\coordindex}{startyear}\of{\sortedtable}
  \edef\startyear{\pgfplotsretval}
  \pgfplotstablegetelem{\coordindex}{endyear}\of{\sortedtable}
  \edef\endyear{\pgfplotsretval}
  \pgfmathsetmacro{\myheight}{(\endyear-\startyear)*\xunit}
  \scope[fill=\mycolor,/pgf/shapes/xbar/height=\myheight pt]},
]

\addplot [xbar stacked,draw=none, forget plot] table [col sep=comma,x=startyear, y expr=-\coordindex]{\sortedtable};
\path let \p1=($(1786,0)-(1785,0)$)    in \pgfextra{\xdef\xunit{\x1}}; % measure x unit
\addplot[only marks,scatter,mark=xbar,
   nodes near coords*,
   nodes near coords align={anchor=west},
   point meta=explicit symbolic, every node near coord/.append style={black}] 
 table[col sep=comma,y expr=-\coordindex,x expr=\thisrow{endyear},meta=label]{\sortedtable};

\end{axis}
\end{tikzpicture}
\end{document}

enter image description here

Here is a way to add a legend.

\documentclass{article}
\usepackage{pgfplots, pgfplotstable}
\pgfplotsset{compat=1.16}
\usetikzlibrary{calc}
\usepackage[utf8]{inputenc}
\pgfkeys{/pgf/shapes/xbar/height/.initial=10cm,/pgf/shapes/xbar/width/.initial=6pt}
\pgfdeclareplotmark{xbar}{%
    \pgfpathrectangle{\pgfpoint{0pt}{-.5*\pgfkeysvalueof{/pgf/shapes/xbar/width}}{0pt}}{%
    \pgfpoint{-\pgfkeysvalueof{/pgf/shapes/xbar/height}}{\pgfkeysvalueof{/pgf/shapes/xbar/width}}}
    \pgfusepath{stroke,fill}}
\begin{document}

\pgfplotstableread[col sep=comma]{
label,startyear,endyear,color  
Washington, 1789, 1797, black!50
Adams, 1797, 1801, red!30
Jefferson, 1801, 1809, green!50
Madison, 1801, 1809, green!50
}\loadedtable
% sort by startyear
\pgfplotstablesort[sort key=startyear]\sortedtable\loadedtable

\begin{tikzpicture}
\begin{axis}[xmin=1785,xmax=1810,height=4cm,
  /pgf/shapes/xbar/width=0.2cm,
  axis lines=left,
  width=\textwidth, 
  enlarge y limits={abs=0.5},
  ytick=\empty,
  scatter/@pre marker code/.code={
  \pgfplotstablegetelem{\coordindex}{color}\of{\sortedtable}
  \edef\mycolor{\pgfplotsretval}
  \pgfplotstablegetelem{\coordindex}{startyear}\of{\sortedtable}
  \edef\startyear{\pgfplotsretval}
  \pgfplotstablegetelem{\coordindex}{endyear}\of{\sortedtable}
  \edef\endyear{\pgfplotsretval}
  \pgfmathsetmacro{\myheight}{(\endyear-\startyear)*\xunit}
  \scope[fill=\mycolor,/pgf/shapes/xbar/height=\myheight pt]},
  legend style={at={(1,1.5)}}
]

\addplot [xbar stacked,draw=none, forget plot] table [col sep=comma,x=startyear, y expr=-\coordindex]{\sortedtable};
\path let \p1=($(1786,0)-(1785,0)$)    in \pgfextra{\xdef\xunit{\x1}}; % measure x unit
\addplot[only marks,scatter,mark=xbar,
   nodes near coords*,forget plot,
   nodes near coords align={anchor=west},
   point meta=explicit symbolic, every node near coord/.append style={black}] 
 table[col sep=comma,y expr=-\coordindex,x expr=\thisrow{endyear},meta=label]{\sortedtable};
 \pgfplotstablegetrowsof{\sortedtable} 
 \pgfmathtruncatemacro{\NumRows}{\pgfplotsretval-1} 
 \pgfplotsinvokeforeach{0,...,\NumRows}{
  \pgfplotstablegetelem{#1}{color}\of{\sortedtable}
  \edef\mycolor{\pgfplotsretval}
  \pgfplotstablegetelem{#1}{label}\of{\sortedtable}
  \edef\mylabel{\pgfplotsretval}
  \edef\temp{\noexpand\addlegendimage{area legend,fill=\mycolor}
  \noexpand\addlegendentry{\mylabel}}
  \temp
 }
\end{axis}
\end{tikzpicture}
\end{document}

enter image description here

6
  • 1
    +1 I am very happy being wrong. Always incredible of what you come up with. And even more interesting is your statement "not too difficult". I would say 99% of all PGFPlots users would never be able to come up with such a solution (including me). So I am very excited with what else "impossible" solutions you'll come up with ;) – Stefan Pinnow Jun 4 '19 at 4:24
  • 1
    @StefanPinnow Thanks! Most of the complication is actually that there is an asymmetry between plotting a plot from a file or the table stored in a macro. This is very nicely explained in tex.stackexchange.com/a/356790/121799, which really deserves more upvotes. And I exploit the fact that the pgfmanual is well written and receives constant feedback from users like you. – user121799 Jun 4 '19 at 4:29
  • True, Symbol1's answer was also awesome and I already upvoted it at that time ... – Stefan Pinnow Jun 4 '19 at 4:40
  • 1
    @marmot if you support that answer, me too. +1 to that answer and +1 for yours! – manooooh Jun 4 '19 at 5:53
  • Thanks a lot. I've added the line x tick label style={/pgf/number format/.cd, set thousands separator={}}, to remove the comma in the years. I am now however wondering how to add a legend for the colors with this setup. Any Idea? – Gerard Jun 6 '19 at 11:45

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.