grid_plot + tikzDevice +乳胶标记的共享图例

grid_plot + tikzDevice +乳胶标记的共享图例

问题描述:

我一直在试图按照this vignette关于如何为多个ggplot2创建共享图例。给出的示例完美地工作,但在我的情况下,我使用tikzDevice来导出tikzpicture环境。主要问题似乎是grid_plot未能正确捕获图例键的宽度。grid_plot + tikzDevice +乳胶标记的共享图例

我想出了能重现问题最小R代码里面:

require(ggplot2) 
require(grid) 
require(gridExtra) 
require(cowplot) 
require(tikzDevice) 

tikz(file = "./tmp.tex", width = 5.6, height = 2.2, standAlone = T) 
mpg2 <- mpg 

mpg2$cyl = as.factor(mpg2$cyl) 
levels(mpg2$cyl) <- c("\\textbf{\\textsc{four}}", 
         "\\textbf{\\textsc{five}}", 
         "\\textbf{\\textsc{six}}", 
         "\\textbf{\\textsc{seven}}", 
         "\\textbf{\\textsc{eight}}") 

plot.mpg <- ggplot(mpg2, aes(x=cty, colour=cyl, y = hwy)) + 
    geom_point() + 
    theme(legend.position='none') 

legend <- get_legend(plot.mpg + theme(legend.position = "top")) 

print(plot_grid(legend, 
       plot.mpg, nrow=2, ncol=1,align='h', 
       rel_heights = c(.1, 1))) 

dev.off() 

生成的PDF文件(编译tmp.tex后)看起来是这样的:

enter image description here

我们可以观察到,第一个图例按键(四)仅部分显示,而图例按键(八)完全不可见。我试图改变tikz命令宽度无济于事。

此外,我怀疑问题背后的原因是,grid_plot命令错误地测量图例键的长度,如果它们包含乳胶标记。要说明的是,这是问题的原因,考虑改变MPG2 $团的水平以下:

levels(mpg2$cyl) <- c("four", 
         "five", 
         "six", 
         "seven", 
         "eight") 

这将导致一个完美的传说以下情节:

enter image description here

请注意,上面的例子只是为了重现问题,而不是我想要做的。相反,我有四个试图为他们使用共享通用图例的地块。

任何人都可以告诉我如何解决传奇问题,当它包含乳胶标记?

顺便说一句,这是我sessionInfo()

R version 3.3.2 (2016-10-31) 
Platform: x86_64-apple-darwin13.4.0 (64-bit) 
Running under: OS X Yosemite 10.10.5 

locale: 
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8 

attached base packages: 
[1] grid  stats  graphics grDevices utils  datasets methods 
[8] base  

other attached packages: 
[1] tikzDevice_0.10-1 dplyr_0.5.0  gdata_2.17.0  cowplot_0.7.0  
[5] gridExtra_2.2.1 ggplot2_2.2.0  

loaded via a namespace (and not attached): 
[1] gtools_3.5.0  colorspace_1.2-6 DBI_0.5   RColorBrewer_1.1-2 
[5] plyr_1.8.4   munsell_0.4.3  gtable_0.2.0  labeling_0.3  
[9] Rcpp_0.12.6  scales_0.4.1  filehash_2.3  digest_0.6.10  
[13] tools_3.3.2  magrittr_1.5  lazyeval_0.2.0  tibble_1.1   
[17] assertthat_0.1  R6_2.1.3   

谢谢大家。

GGPLOT2似乎计算基于原始的字符串,而不是框应由TeX的返回尺寸串宽度。我猜这是一个计算过早(即不在绘图时间)的指导代码。 作为解决方法,您可以通过显式调用getLatexStrWidth来手动编辑gtable中的相关宽度。注意我还在序言中添加了一个包,否则默认字体不会显示大胆的小写字母。

require(ggplot2) 
require(grid) 
require(gridExtra) 
require(tikzDevice) 

setTikzDefaults(overwrite = TRUE) 
preamble <- options("tikzLatexPackages") 
options("tikzLatexPackages" = c(preamble$tikzLatexPackages, "\\usepackage{bold-extra}")) 

tikz(file = "./tmp.tex", width = 5.6, height = 2.2, standAlone = TRUE) 
mpg2 <- mpg 

mpg2$cyl = as.factor(mpg2$cyl) 

levels(mpg2$cyl) <- c("\\textbf{\\textsc{four}}", 
         "\\textbf{\\textsc{five}}", 
         "\\textbf{\\textsc{six}}", 
         "\\textbf{\\textsc{seven}}", 
         "\\textbf{\\textsc{eight}}") 

p <- ggplot(mpg2, aes(x=cty, colour=cyl, y = hwy)) + 
    geom_point() + 
    theme(legend.position='none') 



leg <- cowplot::get_legend(p + theme(legend.position = "top")) 

ids <- grep("label",leg$grobs[[1]]$layout$name) 
pos <- leg$grobs[[1]]$layout$l[ids] 
wl <- sapply(leg$grobs[[1]][["grobs"]][ids], function(g) getLatexStrWidth(g[["label"]])) 

leg$grobs[[1]][["widths"]][pos] <- unit(wl, "pt") 

grid.arrange(p, top=leg) 

dev.off() 

enter image description here

也许更容易引入临时标记不影响多大串宽度,处理后R和乳胶步骤之间的TEX文件,

levels(mpg2$cyl) <- c("$four$", 
         "$five$", 
         "$six$", 
         "$seven$", 
         "$eight$") 

[...]

tmp <- readLines("tmp.tex") 
gs <- gsub("\\$(four|five|six|seven|eight)\\$", "\\\\textsc{\\1}", tmp, perl=TRUE) 
cat(paste(gs, collapse="\n"), file="tmp2.tex") 

enter image description here

+0

另外,使用字符串诸如'\ 4,\ 5,etc.'并在特前导码定义它们(虽然齿隙可能证明痛苦)。 – baptiste

+0

这个答案是“在盒子外面思考”的例子。谢谢! – user8420488483439