具有多个描述性节点的堆叠条形图

具有多个描述性节点的堆叠条形图

我有一个堆积条形图,我想在其中显示每个条形的附加信息(除了它们的累积值之外)。此信息应包括非累积值和每个条形左侧的相应百分比。累积值应显示在条形的右侧,如下所示:

\documentclass{scrartcl}
\usepackage{pgfplots}
\usepackage{pgfplotstable}

\pgfplotsset{compat=1.6}

\begin{document}

\pgfplotstableread{
Country     Accepted Rejected
US          180      100
Germany     70       40
UK          10       5
}\data

\begin{tikzpicture}
  \begin{axis}[ybar stacked, enlargelimits=0.25, symbolic x coords={US, Germany,
    UK}, nodes near coords, nodes near coords align=horizontal,xtick=data,
    every node near coord/.append style={xshift=5pt}]
    \addplot table[y=Accepted] {\data};
    \addplot table[y=Rejected] {\data};
  \end{axis}
\end{tikzpicture}

\end{document}

做这个的适当方法是什么?

答案1

此示例不适用于任意数量的图,但可以很容易地调整为其他情况。也许一些巫师知道如何改变它以使其自动工作。

在此处输入图片描述

目前,由于四舍五入,数字加起来不一定像第一列(18%+59%+24%=101%)那样等于 100%。但这是一个很难解决的问题,例如,据我所知,Microsoft Excel 也存在同样的问题。

平均能量损失

\documentclass{scrartcl}
\usepackage{pgfplots}
\usepackage{pgfplotstable}

\pgfplotsset{compat=newest}

\begin{document}

\pgfplotstableread{
Country     Accepted Rejected Pending
US          40       100      30
Germany     70       40       30
UK          50       65       30
}{\data}

% Add Sum
\pgfplotstablecreatecol[
    create col/expr={
        \thisrow{Accepted} + \thisrow{Rejected} + \thisrow{Pending}
    }
]{Sum}{\data}

% Add AcceptedPercentage
\pgfplotstablecreatecol[
    create col/assign/.code={%
        \pgfkeys{/pgf/fpu=true,/pgf/fpu/output format=fixed}
        \pgfmathparse{\thisrow{Accepted} / \thisrow{Sum} * 100}
        \pgfkeyslet{/pgfplots/table/create col/next content}\pgfmathresult
        \pgfkeys{/pgf/fpu=false}
    }
]{AcceptedPercentage}{\data}

% Add RejectedPercentage
\pgfplotstablecreatecol[
    create col/assign/.code={%
        \pgfkeys{/pgf/fpu=true,/pgf/fpu/output format=fixed}
        \pgfmathparse{\thisrow{Rejected} / \thisrow{Sum} * 100}
        \pgfkeyslet{/pgfplots/table/create col/next content}\pgfmathresult
        \pgfkeys{/pgf/fpu=false}
    }
]{RejectedPercentage}{\data}

% Add RejectedSum
\pgfplotstablecreatecol[
    create col/assign/.code={%
        \pgfkeys{/pgf/fpu=true,/pgf/fpu/output format=fixed}
        \pgfmathparse{\thisrow{Accepted} + \thisrow{Rejected}}
        \pgfkeyslet{/pgfplots/table/create col/next content}\pgfmathresult
        \pgfkeys{/pgf/fpu=false}
    }
]{RejectedSum}{\data}

% Add PendingPercentage
\pgfplotstablecreatecol[
    create col/assign/.code={%
        \pgfkeys{/pgf/fpu=true,/pgf/fpu/output format=fixed}
        \pgfmathparse{\thisrow{Pending} / \thisrow{Sum} * 100}
        \pgfkeyslet{/pgfplots/table/create col/next content}\pgfmathresult
        \pgfkeys{/pgf/fpu=false}
    }
]{PendingPercentage}{\data}

% Add PendingSum 
\pgfplotstablecreatecol[
    create col/assign/.code={%
        \pgfkeys{/pgf/fpu=true,/pgf/fpu/output format=fixed}
        \pgfmathparse{\thisrow{Accepted} + \thisrow{Rejected} + \thisrow{Pending}}
        \pgfkeyslet{/pgfplots/table/create col/next content}\pgfmathresult
        \pgfkeys{/pgf/fpu=false}
    }
]{PendingSum}{\data}

