如何在具有多个堆叠条形图的 pgfplots 中移动 x 刻度

如何在具有多个堆叠条形图的 pgfplots 中移动 x 刻度

我的目标是生成这个条形图:

在此处输入图片描述

我能够将此图表作为我的 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}

结果:

我想要的是:

存在三个问题:

1) 我希望矩阵名称放在相关条形图下方。我无法使用,symbolic x coords={a,b}因为矩阵名称必须从数据文件加载。在我的 MWE 中,只有矩阵名称a可见,但b缺失。我通过移动条形图,bar shift=...但无法移动 x 个刻度。有没有办法移动 x 个刻度?

2) 我无法在条形图内放置数字。矩阵名称和数字必须随着条形图的移动而移动bar shift=...。(同样的问题)再次注意,我无法使用,symbolic x coords={a,b}因为矩阵名称是根据数据文件动态确定的。

3) 我想根据条形图放置处理器编号,并且最好位于相应条形图的正上方或正下方。在我的 MWE 中,我已经手动放置了处理器编号。我想根据相关条形图自动放置。

在我原来的代码中,处理器的数量、矩阵名称、矩阵的数量……一切都可能改变,所以我的代码应该是灵活的。

答案1

我不知道你能多好地适应你的场景,解决方案并不那么优雅。为了给所有四个轴一个图例,它使用克里斯蒂安·费尔桑格的解决方案这个问题

代码

\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}

输出

在此处输入图片描述


编辑1:要在条形图中放置数字,您可以使用point meta={rawy}

代码

\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}

输出

在此处输入图片描述

答案2

我添加了额外的字段来确定条形的位置,并添加了一个空轴来添加 x 刻度。请注意,这些额外的字段可以通过使用 预处理问题中的表格来自动生成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}

输出:

相关内容