Как вы рисуете линию в многозначной среде в R?

#r #plot

#r #График

Вопрос:

Возьмем очень простой пример, mfrow=c(1,3) ; каждая фигура представляет собой отдельную гистограмму; как бы я нарисовал горизонтальную линию (похожую на abline(h=10) ), которая проходила через все 3 фигуры? (То есть даже поля между ними.) Очевидно, что я мог бы добавить abline к каждой фигуре, но это не то, что я хочу. Я могу придумать очень сложный способ сделать это, действительно имея только 1 фигуру и рисуя каждую «фигуру» внутри нее с помощью polygon etc. Это было бы смешно. Нет ли простого способа сделать это?

Комментарии:

1. par(mfrow=c(1,3)); barplot(VADeaths); from <- grconvertX(par('usr')[1], 'user', 'ndc'); barplot(VADeaths); barplot(VADeaths); to <- grconvertX(par('usr')[2], 'user', 'ndc'); segments(grconvertX(from, 'ndc'), 50, grconvertX(to, 'ndc'), xpd = NA)

Ответ №1:

Как отметил @joran, графическая система grid предлагает более гибкий контроль над расположением нескольких графиков на одном устройстве.

Здесь я сначала использую grconvertY() для запроса местоположения высоты 50 на оси y в единицах «нормализованных координат устройства». (т. Е. Как пропорция к общей высоте устройства построения графика, где 0 = снизу, а 1 = сверху). Затем я использую функции сетки, чтобы: (1) нажать viewport , которая заполняет устройство; и (2) построить линию на высоте, возвращаемой grconvertY() .

 ## Create three example plots
par(mfrow=c(1,3))
barplot(VADeaths, border = "dark blue") 
barplot(VADeaths, border = "yellow") 
barplot(VADeaths, border = "green") 

## From third plot, get the "normalized device coordinates" of 
## a point at a height of 50 on the y-axis.
(Y <- grconvertY(50, "user", "ndc"))
# [1] 0.314248

## Add the horizontal line using grid
library(grid)
pushViewport(viewport())
grid.lines(x = c(0,1), y = Y, gp = gpar(col = "red"))
popViewport()
  

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

РЕДАКТИРОВАТЬ: @joran спросил, как построить линию, которая простирается от оси y 1-го графика до края последней полосы на 3-м графике. Вот несколько альтернатив:

 library(grid)
library(gridBase)
par(mfrow=c(1,3))

# barplot #1
barplot(VADeaths, border = "dark blue") 
X1 <- grconvertX(0, "user", "ndc")
# barplot #2
barplot(VADeaths, border = "yellow") 
# barplot #3
m <- barplot(VADeaths, border = "green") 
X2 <- grconvertX(tail(m, 1)   0.5, "user", "ndc") # default width of bars = 1
Y <- grconvertY(50, "user", "ndc")

## Horizontal line
pushViewport(viewport())
grid.lines(x = c(X1, X2), y = Y, gp = gpar(col = "red"))
popViewport()
  

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

Наконец, вот почти эквивалентный и в целом полезный подход. В нем используются функции grid.move.to() и grid.line.to() демонстрации Пола Мюррелла в статье, на которую ссылается @mdsumner’s answer.:

 library(grid)
library(gridBase)
par(mfrow=c(1,3))

barplot(VADeaths); vps1 <- do.call(vpStack, baseViewports())
barplot(VADeaths) 
barplot(VADeaths); vps3 <- do.call(vpStack, baseViewports())

pushViewport(vps1)
Y <- convertY(unit(50,"native"), "npc")
popViewport(3)

grid.move.to(x = unit(0, "npc"), y = Y, vp = vps1)
grid.line.to(x = unit(1, "npc"), y = Y, vp = vps3, 
             gp = gpar(col = "red"))
  

Комментарии:

1. 1 Приятно! Знаете ли вы способ изменения единиц измерения / координат / обрезки таким образом, чтобы линия проходила от самой левой оси y только до правого края зеленых полос?

2. У меня есть идея, и я добавлю ее, если это сработает. Прямо сейчас я ухожу косить газон до захода солнца…

3. Спасибо, это действительно полезно! Я ценю вашу готовность отложить стрижку газона за мой счет 😉

4. @joran — Хорошо, я добавил пару идей. Первый вариант может выглядеть лучше, но не будет хорошо обобщаться даже на гистограммы с наложенными (в отличие от сложенных) столбцами. Второй завершает линию на RHS области построения (а не на RHS последней строки), но он будет функционировать аналогично для любого базового графика R.

5. @joran — Я думаю, что теперь я выяснил относительно чистый и общий способ добавления строк того типа, о котором вы спрашивали. Если вам интересно, посмотрите третий (недавно отредактированный) блок кода.

Ответ №2:

Это лучшее, что я могу сделать, не задумываясь об этом сложнее:

 par(mfrow = c(1,3),xpd = NA)

for (i in 1:3){
    x <- rnorm(200,i)
    hist(x)
    if (i == 1) segments(par("usr")[1],10,30,10)
}
  

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

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

Я бы предположил, что это проще в сеточной графике, но мне пришлось бы провести некоторое исследование, чтобы проверить.

Ответ №3:

В этой статье Пола Мюррелла показано использование grid графики для рисования линий между двумя разными системами координат, в данном случае линий, конечные точки которых указаны в собственном пространстве двух отдельных участков:

Пол Мюррелл. Пакет grid graphics. R News, 2 (2): 14-19, июнь 2002

Это на странице 17 статьи в формате PDF:

http://cran.r-project.org/doc/Rnews/Rnews_2002-2.pdf

Комментарии:

1. Да, спасибо за эту замечательную ссылку. Я только что добавил 3-й блок кода к своему ответу, в котором используется пара функций ( grid.move.to() и grid.line.to() ), продемонстрированных в статье Мюррелла.