Streudiagramm mit zu vielen Punkten

126

Ich versuche zwei Variablen mit N = 700K zu zeichnen. Das Problem ist, dass es zu viele Überlappungen gibt, so dass die Darstellung meist zu einem festen schwarzen Block wird. Gibt es eine Möglichkeit, eine Graustufen- "Wolke" zu haben, bei der die Dunkelheit des Diagramms von der Anzahl der Punkte in einer Region abhängt? Mit anderen Worten, anstatt einzelne Punkte anzuzeigen, möchte ich, dass das Diagramm eine "Wolke" ist. Je mehr Punkte in einer Region vorhanden sind, desto dunkler ist diese Region.

user702432
quelle
4
Es hört sich so an, als ob Sie nach einer Heatmap suchen: flowingdata.com/2010/01/21/…

Antworten:

145

Eine Möglichkeit, damit umzugehen, ist das Alpha-Blending, wodurch jeder Punkt leicht transparent wird. So erscheinen Regionen dunkler, auf denen mehr Punkte eingezeichnet sind.

Dies ist einfach zu tun in ggplot2:

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

Geben Sie hier die Bildbeschreibung ein

Ein weiterer bequemer Weg, um damit umzugehen, ist (und wahrscheinlich besser geeignet für die Anzahl der Punkte, die Sie haben) das hexagonale Binning:

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

Geben Sie hier die Bildbeschreibung ein

Und es gibt auch regelmäßige alte rechteckige Binning (Bild weggelassen), die eher Ihrer traditionellen Heatmap ähneln:

ggplot(df,aes(x=x,y=y)) + geom_bin2d()
Joran
quelle
1
Wie kann ich die Farben ändern? Ich bekomme jetzt blaue bis schwarze Skala, während ich reg, grüne blaue Skala erhalten möchte.
user1007742
@ user1007742 Verwenden scale_fill_gradient()und spezifizieren Sie Ihre eigenen niedrigen und hohen Farben oder verwenden scale_fill_brewer()Sie eine der aufeinander folgenden Paletten und wählen Sie sie aus.
Joran
@joran danke, das funktioniert jetzt. Wie wäre es mit einer Änderung der Art / Form der Punkte? Ich bekomme entweder Sechseck oder Quadrat. Ich möchte nur einfache Punkte. Wenn ich geom_point () benutze, gibt es mir einen Fehler.
user1007742
1
@ user1007742 Nun, es heißt aus einem bestimmten Grund "hexagonales Binning"! ;) Es werden keine "Punkte" gezeichnet, sondern der gesamte Bereich in sechseckige (oder rechteckige) Behälter unterteilt und die Behälter dann einfach basierend auf der Anzahl der Punkte in diesem Behälter eingefärbt. Die kurze Antwort lautet also "Sie können nicht". Wenn Sie unterschiedliche Formen wünschen, müssen Sie geom_point()jeden einzelnen Punkt verwenden und zeichnen.
Joran
Was ist, wenn ich 3D-Daten habe?
Skan
60

Sie können sich auch das ggsubplotPaket ansehen . Dieses Paket implementiert Funktionen, die Hadley Wickham bereits 2011 vorgestellt hat ( http://blog.revolutionanalytics.com/2011/10/ggplot2-for-big-data.html ).

(Im Folgenden füge ich zur Veranschaulichung die "Punkte" -Schicht hinzu.)

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)

Geben Sie hier die Bildbeschreibung ein

Dies funktioniert jedoch, wenn Sie eine dritte Variable steuern müssen.

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

Geben Sie hier die Bildbeschreibung ein

Oder ein anderer Ansatz wäre smoothScatter():

smoothScatter(dat[2:3])

Geben Sie hier die Bildbeschreibung ein

Majom
quelle
3
Diese zweite Handlung ist großartig!
Ricardo Saporta
Was ist, wenn ich 3D-Daten habe?
Skan
2
@ skan: Dafür kannst du eine neue Frage öffnen.
Majom
Leider wird das Paket ggsubplot nicht mehr gewartet und aus dem Cran Repo entfernt. Kennen Sie ein alternatives Paket, mit dem Plots wie die ersten beiden oben erstellt werden können?
dieHellste
Wenn Sie eine alte Version von R & ggplot2 verwenden, sollten Sie in der Lage sein, sie zum
Laufen
59

