ใช้ gganimate เพื่อสร้างการสังเกตฮิสโตแกรมโดยการสังเกต? ต้องการทำงานกับชุดข้อมูลขนาดใหญ่ (~ n = 5,000)


10

ฉันต้องการสุ่มตัวอย่างคะแนนจากการแจกแจงแบบปกติแล้วสร้าง dotplot ทีละตัวโดยใช้gganimateแพ็คเกจจนกว่าเฟรมสุดท้ายจะแสดง dotplot แบบเต็ม

โซลูชันที่ใช้งานได้กับชุดข้อมูลที่มีขนาดใหญ่ขึ้น ~ 5,000 - 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

พล็อตแบบคงที่แสดงดอทพล็อตที่ถูกต้อง:

# 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 ป้อนคำอธิบายรูปภาพที่นี่


Heya ฉันขอแนะนำชื่ออื่นให้ค้นหาได้ดีขึ้นไหม ฉันเริ่มชอบฮิสโตแกรมที่มีการเคลื่อนไหวจริงๆและฉันคิดว่ามันเป็นการสร้างภาพที่ยอดเยี่ยม ... Sth เช่น "แอคทีฟฮิสโตแกรมจุดการสร้างการสังเกตโดยการสังเกต" อาจจะเกี่ยวข้องกันมากกว่านี้?
Tjebo

คำตอบ:


9

อีกทางเลือกหนึ่งคือการวาดคะแนนด้วย geom อื่น คุณจะต้องทำการนับจำนวนข้อมูลของคุณก่อน (และ binning) แต่ไม่จำเป็นต้องทำให้ข้อมูลของคุณอีกต่อไป

ตัวอย่างเช่นคุณสามารถใช้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 ด้วยดัชนี
Tjebo

3

ลองสิ่งนี้ แนวคิดพื้นฐานคือการจัดกลุ่มของ obs to frames เช่นแบ่งตามดัชนีแล้วสะสมตัวอย่างเป็น frames เช่นใน frame 1 เฉพาะ obs แรกที่แสดงในเฟรม 2 obs 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)


ใช้งานได้ แต่จะกลายเป็นชุดข้อมูลที่มีขนาดใหญ่ขึ้นอย่างรวดเร็วเนื่องจากตารางประกอบด้วยข้อมูลที่ซ้ำกันหลายแถว
สูงสุด

ตัวอย่างเช่นในการลงจุด 5,000 จุดเฟรมข้อมูลมี 12 ล้านแถว :(
สูงสุด

ขออภัยสำหรับคำตอบที่ล่าช้า บิตกำลังยุ่งอยู่ในขณะนี้ ใช่. ฉันเห็นประเด็นของคุณ ฉันค่อนข้างแน่ใจว่าจะต้องมีวิธีแก้ปัญหาที่ดีกว่านี้และตรงไปตรงมามากขึ้น อย่างไรก็ตามฉันยังเป็นมือใหม่ที่มีความมั่นใจจนถึงตอนนี้ฉันไม่มีเวลาตรวจสอบความเป็นไปได้และคุณลักษณะทั้งหมดของมัน ดังนั้นฉันกลัวว่าฉันจะไม่สามารถหาทางออกที่ดีกว่าได้ในขณะนี้
ฟาน

3

ฉันคิดว่ากุญแจสำคัญในที่นี้คือการจินตนาการว่าคุณจะสร้างแอนิเมชันนี้ด้วยตนเองได้อย่างไรซึ่งก็คือการพูดว่าคุณจะเพิ่มจุดสังเกตทีละจุดให้กับ dotplot กับในใจวิธีที่ผมใช้นี่คือการสร้าง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เพื่อหลีกเลี่ยงการ overplotting หากคุณพล็อตggplotวัตถุเริ่มต้นคุณจะเห็นสิ่งที่ฉันหมายถึงเนื่องจากการสังเกตครั้งแรกมีการพล็อต 100 ครั้ง 99 ครั้งที่สอง ... เป็นต้น

สิ่งที่เกี่ยวกับการปรับสเกลสำหรับชุดข้อมูลขนาดใหญ่

เนื่องจากจำนวนเฟรม = จำนวนการสังเกตคุณจำเป็นต้องปรับเพื่อความยืดหยุ่น นี่เป็นเพียงแค่ให้ # เฟรมคงหมายความว่าคุณต้องปล่อยให้กลุ่มรหัสเฟรมเป็นกลุ่มที่ฉันทำผ่านฟังก์ชั่นการระบุseq() ยังทราบในตัวอย่างใหม่ชุดข้อมูลที่มีlength.out=100 n=5000เพื่อให้ dotplot อยู่ในกรอบคุณต้องทำให้ขนาดของจุดเล็ก ๆ ฉันอาจทำให้จุดเล็ก ๆ น้อย ๆ ที่นี่ แต่คุณคิด ตอนนี้ # frames = จำนวนกลุ่มการสังเกต

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 ใกล้ถึงขีด จำกัด มากที่สุด
สูงสุด

ใช่นี่คือตัวอย่างมี frame = จำนวนการสังเกต ฉันได้แก้ไขคำตอบสำหรับการขยายขีดความสามารถโดยที่คุณเก็บค่าคงที่ # frames ที่ 100 แล้วปรับสัดส่วนเพื่อให้ frames = จำนวนกลุ่ม
chemdork123
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.