NPC-Koordinaten von geom_point in ggplot2

10

Wie kann ich die x , y- Koordinaten eines geom_point in einem ggplot erhalten , wobei der Referenzrahmen das gesamte geplottete Bild ist?

Ich kann ein ggplot mit einigen geom_point s erstellen mit:

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

Das gibt:

Geben Sie hier die Bildbeschreibung ein

Indem ich dies in einen Grob konvertiere , kann ich einige zusätzliche Informationen zu diesem ggplot extrahieren , wie z . B. die Koordinaten in Bezug auf das Plotfeld , die durch den violetten Pfeil markiert sind. Dies ignoriert jedoch den von den Achsen eingenommenen Raum.

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

Wie kann ich die Werte der x , y- Koordinaten abrufen , wenn ich mit der Messung in der unteren linken Ecke des gesamten Bildes beginne, die durch den grünen Pfeil markiert ist?

Wenn es möglich ist, möchte ich, dass die Lösung das Thema des ggplot berücksichtigt . Das Hinzufügen eines Themas wie + theme_void()wirkt sich auf die Achsen aus und verschiebt auch die Position der Punkte in Bezug auf das gesamte geplottete Bild.

Update : Ich habe festgestellt, dass sich die Schriftgröße der Achsen abhängig von der Breite und Höhe des Plots ändert, was sich auf die relative Größe des Plotfelds auswirkt . So ist es nicht trivial sein wird , die Lage in bereitzustellen npc die Einheiten ohne zu definieren , Grundstück Breite und Grundstück Höhe . Wenn möglich, gibt die Lage der geom_points in Abhängigkeit von der Handlung Breite und Grundstück Höhe .

LBogaardt
quelle
5
Warum 2 Downvotes?
Markus
2
Ja, bitte kommentieren Sie, wenn Sie Bedenken oder Vorschläge haben.
LBogaardt
1
Beachten Sie, dass das Diagramm selbst keine festen Abmessungen hat. Die absoluten Punktpositionen hängen nicht nur von der Größe des Geräts ab, auf das Sie drucken, sondern auch vom Verhältnis Ihrer Achsen. Deshalb ziemlich neugierig, wofür du es brauchst
Tjebo
1
Beachten Sie in Bezug auf die Abstimmungen, dass ich meine Frage nicht begründen muss, damit sie eine gültige Frage zu SE ist. Warum will ich das wissen? Weil ich es tue.
LBogaardt
1
dieses auch. aber nie eine richtige Antwort bekommen stackoverflow.com/questions/48710478/…
Tjebo

Antworten:

5

Wenn Sie die Größe eines ggplot ändern, befindet sich die Position der Elemente innerhalb des Bedienfelds nicht an festen Positionen im NPC-Raum. Dies liegt daran, dass einige der Komponenten des Diagramms feste Größen haben und einige von ihnen (z. B. das Bedienfeld) die Abmessungen entsprechend der Größe des Geräts ändern.

Dies bedeutet, dass jede Lösung die Gerätegröße berücksichtigen muss. Wenn Sie die Größe des Diagramms ändern möchten, müssen Sie die Berechnung erneut ausführen. Allerdings ist dies für die meisten Anwendungen (einschließlich Ihrer, nach den Geräuschen der Dinge) kein Problem.

Eine weitere Schwierigkeit besteht darin, sicherzustellen, dass Sie die richtigen Grobs innerhalb des Panel-Grobs identifizieren, und es ist schwierig zu erkennen, wie dies leicht verallgemeinert werden kann. Die Verwendung der Listenuntermengenfunktionen [[6]]und [[3]]in Ihrem Beispiel ist nicht auf andere Diagramme verallgemeinerbar.

Wie auch immer, diese Lösung misst die Panelgröße und -position innerhalb der gtable und konvertiert alle Größen in Millimeter, bevor sie durch die Plotabmessungen in Millimetern dividiert wird, um sie in den NPC-Raum zu konvertieren. Ich habe versucht, es etwas allgemeiner zu gestalten, indem ich das Panel und die Punkte eher nach Namen als nach numerischem Index extrahierte.

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

Jetzt können wir es mit Ihrem Beispiel testen:

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

Und wir können bestätigen, dass diese Werte korrekt sind, indem wir einige Punktkanten über Ihre roten Punkte zeichnen und unsere Werte als NPC-Koordinaten verwenden:

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

Erstellt am 25.03.2020 durch das reprex-Paket (v0.3.0)

Allan Cameron
quelle
1
Dieser sum(to_mm(gt$heights[seq(panel_pos$t - 1)]))Teil ist der seltsamste. Können Sie erklären, was Sie hier zusammenfassen?
LBogaardt
1
@LBogaardt panel_pos$tgibt die Zeile des Rasters an, in der sich das (flexible) Bedienfeld befindet, also seq(panel_pos$t -1)alle darüber liegenden Zeilennummern und daher sum(to_mm(gt$heights[seq(panel_pos$t - 1)]))die Summe der Höhen dieser Zeilen.
Allan Cameron
@LBogaardt Ich habe versucht, ein Gleichgewicht zwischen Kürze und Klarheit zu finden, aber vielleicht habe ich das nicht ganz richtig verstanden ...
Allan Cameron
Ah, ein ggplot ist also wie eine Tabelle mit einer Spalte für die y-Beschriftung, einer für die Nummerierung der y-Achse usw. Ebenso für Zeilen mit jeweils einer Breite / Höhe. Das Panel ist eine Zelle in dieser Tabelle? Ich habs. Danke Allan.
LBogaardt
1
Genau, @LBogaardt. Tatsächlich erstellt ggplotGrob eine gTable oder Grob-Tabelle
Allan Cameron