Eine Übersicht über einige gute Optionen in ggplot2:

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

Option A: transparente Punkte

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

Option B: Dichtekonturen hinzufügen

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

Option C: Konturen mit gefüllter Dichte hinzufügen

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: Dichte-Heatmap

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: Teppiche

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

Kombinieren Sie in einer Figur:

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

Geben Sie hier die Bildbeschreibung ein

Axeman
quelle
1
Dies ist eine sehr übersichtliche Antwort, die meiner Meinung nach etwas mehr Stimmen verdient.
Lalochezia
Gibt mir einen Fehler Fehler in scale_fill_viridis_c (): Funktion "scale_fill_viridis_c" konnte nicht gefunden werden
JustGettinStarted
ggplot2 aktualisiert, ggplot2 neu installiert und ggplot2 neu geladen. Der Fehler wurde nicht behoben. Separat installiertes 'viridis'-Paket, mit dem ich die Funktion' scale_fill_viridis 'verwenden kann, aber nicht die Funktion' scale_fill_viridis_c ', die immer noch den gleichen Fehler liefert
liefert JustGettinStarted
Oh, ich glaube dir. Keine Probleme da. Ich versuche nur, dem Fehler auf den Grund zu gehen.
JustGettinStarted
51

Alpha-Blending ist auch mit Basisgrafiken einfach durchzuführen.

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

Die ersten sechs Zahlen nach #sind die Farbe in RGB hex und die letzten beiden sind die Deckkraft, wiederum in hex, also 33 ~ 3/16 undurchsichtig.

Geben Sie hier die Bildbeschreibung ein

Aaron verließ Stack Overflow
quelle
20
Um ein wenig Kontext hinzuzufügen, ist "# 000000" die Farbe Schwarz und "33" am Ende der Farbe der Grad der Deckkraft - hier 33%.
Charlie
Danke für die zusätzliche Erklärung.
Aaron verließ Stack Overflow
Macht perfekt Sinn. Danke, sowohl Aaron als auch Charlie.
user702432
12
Kleinere Anmerkung; Die Zahlen sind hexadezimal, also ist 33 tatsächlich 3/16 undurchsichtig.
Aaron verließ Stack Overflow
45

Sie können auch Dichtekonturlinien ( ggplot2) verwenden:

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

Geben Sie hier die Bildbeschreibung ein

Oder kombinieren Sie Dichtekonturen mit Alpha-Blending:

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

Geben Sie hier die Bildbeschreibung ein

ROLO
quelle
29

Möglicherweise finden Sie das hexbinPaket nützlich . Von der Hilfeseite von 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
quelle
+1 Hexbin ist meine bevorzugte Lösung - es kann eine große Anzahl von Punkten benötigen und dann sicher ein Diagramm erstellen. Ich bin mir nicht sicher, ob die anderen nicht versuchen werden, eine Handlung zu produzieren, sondern die Dinge einfach nachträglich anders beschatten.
Iterator
Etwas wie Hexbin für 3D-Daten?
Skan
8

geom_pointdenistyMit dem ggpointdensityPaket (kürzlich von Lukas Kremer und Simon Anders (2019) entwickelt) können Sie Dichte und einzelne Datenpunkte gleichzeitig visualisieren:

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
quelle
2

Meine bevorzugte Methode zum Zeichnen dieser Art von Daten ist die in dieser Frage beschriebene - ein Streudichtediagramm . Die Idee ist, ein Streudiagramm zu erstellen, aber die Punkte nach ihrer Dichte zu färben (grob gesagt, das Ausmaß der Überlappung in diesem Bereich).

Es gleichzeitig:

  • zeigt deutlich die Position der Ausreißer und
  • zeigt jede Struktur im dichten Bereich des Grundstücks.

Hier ist das Ergebnis der Top-Antwort auf die verknüpfte Frage:

Streudichtediagramm

Stephen McAteer
quelle
1
Dies ist auch mein Lieblingsweg. Siehe meine Antwort, wie dies erreicht werden kann R.
Jan-Glx