Sử dụng gganimate để xây dựng một quan sát biểu đồ bằng quan sát? Cần phải làm việc cho các bộ dữ liệu lớn hơn (~ n = 5000)


12

Tôi muốn lấy mẫu các điểm từ một bản phân phối bình thường, và sau đó xây dựng từng điểm một bằng cách sử dụng gganimategói cho đến khi khung cuối cùng hiển thị dấu chấm đầy đủ.

Một giải pháp hoạt động cho các bộ dữ liệu lớn hơn ~ 5.000 - 20.000 điểm là điều cần thiết.

Đây là mã tôi có cho đến nay:

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 trông như thế này:

> 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

Biểu đồ tĩnh hiển thị dotplot chính xác:

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

Tuy nhiên, gganimatephiên bản không (xem bên dưới). Nó chỉ đặt các chấm trên trục x và không xếp chúng.

plot+
  transition_reveal(along=index)

Cốt truyện tĩnh

nhập mô tả hình ảnh ở đây

Một cái gì đó tương tự như thế này sẽ rất lý tưởng: Tín dụng: https://gist.github.com/thomasp85/88d6e7883883315314f341d2207122a1 nhập mô tả hình ảnh ở đây


Này Tôi có thể đề xuất một tiêu đề khác để tìm kiếm tốt hơn? Tôi thực sự bắt đầu thích biểu đồ hoạt hình này và tôi nghĩ đó là một hình ảnh tuyệt vời ... Sth như "Biểu đồ chấm hoạt hình, quan sát được xây dựng bằng quan sát" có lẽ sẽ phù hợp hơn?
Tjebo

Câu trả lời:


11

Một lựa chọn khác là vẽ các điểm với một geom khác. bạn sẽ cần phải thực hiện một số lần đếm trên dữ liệu của mình trước (và tạo thùng) nhưng nó không yêu cầu làm cho dữ liệu của bạn dài hơn.

Ví dụ: bạn có thể sử dụng geom_point, nhưng thách thức sẽ là làm cho kích thước của các điểm của bạn đúng, để chúng chạm / không chạm. Điều này phụ thuộc vào kích thước thiết bị / tập tin.

Nhưng bạn cũng có thể chỉ sử dụng ggforce::geom_ellipseđể vẽ dấu chấm của mình :)

geom_point (dùng thử và lỗi với kích thước thiết bị)

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 (Kiểm soát hoàn toàn kích thước điểm)

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) 

cập nhật trong liên kết mà bạn cung cấp cho ví dụ tuyệt vời của thomas, bạn có thể thấy rằng anh ta sử dụng một cách tiếp cận tương tự - anh ta sử dụng geom_circle thay vì geom_ellipse, mà tôi đã chọn vì kiểm soát tốt hơn cho cả bán kính dọc và ngang.

Để có được hiệu ứng "giọt rơi", bạn sẽ cần transition_statesvà thời lượng dài và nhiều khung hình mỗi giây.

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) 

Được tạo vào ngày 2020-04-29 bởi gói reprex (v0.3.0)

Một số nguồn cảm hứng từ: ggplot dotplot: Sử dụng đúng cách của geom_dotplot là gì?


Tôi đang tìm kiếm các điểm đến từng cái một, không phải trong các hàng theo giá trị Y.
tối đa

2
@max xem cập nhật - chỉ cần thay thế y bằng chỉ mục.
Tjebo

3

Thử cái này. Ý tưởng cơ bản là phân nhóm các obs thành các khung, tức là chia theo chỉ số và sau đó tích lũy các mẫu vào các khung, tức là trong khung 1 chỉ có quan sát đầu tiên được hiển thị, trong khung 2 obs 1 và 2, ..... Có lẽ ở đó là một cách thanh lịch hơn để đạt được điều này, nhưng nó hoạt động:

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`.

Được tạo vào ngày 2020-04-27 bởi gói reprex (v0.3.0)


điều này hoạt động, nhưng nhanh chóng trở nên không khả thi đối với các bộ dữ liệu lớn hơn do bảng chứa nhiều hàng dữ liệu trùng lặp.
tối đa

ví dụ: để vẽ 5000 điểm, khung dữ liệu có 12 triệu hàng :(
tối đa

Xin lỗi vì trả lời muộn. Bit bận rộn vào lúc này. Đúng. Tôi thấy điểm của bạn. Tôi khá chắc chắn rằng phải có một giải pháp tốt hơn và chặt chẽ hơn cho vấn đề này. Tuy nhiên, tôi vẫn là một người mới tham gia và đến bây giờ tôi không có thời gian để kiểm tra tất cả các khả năng và tính năng của nó. Vì vậy, tôi sợ rằng tôi không thể đưa ra một giải pháp tốt hơn vào lúc này.
stefan

3

Tôi nghĩ chìa khóa ở đây là tưởng tượng cách bạn sẽ tạo hoạt hình này theo cách thủ công, nghĩa là bạn sẽ thêm một chấm quan sát tại một thời điểm vào dotplot kết quả. Với ý nghĩ này, cách tiếp cận tôi sử dụng ở đây là tạo ra một ggplotđối tượng bao gồm các lớp cốt truyện = số lượng quan sát, sau đó từng bước qua từng lớp 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)

nhập mô tả hình ảnh ở đây

Lưu ý rằng tôi đặt keep_layers=FALSEđể tránh quá mức. Nếu bạn vẽ đồ thị ban đầu ggplot, bạn sẽ thấy ý tôi là gì, vì lần quan sát đầu tiên được vẽ 100 lần, 99 lần thứ hai ... vv

Điều gì về nhân rộng cho các bộ dữ liệu lớn hơn?

Vì số khung hình = số lượng quan sát, bạn cần điều chỉnh cho khả năng mở rộng. Ở đây, chỉ cần giữ các khung # không đổi, nghĩa là bạn phải để mã nhóm các khung thành các phân đoạn, mà tôi đang thực hiện thông qua seq()chức năng, chỉ định length.out=100. Cũng lưu ý trong ví dụ mới, tập dữ liệu chứa n=5000. Để giữ dotplot trong khung, bạn cần làm cho kích thước của các chấm thực sự nhỏ. Tôi có thể làm cho các chấm hơi quá nhỏ ở đây, nhưng bạn ge ý tưởng. Bây giờ # khung = số nhóm quan sát.

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)

nhập mô tả hình ảnh ở đây


Điều này hoạt động tốt cho các bộ dữ liệu nhỏ, nhưng không mở rộng tốt cho dữ liệu lớn vừa phải (n = 5000).
tối đa

Đây là lỗi được báo cáo cho n = 5000: Lỗi: Sử dụng ngăn xếp C 7969904 quá gần với giới hạn
tối đa

Vâng, ở đây ví dụ có frame = số lượng quan sát. Tôi đã chỉnh sửa câu trả lời cho khả năng mở rộng, trong đó bạn giữ # khung không đổi ở mức 100 và sau đó chia tỷ lệ sao cho khung = số nhóm
chemdork123
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.