Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

My goal is to generate this bar chart:

enter image description here

I was able to achieve this chart as my MWE:

\documentclass[parskip]{scrartcl}
\usepackage[margin=15mm]{geometry}
\usepackage{pgfplots}
\pgfplotsset{width=10cm,compat=1.6}
\usepackage{xifthen}
\usetikzlibrary{patterns}
\usepackage{filecontents}

\makeatletter
\pgfplotsset{
    /pgfplots/flexible xticklabels from table/.code n args={3}{%
        \pgfplotstableread[#3]{#1}\coordinate@table
        \pgfplotstablegetcolumn{#2}\of{\coordinate@table}\to\pgfplots@xticklabels
        \let\pgfplots@xticklabel=\pgfplots@user@ticklabel@list@x
    }
}
\makeatother

% argument #1: any options
\newenvironment{customlegend}[1][]{%
    \begingroup
    % inits/clears the lists (which might be populated from previous
    % axes):
    \csname pgfplots@init@cleared@structures\endcsname
    \pgfplotsset{#1}%
}{%
    % draws the legend:
    \csname pgfplots@createlegend\endcsname
    \endgroup
}%

% makes \addlegendimage available (typically only available within an
% axis environment):
\def\addlegendimage{\csname pgfplots@addlegendimage\endcsname}

\begin{filecontents}{testdata.csv}
matrix   P   methodAfirstPhase   methodAsecondPhase methodBfirstPhase   methodBsecondPhase
a    2   3   7   2  5
a    4   1   4   1  3
b    2   2   6   1  5
b    4   1   2   1  1   
\end{filecontents}

\begin{document}
\begin{tikzpicture}[remember picture]
\def\numpsPLOT{2}
\def\nummtx{2}

\foreach \matrixid/\P/\axisState/\barShift/\Pshift in {0/2//0/0, 0/4/hide axis/30/.1, 1/2/hide axis/70/.3, 1/4/hide axis/100/.4} {
\pgfkeys{/pgf/number format/.cd,fixed,precision=0}%
\pgfmathparse{\matrixid*\numpsPLOT-1}%
\pgfmathtruncatemacro\le{\pgfmathresult+1}%
\pgfmathparse{\matrixid*\numpsPLOT+\numpsPLOT}%
\pgfmathtruncatemacro\us{\pgfmathresult}%
\pgfmathparse{\nummtx*\numpsPLOT}%
\pgfmathtruncatemacro\ue{\pgfmathresult}%

\begin{axis}
[   ybar stacked,
\axisState,
bar shift=\barShift-100,
enlarge x limits=9,
ymin=0,ymax=11,
x filter/.code={\expandafter\ifnum \thisrow{P}=\P\else\def\pgfmathresult{}\fi},
flexible xticklabels from table={testdata.csv}{matrix}{}, %ignore chars={\%,\_}
x tick label style={font=\small,text width=1.7cm,align=center,rotate=45},
xtick=data,
nodes near coords*,
]  
\addplot[black,fill=black!20] table
[   x expr=\coordindex,
    y=methodAfirstPhase,
   skip coords between index={-1}{\le},  skip coords between index={\us}{\ue}
] {testdata.csv};
\addplot[black,pattern=north west lines,] table
[  x expr=\coordindex,
    y=methodAsecondPhase,
   skip coords between index={-1}{\le},  skip coords between index={\us}{\ue}
] {testdata.csv};
\end{axis}

\begin{axis}
[   ybar stacked,
\axisState,
bar shift={\barShift+10-100},
enlarge x limits=9,
ymin=0,ymax=11,
x filter/.code={\expandafter\ifnum \thisrow{P}=\P\else\def\pgfmathresult{}\fi},
flexible xticklabels from table={testdata.csv}{matrix}{}, %ignore chars={\%,\_}
x tick label style={font=\small,text width=1.7cm,align=center,rotate=45},
xtick=data,
nodes near coords*,
]  
\addplot[black,fill=black!40] table
[   x expr=\coordindex,
    y=methodBfirstPhase,
    skip coords between index={-1}{\le},  skip coords between index={\us}{\ue}
] {testdata.csv};
\addplot[black,fill=black!40,pattern=north east lines,] table
[   x expr=\coordindex,
    y=methodBsecondPhase,
   skip coords between index={-1}{\le},  skip coords between index={\us}{\ue}
] {testdata.csv};
\end{axis}
\node[below left] at (rel axis cs:0.65+\Pshift,1) {P=\P};
}
\end{tikzpicture}

\begin{tikzpicture}
    \begin{customlegend}[legend columns=2,legend style={align=left,draw=none,column sep=2ex},legend entries={Method A $\Phi1$,Method B $\Phi1$,Method A $\Phi2$,Method B $\Phi2$}]
    \addlegendimage{black,fill=black!20,area legend}
    \addlegendimage{black,fill=black!40,area legend}   
    \addlegendimage{black,fill=black!50,area legend,pattern=north west lines,}
    \addlegendimage{black,fill=black!0,area legend,pattern=north east lines,}
    \end{customlegend}
 \end{tikzpicture}
\end{document}

Outcome:

Here what I want:

There are three problems:

1) I want names of matrices to be put below related bars. I cannot use symbolic x coords={a,b} since matrix names must be loaded from data file. In my MWE, only matrix name a is visible, but b is missing. I shift bars via bar shift=... but I cannot shift x ticks. Is there any way to shift x ticks?

2) I cannot put numbers inside the bars. Matrix names and numbers must be shifted as the bar shifted via bar shift=.... (Same problem) Again note that I cannot use symbolic x coords={a,b} since matrix names are determined dynamically according to data file.

3) I want to put processor numbers according to bars and just above or preferably below the corresponding bar. In my MWE, I have put processor numbers manually. I want to automatically put according to related bar.

