2016-04-15 4 views
1

У меня есть 2 сюжета одной и той же вещи, за исключением того, что цвета, заполняющие бары, различны на каждом участке. Поскольку легенда на разных графиках имеет разную ширину из-за размера имен на ней, соотношение между графом и легендой становится разным на каждом сюжете. Мне нужно, чтобы оба выглядели одинаково.ggplot2 легенда ширина и строка легенды размер

Это пример:

library(ggplot2) 

x = c(rep("a",20),rep("b",10)) 
y = c(x = c(rep("BIGTEXT",20),rep("EVENBIGGERTEXT",10))) 
df = data.frame(x,y) 

p1 = ggplot(df,aes(x,fill=x)) + geom_bar() 
p2 = ggplot(df,aes(y,fill=y)) + geom_bar() 

p1 
p2 

ответ

3

Вы можете установить gtable ширины к общему значению,

library(gtable) 
library(grid) 
gl <- lapply(list(p1, p2), ggplotGrob) 

gwidth <- do.call(unit.pmax, lapply(gl, "[[", "widths")) 
gl <- lapply(gl, "[[<-", "widths", value = gwidth) 
gridExtra::grid.arrange(grobs=gl) 

В качестве альтернативы, вы можете set the panel size на фиксированное значение.

+1

очень элегантный, но это приводит к тому, что ключи легенды находятся в несколько разных положениях между участками. Есть ли способ заставить приравнивание ширины к легендарному gtable? – user20650

+2

@ user20650 это конечно возможно, но несколько неудобно, потому что я) все это плохо документировано (можно было бы ожидать «legend.margin» или «legend.justification», чтобы помочь с этим, но нет), ii) ggplot продолжает менять свой макет структура с течением времени; iii) gtble никогда не обращался к обоснованию удобным образом, требуя более глубоких и более глубоких уровней вложенных матчей, которые трудно ориентироваться. Вопрос не был конкретным в этом вопросе, поэтому я не уверен, что такое предполагаемый прецедент. – baptiste

0

После комментария @ baptiste: Скудно, но да, это можно сделать. Но никаких гарантий, что это будет работать в будущих версиях. Решение было принято из here, но это решение также нуждалось в обновлении.

library(ggplot2) # v2.2.1 
library(gtable) # v0.2.0 
library(grid) 
library(gridExtra) # v2.2.1 

x = c(rep("a",20),rep("b",10)) 
y = c(x = c(rep("BIGTEXT",20),rep("EVENBIGGERTEXT",10))) 
df = data.frame(x,y) 

p1 = ggplot(df,aes(x,fill=x)) + geom_bar() 
p2 = ggplot(df,aes(y,fill=y)) + geom_bar() 

# Get the grobs 
gA <- ggplotGrob(p1) 
gB <- ggplotGrob(p2) 

# Get the widths of the legends 
index = which(gA$layout$name == "guide-box") 
leg1 <- convertX(sum(with(gA$grobs[[index]], grobs[[1]]$widths)), "mm") 
leg2 <- convertX(sum(with(gB$grobs[[index]], grobs[[1]]$widths)), "mm") 

# Add an empty column of width "abs(diff(c(leg1, leg2))) mm" to the right of 
# legend box for gA (the smaller legend box) 
gA$grobs[[index]] <- gtable_add_cols(gA$grobs[[index]], unit(abs(diff(c(leg1, leg2))), "mm")) 

# Set widths to maximums of corresponding widths 
gl <- list(gA, gB) 
gwidth <- do.call(unit.pmax, lapply(gl, "[[", "widths")) 
gl <- lapply(gl, "[[<-", "widths", value = gwidth) 


# Draw the plots 
grid.newpage() 
grid.draw(gl[[1]]) 

grid.newpage() 
grid.draw(gl[[2]])