Використовувати gganimate для побудови спостереження за гістограмою шляхом спостереження? Потреба в роботі для великих наборів даних (~ n = 5000)


10

Я хотів би відібрати очки з звичайного розподілу, а потім створити точку по одному, використовуючи gganimateпакет, поки в остаточному кадрі не з’явиться повний dotplot.

Рішення, яке працює для великих наборів даних ~ 5000 - 20 000 балів, є надзвичайно важливим.

Ось код, який у мене є:

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 виглядає так:

> 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

Статичний графік показує правильний dotplot:

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

Однак gganimateверсії немає (див. Нижче). Він лише ставить крапки на осі x і не робить їх складання.

plot+
  transition_reveal(along=index)

Статичний сюжет

введіть тут опис зображення

Щось подібне до цього було б ідеально: Кредит: https://gist.github.com/thomasp85/88d6e7883883315314f341d2207122a1 введіть тут опис зображення


Хея. Чи можу я запропонувати іншу назву для кращого пошуку? Мені справді почала подобатися ця анімована гістограма, і я думаю, що це чудова візуалізація ... Sth на кшталт "Гістограма анімованих точок, побудована спостереження за допомогою спостереження", можливо, буде більш доречною?
Тебо

Відповіді:


9

Інший варіант - намалювати точки з іншим геомом. вам потрібно буде спочатку зробити деякі підрахунки ваших даних (і поширювати їх на бінжинг), але це не потребує збільшення даних.

Наприклад, ви можете використовувати geom_point, але завдання буде полягати в правильному розмірі точок, тому вони торкаються / не торкаються. Це залежить від вікна перегляду / розміру файлу.

Але ви також можете просто використовувати ggforce::geom_ellipseсвої малюнки :)

geom_point (проба та помилка з розміром вікна перегляду)

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 (Повний контроль розміру точки)

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) 

оновлення у посиланні, яке ви надаєте на дивовижний приклад томасу, ви бачите, що він використовує подібний підхід - він використовує geom_circle замість geom_ellipse, який я вибрав через кращий контроль як вертикального, так і горизонтального радіуса.

Для отримання ефекту «краплі, що падають» знадобиться transition_statesі тривала тривалість, і багато кадрів в секунду.

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) 

Створено 2020-04-29 пакетом reprex (v0.3.0)

деяке натхнення від: ggplot dotplot: Яке правильне використання geom_dotplot?


Я шукаю, щоб очки збиралися одна за одною, а не рядками відповідно до значення Y.
макс

2
@max див. оновлення - просто замініть y на індекс.
Тебо

3

Спробуйте це. Основна ідея полягає в тому, щоб згрупувати об'єм на кадри, тобто розділити за індексом, а потім накопичити зразки в кадрах, тобто в кадрі 1 показано лише перше ПТ, в кадрі 2 ОЦ 1 і 2, ..... Можливо, там це більш елегантний спосіб досягти цього, але він працює:

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

Створено 2020-04-27 за допомогою пакету reprex (v0.3.0)


це працює, але швидко стає нездійсненним для великих наборів даних, оскільки таблиця містить багато рядків дублюваних даних.
макс

Наприклад, для побудови 5000 точок кадр даних має 12 мільйонів рядків :(
макс.

Вибачте за пізню відповідь. Трохи зайнятий на даний момент. Так. Я бачу вашу думку. Я цілком впевнений, що для цього має бути краще та більш прямого вирішення проблеми. Однак я все ще новачок, який я привітався, і до цього часу я не мав часу перевірити всі його можливості та особливості. Тож я боюся, що поки не можу прийти до кращого рішення.
Стефан

3

Я думаю, що головне тут - уявити, як ви створили б цю анімацію вручну, тобто, ви додавали б крапки по одному спостереженню одночасно до отриманої точки. Зважаючи на це, підхід, який я тут застосував, полягав у створенні ggplotоб'єкта, який складався з шарів сюжету = кількість спостережень, а потім крок через шар за шаром через 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)

введіть тут опис зображення

Зауважте, що я налаштований keep_layers=FALSEуникати перенапруг. Якщо ви побудуєте початковий ggplotоб’єкт, ви побачите, що я маю на увазі, оскільки перше спостереження побудовано 100 разів, друге 99 разів ... і т.д.

Що з масштабуванням для великих наборів даних?

Оскільки кількість кадрів = кількість спостережень, вам потрібно налаштувати масштабованість. Тут просто тримайте # кадри постійними, тобто ви повинні дозволити коду групувати кадри по сегментах, що я роблю за допомогою seq()функції, вказуючи length.out=100. Зауважте також, що в новому прикладі набір даних містить n=5000. Щоб зберегти крапку в кадрі, потрібно зробити розміри крапок справді крихітними. Я, певно, зробив крапки тут занадто маленькими, але ви ідея. Тепер # кадри = кількість груп спостережень.

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)

введіть тут опис зображення


Це добре працює для невеликих наборів даних, але не забезпечує масштабування навіть середньо великих даних (n = 5000).
макс

Ось помилка в звітах за n = 5000: Помилка: використання стека C 7969904 занадто близько до межі
макс.

Так, ось приклад має кадр = кількість спостережень. Я відредагував відповідь на масштабованість, коли ви тримаєте # кадри постійними на 100, а потім масштабуєте, щоб кадри = кількість груп
chemdork123
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.