# Particular bar plot with pgfplots: bar color = category

I want to create a bar plot using pgfplots. In this plot the bars should be represent categorys. So that one color suggest the category.

The categorys are:

• 0-8 None
• 9-13 Minimal
• 14-19 Slightly
• 20-28 Medium heavy
• 29-63 Heavy

Subsequent an example, but there are all bar in the same color:

\documentclass[11pt]{standalone}
\usepackage[T1]{fontenc}
\usepackage{fixltx2e}
\usepackage{pgfplots}

\pgfplotsset{compat=1.8}

\begin{document}
\begin{tikzpicture}
\begin{axis}[
xbar,
width=12cm,
height=8cm,
xmajorgrids=true,
yticklabel={\#\ifnum\ticknum<9 0\fi\pgfmathprintnumber\tick},
ytick={1,2,...,10},
xmin=0,
xmax=36,
xtick={5,10,...,30},
xlabel={Sum},
ylabel={Participants},
%nodes near coords,
ymin=0.25,
ymax=10.75,
]
{(4,1) (16,2) (16,3) (33,4) (5,5) (10,6) (20,7) (8,8) (15,9) (5,10)};
\end{axis}
\end{tikzpicture}
\end{document}


Afterwards it should looks like the attached picture. I'm not sure if it is possible. The order of participants (#01 - #10) should be remain continuously.

• Perhaps you could clarify whether you want the bars to be colored automatically based on the value of the bar (hard) or whether you just want to color the bars (probably easier). I don't know from the top of my head how to do it in either case, but it's important information. – Mythio May 29 '13 at 21:40

Here are two different ways of doing this (code at the bottom):

1. Using a "fake" bar plot (which is actually a scatter plot) with a color map with sharp transitions.

2. Using different \addplot commands for each category, filtering out all the values not belonging to the current category.

The colour scheme is taken from the Colorbrewer website

Single \addplot with color map:

\documentclass[11pt, border=5mm]{standalone}
\usepackage{pgfplots}

\definecolor{ylgnbu1}{RGB}{255, 255, 204}
\definecolor{ylgnbu2}{RGB}{161, 218, 180}
\definecolor{ylgnbu3}{RGB}{65, 182, 196}
\definecolor{ylgnbu4}{RGB}{44, 127, 184}
\definecolor{ylgnbu5}{RGB}{37, 52, 148}

\pgfplotsset{
colormap={colorbrewer-ylgnbu}{[1pt]
color(0pt)=(ylgnbu1);
color(85pt)=(ylgnbu1);
color(85pt)=(ylgnbu2);
color(135pt)=(ylgnbu2);
color(135pt)=(ylgnbu3);
color(195pt)=(ylgnbu3);
color(195pt)=(ylgnbu4);
color(285pt)=(ylgnbu4);
color(285pt)=(ylgnbu5);
color(630pt)=(ylgnbu5);
},
}

\begin{document}
\begin{tikzpicture}
\begin{axis}[
colorbar,
colorbar style={
major tick length=0pt,
ytick={4,11,16.5,24,46},
yticklabels={None,Minimal,Slightly,Medium heavy,Heavy}
},
point meta min=0, point meta max=63,
scatter,
scatter src=x,
only marks,
clip mode=individual,
scatter/@pre marker code/.append code={
\pgfkeys{/pgf/fpu=true,/pgf/fpu/output format=fixed}
\pgfmathsetmacro\negheight{-\pgfplotspointmeta}
\fill [draw=black] (axis direction cs:0,0.3) rectangle (axis direction cs:\negheight,-0.3);
\pgfplotsset{mark=none}
},
xmin=0,
width=12cm,
height=8cm,
xmajorgrids=true,
yticklabel={\#\ifnum\ticknum<9 0\fi\pgfmathprintnumber\tick},
ytick={1,2,...,10},
xmin=0,
xmax=36,
xtick={5,10,...,30},
xlabel={Sum},
ylabel={Participants},
%nodes near coords,
ymin=0.25,
ymax=10.75,
]![enter image description here][3]
{(4,1) (16,2) (16,3) (33,4) (5,5) (10,6) (20,7) (8,8) (15,9) (5,10)};
\end{axis}
\end{tikzpicture}
\end{document}


Using separate \addplot commands.

\documentclass[11pt, border=5mm]{standalone}
\usepackage{pgfplots, pgfplotstable}

\definecolor{ylgnbu1}{RGB}{255, 255, 204}
\definecolor{ylgnbu2}{RGB}{161, 218, 180}
\definecolor{ylgnbu3}{RGB}{65, 182, 196}
\definecolor{ylgnbu4}{RGB}{44, 127, 184}
\definecolor{ylgnbu5}{RGB}{37, 52, 148}

\pgfplotscreateplotcyclelist{colorbrewer-ylgnbu}{
{fill=ylgnbu1, draw=black},
{fill=ylgnbu2, draw=black},
{fill=ylgnbu3, draw=black},
{fill=ylgnbu4, draw=black},
{fill=ylgnbu5, draw=black},
}

Sum Participants
4 1
16 2
16 3
33 4
5 5
8 6
20 7
8 8
15 9
5 10
}\datatable
\newcounter{plotindex}

\begin{document}
\begin{tikzpicture}
\begin{axis}[
xbar=0pt, bar shift=0pt,
cycle list name=colorbrewer-ylgnbu,
xmin=0,
width=12cm,
height=8cm,
xmajorgrids=true,
yticklabel={\#\ifnum\ticknum<9 0\fi\pgfmathprintnumber\tick},
ytick={1,2,...,10},
xmin=0,
xmax=36,
xtick={5,10,...,30},
xlabel={Sum},
ylabel={Participants},
ymin=0.25,
ymax=10.75,
legend entries={None,Minimal,Slightly, Medium heavy,Heavy},
legend cell align=left
]
\pgfplotsinvokeforeach{1,...,5}{
}
\pgfplotsinvokeforeach{0:8,9:13,14:19,20:28,29:63}{
\addplot +[restrict x to domain=#1] table {\datatable};
}
\end{axis}
\end{tikzpicture}
\end{document}

• Thank you! The 2. solution (using separate \addplot commands) is really the best and looks similar like my ohter bar plots in the document. Only: When some categories are not existent (e. g. #06 and #07 are < 9, then this categories don't appear in legend. Is it possile that these categories in this case still appear in the legend? – André May 30 '13 at 8:55
• Furthermore, there appear a warning the current plot has no coordinates (or all have been filtered away) and the classification to the categories is not correct (still used the last entries). – André May 30 '13 at 9:15
• @André: Unfortunately, I can't think of an elegant way to get a legend entry even if all coordinates are filtered away, short of patching one of PGFPlots' internal commands. The same goes for the warning (but it's only a warning, not an error message, so you can just ignore it). I've added a clumsy manual way for getting the correct legend. Maybe you could file a feature request? – Jake May 30 '13 at 17:41
• I managed this with adding with adding two fake entrys (10 20 and 20 21) in "pgfplotstableread" wich are not displayed because out of the displayed range. How I can "file a feature request" in these list? – André Jun 8 '13 at 10:40

This is an Asymptote solution, that includes a rangebargraph.asy module (it needs more work to handle possible case variations). The opacity levels are used to get a color variations from the basic color catPen, which can be set up for the graph.

crbg.tex:

\begin{filecontents*}{rangebargraph.asy}
import graph;
import palette;

struct coloredRangeBarGraph{
string[] catName;

real[] catRange;

pen catPen=darkgreen;
pen[] catOpacity;

int[] data;

int getCat(real dataPoint,real[] catRange){
for(int i=0;i<catRange.length;++i){
if(dataPoint<catRange[i]) return i;
}
return catRange.length;
}

real boxwidth;;

pen axisPen=darkblue;

real xmin;
real xmax;

real ymin;
real ymax;

void drawBars(){
for(int i=0;i<data.length;++i){
filldraw(box((0,i+1-boxwidth),(data[i],i+1+boxwidth))
,catOpacity[getCat(data[i],catRange)]
);
}
}

void drawLegend(real w=1, real h=1){
for(int i=0;i<catName.length;++i){
filldraw(box( (xmax+1,ymax-0.5-i-h/2),(xmax+1+w,ymax-0.5-i+h/2) ),catOpacity[i]);
label(Label(catName[i]),(xmax+1+w,ymax-0.5-i),E);
}
}

void drawAxes(){
ylimits(ymin,ymax);
xaxis("Sum"
,BottomTop(extend=true)
,p=axisPen
,xmin,xmax,Ticks(extend=true,Step=5,pTick=lightblue,begin=false));

yaxis("Participants"
,ymin,ymax
,p=axisPen
,LeftTicks(ticklabel=new string(real x){return format("\#%#.2d",(int)x);}
,Step=1
,beginlabel=false
,pTick=darkblue
)
);
};

void operator init(int[] data
,string[] catName=new string[]{"None","Minimal","Slightly","Medium heavy","Heavy"}
,int[] catRange=new int[]{9,14,20,29}
,pen catPen=darkgreen
,pen[] catOpacity=new pen[]{
catPen+opacity(0.05),
catPen+opacity(0.2),
catPen+opacity(0.4),
catPen+opacity(0.8),
catPen+opacity(1)}
,real boxwidth=0.5
,pen axisPen=darkblue
,real xmin=0
,real xmax=max(data)+1
,real ymin=0
,real ymax=data.length+0.5
){
this.data=copy(data);
this.catName   =catName   ;
this.catRange  =catRange  ;
this.catPen    =catPen    ;
this.catOpacity=catOpacity;
this.boxwidth  =boxwidth  ;
this.axisPen   =axisPen   ;
this.xmin      =xmin      ;
this.xmax      =xmax      ;
this.ymin      =ymin      ;
this.ymax      =ymax      ;
}
};
\end{filecontents*}
\documentclass[10pt,a4paper]{article}
\usepackage[inline]{asymptote}
\usepackage{lmodern}
\begin{document}

\begin{figure}
\begin{asy}
import rangebargraph;
size(300,200,IgnoreAspect);
int[] data={4, 16, 16, 33, 5, 10, 20, 8, 15, 5,};
coloredRangeBarGraph g=coloredRangeBarGraph(data);
g.drawBars();
g.drawAxes();
g.drawLegend();
\end{asy}
\caption{Default}
\end{figure}

\begin{figure}
\begin{asy}
import rangebargraph;
size(400,300,IgnoreAspect);
int[] data={29,38,27,8,57,9,49,23,18,48,4,42,25,5,30,37};
coloredRangeBarGraph g=
coloredRangeBarGraph(data,boxwidth=0.309
,catPen=darkblue
,axisPen=olive
, xmax=62
);
g.drawBars();
g.drawAxes();
g.drawLegend();
\end{asy}
\caption{Customized}
\end{figure}

\end{document}


To process it with latexmk, create file latexmkrc:

sub asy {return system("asy '\$_[0]'");}

and run latexmk -pdf crbg.tex.