假设有如下图表:
该图表是使用以下代码创建的:
\documentclass{article}
\usepackage{tikz}
\usepackage{pgfplots}
\begin{document}
\begin{tikzpicture}
\begin{axis}[
ybar,
enlargelimits=0.15,
symbolic x coords={Category 1,Category 2,Category 3},
xtick=data,
nodes near coords,
]
\addplot coordinates {(Category 1,6) (Category 2,2) (Category 3,3.5)};
\addplot coordinates {(Category 2,2) (Category 3,2.5)};
\addplot coordinates {(Category 3,4)};
\end{axis}
\end{tikzpicture}
\end{document}
我想知道是否可以在 pgfplots 中修改此图表,使 y 轴表示百分比。因此,在这种情况下,类别 1 中的蓝色条将上升到 100%;类别 2 中的蓝色条和红色条将分别上升到 50%;类别 3 中的蓝色条、红色条和棕色条将分别上升到 35%、25% 和 40%。(换句话说,假设在每个类别中,条形图的组合值等于 100%。)同时,我想保留条形图标签中的非百分比值并仅标记这些值(类别 1 中的 6;类别 2 中的 2 和 2 等)或将它们与百分比相结合(类别 1 中的 6,100%;类别 2 中的 2,50% 和 2,50% 等)。
简而言之,我的问题是:如何在 pgfplots 中做到这一点?(并且,如果这不可能,那么也许直接在 PGF/TikZ 中实现。)
编辑:显然,您可以在 pgfplots 中手动实现此操作,方法是计算百分比,然后像 一样写入它们(Category 1,100)
,然后为 y 轴提供适当的描述(例如“以百分比表示”),然后更改每个条形的标签以显示非百分比值。然而,我正在寻找的是更自动化的解决方案 :)
答案1
对于此类情况,我总是以 a 的形式提供数据pgfplotstable
(这需要加载同名的包)。您可以使用类似
\pgfplotstableread[col sep=comma,header=false]{
Category 1,6,0,0
Category 2,2,2,0
Category 3,3.5,2.5,4
}\data
然后该表即可用作\data
。
然后,您可以sum
使用以下方法添加一个包含每行总和的新列
\pgfplotstablecreatecol[
create col/expr={
\thisrow{1} + \thisrow{2} + \thisrow{3}
}
]{sum}{\data}
然后,您可以在绘制数据时缩放数据,使用
\addplot table [y expr=\thisrow{1}/\thisrow{sum}*100,meta=1] {\data};
它指定数据点应除以sum
当前行中的条目并乘以 100,而标签(值meta
)仍应来自未更改的列(在本例中为第 1 列)。
您可以将其包装成更舒适的样式,这样您只需调用
\addplot table [percentage series=1] {\data};
添加情节。
编辑:要打印原始值和条形上方的百分比,可以使用 的参数nodes near coords={...}
。由于您要打印两个不同的变量,但只有一个变量可用作\pgfplotspointmeta
,因此您需要使用 使另一个变量可用visualization depends on=<value> \as \<macro>
。不幸的是,如果您使用restrict y to domain=...
或删除一些点y filter
(这看起来像是一个错误,我会研究如何解决此问题),则此方法不起作用。因此,为了仍然只显示具有非零值的条形,一种解决方法是在图表顶部绘制轴(否则您会在零条形所在的位置看到细线),并让代码nodes near coords
检查值是否大于零。
完整代码如下:
\documentclass{article}
\usepackage{tikz}
\usepackage{pgfplots}
\usepackage{pgfplotstable}
\begin{document}
\pgfplotstableread[col sep=comma,header=false]{
Category 1,6,0,0
Category 2,2,2,0
Category 3,3.5,2.5,4
}\data
\pgfplotstablecreatecol[
create col/expr={
\thisrow{1} + \thisrow{2} + \thisrow{3}
}
]{sum}{\data}
\pgfplotsset{
percentage plot/.style={
point meta=explicit,
every node near coord/.append style={
align=center,
text width=1cm
},
nodes near coords={
\pgfmathtruncatemacro\iszero{\originalvalue==0}
\ifnum\iszero=0
\pgfmathprintnumber{\originalvalue}$\,\%$\\ \pgfmathprintnumber[fixed zerofill,precision=1]{\pgfplotspointmeta}
\fi},
nodes near coords align=vertical,
yticklabel=\pgfmathprintnumber{\tick}\,$\%$,
ymin=0,
ymax=100,
enlarge y limits={upper,value=0.18},
visualization depends on={y \as \originalvalue}
},
percentage series/.style={
table/y expr=\thisrow{#1}/\thisrow{sum}*100,table/meta=#1
}
}
\begin{tikzpicture}
\begin{axis}[
axis on top,
width=10cm,
percentage plot,ybar,bar width=0.75cm,
enlarge x limits=0.25,
symbolic x coords={Category 1,Category 2,Category 3},
xtick=data
]
\addplot table [percentage series=1] {\data};
\addplot table [percentage series=2] {\data};
\addplot table [percentage series=3] {\data};
\end{axis}
\end{tikzpicture}
\end{document}