Scatterplot ที่มีจุดมากเกินไป


126

ฉันพยายามพล็อตตัวแปรสองตัวโดยที่ N = 700K ปัญหาคือมีการทับซ้อนกันมากเกินไปจนพล็อตส่วนใหญ่กลายเป็นบล็อกสีดำทึบ มีวิธีใดบ้างในการมี "เมฆ" ระดับสีเทาที่ความมืดของพล็อตเป็นฟังก์ชันของจำนวนจุดในภูมิภาค กล่าวอีกนัยหนึ่งคือแทนที่จะแสดงจุดแต่ละจุดฉันต้องการให้พล็อตเป็น "เมฆ" ยิ่งมีจำนวนจุดในพื้นที่มากเท่าใดพื้นที่นั้นก็จะยิ่งมืดลง


4
ดูเหมือนว่าคุณกำลังมองหาแผนที่ความร้อน: flowdata.com/2010/01/21/…

คำตอบ:


145

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

ทำได้ง่ายในggplot2:

df <- data.frame(x = rnorm(5000),y=rnorm(5000))
ggplot(df,aes(x=x,y=y)) + geom_point(alpha = 0.3)

ใส่คำอธิบายภาพที่นี่

อีกวิธีที่สะดวกในการจัดการกับปัญหานี้คือ (และน่าจะเหมาะสมกว่าสำหรับจำนวนจุดที่คุณมี) คือการเก็บขยะหกเหลี่ยม:

ggplot(df,aes(x=x,y=y)) + stat_binhex()

ใส่คำอธิบายภาพที่นี่

นอกจากนี้ยังมี binning สี่เหลี่ยมเก่า ๆ ปกติ (ละเว้นภาพ) ซึ่งคล้ายกับแผนที่ความร้อนแบบเดิมของคุณ:

ggplot(df,aes(x=x,y=y)) + geom_bin2d()

1
ฉันจะเปลี่ยนสีได้อย่างไร? ตอนนี้ฉันได้ระดับสีน้ำเงินเป็นสีดำในขณะที่ฉันต้องการได้ reg เป็นระดับสีเขียวสีน้ำเงิน
user1007742

@ user1007742 ใช้scale_fill_gradient()และระบุสีต่ำและสูงของคุณเองหรือใช้scale_fill_brewer()และเลือกจากหนึ่งในจานสีตามลำดับ
joran

@joran ขอบคุณที่ทำงานตอนนี้ วิธีการเปลี่ยนประเภท / รูปร่างของจุด? ฉันได้รับทั้งหกเหลี่ยมหรือสี่เหลี่ยม ฉันต้องการแค่จุดง่ายๆ เมื่อฉันใช้ geom_point () มันทำให้ฉันมีข้อผิดพลาด
user1007742

1
@ user1007742 อืมมันเรียกว่า "hexagonal binning" ด้วยเหตุผล! ;) ไม่ใช่การพล็อต "จุด" แต่เป็นการแบ่งพื้นที่ทั้งหมดออกเป็นถังขยะหกเหลี่ยม (หรือสี่เหลี่ยม) จากนั้นก็ระบายสีถังขยะตามจำนวนจุดในถังนั้น ดังนั้นคำตอบสั้น ๆ คือ "คุณทำไม่ได้" หากคุณต้องการรูปทรงที่แตกต่างกันคุณต้องใช้geom_point()และลงจุดแต่ละจุด
joran

จะเกิดอะไรขึ้นถ้าฉันมีข้อมูล 3 มิติ
กัน

60

