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.


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

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


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


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


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


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


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


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


1
Esta é a minha maneira favorita também. Veja minha resposta sobre como conseguir isso em R.
jan-GLX
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.