In my original code; number of processors, matrix names, number of matrices, ... everything may change so my code should be flexible.

share|improve this question
1  
Can you cook up something in excel or scribble on to a paper to describe the expected outcome better? It is kind of difficult to get what you are after. –  percusse Apr 29 '13 at 15:11
    
Dear @percusse, thanks for this comment. From now on, I will try to include sample outcomes that I expect. For this question, I have included link of a sample bar chart that I need. –  Kadir Apr 30 '13 at 8:12
    
Thank you for the sample. –  percusse Apr 30 '13 at 8:19
    
Is this what you're looking for? –  Tom Bombadil Apr 30 '13 at 9:13
    
Dear @TomBombadil, thanks for the link and solution. My second problem was asked in that link. –  Kadir May 1 '13 at 9:00
show 3 more comments

2 Answers

I don't know how well you can adapt this to your scenario, the solution is not that elegant. In order to have one legend for all four axes, it uses Christian Feuersänger's solution to this question.

Code

\documentclass[parskip]{scrartcl}
\usepackage[margin=15mm]{geometry}
\usepackage{pgfplots}
\pgfplotsset{width=10cm,compat=1.6}
\usepackage{xifthen}

\usepackage{filecontents}

% argument #1: any options
\newenvironment{customlegend}[1][]{%
    \begingroup
    % inits/clears the lists (which might be populated from previous
    % axes):
    \csname pgfplots@init@cleared@structures\endcsname
    \pgfplotsset{#1}%
}{%
    % draws the legend:
    \csname pgfplots@createlegend\endcsname
    \endgroup
}%

% makes \addlegendimage available (typically only available within an
% axis environment):
\def\addlegendimage{\csname pgfplots@addlegendimage\endcsname}

\begin{filecontents}{testdata.csv}
matrix   P   methodAfirstPhase   methodAsecondPhase methodBfirstPhase   methodBsecondPhase
a    2   3   7   2  6
a    4   1   4   1  3
b    2   2   6   1  5
b    4   1   2   1  1   
\end{filecontents}

\begin{document}

\begin{tikzpicture}[remember picture]
\begin{axis}
[   ybar stacked,
    bar shift=-20pt,
    ymin=0,ymax=11,
    symbolic x coords={a,b},
    x filter/.code={\expandafter\ifnum \thisrow{P}=4 \def\pgfmathresult{}\fi},
    xtick={a,b},
    enlarge x limits=0.5,
    grid=major,
]  
    \addplot[black,fill=black!20] table
    [   x=matrix,
        y=methodAfirstPhase,
    ] {testdata.csv};
    \addplot[black,fill=black!0] table
    [   x=matrix,
        y=methodAsecondPhase,
    ] {testdata.csv};
\end{axis}
\begin{axis}
[   ybar stacked,
    bar shift=-8pt,
    ymin=0,ymax=11,
    symbolic x coords={a,b},
    x filter/.code={\expandafter\ifnum \thisrow{P}=2 \def\pgfmathresult{}\fi},
    hide axis,
    enlarge x limits=0.5,
]  
    \addplot[black,fill=black!70] table
    [   x=matrix,
        y=methodBfirstPhase,
    ] {testdata.csv};
    \addplot[black,fill=black!50] table
    [   x=matrix,
        y=methodBsecondPhase,
    ] {testdata.csv};
\end{axis}
\begin{axis}
[   ybar stacked,
    bar shift=8pt,
    ymin=0,ymax=11,
    symbolic x coords={a,b},
    x filter/.code={\expandafter\ifnum \thisrow{P}=2 \def\pgfmathresult{}\fi},
    hide axis,
    enlarge x limits=0.5,
]  
    \addplot[black,fill=black!20] table
    [   x=matrix,
        y=methodAfirstPhase,
    ] {testdata.csv};
    \addplot[black,fill=black!0] table
    [   x=matrix,
        y=methodAsecondPhase,
    ] {testdata.csv};
\end{axis}
\begin{axis}
[   ybar stacked,
    bar shift=20pt,
    ymin=0,ymax=11,
    symbolic x coords={a,b},
    x filter/.code={\expandafter\ifnum \thisrow{P}=2 \def\pgfmathresult{}\fi},
    hide axis,
    enlarge x limits=0.5,
]  
    \addplot[black,fill=black!70] table
    [   x=matrix,
        y=methodBfirstPhase,
    ] {testdata.csv};
    \addplot[black,fill=black!50] table
    [   x=matrix,
        y=methodBsecondPhase,
    ] {testdata.csv};
    \node[below left] at (rel axis cs:0.25,1) {P=2};
    \node[below right] at (rel axis cs:0.25,1) {P=4};
    \node[below left] at (rel axis cs:0.75,1) {P=2};
    \node[below right] at (rel axis cs:0.75,1) {P=4};
\end{axis}
\end{tikzpicture}
\begin{tikzpicture}
    \begin{customlegend}[legend entries={Method A (First Phase),Method B (First Phase),Method A (Second Phase),Method B (Second Phase)}]
    \addlegendimage{black,fill=black!70,area legend}
    \addlegendimage{black,fill=black!20,area legend}
    \addlegendimage{black,fill=black!50,area legend}
    \addlegendimage{black,fill=black!0,area legend}
    \end{customlegend}
\end{tikzpicture}

\end{document}

Output

enter image description here


Edit 1: To put numbers in the bars, you can use point meta={rawy}:

Code

\documentclass[parskip]{scrartcl}
\usepackage[margin=15mm]{geometry}
\usepackage{pgfplots}
\pgfplotsset{width=10cm,compat=1.6}
\usepackage{xifthen}

\usepackage{filecontents}

% argument #1: any options
\newenvironment{customlegend}[1][]{%
    \begingroup
    % inits/clears the lists (which might be populated from previous
    % axes):
    \csname pgfplots@init@cleared@structures\endcsname
    \pgfplotsset{#1}%
}{%
    % draws the legend:
    \csname pgfplots@createlegend\endcsname
    \endgroup
}%

% makes \addlegendimage available (typically only available within an
% axis environment):
\def\addlegendimage{\csname pgfplots@addlegendimage\endcsname}

\begin{filecontents}{testdata.csv}
matrix   P   methodAfirstPhase   methodAsecondPhase methodBfirstPhase   methodBsecondPhase
a    2   3   7   2  6
a    4   1   4   1  3
b    2   2   6   1  5
b    4   1   2   1  1   
\end{filecontents}

\begin{document}

\begin{tikzpicture}[remember picture]
\begin{axis}
[   ybar stacked,
    bar shift=-20pt,
    ymin=0,ymax=11,
    symbolic x coords={a,b},
    x filter/.code={\expandafter\ifnum \thisrow{P}=4 \def\pgfmathresult{}\fi},
    xtick={a,b},
    enlarge x limits=0.5,
    grid=major,
    every node near coord/.append style={anchor=north,xshift=-20pt,font=\tiny},
    nodes near coords,
]  
    \addplot[black,fill=black!20] table
    [   x=matrix,
        y=methodAfirstPhase,
    ] {testdata.csv};
    \addplot[black,fill=black!0] table
    [   x=matrix,
        y=methodAsecondPhase,
        point meta={rawy},
    ] {testdata.csv};
\end{axis}
\begin{axis}
[   ybar stacked,
    bar shift=-8pt,
    ymin=0,ymax=11,
    symbolic x coords={a,b},
    x filter/.code={\expandafter\ifnum \thisrow{P}=2 \def\pgfmathresult{}\fi},
    hide axis,
    enlarge x limits=0.5,
    every node near coord/.append style={anchor=north,xshift=-8pt,font=\tiny},
    nodes near coords,
]  
    \addplot[black,fill=black!70] table
    [   x=matrix,
        y=methodBfirstPhase,
    ] {testdata.csv};
    \addplot[black,fill=black!50] table
    [   x=matrix,
        y=methodBsecondPhase,
        point meta={rawy},
    ] {testdata.csv};
\end{axis}
\begin{axis}
[   ybar stacked,
    bar shift=8pt,
    ymin=0,ymax=11,
    symbolic x coords={a,b},
    x filter/.code={\expandafter\ifnum \thisrow{P}=2 \def\pgfmathresult{}\fi},
    hide axis,
    enlarge x limits=0.5,
        every node near coord/.append style={anchor=north,xshift=8pt,font=\tiny},
    nodes near coords,
]  
    \addplot[black,fill=black!20] table
    [   x=matrix,
        y=methodAfirstPhase,
    ] {testdata.csv};
    \addplot[black,fill=black!0] table
    [   x=matrix,
        y=methodAsecondPhase,
        point meta={rawy},
    ] {testdata.csv};
\end{axis}
\begin{axis}
[   ybar stacked,
    bar shift=20pt,
    ymin=0,ymax=11,
    symbolic x coords={a,b},
    x filter/.code={\expandafter\ifnum \thisrow{P}=2 \def\pgfmathresult{}\fi},
    hide axis,
    enlarge x limits=0.5,
    every node near coord/.append style={anchor=north,xshift=20pt,font=\tiny},
    nodes near coords,
]  
    \addplot[black,fill=black!70] table
    [   x=matrix,
        y=methodBfirstPhase,
    ] {testdata.csv};
    \addplot[black,fill=black!50] table
    [   x=matrix,
        y=methodBsecondPhase,
        point meta={rawy},
    ] {testdata.csv};
    \node[below left] at (rel axis cs:0.25,1) {P=2};
    \node[below right] at (rel axis cs:0.25,1) {P=4};
    \node[below left] at (rel axis cs:0.75,1) {P=2};
    \node[below right] at (rel axis cs:0.75,1) {P=4};
\end{axis}
\end{tikzpicture}

\begin{tikzpicture}
    \begin{customlegend}[legend entries={Method A (First Phase),Method B (First Phase),Method A (Second Phase),Method B (Second Phase)}]
    \addlegendimage{black,fill=black!70,area legend}
    \addlegendimage{black,fill=black!20,area legend}
    \addlegendimage{black,fill=black!50,area legend}
    \addlegendimage{black,fill=black!0,area legend}
    \end{customlegend}
\end{tikzpicture}

\end{document}

Output

enter image description here

share|improve this answer
    
Dear @TomBombadil, thanks for your solution. I have improved my MWE according to your solution. However, I have encountered three problems as indicated in the updated question. –  Kadir May 2 '13 at 7:02
    
Dear @TomBombadil, thanks for your Edit 1. It works in your case -- when symbolic x coords={a,b} is used. However, I cannot use symbolic x coords={a,b} since matrix names must be dynamically loaded from data file as I do in my MWE (this is taken from tex.stackexchange.com/questions/63335/…). –  Kadir May 3 '13 at 21:44
add comment
up vote 1 down vote accepted

I have added additional fields to determine places of bars and an empty axis to add x ticks. Note that these additional fields can be generated automatically via preprocessing the table in the question via using pgfplotstable.

\documentclass[parskip]{scrartcl}
\usepackage[margin=15mm]{geometry}
\usepackage{pgfplots}
\pgfplotsset{width=10cm,compat=1.6}
\usepackage{xifthen}
\usetikzlibrary{patterns}
\usepackage{filecontents}

\makeatletter
\pgfplotsset{
    /pgfplots/flexible xticklabels from table/.code n args={3}{%
        \pgfplotstableread[#3]{#1}\coordinate@table
        \pgfplotstablegetcolumn{#2}\of{\coordinate@table}\to\pgfplots@xticklabels
        \let\pgfplots@xticklabel=\pgfplots@user@ticklabel@list@x
    }
}
\makeatother

% argument #1: any options
\newenvironment{customlegend}[1][]{%
    \begingroup
    % inits/clears the lists (which might be populated from previous
    % axes):
    \csname pgfplots@init@cleared@structures\endcsname
    \pgfplotsset{#1}%
}{%
    % draws the legend:
    \csname pgfplots@createlegend\endcsname
    \endgroup
}%

% makes \addlegendimage available (typically only available within an
% axis environment):
\def\addlegendimage{\csname pgfplots@addlegendimage\endcsname}

\begin{filecontents}{testdata.csv}
id    idb   matrix   P   methodAfirstPhase   methodAsecondPhase methodBfirstPhase   methodBsecondPhase
0      .5   a    2   3   7   2  5
1.5    2    a    4   1   4   1  3
3.5    4    b    2   2   6   1  5
5    5.5    b    4   1   2   1  1   
\end{filecontents}

\begin{filecontents}{matrixnames.csv}
matrix xval yval
a           1.5      0
b           4.5     0
\end{filecontents}

\begin{document}
\begin{tikzpicture} [remember picture]
\def\numpsPLOT{2}
\def\nummtx{2}

\begin{axis}[ybar,
xticklabels from table={matrixnames.csv}{matrix},
xtick=data,ymin=0,ymax=11,xmin=0,xmax=10,]
\addplot table 
[  x=xval,
   y=yval
 ]{matrixnames.csv};
\end{axis}

\foreach \matrixid/\P/\axisState/\barShift/\Pshift in {0/2/hide axis/0/0, 0/4/hide axis/30/.1, 1/2/hide axis/70/.3, 1/4/hide axis/100/.4} {
\pgfkeys{/pgf/number format/.cd,fixed,precision=0}%
\pgfmathparse{\matrixid*\numpsPLOT-1}%
\pgfmathtruncatemacro\le{\pgfmathresult+1}%
\pgfmathparse{\matrixid*\numpsPLOT+\numpsPLOT}%
\pgfmathtruncatemacro\us{\pgfmathresult}%
\pgfmathparse{\nummtx*\numpsPLOT}%
\pgfmathtruncatemacro\ue{\pgfmathresult}%

\begin{axis}
[   ybar stacked,
    \axisState,
    enlarge x limits,
    ymin=0,ymax=11,
    x filter/.code={\expandafter\ifnum \thisrow{P}=\P\else\def\pgfmathresult{}\fi},
    nodes near coords*,
    xmin=0,
    xmax=10,
]  
\addplot[black,fill=black!20] table
[  % x expr=\coordindex,
x=id,
    y=methodAfirstPhase,
   skip coords between index={-1}{\le},  skip coords between index={\us}{\ue}
] {testdata.csv};
\addplot[black,pattern=north west lines,] table
[  x=id,
    y=methodAsecondPhase,
   skip coords between index={-1}{\le},  skip coords between index={\us}{\ue},
] {testdata.csv};
\end{axis}

\begin{axis}
[   ybar stacked,
    \axisState,
    enlarge x limits,
    ymin=0,ymax=11,
    x filter/.code={\expandafter\ifnum \thisrow{P}=\P\else\def\pgfmathresult{}\fi},
    xtick=data,
   nodes near coords*,
   xmin=0,
   xmax=10,
]  
\addplot[black,fill=black!40] table
[   x=idb,
    y=methodBfirstPhase,
    skip coords between index={-1}{\le},  skip coords between index={\us}{\ue}
] {testdata.csv};
\addplot[black,fill=black!40,pattern=north east lines,] table
[  x=idb,
    y=methodBsecondPhase,
   skip coords between index={-1}{\le},  skip coords between index={\us}{\ue}
] {testdata.csv};
\end{axis}
}
\end{tikzpicture}

\begin{tikzpicture}
    \begin{customlegend}[legend columns=2,legend style={align=left,draw=none,column sep=2ex},legend entries={Method A $\Phi1$,Method B $\Phi1$,Method A $\Phi2$,Method B $\Phi2$}]
    \addlegendimage{black,fill=black!20,area legend}
    \addlegendimage{black,fill=black!40,area legend}   
    \addlegendimage{black,fill=black!50,area legend,pattern=north west lines,}
    \addlegendimage{black,fill=black!0,area legend,pattern=north east lines,}
    \end{customlegend}
 \end{tikzpicture}
\end{document}

Output:

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.