npc koordinat geom_point di ggplot2

10

Bagaimana saya bisa mendapatkan koordinat x , y dari geom_point dalam ggplot , di mana kerangka referensi adalah seluruh gambar yang diplot?

Saya dapat membuat ggplot dengan beberapa geom_point menggunakan:

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

Ini memberi:

masukkan deskripsi gambar di sini

Dengan mengonversinya menjadi grob , saya dapat mengekstrak beberapa informasi tambahan tentang ggplot ini , seperti koordinat yang berkaitan dengan panel plot, yang ditandai oleh panah ungu. Namun, ini mengabaikan ruang yang diambil oleh sumbu.

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

Bagaimana saya bisa mendapatkan nilai koordinat x , y ketika saya mulai mengukur dari sudut kiri bawah seluruh gambar, yang ditandai oleh panah hijau?

Jika mungkin, saya ingin solusi untuk memperhitungkan tema dari ggplot . Menambahkan tema seperti + theme_void()memengaruhi sumbu dan juga menggeser lokasi titik sehubungan dengan keseluruhan gambar yang diplot.

Pembaruan : Saya menyadari bahwa ukuran font sumbu berubah tergantung pada lebar dan tinggi plot, memengaruhi ukuran relatif panel plot . Jadi tidak akan sepele untuk menyediakan lokasi dalam satuan npc tanpa menentukan lebar plot dan tinggi plot . Jika memungkinkan, berikan lokasi geom_points sebagai fungsi dari lebar plot dan tinggi plot .

LBogaardt
sumber
5
Kenapa 2 downvotes?
markus
2
Ya, beri komentar jika Anda memiliki masalah atau saran.
LBogaardt
1
Pertimbangkan bahwa plot itu sendiri tidak memiliki dimensi tetap - posisi titik absolut tidak hanya tergantung pada ukuran perangkat yang Anda cetak, tetapi juga dengan rasio sumbu Anda. Karenanya cukup penasaran untuk apa Anda membutuhkannya
Tjebo
1
Mengenai downvotes, perhatikan bahwa saya tidak perlu membenarkan pertanyaan saya untuk itu menjadi pertanyaan yang valid di SE. Mengapa saya ingin tahu? Karena saya melakukannya.
LBogaardt
1
yang satu ini juga. tetapi tidak pernah mendapat jawaban nyata stackoverflow.com/questions/48710478/…
Tjebo

Jawaban:

5

Ketika Anda mengubah ukuran ggplot, posisi elemen dalam panel tidak pada posisi tetap di ruang NPC. Ini karena beberapa komponen plot memiliki ukuran tetap, dan beberapa di antaranya (misalnya, panel) mengubah dimensi sesuai dengan ukuran perangkat.

Ini berarti bahwa solusi apa pun harus memperhitungkan ukuran perangkat, dan jika Anda ingin mengubah ukuran plot, Anda harus menjalankan perhitungan lagi. Karena itu, untuk sebagian besar aplikasi (termasuk aplikasi Anda, dari berbagai hal), ini bukan masalah.

Kesulitan lain adalah memastikan Anda mengidentifikasi grob yang benar di dalam panel grob, dan sulit untuk melihat bagaimana ini dapat dengan mudah digeneralisasikan. Menggunakan fungsi subset daftar [[6]]dan [[3]]dalam contoh Anda tidak dapat digeneralisasi ke plot lain.

Bagaimanapun, solusi ini bekerja dengan mengukur ukuran dan posisi panel di dalam gtable, dan mengubah semua ukuran menjadi milimetre sebelum membaginya dengan dimensi plot dalam milimetre untuk dikonversi ke ruang NPC. Saya telah mencoba membuatnya sedikit lebih umum dengan mengekstraksi panel dan poin dengan nama daripada indeks numerik.

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

Sekarang kita dapat mengujinya dengan contoh Anda:

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

Dan kami dapat mengonfirmasi bahwa nilai-nilai ini benar dengan memplot beberapa poin grob di atas poin merah Anda, menggunakan nilai kami sebagai koordinator NPC:

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

Dibuat pada 2020-03-25 oleh paket reprex (v0.3.0)

Allan Cameron
sumber
1
sum(to_mm(gt$heights[seq(panel_pos$t - 1)]))Bagian ini adalah yang paling aneh. Bisakah Anda menjelaskan apa yang Anda simpulkan di sini?
LBogaardt
1
@ LBogaardt panel_pos$tmemberikan baris kisi di mana panel (fleksibel) duduk, demikian seq(panel_pos$t -1)juga semua nomor baris di atas ini, dan oleh karena itu sum(to_mm(gt$heights[seq(panel_pos$t - 1)]))adalah jumlah dari ketinggian baris ini.
Allan Cameron
@ LBogaardt Saya mencoba untuk menyeimbangkan antara singkatnya dan kejelasan, tapi mungkin saya tidak mengerti dengan benar ...
Allan Cameron
Ah, jadi ggplot seperti tabel, dengan satu kolom untuk label-y, satu untuk penomoran sumbu y, dll. Demikian juga untuk baris, masing-masing dengan lebar / tinggi. Panel adalah satu sel dalam tabel ini? Oke. Terima kasih, Allan.
LBogaardt
1
Tepatnya, @LBogaardt. Faktanya, ggplotGrob menghasilkan gTable, atau grob table
Allan Cameron