Построить легенду за пределами области графика в базовой графике?

Как говорится в названии: Как я могу построить легенду за пределами области графика при использовании базовой графики?

Я думал о том, чтобы возиться с layout и создать пустой сюжет, чтобы содержать только легенду, но меня бы интересовал способ, используя только базовые функции графа и, например, par(mar = ), чтобы получить некоторое пространство справа сюжета для легенды.


Вот пример:

plot(1:3, rnorm(3), pch = 1, lty = 1, type = "o", ylim=c(-2,2))
lines(1:3, rnorm(3), pch = 2, lty = 2, type="o")
legend(1,-1,c("group A", "group B"), pch = c(1,2), lty = c(1,2))

дает:

alt text

Но, как сказано, я хотел бы, чтобы легенда была вне области построения графика (например, справа от графика/графика.

Ответ 1

Возможно, вам понадобится par(xpd=TRUE), чтобы можно было рисовать объекты вне области сюжета. Так что если вы делаете основной сюжет с bty='L', у вас будет некоторое пространство справа для легенды. Обычно это будет привязано к области сюжета, но сделайте par(xpd=TRUE), и с небольшой настройкой вы можете получить легенду как можно дальше:

 set.seed(1) # just to get the same random numbers
 par(xpd=FALSE) # this is usually the default

 plot(1:3, rnorm(3), pch = 1, lty = 1, type = "o", ylim=c(-2,2), bty='L')
 # this legend gets clipped:
 legend(2.8,0,c("group A", "group B"), pch = c(1,2), lty = c(1,2))

 # so turn off clipping:
 par(xpd=TRUE)
 legend(2.8,-1,c("group A", "group B"), pch = c(1,2), lty = c(1,2))

Ответ 2

Никто не упомянул об использовании отрицательных значений inset для legend. Вот пример, где легенда находится справа от графика, выровненного вверху (используя ключевое слово "topright").

# Random data to plot:
A <- data.frame(x=rnorm(100, 20, 2), y=rnorm(100, 20, 2))
B <- data.frame(x=rnorm(100, 21, 1), y=rnorm(100, 21, 1))

# Add extra space to right of plot area; change clipping to figure
par(mar=c(5.1, 4.1, 4.1, 8.1), xpd=TRUE)

# Plot both groups
plot(y ~ x, A, ylim=range(c(A$y, B$y)), xlim=range(c(A$x, B$x)), pch=1,
               main="Scatter plot of two groups")
points(y ~ x, B, pch=3)

# Add legend to top right, outside plot region
legend("topright", inset=c(-0.2,0), legend=c("A","B"), pch=c(1,3), title="Group")

Первому значению inset=c(-0.2,0) может потребоваться корректировка в зависимости от ширины легенды.

legend_right

Ответ 3

Другое решение, помимо уже упомянутых ondes (с использованием layout или par(xpd=TRUE)), состоит в том, чтобы наложить ваш график на прозрачный график на всем устройстве, а затем добавить к нему легенду.

Трюк состоит в том, чтобы наложить (пустой) график на всю область построения и добавить к этому легенду. Мы можем использовать опцию par(fig=...). Сначала мы поручаем R создать новый сюжет по всему устройству построения:

par(fig=c(0, 1, 0, 1), oma=c(0, 0, 0, 0), mar=c(0, 0, 0, 0), new=TRUE)

Настройка oma и mar необходима, так как мы хотим, чтобы внутренняя часть сюжета охватывала все устройство. new=TRUE необходим, чтобы R не запускал новое устройство. Затем мы можем добавить пустой сюжет:

plot(0, 0, type='n', bty='n', xaxt='n', yaxt='n')

И мы готовы добавить легенду:

legend("bottomright", ...)

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

Включение всего этого в функцию;

add_legend <- function(...) {
  opar <- par(fig=c(0, 1, 0, 1), oma=c(0, 0, 0, 0), 
    mar=c(0, 0, 0, 0), new=TRUE)
  on.exit(par(opar))
  plot(0, 0, type='n', bty='n', xaxt='n', yaxt='n')
  legend(...)
}

И пример. Сначала создайте сюжет, убедившись, что у нас достаточно места внизу, чтобы добавить легенду:

par(mar = c(5, 4, 1.4, 0.2))
plot(rnorm(50), rnorm(50), col=c("steelblue", "indianred"), pch=20)

Затем добавьте легенду

add_legend("topright", legend=c("Foo", "Bar"), pch=20, 
   col=c("steelblue", "indianred"),
   horiz=TRUE, bty='n', cex=0.8)

Результат:

Example figure shown legend in top margin

Ответ 4

Извините за воскрешение старого потока, но сегодня у меня была та же проблема. Самый простой способ, который я нашел, это следующее:

# Expand right side of clipping rect to make room for the legend
par(xpd=T, mar=par()$mar+c(0,0,0,6))

# Plot graph normally
plot(1:3, rnorm(3), pch = 1, lty = 1, type = "o", ylim=c(-2,2))
lines(1:3, rnorm(3), pch = 2, lty = 2, type="o")

# Plot legend where you want
legend(3.2,1,c("group A", "group B"), pch = c(1,2), lty = c(1,2))

# Restore default clipping rect
par(mar=c(5, 4, 4, 2) + 0.1)

Найдено здесь: http://www.harding.edu/fmccown/R/

Ответ 5

Мне нравится делать это вот так:

par(oma=c(0, 0, 0, 5))
plot(1:3, rnorm(3), pch=1, lty=1, type="o", ylim=c(-2,2))
lines(1:3, rnorm(3), pch=2, lty=2, type="o")
legend(par('usr')[2], par('usr')[4], bty='n', xpd=NA,
       c("group A", "group B"), pch=c(1, 2), lty=c(1,2))

введите описание изображения здесь

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

Однако это также можно автоматизировать:

dev.off() # to reset the graphics pars to defaults
par(mar=c(par('mar')[1:3], 0)) # optional, removes extraneous right inner margin space
plot.new()
l <- legend(0, 0, bty='n', c("group A", "group B"), 
            plot=FALSE, pch=c(1, 2), lty=c(1, 2))
# calculate right margin width in ndc
w <- grconvertX(l$rect$w, to='ndc') - grconvertX(0, to='ndc')
par(omd=c(0, 1-w, 0, 1))
plot(1:3, rnorm(3), pch=1, lty=1, type="o", ylim=c(-2, 2))
lines(1:3, rnorm(3), pch=2, lty=2, type="o")
legend(par('usr')[2], par('usr')[4], bty='n', xpd=NA,
       c("group A", "group B"), pch=c(1, 2), lty=c(1, 2))

введите описание изображения здесь

Ответ 6

Недавно я нашел очень легкую и интересную функцию для печати легенды за пределами области графика, в которой вы хотите.

Сделайте внешний край в правой части графика.

par(xpd=T, mar=par()$mar+c(0,0,0,5))

Создать сюжет

plot(1:3, rnorm(3), pch = 1, lty = 1, type = "o", ylim=c(-2,2))
lines(1:3, rnorm(3), pch = 2, lty = 2, type="o")

Добавьте легенду и просто используйте функцию locator (1), как показано ниже. Затем вам нужно просто щелкнуть, где вы хотите, после загрузки после script.

legend(locator(1),c("group A", "group B"), pch = c(1,2), lty = c(1,2))

Попробуйте

Ответ 7

Я могу предложить только пример уже упомянутого решения компоновки.

layout(matrix(c(1,2), nrow = 1), widths = c(0.7, 0.3))
par(mar = c(5, 4, 4, 2) + 0.1)
plot(1:3, rnorm(3), pch = 1, lty = 1, type = "o", ylim=c(-2,2))
lines(1:3, rnorm(3), pch = 2, lty = 2, type="o")
par(mar = c(5, 0, 4, 2) + 0.1)
plot(1:3, rnorm(3), pch = 1, lty = 1, ylim=c(-2,2), type = "n", axes = FALSE, ann = FALSE)
legend(1, 1, c("group A", "group B"), pch = c(1,2), lty = c(1,2))

an ugly picture :S

Ответ 8

Попробуйте layout(), который я использовал для этого в прошлом, просто создав пустой сюжет ниже, правильно масштабированный примерно на 1/4 или около того и размещение частей легенды вручную.

Здесь есть несколько более старых вопросов о legend(), которые должны вас запустить.

Ответ 9

Вы можете сделать это с помощью Plotly R API, либо с помощью кода, либо из графического интерфейса, перетащив легенду туда, где вы хотите.

Вот пример. Граф и код также здесь.

x = c(0,1,2,3,4,5,6,7,8) 
y = c(0,3,6,4,5,2,3,5,4) 
x2 = c(0,1,2,3,4,5,6,7,8) 
y2 = c(0,4,7,8,3,6,3,3,4)

Вы можете расположить легенду за пределами графика, назначив одно из значений x и y либо 100, либо -100.

legendstyle = list("x"=100, "y"=1)
layoutstyle = list(legend=legendstyle)

Вот другие варианты:

  • list("x" = 100, "y" = 0) для наружной правой нижней части
  • list("x" = 100, "y"= 1) Сверху справа Вверх
  • list("x" = 100, "y" = .5) Снаружи справа.
  • list("x" = 0, "y" = -100) В левой части
  • list("x" = 0.5, "y" = -100) В центре
  • list("x" = 1, "y" = -100) В правой части

Тогда ответ.

response = p$plotly(x,y,x2,y2, kwargs=list(layout=layoutstyle));

При выполнении вызова Plotly возвращает URL-адрес с вашим графиком. Вы можете получить доступ к этому быстрее, вызвав browseURL(response$url), чтобы он открыл ваш график в вашем браузере для вас.

url = response$url
filename = response$filename

Это дает нам этот график. Вы также можете переместить легенду из GUI, а затем график будет масштабироваться соответствующим образом. Полное раскрытие: я нахожусь в команде Plotly.

Legend on side of graph