Gráfico de dispersão com muitos pontos

126

Estou tentando plotar duas variáveis ​​em que N = 700K. O problema é que há muita sobreposição, de modo que a trama se torna principalmente um sólido bloco de preto. Existe alguma maneira de ter uma "nuvem" em escala de cinza em que a escuridão da trama é uma função do número de pontos em uma região? Em outras palavras, em vez de mostrar pontos individuais, quero que o gráfico seja uma "nuvem", com o número de pontos em uma região, mais escura será a região.

user702432
fonte
4
Parece que você está procurando um mapa de calor: flowdata.com/2010/01/21/…

Respostas:

145

Uma maneira de lidar com isso é com a mistura alfa, que torna cada ponto um pouco transparente. Portanto, as regiões parecem mais escuras e com mais pontos traçados nelas.

Isso é fácil de fazer em ggplot2:

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

insira a descrição da imagem aqui

Outra maneira conveniente de lidar com isso é (e provavelmente mais apropriado para o número de pontos que você possui) é o bin hexagonal:

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

insira a descrição da imagem aqui

E também há binning retangular antigo regular (imagem omitida), que é mais parecido com o seu mapa de calor tradicional:

ggplot(df,aes(x=x,y=y)) + geom_bin2d()
joran
fonte
1
Como posso mudar as cores? Agora estou ficando azul para preto, enquanto eu gostaria de obter reg, verde azul escala.
user1007742
@ user1007742 Use scale_fill_gradient()e especifique suas próprias cores baixa e alta, ou use scale_fill_brewer()e escolha uma das paletas seqüenciais.
joran
@ obrigado obrigado, isso está funcionando agora. Que tal mudar o tipo / forma dos pontos? Eu recebo hexágono ou quadrado. Eu só quero pontos simples. Quando eu uso geom_point (), isso me dá erro.
user1007742
1
@ user1007742 Bem, é chamado de "compartimento hexagonal" por um motivo! ;) Não está plotando "pontos", está dividindo toda a região em compartimentos hexagonais (ou retangulares) e, em seguida, simplesmente colorindo os compartimentos com base em quantos pontos existem nesse compartimento. Portanto, a resposta curta é "você não pode". Se você quiser formas diferentes, precisará usar geom_point()e plotar cada ponto individual.
joran
E se eu tiver dados 3D?
skan
60

Você também pode dar uma olhada no ggsubplotpacote. Este pacote implementa os recursos apresentados por Hadley Wickham em 2011 ( http://blog.revolutionanalytics.com/2011/10/ggplot2-for-big-data.html ).

(A seguir, incluo a camada "points" para fins de ilustração.)

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)

insira a descrição da imagem aqui

No entanto, esse recurso é ótimo se você tiver uma terceira variável 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)  

insira a descrição da imagem aqui

Ou outra abordagem seria usar smoothScatter():

smoothScatter(dat[2:3])

insira a descrição da imagem aqui

majom
fonte
3
esse segundo enredo é ótimo!
Ricardo Saporta
E se eu tiver dados 3D?
skan
2
@ skan: Você pode abrir uma nova pergunta para isso.
majom
infelizmente, o pacote ggsubplot não é mais mantido e removido do repositório do cran ... você conhece um pacote alternativo que poderia ser usado para gerar gráficos como os dois primeiros acima?
dieHellste
Se você usar uma versão antiga do R & ggplot2, você deve ser capaz de fazê-lo funcionar
majom
59

Uma visão geral de várias boas opções em ggplot2:

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

Opção A: pontos transparentes

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

Opção B: adicione contornos de densidade

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

Opção C: adicione contornos de densidade preenchidos

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

Opção D: mapa de calor de densidade

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

Opção E: hexbins

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

Opção F: tapetes

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

Combine em uma figura:

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

insira a descrição da imagem aqui

Axeman
fonte
1
Esta é uma resposta muito bem definida que eu acho que merece um pouco mais de votos.
Lalochezia 26/03
Dá-me um erro Erro em scale_fill_viridis_c (): não foi possível encontrar a função "scale_fill_viridis_c"
JustGettinStarted
atualizado ggplot2, reinstalado o ggplot2 e recarregado o ggplot2. Não corrigiu o erro. Pacote 'viridis' instalado separadamente e que me permita usar a função 'scale_fill_viridis', mas não a função 'scale_fill_viridis_c' que ainda dá o mesmo erro
JustGettinStarted
oh eu acredito em você. Não há problemas lá. Apenas tentando chegar ao fundo do erro.
usar o seguinte código
51

A mistura alfa também é fácil com os gráficos básicos.

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

Os seis primeiros números após o #são a cor em hexadecimal RGB e os dois últimos são a opacidade, novamente em hexadecimal, de modo 33 a 3 / 16º opaco.

insira a descrição da imagem aqui

Aaron deixou Stack Overflow
fonte
20
Apenas para adicionar um pouco de contexto, "# 000000" é a cor preta e o "33" adicionado ao final da cor é o grau de opacidade --- aqui, 33%.
Charlie
Obrigado pela explicação adicionada.
Aaron saiu de Stack Overflow
Faz todo o sentido. Obrigado, Aaron e Charlie.
user702432
12
Nota menor; os números estão em hexadecimal, então 33 é na verdade 1/16 de opaco.
Aaron saiu de Stack Overflow
45

Você também pode usar linhas de contorno de densidade ( ggplot2):

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

insira a descrição da imagem aqui

Ou combine contornos de densidade com mistura alfa:

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

insira a descrição da imagem aqui

ROLO
fonte
29

Você pode achar útil o hexbinpacote. Na página de ajuda 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
fonte
O hexbin com +1 é minha solução preferida - ele pode levar um grande número de pontos e criar um gráfico com segurança. Não tenho certeza de que os outros não tentem produzir um enredo, mas simplesmente sombreie as coisas de maneira diferente ex post.
Iterator
Algo como hexbin para dados 3D?
skan
8

geom_pointdenistydo ggpointdensitypacote (desenvolvido recentemente por Lukas Kremer e Simon Anders (2019)) permite visualizar a densidade e os pontos de dados individuais ao mesmo 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()

jan-glx
fonte
2

Meu método favorito para plotar esse tipo de dados é o descrito nesta pergunta - um gráfico de densidade de dispersão . A idéia é fazer um gráfico de dispersão, mas colorir os pontos de acordo com sua densidade (grosso modo, a quantidade de sobreposição nessa área).

Simultaneamente:

  • mostra claramente a localização dos outliers e
  • revela qualquer estrutura na área densa da trama.

Aqui está o resultado da resposta principal à pergunta vinculada:

gráfico de densidade de dispersão

Stephen McAteer
fonte
1
Esta é a minha maneira favorita também. Veja minha resposta sobre como conseguir isso em R.
jan-GLX