Створіть легенду поза площею графіки в базовій графіці?


185

Як випливає з назви: Як я можу побудувати легенду за межами ділянки, коли використовується базова графіка?

Я подумав про те, щоб обмінятись 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 текст

Але, як було сказано, я хотів би, щоб легенда знаходилася поза площею графіку (наприклад, праворуч від графіка / сюжету.


... ви також можете зламати парі з фіктивним контейнером для легенди, простий і досить зручний час від часу. Подібне питання тут .
— hhh

3
@hhh Посилання більше не працює. Чи можете ви оновити його або опублікувати відповідь, використовуючи такий підхід?
— Генрік

Відповіді:


111

Можливо, що вам потрібно - це 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))

33
Зауважте, що ви можете передати xpd безпосередньо в легенду, тому вам не потрібно буде турбуватися про скидання par після цього. Також дивіться у grconvertX & Y про спосіб визначення місця розташування легенди таким чином, що не залежить від меж даних, які ви плануєте.
— Чарльз

6
оскільки це питання і відповідь все ще дуже популярні, par(xpd=NA)він ще сильніший (тобто сюжети для більшої кількості регіонів).
— Генрік

+1. Слід зазначити, що має сенс мати окремий parдзвінок безпосередньо перед легендою. У своєму сюжеті я використовував par(new=T)кілька інших випадків і просто хотів додати xpdпарам в той же дзвінок, що викликає неприємності.
— Метт Баннерт

146

Ніхто не згадав про використання негативних 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


14
@Henrik ні, це не працює без xpd = ІСТИНА. Також зауважте, що краще встановити xpd = TRUE як аргумент функції legend ().
— Стефан Лоран

1
Іноді xpdпотрібно налаштувати, щоб TRUEнегативна вставка працювала. Але іноді ні. З командою args.legend=list(x="bottom", horiz=TRUE, inset=-0.2)всередині barplot(...це, мабуть, не потрібно, xpd=TRUEале просто legend(x="bottom", horiz=TRUE, inset=-0.2)здається, що це потрібно xpd=TRUE. Будь-які уявлення? Я просто розгублений, передаючи свої аргументи?
— користувач3386170

28

Ще одне рішення, окрім вже згадуваних судин (за допомогою 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)

Результат:

Приклад рисунка показаний легендою у верхньому полі


2
Чудове доповнення до списку тут. Там є пояснення про те , як зробити цю роботу з декількома ділянками в графіку тут .
— ширі

Ян, чи є спосіб збільшити розмір шрифту в легенді, не обрізаючи якогось тексту? Наприклад, у мене є графічні 4 різного типу етикетки, але з великою кількістю порожнього місця між ними.
— Старий чоловік у морі.

Я написав запитання з більш детальною інформацією stackoverflow.com/questions/42707308/…
— Старий чоловік у морі.

16

Вибачте за те, що воскресив стару нитку, але я був із тією ж проблемою сьогодні. Найпростіший спосіб, який я знайшов:

# 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/


4
Ще краще - oldpar <- par (xpd = T, mar = par () $ mar + c (0,0,0,6)) ... par (oldpar) (Див. Допомогу par)
— rakensi

Це рішення краще, оскільки місце для легенди закріплено незалежно від довжини струн легенди
— Серхіо

15

Мені подобається це робити так:

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))

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


Використання xpd = T або xpd = NA не заважає моєму "головному" (заголовку) відсікатися, коли він розтягується, щоб спробувати використовувати область, додану з широким правим полем.
— Філ Гец

@PhilGoetz Ви впевнені, що плануєте головне в межах ділянки? Чи можливо, у вас там недостатньо рядків поля для побудови?
— jbaums

10

Нещодавно я знайшов дуже легку та цікаву функцію друкувати легенду за межами ділянки, де ви хочете.

Зробіть зовнішній край у правій частині ділянки.

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")

Додайте легенду і просто використовуйте функцію локатора (1), як показано нижче. Тоді вам доведеться просто натиснути куди потрібно після завантаження наступного сценарію.

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

Спробуй це


9

Я можу запропонувати лише приклад рішення, яке вже було зазначено.

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))

потворна картина: S


9

Додамо ще одну просту альтернативу, яка є досить елегантною, на мою думку.

Ваш сюжет:

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("bottomright", c("group A", "group B"), pch=c(1,2), lty=c(1,2),
       inset=c(0,1), xpd=TRUE, horiz=TRUE, bty="n"
       )

Результат:

картинка з легендою

Тут до вашого прикладу було додано лише другий рядок легенди. У свою чергу:

  • inset=c(0,1)- переміщує легенду за часткою ділянки ділянки в (x, y) напрямках. У цьому випадку легенда стоїть на "bottomright"місці. Він переміщується на 0 графічних областей у напрямку x (так, що залишається на "праворуч") та на 1 ділянку графіки у напрямку y (знизу вгору). І буває так, що вона з’являється прямо над сюжетом.
  • xpd=TRUE - Давайте легенда з'явиться поза графіком регіону.
  • horiz=TRUE - доручає скласти горизонтальну легенду.
  • bty="n" - деталь стилю, щоб позбутися легендної рамки.

Те саме стосується додавання легенди в бік:

par(mar=c(5,4,2,6))
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("topleft", c("group A", "group B"), pch=c(1,2), lty=c(1,2),
       inset=c(1,0), xpd=TRUE, bty="n"
       )

Тут ми просто відрегулювали положення легенди та додали додатковий простір у правій частині сюжету. Результат:

картинка з легендою 2


4

Ви можете зробити це за допомогою API Plotly R з будь-яким кодом або з графічного інтерфейсу, перетягнувши легенду там, де ви цього хочете.

Ось приклад. Графік та код також є тут .

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.

Легенда на стороні графіка


2

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

Тут є кілька старіших запитань, щодо legend()яких слід розпочати.


Як уже було сказано в питанні, про це я і думав. Але було б ідеально, якби був інший шлях. Я певно думаю, що немає.
— Генрік
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.