npc координаты geom_point в ggplot2
Как я могу получить координаты x, 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")
Это дает:
Преобразуя это в grob, я могу извлечь дополнительную информацию об этом 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 в зависимости от ширины и высоты графика.
1 ответ
Когда вы изменяете размер 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"))
Создано 25.03.2020 в пакете REPEX (v0.3.0)