Ggplot2, легенда сверху и маржа

Рассмотрим следующее:

library(ggplot2)
library(grid)
ggplot(diamonds, aes(clarity, fill=cut)) + 
  geom_bar() +   
  theme(
    plot.margin=unit(x=c(0,0,0,0),units="mm"),
    legend.position="top",
    plot.background=element_rect(fill="red")) +
  guides(fill=guide_legend(title.position="top"))

Результат этого выглядит примерно так: ggplot2 output В контексте plot.margin=unit(x=c(0,0,0,0),units="mm") есть неподходящее количество белого (красного) пространства над легендой. Кто-нибудь знает, как исправить это?

Спасибо за любой намек.

С уважением, Joh

Ответ 1

Как вы сказали, я не могу видеть это в вашем примере, но я предполагаю, что маржа принадлежит самой легенде. Вы можете устранить маржу вокруг самой легенды, добавив

theme(legend.margin=unit(-0.6,"cm")) # version 0.9.x

к вашему рисунку рисунка ggplot.

ОБНОВЛЕНИЕ: Начиная с версии 2.1.0, синтаксис изменился так, что вы должны использовать

theme(legend.margin=margin(t = 0, unit='cm'))

Обратите внимание, что, по крайней мере на данный момент, старое решение все еще работает.

enter image description here

Ответ 2

Если я преувеличиваю поля для большей видимости и запускает showViewports, я получаю следующее:

p + guides(fill=guide_legend(keyheight=unit(1,"cm"))) + theme(plot.margin=unit(c(1,1,1,1),"cm"))
showViewport(col="black",label=TRUE, newpage=TRUE, leaves=FALSE)

enter image description here

из которого казалось бы, что несуществующий заголовок каким-то образом занимает пространство.

Изменить: нет, это просто неудачное совпадение ярлыков. Это не название.

Посмотрите на легенду, которая, кажется, вызывает проблему.

library(gtable)
g = ggplotGrob(p)
leg = gtable_filter(g, "guide")
plot(leg)
leg$heights
# sum(0.5lines, sum(1.5mm, 10mm, 0mm, 1.5mm), 0.5lines)+0cm
grid.rect(height=leg$heights) 
grid.rect(height=leg$heights - unit(1,"line"), gp=gpar(lty=2))

так что это легенда, добавляющая некоторые поля (всего 0,5 + 0,5 = 1 строка). Я считаю это отсутствующей опцией guide.margin в теме, которая заменяется значением по умолчанию для половины строки.

enter image description here

Ответ 3

В течение года, когда этот вопрос был задан/ответил, ggplot вошел в режим обслуживания, поэтому не будет никаких будущих обновлений (что означает OP стратегия ожидания обновления не будет работать).

Принятый ответ полагается на fudging маржу вокруг легенды с помощью legend.margin. Однако это не очень хорошо обобщается, особенно при использовании ggsave() с различными размерами или масштабными коэффициентами. К счастью, существует более обобщаемое универсальное решение.

legend.margin принимает только одно значение для заполнения со всех сторон, а plot.margin принимает четыре значения для полей верхнего, правого, нижнего и левого полей. По умолчанию значения основаны на строках (а не на мм или дюймах), например: plot.margin=unit(c(c(1, 1, 0.5, 0.5)), units="line")

Если вы установили legend.margin в 0, вы можете использовать отрицательные значения plot.margin, основанные на строках строк, для перемещения легенды к краю области графика. Установка верхнего края на -0.5 отлично работает:

ggplot(diamonds, aes(clarity, fill=cut)) + 
  geom_bar() +   
  theme(
    plot.margin=unit(c(-0.5, 1, 0.5, 0.5), units="line"),
    legend.position="top",
    plot.background=element_rect(fill="red"),
    legend.margin=unit(0, "lines")) +
  guides(fill=guide_legend(title.position="top"))

Correct legend on top

Эта же идея работает, если легенда расположена внизу:

ggplot(diamonds, aes(clarity, fill=cut)) + 
  geom_bar() +   
  theme(
    plot.margin=unit(c(1, 1, -0.5, 0.5), units="line"),
    legend.position="bottom",
    plot.background=element_rect(fill="red"),
    legend.margin=unit(0, "lines")) +
  guides(fill=guide_legend(title.position="top"))

Correct legend on bottom

Пока вы задаете поле интереса к -0,5 строк, дополнительные пробелы должны исчезнуть. Это должно работать при любом размере видового экрана и любой комбинации ширины/высоты/масштаба с помощью ggsave()