coordonnées npc de geom_point dans ggplot2


10

Comment puis-je obtenir les coordonnées x , y d'un geom_point dans un ggplot , où le cadre de référence est la totalité de l'image tracée?

Je peux créer un ggplot avec quelques geom_point en utilisant:

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

Cela donne:

entrez la description de l'image ici

En convertissant cela en un grob , je peux extraire des informations supplémentaires sur ce ggplot , comme les coordonnées par rapport au panneau de tracé, marquées par la flèche violette. Cependant, cela ignore l'espace occupé par les axes.

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

Comment puis-je obtenir les valeurs des coordonnées x , y lorsque je commence à mesurer à partir du coin inférieur gauche de l'image entière, marquée par la flèche verte?

Si c'est possible, j'aimerais que la solution prenne en compte le thème du ggplot . L'ajout d'un thème comme + theme_void()affecte les axes et décale également l'emplacement des points par rapport à l'ensemble de l'image tracée.

Mise à jour : j'ai réalisé que la taille de police des axes change en fonction de la largeur et de la hauteur du tracé, affectant la taille relative du panneau de tracé . Il ne sera donc pas trivial de fournir l'emplacement en unités npc sans définir la largeur et la hauteur du tracé . Si possible, indiquez l'emplacement des geom_points en fonction de la largeur et de la hauteur du tracé .


5
Pourquoi 2 downvotes?
Markus

2
Oui, veuillez commenter si vous avez des préoccupations ou des suggestions.
LBogaardt

1
Considérez que le tracé lui-même n'a pas de dimensions fixes - les positions absolues des points ne dépendent pas seulement de la taille du périphérique sur lequel vous imprimez, mais également du rapport de vos axes. Donc assez curieux de savoir pourquoi vous en avez besoin
Tjebo

1
Concernant les downvotes, notez que je n'ai pas besoin de justifier ma question pour qu'elle soit valide sur SE. Pourquoi je veux savoir? Parce que je le fais.
LBogaardt

1
celui-là aussi. mais jamais eu de vraie réponse stackoverflow.com/questions/48710478/…
Tjebo

Réponses:


5

Lorsque vous redimensionnez un ggplot, la position des éléments dans le panneau n'est pas à des positions fixes dans l'espace npc. En effet, certains composants du tracé ont des tailles fixes et certains d'entre eux (par exemple, le panneau) changent de dimensions en fonction de la taille de l'appareil.

Cela signifie que toute solution doit prendre en compte la taille de l'appareil et si vous souhaitez redimensionner le tracé, vous devrez réexécuter le calcul. Cela dit, pour la plupart des applications (y compris la vôtre, par le son des choses), ce n'est pas un problème.

Une autre difficulté consiste à s'assurer que vous identifiez les bons grobs dans le panneau grob, et il est difficile de voir comment cela pourrait facilement être généralisé. L'utilisation des fonctions de sous-ensemble de liste [[6]]et [[3]]dans votre exemple n'est pas généralisable à d'autres tracés.

Quoi qu'il en soit, cette solution fonctionne en mesurant la taille et la position du panneau dans le gtable, et en convertissant toutes les tailles en millimètres avant de les diviser par les dimensions du tracé en millimètres pour les convertir en espace npc. J'ai essayé de le rendre un peu plus général en extrayant le panneau et les points par nom plutôt que par index numérique.

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

Maintenant, nous pouvons le tester avec votre exemple:

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

Et nous pouvons confirmer que ces valeurs sont correctes en traçant des points de points sur vos points rouges, en utilisant nos valeurs comme coordonnées npc:

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

Créé le 2020-03-25 par le package reprex (v0.3.0)


1
Cette sum(to_mm(gt$heights[seq(panel_pos$t - 1)]))partie est la plus étrange. Pourriez-vous expliquer ce que vous résumez ici?
LBogaardt

1
@LBogaardt panel_pos$tdonne la ligne de la grille dans laquelle se trouve le panneau (flexible), ainsi que seq(panel_pos$t -1)tous les numéros de ligne au-dessus de celui-ci, et donc sum(to_mm(gt$heights[seq(panel_pos$t - 1)]))la somme des hauteurs de ces lignes.
Allan Cameron

@LBogaardt J'essayais de trouver un équilibre entre brièveté et clarté, mais peut-être que je n'ai pas tout à fait raison ...
Allan Cameron

Ah, donc un ggplot est comme un tableau, avec une colonne pour l'étiquette y, une pour la numérotation de l'axe y, etc. De même pour les lignes, chacune avec une largeur / hauteur. Le panneau est une cellule de ce tableau? Je l'ai. Merci Allan.
LBogaardt

1
Exactement, @LBogaardt. En fait, ggplotGrob produit une table gTable ou grob
Allan Cameron
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.