Grafico a dispersione con troppi punti


126

Sto cercando di tracciare due variabili in cui N = 700K. Il problema è che c'è troppa sovrapposizione, in modo che la trama diventi per lo più un solido blocco di nero. Esiste un modo per avere una "nuvola" in scala di grigi in cui l'oscurità della trama è una funzione del numero di punti in una regione? In altre parole, invece di mostrare singoli punti, voglio che la trama sia una "nuvola", con più il numero di punti in una regione, più scura è quella regione.


4
Sembra che tu stia cercando una mappa di calore

Risposte:


145

Un modo per gestirlo è la fusione alfa, che rende ciascun punto leggermente trasparente. Quindi le regioni appaiono più scure con più punti tracciati su di esse.

Questo è facile da fare in ggplot2:

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

inserisci qui la descrizione dell'immagine

Un altro modo conveniente per affrontare questo è (e probabilmente più appropriato per il numero di punti che hai) è il binning esagonale:

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

inserisci qui la descrizione dell'immagine

E c'è anche il vecchio binning rettangolare regolare (immagine omessa), che è più simile alla tua mappa di calore tradizionale:

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

1
Come posso cambiare i colori? Ora sto diventando blu su scala nera, mentre mi piacerebbe ottenere reg, scala blu verde.
user1007742

@ user1007742 Usa scale_fill_gradient()e specifica i tuoi colori bassi e alti, oppure usa scale_fill_brewer()e scegli da una delle tavolozze sequenziali.
joran,

@joran grazie, ora funziona. Che ne dici di cambiare il tipo / forma dei punti? Ottengo esagono o quadrato. Voglio solo punti semplici. Quando uso geom_point (), mi dà un errore.
user1007742

1
@ user1007742 Beh, si chiama "binning esagonale" per un motivo! ;) Non sta tramando "punti", sta dividendo l'intera regione in contenitori esagonali (o rettangolari) e quindi semplicemente colorando i contenitori in base a quanti punti ci sono in quel cestino. Quindi la risposta breve è "non puoi". Se vuoi forme diverse, devi usare geom_point()e tracciare ogni singolo punto.
joran,

Cosa succede se ho dati 3D?
skan

60

Puoi anche dare un'occhiata al ggsubplotpacchetto. Questo pacchetto implementa le funzionalità presentate da Hadley Wickham nel 2011 ( http://blog.revolutionanalytics.com/2011/10/ggplot2-for-big-data.html ).

(Di seguito, includo il giocatore "punti" a scopo illustrativo.)

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)

inserisci qui la descrizione dell'immagine

Tuttavia, questa funzionalità oscilla se hai una terza variabile da controllare.

# 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)  

inserisci qui la descrizione dell'immagine

O un altro approccio sarebbe quello di usare smoothScatter():

smoothScatter(dat[2:3])

inserisci qui la descrizione dell'immagine


3
quella seconda trama è fantastica!
Ricardo Saporta,

Cosa succede se ho dati 3D?
skan

2
@ skan: puoi aprire una nuova domanda per questo.
Maj

sfortunatamente il pacchetto ggsubplot non è più mantenuto e rimosso dal repository cran ... conosci un pacchetto alternativo che potrebbe essere usato per generare grafici come i primi due sopra?
dieHellste,

Se si utilizza una vecchia versione di R & ggplot2, si dovrebbe essere in grado di farlo funzionare
majom

59

Una panoramica di diverse buone opzioni in ggplot2:

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

Opzione A: punti trasparenti

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

Opzione B: aggiungere contorni di densità

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

Opzione C: aggiungere contorni di densità riempiti

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

Opzione D: mappa termica della densità

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')

Opzione E: hexbins

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

Opzione F: tappeti

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

Combina in una sola figura:

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

inserisci qui la descrizione dell'immagine


1
Questa è una risposta molto ben strutturata che penso meriti un po 'più di voti positivi.
Lalochezia,

Mi dà un errore Errore in scale_fill_viridis_c (): impossibile trovare la funzione "scale_fill_viridis_c"
JustGettin Data di inizio

ggplot2 aggiornato, ggplot2 reinstallato e ggplot2 ricaricato. Non ha riparato l'errore. Pacchetto 'viridis' installato separatamente e che mi permette di usare la funzione 'scale_fill_viridis' ma non la funzione 'scale_fill_viridis_c' che dà ancora lo stesso errore
JustGettinStarted

oh ti credo. Nessun problema lì. Sto solo cercando di arrivare alla fine dell'errore.
JustGettin è partito il

51

La fusione alfa è facile anche con la grafica di base.

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

I primi sei numeri dopo il #sono il colore in esadecimale RGB e gli ultimi due sono l'opacità, sempre in esadecimale, quindi 33 ~ 3 / sedicesimo opaco.

inserisci qui la descrizione dell'immagine


20
Solo per aggiungere un po 'di contesto, "# 000000" è il colore nero e "33" aggiunto alla fine del colore è il grado di opacità --- qui, 33%.
Charlie,

Grazie per la spiegazione aggiunta.
Aaron ha lasciato Stack Overflow l'

Ha perfettamente senso. Grazie, sia Aaron che Charlie.
user702432,

12
Nota minore; i numeri sono in esadecimale, quindi 33 è in realtà 3/16 opaco.
Aaron ha lasciato Stack Overflow il

45

Puoi anche usare le curve di livello ( ggplot2):

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

inserisci qui la descrizione dell'immagine

Oppure combina i contorni della densità con la fusione alfa:

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

inserisci qui la descrizione dell'immagine


29

Potrebbe esserti utile il hexbinpacchetto. Dalla pagina di aiuto di 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 è la mia soluzione preferita: può richiedere un gran numero di punti e quindi creare in modo sicuro un diagramma. Non sono sicuro che gli altri non provino a produrre una trama, ma semplicemente ombreggiano le cose in modo diverso ex post.
Iteratore,

Qualcosa come hexbin per i dati 3D?
skan

8

geom_pointdenistydal ggpointdensitypacchetto (recentemente sviluppato da Lukas Kremer e Simon Anders (2019)) consente di visualizzare la densità e i singoli punti dati allo stesso tempo:

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

Il mio metodo preferito per tracciare questo tipo di dati è quello descritto in questa domanda : un diagramma a densità di dispersione . L'idea è di fare un diagramma a dispersione ma di colorare i punti in base alla loro densità (approssimativamente parlando, la quantità di sovrapposizione in quell'area).

Allo stesso tempo:

  • mostra chiaramente la posizione dei valori anomali e
  • rivela qualsiasi struttura nell'area densa della trama.

Ecco il risultato dalla risposta in alto alla domanda collegata:

grafico a densità di dispersione


1
Anche questo è il mio modo preferito. Vedi la mia risposta per come raggiungere questo obiettivo R.
Jan-Glx,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.