6

I have the following:

\documentclass[11pt,twoside,openright]{memoir}

\usepackage{tikz}
\usepackage{pgfplots}
\usepackage{pgfplotstable}
\usepackage{xcolor}

\definecolor{color1}{RGB}{146,200,180}
\definecolor{color2}{RGB}{124,206,89}

\pgfplotstableread[col sep=comma]{
start,end,Name,color
0,600,fooer,color1
600,1020,foo2bar,color2
}\loadedtable


\begin{document}

\begin{tikzpicture}
\begin{axis}[
    xbar, xmin=0,
    y axis line style = { opacity = 0 },
    tickwidth         = 0pt,
    width=12cm, height=3.5cm, enlarge y limits=0.5,
    symbolic y coords={fooer,foo2bar},
    ytick=data, xbar stacked,
    bar shift=0pt,
    y dir=reverse,
    xtick={1, 500, 1000},
    xticklabels={1 ms, 500 ms, 1 s}
]

\addplot [draw=none, forget plot] table [x=end, y=Name]{\loadedtable};
\addplot+[color1] table [x expr=\thisrow{start}-\thisrow{end}, y=Name]{\loadedtable};
\end{axis}
\end{tikzpicture}

\end{document}

enter image description here

As you can see my color1 gets picked up but now I would want only "fooer" to be color1 and "foo2bar" to be color2. However if I change the line into:

\addplot+[\thisrow{color}] table [x expr=\thisrow{start}-\thisrow{end}, y=Name]{\loadedtable};

I get:

! Undefined control sequence.
\pgfkeyscurrentkey ->\thisrow 
                              {color}