% Save table
\pgfplotstablesave[columns/Country/.style={string type}, columns/Sum/.style={numeric as string type}, col sep=comma, disable rowcol styles=false]{\data}{temptable.txt}

\makeatletter
\begin{tikzpicture}
  \begin{axis}[
    ymin=0,
    width=0.7\textwidth,
    enlarge x limits=0.30,
    symbolic x coords={US, Germany, UK},
    xtick=data,
    point meta=explicit,
    calculate offset/.code={
        \pgfkeys{/pgf/fpu=true,/pgf/fpu/output format=fixed}
        \pgfmathsetmacro\testmacro{(\pgfplotspointmetatransformed)/1000)}
        \pgfkeys{/pgf/fpu=false}
    },
    every node near coord/.style={
        /pgfplots/calculate offset,
        yshift=-\testmacro,
        xshift=-5pt,
        font=\tiny
    },
    nodes near coords align=center,
    ybar stacked, nodes near coords={\hspace{-.5cm} \pgfmathprintnumber[precision=0]{\pgfplotspointmeta} (\pgfmathprintnumber[precision=0]{\labela}\%)  \hspace{.4cm} \pgfmathprintnumber[precision=0]{\labelb}},
    ]

    \addplot+[
    visualization depends on={\thisrow{AcceptedPercentage} \as \labela},
    visualization depends on={\thisrow{Accepted} \as \labelb},
    ] table[y=Accepted, meta=Accepted, col sep=comma] {temptable.txt};
    \addplot+[
      visualization depends on={\thisrow{RejectedPercentage} \as \labela},
      visualization depends on={\thisrow{RejectedSum} \as \labelb},
    ] table[y=Rejected, meta=Rejected, col sep=comma] {temptable.txt};
    \addplot+[
      visualization depends on={\thisrow{PendingPercentage} \as \labela},
      visualization depends on={\thisrow{PendingSum} \as \labelb},
    ] table[y=Pending, meta=Pending, col sep=comma] {temptable.txt};

  \end{axis}
\end{tikzpicture}
\makeatother
\end{document}

答案2

概括:

此解决方案结合使用了 knitr 和 R。Knitr 提供了(除其他外)一种方法,可以在排版时从 LaTeX 内部访问 R 平台。这为以下方面提供了机会:圣经比例但是,就此线程而言,获得 R 访问权限意味着可以使用 ggplot2(一个高级绘图包)来生成绘图,然后将其直接嵌入到相应的 LaTeX 文档中。

对于那些参与撰写技术论文、学位论文、毕业论文等的人来说,您可能会立即认识到能够在排版时动态创建图表的好处,因为您可以方便、安心地知道每一个图表都是最新的。

顺便说一句,R 中有一个包 (xtable),它允许您调用 LaTeX 识别格式的数据(即 LaTeX 表)。这意味着使用 knitr 和 R(通过 xtable 和 RODBC 包),可以在 LaTeX 中从外部 ODBC 源创建数据驱动表。

还有在 ggplot2 对象中嵌入方程和 bibtex 引用的问题,这两者都对 tikzDevice 来说没有问题。也许您正在撰写两篇论文,论文 X 和论文 Y,并且您希望在论文 X 和论文 Y 中使用完全相同的图,但论文 X 和论文 Y 有一组不同的参考文献。此外,这个特定的图代表了先前研究的文献调查,因此您需要在图中引用,引用的编号顺序与论文 X 和论文 Y 参考书目相同。本质上,论文 X 图中引用的“[10]”可能最终成为论文 Y 图中引用的“[11]”,即使它们都引用相同的来源。Knitr 使这些重要差异变得微不足道。

此时,经过深思熟虑,恢复使用 M$ Word 似乎就如同在有打火机的情况下用火石生火一样。当然,贝尔·格里尔斯可以用更少的东西生火,包括一个装满黄色液体的塑料背,但他有一支安全团队……

