Використовувати 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.