Nuage de points avec trop de points

126

J'essaye de tracer deux variables où N = 700K. Le problème est qu'il y a trop de chevauchement, de sorte que l'intrigue devient principalement un bloc solide de noir. Existe-t-il un moyen d'avoir un "nuage" en niveaux de gris où l'obscurité du tracé est fonction du nombre de points dans une région? En d'autres termes, au lieu d'afficher des points individuels, je veux que le tracé soit un "nuage", avec plus il y a de points dans une région, plus cette région est sombre.

utilisateur702432
la source
4
On dirait que vous cherchez une carte thermique

Réponses:

145

Une façon de résoudre ce problème est d'utiliser le mélange alpha, qui rend chaque point légèrement transparent. Ainsi, les régions apparaissent plus sombres sur lesquelles plus de points sont tracés.

C'est facile à faire dans ggplot2:

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

entrez la description de l'image ici

Un autre moyen pratique de gérer cela est (et probablement plus approprié pour le nombre de points que vous avez) est le regroupement hexagonal:

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

entrez la description de l'image ici

Et il y a aussi un ancien binning rectangulaire régulier (image omise), qui ressemble plus à votre carte thermique traditionnelle:

ggplot(df,aes(x=x,y=y)) + geom_bin2d()
joran
la source
1
Comment puis-je changer les couleurs? J'obtiens maintenant une échelle bleue à noire, alors que je voudrais obtenir une échelle bleue verte et verte.
user1007742
@ user1007742 Utilisez scale_fill_gradient()et spécifiez vos propres couleurs basses et hautes, ou utilisez scale_fill_brewer()et choisissez parmi l'une des palettes séquentielles.
joran
@joran merci, cela fonctionne maintenant. Que diriez-vous de changer le type / la forme des points? J'obtiens soit un hexagone, soit un carré. Je veux juste des points simples. Quand j'utilise geom_point (), cela me donne une erreur.
user1007742
1
@ user1007742 Eh bien, ça s'appelle "binning hexagonal" pour une raison! ;) Il ne trace pas des «points», il divise la région entière en cases hexagonales (ou rectangulaires) et ensuite simplement colorie les cases en fonction du nombre de points dans cette case. La réponse courte est donc "vous ne pouvez pas". Si vous voulez des formes différentes, vous devez utiliser geom_point()et tracer chaque point individuel.
joran
Et si j'ai des données 3D?
skan
60

Vous pouvez également consulter le ggsubplotpackage. Ce package implémente des fonctionnalités qui ont été présentées par Hadley Wickham en 2011 ( http://blog.revolutionanalytics.com/2011/10/ggplot2-for-big-data.html ).

(Dans ce qui suit, j'inclus la couche "points" à des fins d'illustration.)

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)

entrez la description de l'image ici

Cependant, cela fonctionne si vous avez une troisième variable à contrôler.

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

entrez la description de l'image ici

Ou une autre approche serait d'utiliser smoothScatter():

smoothScatter(dat[2:3])

entrez la description de l'image ici

majom
la source
3
ce deuxième complot est génial!
Ricardo Saporta
Et si j'ai des données 3D?
skan
2
@ skan: Vous pouvez ouvrir une nouvelle question pour cela.
majom
malheureusement le paquet ggsubplot n'est plus maintenu et retiré du repo cran ... connaissez-vous un autre paquetage qui pourrait être utilisé pour générer des graphiques comme les deux premiers ci-dessus?
dieHellste
Si vous utilisez une ancienne version de R & ggplot2, vous devriez pouvoir la faire fonctionner
majom
59

Un aperçu de plusieurs bonnes options dans ggplot2:

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

Option A: points transparents

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

Option B: ajouter des contours de densité

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

Option C: ajouter des contours de densité remplis

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

Option D: carte thermique de 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')

Option E: hexbins

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

Option F: tapis

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

Combinez en un seul chiffre:

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

entrez la description de l'image ici

Axeman
la source
1
C'est une réponse très bien présentée qui, à mon avis, mérite un peu plus de votes favorables.
Lalochezia
Me donne une erreur Erreur dans scale_fill_viridis_c (): impossible de trouver la fonction "scale_fill_viridis_c"
JustGettinDu
mis à jour ggplot2, réinstallé ggplot2 et rechargé ggplot2. N'a pas corrigé l'erreur. Package 'viridis' installé séparément et qui me permet d'utiliser la fonction 'scale_fill_viridis' mais pas la fonction 'scale_fill_viridis_c' qui donne toujours la même erreur
JustGettinDébut le
oh je te crois. Aucun problème là-bas. J'essaie juste d'aller au fond de l'erreur.
JustGettinDu
51

Le mélange alpha est également facile à faire avec les graphiques de base.

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

Les six premiers chiffres après le #sont la couleur en hexadécimal RVB et les deux derniers sont l'opacité, encore une fois en hexadécimal, donc 33 ~ 3 / 16ème opaque.

entrez la description de l'image ici

Aaron a quitté le débordement de pile
la source
20
Juste pour ajouter un peu de contexte, "# 000000" est la couleur noire et le "33" ajouté à la fin de la couleur est le degré d'opacité --- ici, 33%.
Charlie
Merci pour l'explication supplémentaire.
Aaron a quitté Stack Overflow
Cela a du sens. Merci, Aaron et Charlie.
user702432
12
Note mineure; les nombres sont en hexadécimal donc 33 est en fait opaque aux 3/16.
Aaron a quitté Stack Overflow
45

Vous pouvez également utiliser des courbes de niveau de densité ( ggplot2):

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

entrez la description de l'image ici

Ou combinez les contours de densité avec le mélange alpha:

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

entrez la description de l'image ici

ROLO
la source
29

Vous pouvez trouver utile le hexbinpackage. Depuis la page d'aide 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
la source
+1 hexbin est ma solution préférée - cela peut prendre un grand nombre de points, puis créer un tracé en toute sécurité. Je ne suis pas sûr que les autres n'essaieront pas de produire une intrigue, mais simplement nuancer les choses différemment ex post.
Iterator
Quelque chose comme hexbin pour les données 3D?
skan
8

geom_pointdenistydu ggpointdensitypackage (récemment développé par Lukas Kremer et Simon Anders (2019)) vous permet de visualiser la densité et les points de données individuels en même temps:

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
la source
2

Ma méthode préférée pour tracer ce type de données est celle décrite dans cette question - un diagramme de densité de dispersion . L'idée est de faire un nuage de points mais de colorer les points par leur densité (grosso modo, la quantité de chevauchement dans cette zone).

Il simultanément:

  • indique clairement l'emplacement des valeurs aberrantes, et
  • révèle toute structure dans la zone dense de la parcelle.

Voici le résultat de la première réponse à la question liée:

diagramme de densité de dispersion

Stephen McAteer
la source
1
C'est aussi ma manière préférée. Voir ma réponse pour savoir comment y parvenir R.
jan-glx