回到正题上,在这个解决方案中,R 已直接从 LaTeX 文档中调用。R 代码块保存在几个(称为)“块”中。这些块可以被识别为保存在 <<>>= 和 @ 标志之间的代码。

块可以调用其他块。这意味着同一个块可以在同一个文档中被调用多次。

深入到每个块,<< 和 >> 中解析的选项是 knitr 特定的选项,可以控制块的功能。我的另一篇文章,随机放置水印更详细地介绍了用于解决此任务的基本原理。

您可以在这里找到 Knitr:Knitr 主页,应该给作者一辉颁发勋章。

结果:

请参阅下面解决方案文档的摘录(第 4 页)。

文件的最终摘录。

工作示例。

请参阅下文,生成解决方案文档的完整代码。

非常基本的序言....

\documentclass[a4paper,9pt,hidelinks]{article}
    \usepackage[inner=2.0cm,outer=2.0cm,top=4cm,bottom=3cm,marginparwidth=1.75cm,marginparsep=2mm]{geometry}

    %opening
    \title{Sample Stacked Bar}
    \author{ADP}

运行 Chunk 来定义设置,包括消息抑制和 R 中所需的最低包。

%Define the Settings
    <<setup_packages,eval=FALSE,echo=FALSE>>=
            ##Install latest version of tikzDevice (Installation Currently Disabled)
            ##install.packages("tikzDevice", repos="http://R-Forge.R-project.org")

            ##Suppress Messages
            suppressMessages( library(ggplot2)) #Dont Want spam-like messages.      
            suppressMessages( library(reshape)) 
            suppressMessages( library(grid))        
            suppressMessages( library(tikzDevice))
            suppressMessages( library(knitr))       

            ##Load Packages Quietly 
            require(ggplot2,quiet=TRUE)
            require(reshape,quiet=TRUE)
            require(grid,quiet=TRUE)
            require(tikzDevice,quiet=TRUE)
            require(knitr,quiet=TRUE)
    @

运行 chunk 来定义主题。这将在多个图中保持有效,从而促进整个文档的一致性。

<<setup_theme,eval=FALSE,echo=FALSE>>=      
        ##Set the Theme
        theme_new <- theme_set(theme_bw(10))  
        col_bg <- "grey95"
        col_axis <- "grey20"            
        theme_new <- theme_update(
            plot.title = element_text(lineheight = 2, angle = 0,size = 12,colour = col_axis),
            axis.title.x = element_text(angle = 0,size = 10, colour = col_axis),
            axis.title.y = element_text(angle = 90,size=10, colour = col_axis),

            axis.text.x = element_text(colour =col_axis,size=8,angle=0,hjust=0.5,
                                            vjust=0,face="plain"),   

            axis.text.y = element_text(colour =col_axis, size=8,angle=0, hjust=1, 
                                            vjust=0.5,face="plain"),  

            axis.ticks = element_line(  colour=col_axis),                                       
            axis.ticks.x = element_line(colour=col_axis),   
            axis.ticks.y = element_line(colour=col_axis),                                   
            legend.position = c(0,1),
            legend.direction='vertical',
            legend.box='horizontal',
            legend.justification = c(0, 1),
            legend.text = element_text(size = 8),
            legend.title = element_text(size = 9),
            legend.text.align =0,
            legend.background = element_rect(fill = 'white',colour = "gray", size = 0.1),
            legend.key = element_rect(colour = 'white', fill = 'white', size = 0, linetype='solid'),
            legend.key.height = unit(0.3,"cm"),
            panel.background = element_rect(fill=col_bg))
@

这是从此时点开始定义全局块设置的块。

<<chunk_settings,eval=FALSE,echo=FALSE>>=
        ## Default Chunk Settings, For Returned Graphics.       
        opts_chunk$set(fig.width = 6)
        opts_chunk$set(fig.height = 5)
        opts_chunk$set(fig.align = 'center')
        opts_chunk$set(fig.path = 'Images_Knitr/')
        opts_chunk$set(fig.keep = 'all')
        opts_chunk$set(dev='tikz')
        opts_chunk$set(external = FALSE)
        opts_chunk$set(size = 'small')  
@

接下来的两个块在绘图之前生成并融合数据。

