NPC координаты geom_point в ggplot2

10

Как я могу получить х , Y координаты geom_point в ggplot , где опорный кадр весь график изображения?

Я могу создать ggplot с некоторыми geom_point с помощью:

library(ggplot2)

my.plot <- ggplot(data.frame(x = c(0, 0.456, 1), y = c(0, 0.123, 1))) +
             geom_point(aes(x, y), color = "red")

Это дает:

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

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

my.grob <- ggplotGrob(my.plot)
my.grob$grobs[[6]]$children[[3]]$x
# [1] 0.0454545454545455native 0.46native 0.954545454545454native 
my.grob$grobs[[6]]$children[[3]]$y
# [1] 0.0454545454545455native 0.157272727272727native 0.954545454545454native

Как я могу получить значения координат x , y, когда я начинаю измерения из левого нижнего угла всего изображения, отмеченного зеленой стрелкой?

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

Обновление : я понял, что размер шрифта осей изменяется в зависимости от ширины и высоты графика, влияя на относительный размер панели графика . Таким образом, будет не просто указать местоположение в единицах NPC без определения ширины и высоты графика . Если возможно, укажите расположение geom_points в зависимости от ширины участка и высоты участка .

LBogaardt
источник
5
Почему 2 отрицательных голоса?
Маркус
2
Да, пожалуйста, прокомментируйте, если у вас есть проблемы или предложения.
Л.Богаардт
1
Учтите, что сам график не имеет фиксированных размеров - положения абсолютных точек зависят не только от размера устройства, на котором вы печатаете, но и от соотношения ваших осей. Поэтому довольно любопытно, зачем вам это нужно
Tjebo
1
Что касается отрицательных голосов, обратите внимание, что мне не нужно обосновывать свой вопрос, чтобы он был действительным вопросом на SE. Почему я хочу знать? Потому что я делаю.
Л.Богаардт
1
и этот тоже. но так и не получил реального ответа stackoverflow.com/questions/48710478/…
Tjebo

Ответы:

5

Когда вы изменяете размер ggplot, положение элементов на панели не является фиксированным в пространстве NPC. Это связано с тем, что некоторые компоненты графика имеют фиксированные размеры, а некоторые из них (например, панель) изменяют размеры в соответствии с размером устройства.

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

Другая трудность заключается в том, чтобы убедиться, что вы идентифицируете правильные группы в панели панелей, и трудно понять, как это можно легко обобщить. Использование функций подмножества списка [[6]]и [[3]]в вашем примере не распространяется на другие графики.

В любом случае, это решение работает путем измерения размера и положения панели в gtable и преобразования всех размеров в миллиметры перед делением на размеры графика в миллиметрах для преобразования в пространство NPC. Я попытался сделать его более общим, выделив панель и точки по имени, а не по числовому индексу.

library(ggplot2)
library(grid)
require(gtable)

get_x_y_values <- function(gg_plot)
{
  img_dim      <- grDevices::dev.size("cm") * 10
  gt           <- ggplot2::ggplotGrob(gg_plot)
  to_mm        <- function(x) grid::convertUnit(x, "mm", valueOnly = TRUE)
  n_panel      <- which(gt$layout$name == "panel")
  panel_pos    <- gt$layout[n_panel, ]
  panel_kids   <- gtable::gtable_filter(gt, "panel")$grobs[[1]]$children
  point_grobs  <- panel_kids[[grep("point", names(panel_kids))]]
  from_top     <- sum(to_mm(gt$heights[seq(panel_pos$t - 1)]))
  from_left    <- sum(to_mm(gt$widths[seq(panel_pos$l - 1)]))
  from_right   <- sum(to_mm(gt$widths[-seq(panel_pos$l)]))
  from_bottom  <- sum(to_mm(gt$heights[-seq(panel_pos$t)]))
  panel_height <- img_dim[2] - from_top - from_bottom
  panel_width  <- img_dim[1] - from_left - from_right
  xvals        <- as.numeric(point_grobs$x)
  yvals        <- as.numeric(point_grobs$y)
  yvals        <- yvals * panel_height + from_bottom
  xvals        <- xvals * panel_width + from_left
  data.frame(x = xvals/img_dim[1], y = yvals/img_dim[2])
}

Теперь мы можем проверить это на вашем примере:

my.plot <- ggplot(data.frame(x = c(0, 0.456, 1), y = c(0, 0.123, 1))) +
             geom_point(aes(x, y), color = "red")

my.points <- get_x_y_values(my.plot)
my.points
#>           x         y
#> 1 0.1252647 0.1333251
#> 2 0.5004282 0.2330669
#> 3 0.9479917 0.9442339

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

my.plot
grid::grid.draw(pointsGrob(x = my.points$x, y = my.points$y, default.units = "npc"))

Создано в 2020-03-25 пакетом представлением (v0.3.0)

Аллан Кэмерон
источник
1
Эта sum(to_mm(gt$heights[seq(panel_pos$t - 1)]))часть самая странная. Не могли бы вы объяснить, что вы здесь суммируете?
Л.Богаардт
1
@LBogaardt panel_pos$tдает строку сетки, в которой расположена (гибкая) панель, seq(panel_pos$t -1)как и все номера строк над ней, и, следовательно, sum(to_mm(gt$heights[seq(panel_pos$t - 1)]))является суммой высот этих строк.
Аллан Кэмерон
@LBogaardt Я пытался найти баланс между краткостью и ясностью, но, возможно, я не совсем понял это правильно ...
Аллан Кэмерон
Итак, ggplot похож на таблицу с одним столбцом для метки y, одним для нумерации оси y и т. Д. Аналогично для строк, каждая из которых имеет ширину / высоту. Панель это одна ячейка в этой таблице? Понял. Спасибо, Аллан.
Л.Богаардт
1
Точно, @LBogaardt. Фактически, ggplotGrob создает таблицу gTable, или таблицу grob
Аллан Кэмерон