如何创建 y 轴以百分比表示的条形图?

如何创建 y 轴以百分比表示的条形图?

假设有如下图表:
图表示例

该图表是使用以下代码创建的:

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

相关内容