<<process_data,echo=FALSE,eval=FALSE>>=
        #Assemble Data.
        country <- c("USA","Germany","United Kingdom")
        accept <- c(40,70,50)
        reject <- c(100,40,65)
        pend <- c(30,30,30)
        tot <- accept + reject + pend
        data.in <- data.frame(Country=country,Rejected=reject,Accepted=accept,Pending=pend,Total=tot)
        rm(country,accept,reject,pend,tot)

        #Determine Cumulative Values.
        data.in.cum <- data.in[,-5]
        for(c in 3:ncol(data.in.cum)){
            data.in.cum[,c] <- data.in.cum[,c] + data.in.cum[,c-1]
        }
        rm(c)
    @

    <<melt_data,echo=FALSE,eval=FALSE>>=
        #Melt Data into data frame
        data.melt <- data.frame(melt(data.in,id=c("Country","Total"))) #need
        data.melt.cum <- data.frame(melt(data.in.cum,id=c("Country")))

        ##Set Arrays of Mis Values used in the Plot.    
        data.total <- data.melt[,2]
        data.cum <- data.melt.cum[,3]
        data.melt <- data.melt[,-2]
        data.pcnt <- round(100*data.melt[,3]/data.total,0)
        colnames(data.melt) <- c("Country","Status","Count")
    @

最后部分是创建情节的实际部分。

<<plot_data,echo=FALSE,eval=FALSE,dev='tikz'>>=
    ##This is a bit of a hack to split the labels either side of the bars
    ##Otherwise, two geom_text layers would need to be used.
    spc <- "                     " 

    ##Create the Final Plot.
    ggplot(data.melt,aes(x=Country,y=Count,fill=Status,ymax=-1)) + 
        geom_bar(width = 0.3,color="black") +   
        geom_text(aes(label = paste(Count," (",data.pcnt,"%)",spc,data.cum,sep="")),position="stack",size = 3,  hjust = 0.6, vjust = 3) +
        scale_y_continuous(name="Amount") +
        scale_x_discrete(name="Country") +
        ggtitle("Acceptance Statistics for Various Countries")
@

剩余的代码应该很熟悉,因为它们与标准文档有共性,并且上述块在适当的位置被调用......

\begin{document}
    \maketitle  #make titlepage.
    \begin{abstract}
         In this sample, the R packages ggplot2 is used to plot a simple stacked bar, demonstrating use of labels. This is called directly from inside \LaTeX document using the knitr package.
    \end{abstract}
    \section{Load Packages and Set Theme}
    Call the chunk that loads packages that are required for this excercise.
    <<setup_packages,eval=TRUE,echo=TRUE>>=
    @

    Defines the formatting for charts. This formatting will hold for all subsequent charts, providing a 'template' for document consistency. Each chart, of course can be modified on a case by case basis. The theme set function is as per ggplot2 package.
    <<setup_theme,eval=TRUE,echo=TRUE>>=
    @

    \section{Set Default Chunk Settings}
    Some default chunk settings can be set, to create consistent environment. Note the image size variables which are reflected in the size of the plots.
    <<chunk_settings,eval=TRUE,echo=TRUE>>=
    @

    \section{Process the Data}
    We need to now process the data, determining cumulative values etc...
    <<process_data,echo=TRUE,eval=TRUE>>=
    @

    We need to now melt the data, so that it is in a format which can be called by the ggplot2 class, taking advantage of aesthetics. 

    <<melt_data,eval=TRUE,echo=TRUE>>=
    @

    \newpage
    \section{Create the Plot}
    Finally, we can plot the object,using the tikzdevice to insert directly into the document. This chunk is called with the eval=FALSE, echo = TRUE flags, which returns console messages, but not the plot.
    <<plot_data,echo=TRUE,eval=FALSE,dev='png',dpi=1000>>=
    @

    However, the same chunk can be executed to return the plot only and  none of the R message or used code by setting echo = FALSE and eval = TRUE.

    \begin{figure}[b!]
    <<plot_data,echo=FALSE,eval=TRUE,dev='png',dpi=1000>>=
    @
    \caption{The Resulting Stacked Bar Chart.}
    \end{figure}

    \end{document}

相关内容