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