Diagrama de dispersión con demasiados puntos

126

Estoy tratando de trazar dos variables donde N = 700K. El problema es que hay demasiada superposición, por lo que la trama se convierte principalmente en un bloque sólido de negro. ¿Hay alguna forma de tener una "nube" en escala de grises donde la oscuridad de la trama sea una función del número de puntos en una región? En otras palabras, en lugar de mostrar puntos individuales, quiero que la trama sea una "nube", cuanto mayor sea el número de puntos en una región, más oscura será esa región.

usuario702432
fuente
44
Parece que estás buscando un mapa de calor: flowdata.com/2010/01/21/…

Respuestas:

145

Una forma de lidiar con esto es con la mezcla alfa, que hace que cada punto sea ligeramente transparente. Entonces las regiones aparecen más oscuras que tienen más puntos trazados en ellas.

Esto es fácil de hacer en ggplot2:

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

ingrese la descripción de la imagen aquí

Otra forma conveniente de lidiar con esto es (y probablemente más apropiada para la cantidad de puntos que tiene) es el binning hexagonal:

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

ingrese la descripción de la imagen aquí

Y también hay un binning rectangular antiguo normal (imagen omitida), que se parece más a su mapa de calor tradicional:

ggplot(df,aes(x=x,y=y)) + geom_bin2d()
joran
fuente
1
¿Como puedo cambiar los colores? Ahora estoy obteniendo una escala de azul a negro, mientras que me gustaría obtener una escala azul verde.
user1007742
@ user1007742 Use scale_fill_gradient()y especifique sus propios colores bajos y altos, o use scale_fill_brewer()y elija una de las paletas secuenciales.
joran
@joran gracias, eso está funcionando ahora. ¿Qué tal cambiar el tipo / forma de los puntos? Obtengo hexágono o cuadrado. Solo quiero puntos simples. Cuando uso geom_point (), me da un error.
user1007742
1
@ user1007742 Bueno, se llama "binning hexagonal" por una razón. ;) No está trazando "puntos", está dividiendo toda la región en contenedores hexagonales (o rectangulares) y luego simplemente coloreando los contenedores en función de cuántos puntos hay en ese contenedor. Entonces la respuesta corta es "no puedes". Si desea diferentes formas, debe usar geom_point()y trazar cada punto individual.
joran
¿Qué pasa si tengo datos 3D?
skan
60

También puedes echar un vistazo al ggsubplotpaquete. Este paquete implementa características que fueron presentadas por Hadley Wickham en 2011 ( http://blog.revolutionanalytics.com/2011/10/ggplot2-for-big-data.html ).

(A continuación, incluyo la capa de "puntos" con fines ilustrativos).

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)

ingrese la descripción de la imagen aquí

Sin embargo, esto presenta rocas si tiene una tercera variable para controlar.

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

ingrese la descripción de la imagen aquí

O otro enfoque sería usar smoothScatter():

smoothScatter(dat[2:3])

ingrese la descripción de la imagen aquí

majom
fuente
3
esa segunda trama es genial!
Ricardo Saporta
¿Qué pasa si tengo datos 3D?
skan
2
@ skan: puede abrir una nueva pregunta para eso.
majom
desafortunadamente, el paquete ggsubplot ya no se mantiene y se elimina del repositorio de cran ... ¿conoce un paquete alternativo que pueda usarse para generar tramas como los dos primeros anteriores?
dieHellste
Si usa una versión anterior de R & ggplot2, debería poder hacerlo funcionar
majom
59

Una descripción general de varias buenas opciones en ggplot2:

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

Opción A: puntos transparentes

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

Opción B: agregar contornos de densidad

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

Opción C: agregar contornos de densidad rellenos

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

Opción D: mapa de calor de densidad

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

Opción E: hexbins

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

Opción F: alfombras

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

Combina en una figura:

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

ingrese la descripción de la imagen aquí

Axeman
fuente
1
Esta es una respuesta muy bien presentada que creo que merece un poco más de votos positivos.
Lalochezia
Me da un error Error en scale_fill_viridis_c (): no se pudo encontrar la función "scale_fill_viridis_c"
JustGettin Comenzó el
ggplot2 actualizado, reinstalado ggplot2 y recargado ggplot2. No solucionó el error. Paquete 'viridis' instalado por separado y que me permite usar la función 'scale_fill_viridis' pero no la función 'scale_fill_viridis_c' que todavía da el mismo error
JustGettin comenzó el
oh te creo No hay problemas allí. Solo trato de llegar al fondo del error.
JustGettin Comenzó el
51

La combinación alfa también es fácil de hacer con gráficos base.

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

Los primeros seis números después del #son el color en hexadecimal RGB y los dos últimos son la opacidad, nuevamente en hexadecimal, por lo que 33 ~ 3/16 opaco.

ingrese la descripción de la imagen aquí

Aaron dejó Stack Overflow
fuente
20
Solo para agregar un poco de contexto, "# 000000" es el color negro y el "33" agregado al final del color es el grado de opacidad --- aquí, 33%.
Charlie
Gracias por la explicación agregada.
Aaron dejó Stack Overflow el
Tiene mucho sentido. Gracias, Aaron y Charlie.
user702432
12
Nota menor; los números están en hexadecimal, por lo que 33 es en realidad 3/16 opaco.
Aaron dejó Stack Overflow el
45

También puede usar líneas de contorno de densidad ( ggplot2):

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

ingrese la descripción de la imagen aquí

O combine contornos de densidad con mezcla alfa:

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

ingrese la descripción de la imagen aquí

ROLO
fuente
29

Puede encontrar útil el hexbinpaquete. Desde la página de ayuda de 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

Oscar Perpiñán
fuente
+1 hexbin es mi solución preferida: puede tomar una gran cantidad de puntos y luego crear un gráfico de forma segura. No estoy seguro de que los demás no intenten producir una trama, sino que simplemente sombreen las cosas de manera diferente ex post.
Iterator
¿Algo como hexbin para datos 3D?
skan
8

geom_pointdenistydel ggpointdensitypaquete (desarrollado recientemente por Lukas Kremer y Simon Anders (2019)) le permite visualizar la densidad y los puntos de datos individuales al mismo tiempo:

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

jan-glx
fuente
2

Mi método favorito para trazar este tipo de datos es el que se describe en esta pregunta : un diagrama de densidad de dispersión . La idea es hacer un diagrama de dispersión pero colorear los puntos por su densidad (en términos generales, la cantidad de superposición en esa área).

Simultáneamente:

  • muestra claramente la ubicación de los valores atípicos, y
  • revela cualquier estructura en el área densa de la trama.

Aquí está el resultado de la respuesta principal a la pregunta vinculada:

diagrama de densidad de dispersión

Stephen McAteer
fuente
1
Esta es mi forma favorita también. Vea mi respuesta sobre cómo lograr esto en R.
Jan-glx