Диаграмма рассеяния со слишком большим количеством точек

126

Я пытаюсь построить две переменные, где N = 700K. Проблема в том, что наложений слишком много, так что сюжет в основном становится сплошным черным блоком. Есть ли способ получить «облако» в градациях серого, где темнота графика зависит от количества точек в регионе? Другими словами, вместо того, чтобы показывать отдельные точки, я хочу, чтобы график был «облаком», и чем больше количество точек в области, тем темнее эта область.

user702432
источник
4
Похоже, вы ищете тепловую

Ответы:

145

Один из способов справиться с этим - альфа-смешивание, которое делает каждую точку слегка прозрачной. Таким образом, области кажутся более темными, на которых нанесено больше точек.

Это легко сделать в ggplot2:

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

введите описание изображения здесь

Другой удобный способ справиться с этим (и, вероятно, более подходящий для количества имеющихся у вас точек) - это шестиугольное бинирование:

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

введите описание изображения здесь

И есть также обычный старый прямоугольный биннинг (изображение опущено), который больше похож на вашу традиционную тепловую карту:

ggplot(df,aes(x=x,y=y)) + geom_bin2d()
Joran
источник
1
Как я могу изменить цвета? Теперь у меня шкала от синего до черного, тогда как я хотел бы получить шкалу рег, зеленый синий.
user1007742
@ user1007742 Используйте scale_fill_gradient()и укажите свои собственные низкие и высокие цвета или используйте scale_fill_brewer()и выберите одну из последовательных палитр.
Joran
@joran спасибо, теперь это работает. Как насчет изменения типа / формы точек? Получается либо шестиугольник, либо квадрат. Я просто хочу простые точки. Когда я использую geom_point (), это дает мне ошибку.
user1007742
1
@ user1007742 Ну, не зря это называется "шестиугольным биннингом"! ;) Он не отображает «точки», а делит всю область на шестиугольные (или прямоугольные) ячейки, а затем просто окрашивает ячейки в зависимости от того, сколько точек находится в этой ячейке. Итак, краткий ответ - «вы не можете». Если вам нужны разные формы, вы должны использовать geom_point()и нанести каждую отдельную точку.
Joran
Что делать, если у меня есть 3D-данные?
skan
60

Вы также можете посмотреть на ggsubplotупаковку. Этот пакет реализует функции, которые были представлены Хэдли Уикхэмом еще в 2011 году ( http://blog.revolutionanalytics.com/2011/10/ggplot2-for-big-data.html ).

(В дальнейшем я включаю слой «точек» для иллюстрации.)

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)

введите описание изображения здесь

Тем не менее, здесь есть проблемы, если у вас есть третья переменная, которую нужно контролировать.

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

введите описание изображения здесь

Или другой подход smoothScatter():

smoothScatter(dat[2:3])

введите описание изображения здесь

majom
источник
3
этот второй сюжет великолепен!
Рикардо Сапорта
Что делать, если у меня есть 3D-данные?
skan
2
@ skan: Для этого вы можете задать новый вопрос.
majom
к сожалению, пакет ggsubplot больше не поддерживается и удален из репозитория кранов ... знаете ли вы об альтернативном пакете, который можно было бы использовать для создания графиков, подобных первым двум выше?
dieHellste
Если вы используете старую версию R & ggplot2, вы сможете заставить ее работать
majom
59

Обзор нескольких хороших вариантов в ggplot2:

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

Вариант А: прозрачные точки

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

Вариант Б: добавить контуры плотности

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

Вариант C: добавить контуры плотности с заливкой

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

Вариант D: тепловая карта плотности

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

Вариант E: шестиугольники

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

Вариант F: коврики

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

Совместите в одной фигуре:

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

введите описание изображения здесь

лесоруб
источник
1
Это очень хорошо продуманный ответ, который, я думаю, заслуживает большего количества голосов.
Lalochezia
Выдает ошибку Ошибка в scale_fill_viridis_c (): не удалось найти функцию «scale_fill_viridis_c»
JustGettin запущен
обновил ggplot2, переустановил ggplot2 и перезагрузил ggplot2. Не исправил ошибку. Отдельно установленный пакет viridis, позволяющий использовать функцию scale_fill_viridis, но не функцию scale_fill_viridis_c, которая по-прежнему выдает ту же ошибку
JustGettinStarted
о, я тебе верю. Там нет проблем. Просто пытаюсь разобраться в ошибке.
JustGettinНачало
51

Альфа-смешивание легко выполняется и с базовой графикой.

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

Первые шесть чисел после #- это цвет в шестнадцатеричном формате RGB, а последние два - непрозрачность, опять же в шестнадцатеричном формате, поэтому 33 ~ 3/16 непрозрачности.

введите описание изображения здесь

Аарон покинул Stack Overflow
источник
20
Чтобы добавить немного контекста, «# 000000» - это черный цвет, а цифра «33», добавленная в конец цвета, - это степень непрозрачности - здесь 33%.
Чарли
Спасибо за добавленное объяснение.
Аарон покинул Stack Overflow
Имеет смысл. Спасибо, и Аарон, и Чарли.
user702432
12
Незначительное примечание; числа в шестнадцатеричном формате, поэтому 33 фактически непрозрачно на 3/16.
Аарон покинул Stack Overflow
45

Вы также можете использовать контурные линии плотности ( ggplot2):

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

введите описание изображения здесь

Или объедините контуры плотности с альфа-смешением:

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

введите описание изображения здесь

ROLO
источник
29

Вам может пригодиться hexbinпакет. Со страницы справки 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

Оскар Перпиньян
источник
+1 hexbin - мое предпочтительное решение - оно может занять большое # точек, а затем безопасно создать график. Я не уверен, что другие не будут пытаться создать сюжет, а просто по-другому затеняют вещи постфактум.
Итератор
Что-нибудь вроде hexbin для 3D-данных?
skan
8

geom_pointdenistyиз ggpointdensityпакета (недавно разработанного Лукасом Кремером и Саймоном Андерсом (2019)) позволяет визуализировать плотность и отдельные точки данных одновременно:

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

Январь-GLX
источник
2

Мой любимый метод построения этого типа данных - это тот, который описан в этом вопросе - график плотности рассеяния . Идея состоит в том, чтобы сделать диаграмму рассеяния, но раскрасить точки по их плотности (грубо говоря, количеству перекрытия в этой области).

Это одновременно:

  • четко показывает расположение выбросов, и
  • выявляет любую структуру в плотной зоне участка.

Вот результат верхнего ответа на связанный вопрос:

график плотности рассеяния

Стивен Макэтир
источник
1
Это тоже мой любимый способ. См. Мой ответ о том, как этого добиться R.
jan-