控制ggplot2 facet height独立于行facet的数量

时间:2013-09-08 11:53:21

标签: r ggplot2 knitr

问题

ggplot2 / knitr强制绘制(在LaTeX中)具有默认宽高比。具有不同面数的两个图导致具有小平面高度的图。这不太好。

Example for problem

我一直在寻找一种独立于行方面数量来控制ggplot2方面高度的解决方案。

9月9日编辑: 解决方案应该在一个块中工作,因为两个块都在一个块中(如示例代码中所示)。因此,调整knitr的数字相关块选项是不可行的,因为块选项同样适用于两个图。

解决方案 - 但遇到问题

将每个绘图放入gridExtra框并使用刻面的数量缩放其高度,从而产生不再不同的刻面高度:更好但不完美。

  • 页面上出现的图表边距太大,即使下面还有剩余文字,因此图表的移动距离会更近。
  • 似乎被这种被裁剪的情节所操纵。

是否存在更智能且无问题的解决方案,可以独立于行方面的数量来控制ggplot2方面的高度?

\documentclass[a4paper]{article}
\usepackage[margin=1in]{geometry}

\begin{document}

<<setup, results='asis', message=FALSE, echo=FALSE>>=
require(ggplot2)
require(gridExtra)

### Generate two data frames

# Data frame with 2 classes
db.small = data.frame (
  class = as.factor(c(rep("A", 12), rep("B", 12))),
  month = as.factor(rep(1:12, 2)),
  value = runif(2*12, 0, 100)
  )

# Data frame with 5 classes
db.large = data.frame (
  class = as.factor(c(rep("A", 12), rep("B", 12), rep("C", 12), rep("C", 12), rep("D", 12))),
  month = as.factor(rep(1:12, 5)),
  value = runif(5*12, 0, 100)
)

# Generate plots
plot1 = ggplot(db.small, aes(month, value)) + geom_bar(stat="identity") + facet_grid(class ~ .) + ylim(c(0, 100))
plot2 = ggplot(db.large, aes(month, value)) + geom_bar(stat="identity") + facet_grid(class ~ .) + ylim(c(0, 100))
@

\section{Before: Native plots without modification}
Ggplot2/knitr forces both plots to have the default aspect ratio. As both plots have different number of facets the result is that the facet heights are different. This is not nice.

<<before, results='asis', message=FALSE, echo=FALSE, out.width="0.6\\linewidth">>=
print(plot1)
print(plot2)
@

\pagebreak
\section{After: Plots with modification}
Putting each plot into a gridExtra box and scaling it's height with the number of facets, results in facet heights which are no longer different: nicer but not perfect, see problems below.

<<After, results='asis', message=FALSE, echo=FALSE, out.width="0.6\\linewidth">>=
# Calculate number of facets for the two plots
db.small.numberfacets = length(unique(db.small$class))
db.large.numberfacets = length(unique(db.large$class))

# Define heights for modification of plots
facet.height = 4
other.height = 2

plot1 = plot1 + theme( plot.margin = unit(c(0, 0, 0, 0), "cm"))
plot2 = plot2 + theme( plot.margin = unit(c(0, 0, 0, 0), "cm"))

# Put plots inside a gridExtra box and change height plots
grid.arrange(arrangeGrob(plot1, heights=unit(db.small.numberfacets*facet.height+other.height, "cm")), nrow=1)
grid.arrange(arrangeGrob(plot2, heights=unit(db.large.numberfacets*facet.height+other.height, "cm")), nrow=1)
@


2 Problems:
\begin{itemize}
\item Plots appear on the page with too much margin, even there's remaining text below so plots shall move more closer.
\item Seems the second plot is cropped, see the x-axis label.
\end{itemize}

Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat.

\end{document}

pdf输出: Page 1 Page 2

1 个答案:

答案 0 :(得分:3)

你知道knitr chunk options可以采用任意R表达式吗? example 40显示了如何动态计算fig.widthfig.height

对于您的情况,您可以根据分面因子变量中的级别数为fig.height分配值。例如,

\documentclass{article}

\begin{document}
<<setup>>=
library(ggplot2)
calc_height = function(f) length(levels(f))
p = ggplot(diamonds, aes(color)) + geom_bar()
@

<<test-a, fig.width=7, fig.height=calc_height(diamonds$cut)>>==
p + facet_grid(cut ~ .)
@

<<test-b, fig.width=7, fig.height=calc_height(diamonds$clarity)>>==
p + facet_grid(clarity ~ .)
@

\end{document}

输出: