Gunakan gganimate untuk membangun pengamatan histogram dengan observasi? Perlu bekerja untuk kumpulan data yang lebih besar (~ n = 5000)


12

Saya ingin mengambil sampel poin dari distribusi normal, dan kemudian membangun dotplot satu per satu menggunakan gganimatepaket sampai frame terakhir menunjukkan dotplot penuh.

Solusi yang bekerja untuk kumpulan data yang lebih besar ~ 5.000 - 20.000 poin sangat penting.

Berikut adalah kode yang saya miliki sejauh ini:

library(gganimate)
library(tidyverse)

# Generate 100 normal data points, along an index for each sample 
samples <- rnorm(100)
index <- seq(1:length(samples))

# Put data into a data frame
df <- tibble(value=samples, index=index)

Df terlihat seperti ini:

> head(df)
# A tibble: 6 x 2
    value index
    <dbl> <int>
1  0.0818     1
2 -0.311      2
3 -0.966      3
4 -0.615      4
5  0.388      5
6 -1.66       6

Plot statis menunjukkan dotplot yang benar:

# Create static version
plot <- ggplot(data=df, mapping=aes(x=value))+
          geom_dotplot()

Namun, gganimateversinya tidak (lihat di bawah). Itu hanya menempatkan titik pada sumbu x dan tidak menumpuknya.

plot+
  transition_reveal(along=index)

Plot statis

masukkan deskripsi gambar di sini

Sesuatu yang mirip dengan ini akan ideal: Kredit: https://gist.github.com/thomasp85/88d6e7883883315314f341d2207122a1 masukkan deskripsi gambar di sini


Heya. Bolehkah saya menyarankan judul yang berbeda untuk penelusuran yang lebih baik? Saya benar-benar mulai menyukai histogram animasi ini, dan saya pikir ini adalah visualisasi yang hebat ... Seperti "Animasi dot histogram, observasi yang dibangun dengan pengamatan" mungkin akan lebih relevan?
Tjebo

Jawaban:


11

Pilihan lain adalah menggambar poin dengan geom lain. Anda harus melakukan penghitungan pada data Anda terlebih dahulu (dan binning) tetapi tidak perlu membuat data Anda lebih lama.

Misalnya, Anda dapat menggunakan geom_point, tetapi tantangannya adalah untuk mendapatkan dimensi poin Anda dengan benar, sehingga mereka menyentuh / tidak menyentuh. Ini tergantung pada ukuran perangkat / file.

Tapi Anda juga bisa menggunakan ggforce::geom_ellipseuntuk menggambar titik Anda :)

geom_point (coba-coba dengan dimensi perangkat)

library(tidyverse)
library(gganimate)

set.seed(42)
samples <- rnorm(100)
index <- seq(1:length(samples))
df <- tibble(value = samples, index = index)

bin_width <- 0.25

count_data <- # some minor data transformation
  df %>%
  mutate(x = plyr::round_any(value, bin_width)) %>%
  group_by(x) %>%
  mutate(y = seq_along(x))

plot <-
  ggplot(count_data, aes(group = index, x, y)) + # group by index is important
  geom_point(size = 5)

p_anim <- 
  plot +
  transition_reveal(index)

animate(p_anim, width = 550, height = 230, res = 96)

geom_ellipse (Kontrol penuh ukuran titik)

library(ggforce)
plot2 <- 
  ggplot(count_data) +
  geom_ellipse(aes(group = index, x0 = x, y0 = y, a = bin_width/2, b = 0.5, angle = 0), fill = 'black') +
  coord_equal(bin_width) # to make the dots look nice and round

p_anim2 <- 
  plot2 +
  transition_reveal(index) 

animate(p_anim2) 

perbarui dalam tautan yang Anda berikan kepada contoh menakjubkan thomas, Anda dapat melihat bahwa ia menggunakan pendekatan serupa - ia menggunakan geom_circle alih-alih geom_ellipse, yang saya pilih karena kontrol yang lebih baik untuk jari-jari vertikal dan horizontal.

Untuk mendapatkan efek "tetes jatuh", Anda perlu transition_statesdan durasi yang lama dan banyak frame per detik.

p_anim2 <- 
  plot2 +
  transition_states(states = index, transition_length = 100, state_length = 1) +
  shadow_mark() +
  enter_fly(y_loc = 12) 

animate(p_anim2, fps = 40, duration = 20) 

Dibuat pada 2020-04-29 oleh paket reprex (v0.3.0)

beberapa inspirasi dari: ggplot dotplot: Apa penggunaan yang tepat dari geom_dotplot?


Saya mencari poin yang datang satu per satu, bukan dalam baris sesuai dengan nilai Y.
Maks.

2
@max lihat pembaruan - ganti saja y dengan indeks.
Tjebo

3

Coba ini. Ide dasarnya adalah ke grup obs untuk frame, yaitu dibagi dengan indeks dan kemudian mengumpulkan sampel ke frame, yaitu dalam frame 1 hanya obs pertama yang ditampilkan, dalam frame 2 obs 1 dan 2, ..... Mungkin ada adalah cara yang lebih elegan untuk mencapai ini, tetapi berhasil:

library(ggplot2)
library(gganimate)
library(dplyr)
library(purrr)

set.seed(42)

# example data
samples <- rnorm(100)
index <- seq(1:length(samples))

# Put data into a data frame
df <- tibble(value=samples, index=index)

# inflated df. Group obs together into frames
df_ani <- df %>% 
  split(.$index) %>% 
  accumulate(~ bind_rows(.x, .y)) %>% 
  bind_rows(.id = "frame") %>% 
  mutate(frame = as.integer(frame))
head(df_ani)
#> # A tibble: 6 x 3
#>   frame  value index
#>   <int>  <dbl> <int>
#> 1     1  1.37      1
#> 2     2  1.37      1
#> 3     2 -0.565     2
#> 4     3  1.37      1
#> 5     3 -0.565     2
#> 6     3  0.363     3

p_gg <- ggplot(data=df, mapping=aes(x=value))+
  geom_dotplot()
p_gg
#> `stat_bindot()` using `bins = 30`. Pick better value with `binwidth`.

p_anim <- ggplot(data=df_ani, mapping=aes(x=value))+
  geom_dotplot()

anim <- p_anim + 
  transition_manual(frame) +
  ease_aes("linear") +
  enter_fade() +
  exit_fade()
anim
#> `stat_bindot()` using `bins = 30`. Pick better value with `binwidth`.

Dibuat pada 2020-04-27 oleh paket reprex (v0.3.0)


ini berfungsi, tetapi dengan cepat menjadi tidak layak untuk kumpulan data yang lebih besar karena tabel berisi banyak baris data yang digandakan.
Maks.

misalnya, untuk memetakan 5000 poin, bingkai data memiliki 12 juta baris :(
maks

Maaf atas jawaban yang terlambat. Agak sibuk saat ini. Iya. Saya mengerti maksud Anda. Saya cukup yakin bahwa harus ada solusi yang lebih baik dan lebih maju untuk masalah seperti ini. Namun, saya masih pemula untuk gganimate dan sampai sekarang saya tidak punya waktu untuk memeriksa semua kemungkinan dan fitur-fiturnya. Jadi, saya khawatir saya tidak dapat memberikan solusi yang lebih baik untuk saat ini.
Stefan

3

Saya pikir kuncinya di sini adalah membayangkan bagaimana Anda akan membuat animasi ini secara manual, yang berarti Anda akan menambahkan titik-titik satu pengamatan pada satu waktu ke dotplot yang dihasilkan. Dengan pemikiran ini, pendekatan yang saya gunakan di sini adalah untuk membuat ggplotobjek yang terdiri dari plot layer = jumlah pengamatan, kemudian melangkah melalui lapisan demi lapisan melalui transition_layer.

# create the ggplot object
df <- data.frame(id=1:100, y=rnorm(100))

p <- ggplot(df, aes(y))

for (i in df$id) {
  p <- p + geom_dotplot(data=df[1:i,])
}

# animation
anim <- p + transition_layers(keep_layers = FALSE) +
    labs(title='Number of dots: {frame}')
animate(anim, end_pause = 20, nframes=120, fps=20)

masukkan deskripsi gambar di sini

Perhatikan bahwa saya mengatur keep_layers=FALSEuntuk menghindari overplotting. Jika Anda memplot ggplotobjek awal , Anda akan melihat apa yang saya maksudkan, karena pengamatan pertama diplot 100 kali, 99 kali kedua ... dll.

Bagaimana dengan penskalaan untuk kumpulan data yang lebih besar?

Karena jumlah bingkai = jumlah pengamatan, Anda perlu menyesuaikan skalabilitas. Di sini, biarkan # frames konstan, artinya Anda harus membiarkan kode mengelompokkan frame ke dalam segmen, yang saya lakukan melalui seq()fungsi, menentukan length.out=100. Perhatikan juga dalam contoh baru, dataset berisi n=5000. Untuk menjaga dotplot dalam bingkai, Anda harus membuat ukuran titik-titik tersebut sangat kecil. Saya mungkin membuat titik-titik sedikit terlalu kecil di sini, tetapi Anda tahu idenya. Sekarang # frames = jumlah kelompok pengamatan.

df <- data.frame(id=1:5000, y=rnorm(5000))

p <- ggplot(df, aes(y))

for (i in seq(0,length(df$id), length.out=100)) {
  p <- p + geom_dotplot(data=df[1:i,], dotsize=0.08)
}

anim <- p + transition_layers(keep_layers=FALSE) +
  labs(title='Frame: {frame}')

animate(anim, end_pause=20, nframes=120, fps=20)

masukkan deskripsi gambar di sini


Ini bekerja dengan baik untuk dataset kecil, tetapi tidak skala dengan baik bahkan untuk data yang cukup besar (n = 5000).
Maks.

Berikut adalah laporan kesalahan untuk n = 5000: Kesalahan: Penggunaan C stack 7969904 terlalu dekat dengan batas
maks

Ya, di sini contohnya memiliki bingkai = jumlah pengamatan. Saya telah mengedit jawaban untuk skalabilitas, di mana Anda memegang # frame konstan pada 100 dan kemudian menskala sehingga frame = jumlah kelompok
chemdork123
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.