นอกจากนี้คุณยังสามารถดูggsubplotแพ็คเกจ แพ็คเกจนี้ใช้คุณสมบัติที่ Hadley Wickham นำเสนอในปี 2011 ( http://blog.revolutionanalytics.com/2011/10/ggplot2-for-big-data.html )

(ต่อไปนี้ฉันจะรวม - ชั้นวาง "คะแนน" เพื่อจุดประสงค์ในการอธิบาย)

library(ggplot2)
library(ggsubplot)

# Make up some data
set.seed(955)
dat <- data.frame(cond = rep(c("A", "B"), each=5000),
                  xvar = c(rep(1:20,250) + rnorm(5000,sd=5),rep(16:35,250) + rnorm(5000,sd=5)),
                  yvar = c(rep(1:20,250) + rnorm(5000,sd=5),rep(16:35,250) + rnorm(5000,sd=5)))


# Scatterplot with subplots (simple)
ggplot(dat, aes(x=xvar, y=yvar)) +
  geom_point(shape=1) +
  geom_subplot2d(aes(xvar, yvar,
                     subplot = geom_bar(aes(rep("dummy", length(xvar)), ..count..))), bins = c(15,15), ref = NULL, width = rel(0.8), ply.aes = FALSE)

ใส่คำอธิบายภาพที่นี่

อย่างไรก็ตามสิ่งนี้มีลักษณะเป็นหินหากคุณมีตัวแปรที่สามให้ควบคุม

# Scatterplot with subplots (including a third variable) 

ggplot(dat, aes(x=xvar, y=yvar)) +
  geom_point(shape=1, aes(color = factor(cond))) +
  geom_subplot2d(aes(xvar, yvar,
                     subplot = geom_bar(aes(cond, ..count.., fill = cond))),
                 bins = c(15,15), ref = NULL, width = rel(0.8), ply.aes = FALSE)  

ใส่คำอธิบายภาพที่นี่

หรือวิธีอื่นที่จะใช้smoothScatter():

smoothScatter(dat[2:3])

ใส่คำอธิบายภาพที่นี่


3
พล็อตที่สองนั้นยอดเยี่ยมมาก!
Ricardo Saporta

จะเกิดอะไรขึ้นถ้าฉันมีข้อมูล 3 มิติ
กัน

2
@ skan: คุณสามารถเปิดคำถามใหม่ได้

น่าเสียดายที่แพ็กเกจ ggsubplot ไม่ได้รับการบำรุงรักษาอีกต่อไปและถูกลบออกจาก cran repo ... คุณรู้หรือไม่ว่ามีแพ็คเกจทางเลือกที่สามารถใช้ในการสร้างพล็อตเหมือนสองตัวแรกข้างต้นได้หรือไม่?
dieHellste

ถ้าคุณใช้รุ่นเก่า R & ggplot2 คุณควรจะสามารถที่จะได้รับมันทำงาน
majom

59

ภาพรวมของตัวเลือกที่ดีมากมายในggplot2:

library(ggplot2)
x <- rnorm(n = 10000)
y <- rnorm(n = 10000, sd=2) + x
df <- data.frame(x, y)

ตัวเลือก A: จุดโปร่งใส

o1 <- ggplot(df, aes(x, y)) +
  geom_point(alpha = 0.05)

ตัวเลือก B: เพิ่มรูปทรงความหนาแน่น

o2 <- ggplot(df, aes(x, y)) +
  geom_point(alpha = 0.05) +
  geom_density_2d()

ตัวเลือก C: เพิ่มรูปทรงความหนาแน่นที่เติม

o3 <- ggplot(df, aes(x, y)) +
  stat_density_2d(aes(fill = stat(level)), geom = 'polygon') +
  scale_fill_viridis_c(name = "density") +
  geom_point(shape = '.')

ตัวเลือก D: แผนที่ความหนาแน่นของความหนาแน่น

o4 <- ggplot(df, aes(x, y)) +
  stat_density_2d(aes(fill = stat(density)), geom = 'raster', contour = FALSE) +       
  scale_fill_viridis_c() +
  coord_cartesian(expand = FALSE) +
  geom_point(shape = '.', col = 'white')

ตัวเลือก E: hexbins

o5 <- ggplot(df, aes(x, y)) +
  geom_hex() +
  scale_fill_viridis_c() +
  geom_point(shape = '.', col = 'white')

ตัวเลือก F: พรม

o6 <- ggplot(df, aes(x, y)) +
  geom_point(alpha = 0.1) +
  geom_rug(alpha = 0.01)

รวมเป็นรูปเดียว:

cowplot::plot_grid(
  o1, o2, o3, o4, o5, o6,
  ncol = 2, labels = 'AUTO', align = 'v', axis = 'lr'
)

ใส่คำอธิบายภาพที่นี่


1
นี่เป็นคำตอบที่วางไว้อย่างดีซึ่งฉันคิดว่าสมควรได้รับการโหวตเพิ่มขึ้นเล็กน้อย
Lalochezia

ทำให้ฉันเกิดข้อผิดพลาดใน scale_fill_viridis_c (): ไม่พบฟังก์ชัน "scale_fill_viridis_c"
JustGettin เริ่ม

อัปเดต ggplot2 ติดตั้ง ggplot2 ใหม่และโหลดใหม่ ggplot2 ไม่ได้แก้ไขข้อผิดพลาด แพ็คเกจ 'viridis' ที่ติดตั้งแยกต่างหากและให้ฉันใช้ฟังก์ชัน 'scale_fill_viridis' แต่ไม่ใช่ฟังก์ชัน 'scale_fill_viridis_c' ซึ่งยังคงให้ข้อผิดพลาดเหมือนเดิม
JustGettin เริ่ม

โอ้ฉันเชื่อคุณ ไม่มีปัญหา เพียงแค่พยายามไปที่ด้านล่างของข้อผิดพลาด
JustGettin เริ่ม

51

การผสมอัลฟ่าทำได้ง่ายด้วยกราฟิกพื้นฐานเช่นกัน

df <- data.frame(x = rnorm(5000),y=rnorm(5000))
with(df, plot(x, y, col="#00000033"))

ตัวเลขหกตัวแรกหลัง#เป็นสีใน RGB hex และสองตัวสุดท้ายคือความทึบอีกครั้งเป็นเลขฐานสิบหกดังนั้นจึงทึบแสง 33 ~ 3 / 16th

ใส่คำอธิบายภาพที่นี่


20
เพียงเพื่อเพิ่มบริบทเล็กน้อย "# 000000" คือสีดำและ "33" ที่ต่อท้ายสีคือระดับความทึบ --- ที่นี่ 33%
Charlie

ขอบคุณสำหรับคำอธิบายเพิ่มเติม
แอรอนออกจาก Stack Overflow

ทำให้รู้สึกสมบูรณ์แบบ ขอบคุณทั้งแอรอนและชาร์ลี
user702432

12
หมายเหตุเล็กน้อย; ตัวเลขอยู่ในฐานสิบหกดังนั้น 33 จึงเป็นทึบแสง 3/16
Aaron ออกจาก Stack Overflow

45

คุณยังสามารถใช้เส้นชั้นความหนาแน่น ( ggplot2):

df <- data.frame(x = rnorm(15000),y=rnorm(15000))
ggplot(df,aes(x=x,y=y)) + geom_point() + geom_density2d()

ใส่คำอธิบายภาพที่นี่

หรือรวมรูปทรงความหนาแน่นด้วยการผสมอัลฟา:

ggplot(df,aes(x=x,y=y)) + 
    geom_point(colour="blue", alpha=0.2) + 
    geom_density2d(colour="black")

ใส่คำอธิบายภาพที่นี่


29

คุณอาจพบว่าhexbinแพ็คเกจมีประโยชน์ จากหน้าความช่วยเหลือของhexbinplot:

library(hexbin)
mixdata <- data.frame(x = c(rnorm(5000),rnorm(5000,4,1.5)),
                      y = c(rnorm(5000),rnorm(5000,2,3)),
                      a = gl(2, 5000))
hexbinplot(y ~ x | a, mixdata)

hexbinplot


+1 hexbin เป็นวิธีแก้ปัญหาที่ฉันต้องการ - อาจใช้ # จุดจำนวนมากจากนั้นจึงสร้างพล็อตอย่างปลอดภัย ฉันไม่แน่ใจว่าคนอื่น ๆ จะไม่พยายามสร้างพล็อต แต่เพียงแค่แรเงาสิ่งต่าง ๆ เช่นโพสต์
Iterator

อะไรเช่น hexbin สำหรับข้อมูล 3 มิติ?
กัน

8

geom_pointdenistyจากggpointdensityแพ็คเกจ (พัฒนาล่าสุดโดย Lukas Kremer และ Simon Anders (2019)) ช่วยให้คุณเห็นภาพความหนาแน่นและจุดข้อมูลแต่ละจุดในเวลาเดียวกัน:

library(ggplot2)
# install.packages("ggpointdensity")
library(ggpointdensity)

df <- data.frame(x = rnorm(5000), y = rnorm(5000))
ggplot(df, aes(x=x, y=y)) + geom_pointdensity() + scale_color_viridis_c()


2

วิธีการที่ชื่นชอบสำหรับการวางแผนข้อมูลประเภทนี้เป็นหนึ่งที่อธิบายไว้ในคำถามนี้ - เป็นพล็อตที่กระจายความหนาแน่น แนวคิดคือการทำ scatter-plot แต่ให้แต้มสีตามความหนาแน่น (พูดโดยประมาณคือจำนวนที่ทับซ้อนกันในพื้นที่นั้น)

พร้อมกัน:

  • แสดงตำแหน่งของค่าผิดปกติอย่างชัดเจนและ
  • เผยให้เห็นโครงสร้างใด ๆ ในพื้นที่หนาแน่นของพล็อต

นี่คือผลลัพธ์จากคำตอบยอดนิยมสำหรับคำถามที่เชื่อมโยง:

พล็อตความหนาแน่นกระจาย


1
นี่เป็นวิธีที่ฉันชอบด้วย ดูคำตอบของฉันสำหรับวิธีบรรลุเป้าหมายนี้ในR.
jan-glx
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.