l.35 \addplot+[\thisrow{color}] t
                                 able [x expr=\thisrow{start}-\thisrow{end},...

? 

How can I make the plots colored with my different colors?


EDIT: I have decided that the easiest way must be to get rid of the pgfplots dependency and add each line separately with the color I want. So now I have this instead: (I added a third because I noticed strange behaviour)

\documentclass[11pt,twoside,openright]{memoir}

\usepackage{tikz}
\usepackage{pgfplots}
\usepackage{xcolor}

\definecolor{color1}{RGB}{146,200,180}
\definecolor{color2}{RGB}{124,206,89}

\begin{document}

\begin{tikzpicture}
\begin{axis}[
    xbar, xmin=0,
    y axis line style = { opacity = 0 },
    tickwidth         = 0pt,
    width=12cm, height=3.5cm, enlarge y limits=0.5,
    symbolic y coords={a,b,c},
    ytick=data, xbar stacked,
    bar shift=0pt,
    y dir=reverse,
    xtick={1, 500, 1000},
    xticklabels={1 ms, 500 ms, 1 s}
]


\addplot+[color1]                 coordinates { (600,a) };

\addplot [draw=none, forget plot] coordinates { (600,b) };
\addplot+[color2]                 coordinates { (1020,b) };

\addplot [draw=none, forget plot] coordinates { (600,c) };
\addplot+[color2]                 coordinates { (900,c) };


\end{axis}
\end{tikzpicture}

\end{document}

enter image description here However, now there is something seriously strange going on with the coordinates. Why are they not placed where I tell it to place the bars? The two ones with color2 should start immediately underneath each other and they also are way too far to the right...

Oh and only the a is printed not the b and c...

3 Answers 3

6
+100

As you already noticed, you need a plot for each bar in order to have individual colors. With some help from this answer you can automate this. Also, there is no need to retype the names in symbolic y coords. And some additional code reads the color from the table and passes it to the plots.

Because it's a stacked plot and the first bar starts at 0, there is no need for \addplot [draw=none, forget plot]. In fact, this causes the problems in the edit of your question.

There are some comments in the code, which should explain things. But if you have any questions, feel free to ask.

The code:

\documentclass[11pt,twoside,openright]{memoir}

\usepackage{tikz}
\usepackage{pgfplots}
\usepackage{pgfplotstable}
\usepackage{xcolor}

\definecolor{color1}{RGB}{146,200,180}
\definecolor{color2}{RGB}{124,206,89}

% from https://tex.stackexchange.com/a/128040/110842
% filter to only get the current row in \pgfplotsinvokeforeach
\pgfplotsset{
    select row/.style={
        x filter/.code={\ifnum\coordindex=#1\else\def\pgfmathresult{}\fi}
    }
}


\pgfplotstableread[col sep=comma]{
start,end,Name,color
0,300,fooer,color1
300,800,foo2bar,color2
800,1020,bar2baz,green!60!red
}\loadedtable
% getting number of data rows - 1
\pgfplotstablegetrowsof{\loadedtable}
\pgfmathsetmacro{\tablerows}{int(\pgfplotsretval-1)}



\begin{document}

\begin{tikzpicture}
\begin{axis}[
    xbar, xmin=0,
    y axis line style = { opacity = 0 },
    tickwidth         = 0pt,
    width=12cm, height=3.5cm, enlarge y limits=0.5,
    % next two lines also from https://tex.stackexchange.com/a/128040/110842,
    ytick={0,...,\tablerows},
    yticklabels from table={\loadedtable}{Name},
    xbar stacked,
    bar shift=0pt,
    y dir=reverse,
    xtick={1, 500, 1000},
    xticklabels={1 ms, 500 ms, 1 s},
]

\pgfplotsinvokeforeach{0,...,\tablerows}{
    % get color from table, commands defined must be individual for each plot
    % because the color is used in \end{axis} and therefore would otherwise
    % use the last definition
    \pgfplotstablegetelem{#1}{color}\of{\loadedtable}
    \expandafter\edef\csname barcolor.#1\endcsname{\pgfplotsretval}
    \addplot+[color=\csname barcolor.#1\endcsname] table [select row=#1, x expr=\thisrow{end}-\thisrow{start}, y expr=#1]{\loadedtable};
}
\end{axis}
\end{tikzpicture}

\end{document}

The result:

enter image description here

1

Okay, so xbar stacked means just that. Each new bar starts where the previous ends, i.e., there is no way the bars can start at the same location without getting rid of that. Now, with that change we cna no longer first draw an invisible bar and then continue drawing from that spot. Instead we will first draw the entire thing and then draw a white bar to remove the things we don't want. Sadly the only way to draw a white bar I have found is to first draw a bar filled with white and then draw a bar with white outline. Hence, the whole thing becomes something like this:

\begin{document}

\begin{tikzpicture}
\begin{axis}[
    xbar, xmin=0,
    y axis line style = { opacity = 0 },
    tickwidth         = 0pt,
    width=12cm, height=3.5cm, enlarge y limits=0.5,
    symbolic y coords={a,b,c},
    ytick=data,
    bar shift=0pt,
    y dir=reverse,
    xtick={1, 500, 1000},
    xticklabels={1 ms, 500 ms, 1 s}
]


\addplot+[color1, forget plot]    coordinates { (600,a) };

\addplot+[color2, forget plot]    coordinates { (1020,b) };
\addplot [white, forget plot] coordinates { (600,b) };
\addplot+[white, forget plot] coordinates { (600,b) };

\addplot+[color2, forget plot]    coordinates { (900,c) };
\addplot [white, forget plot] coordinates { (600,c) };
\addplot+[white, forget plot] coordinates { (600,c) };

\end{axis}
\end{tikzpicture}

\end{document}

enter image description here

1
  • hm just noticed that there is in fact a little bit color left, clearly drawing white didn't get rid of all of the bar :(
    – jonalv
    Commented Jul 2, 2018 at 11:01
1

With regard to the "table plot" of the start post.

  1. If the tick names are in the table, there is no need to do something like this:
    symbolic y coords={fooer,foo2bar,...}, (that is not a good style!)

Instead:

ytick={0,...,\RowsNo}, % <---- !
yticklabels from table={\loadedtable}{Name}, 
  1. You can read out the color column and use it to define colors.

(for reasons of clarity, here separately)

% Define Colors separatly
\xdef\tempcolor{black}% 
\pgfplotsinvokeforeach{0,...,\RowsNo}{%%
\pgfplotstablegetelem{#1}{Color}\of{\loadedtable}
\xdef\tempcolor{\ifx \pgfplotsretval\empty \tempcolor \else \pgfplotsretval \fi}
\colorlet{barcolor#1}{\tempcolor}% define
%\colorbox{\tempcolor}{\tempcolor}, % show test 1
}%%
%\colorbox{barcolor3}{Text}, % show test 2
  1. With

the filter

\pgfplotsset{
select row/.style={
x filter/.code={\ifnum\coordindex=#1\else\def\pgfmathresult{}\fi}
}                }

and then

\pgfplotsinvokeforeach{0,...,\RowsNo}{%%  
\addplot[fill=barcolor#1] table [select row=#1, 
x expr=\thisrow{start}-\thisrow{end}, 
y expr=#1
] {\loadedtable};
}%%

the bars are drawn individually, in the defined colors.

To see the effect, the table (in the somewhat strange MWE of the start post) was expanded by a few rows:

enter image description here

\documentclass[a4paper]{article}
\usepackage{pgfplots, pgfplotstable}
\pgfplotsset{compat=1.17}
\pgfplotsset{
select row/.style={
x filter/.code={\ifnum\coordindex=#1\else\def\pgfmathresult{}\fi}
}                }
 
\begin{document}


\definecolor{color1}{RGB}{146,200,180}
\definecolor{color2}{RGB}{124,206,89}

\pgfplotstableread[col sep=comma]{
start,   end,      Name,   Color
0,        600,      foo,       color1
600,    1020,     bar,      color2
700,    1020,     foo2,       
0,        700,      bar2,     red
700,    1020,     foo3,        
700,    1020,     bar3,     
700,    1020,     foo4,     blue
700,    1020,     bar4,     blue
700,    1020,     foo4,     
700,    1020,     bar4,     orange
}\loadedtable
\pgfplotstablegetrowsof{\loadedtable}
\pgfmathtruncatemacro{\RowsNo}{\pgfplotsretval-1}

% Define Colors separatly
\xdef\tempcolor{black}% 
\pgfplotsinvokeforeach{0,...,\RowsNo}{%%
\pgfplotstablegetelem{#1}{Color}\of{\loadedtable}
\xdef\tempcolor{\ifx \pgfplotsretval\empty \tempcolor \else \pgfplotsretval \fi}
\colorlet{barcolor#1}{\tempcolor}% define
%\colorbox{\tempcolor}{\tempcolor}, % show test 1
}%%
%\colorbox{barcolor3}{Text}, % show test 2

\begin{tikzpicture}
\begin{axis}[
xbar, xmin=0,
    y axis line style = { opacity = 0 },
%    tickwidth         = 0pt,
width=12cm,  height=3cm+3.5cm, % with that, ....
bar width=5pt, %... you would need sth. like that. 
enlarge y limits=0.5,
 %   ytick=data, 
%    symbolic y coords={foo,bar},  % No!
ytick={0,...,\RowsNo}, % <---- !
yticklabels from table={\loadedtable}{Name}, % Yes!
%    xbar stacked,
    bar shift=0pt,
    y dir=reverse,
%    xtick={1, 500, 1000},  % strange, because does not match...
xticklabels={1 ms, 500 ms, 1 s} % strange....
]
% Old:
%\addplot [draw=none, forget plot] table [x=end, y=Name]{\loadedtable};
%\addplot+[color1] table [x expr=\thisrow{start}-\thisrow{end}, y expr=\coordindex]{\loadedtable};

% New:
\pgfplotsinvokeforeach{0,...,\RowsNo}{%%  
\addplot[fill=barcolor#1] table [select row=#1, 
x expr=\thisrow{start}-\thisrow{end}, 
y expr=#1
] {\loadedtable};
}%%
\end{axis}
\end{tikzpicture}
\end{document}

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .