Scatterplot с маргинальными гистограммами в ggplot2

Есть ли способ создания диаграмм рассеяния с маргинальными гистограммами, как в примере ниже в ggplot2? В Matlab это функция scatterhist() и существуют эквиваленты для R. Однако я не видел его для ggplot2.

scatterplot with marginal histograms

Я попытался создать одиночные графы, но не знаю, как правильно их упорядочить.

 require(ggplot2)
 x<-rnorm(300)
 y<-rt(300,df=2)
 xy<-data.frame(x,y)
     xhist <- qplot(x, geom="histogram") + scale_x_continuous(limits=c(min(x),max(x))) + opts(axis.text.x = theme_blank(), axis.title.x=theme_blank(), axis.ticks = theme_blank(), aspect.ratio = 5/16, axis.text.y = theme_blank(), axis.title.y=theme_blank(), background.colour="white")
     yhist <- qplot(y, geom="histogram") + coord_flip() + opts(background.fill = "white", background.color ="black")

     yhist <- yhist + scale_x_continuous(limits=c(min(x),max(x))) + opts(axis.text.x = theme_blank(), axis.title.x=theme_blank(), axis.ticks = theme_blank(), aspect.ratio = 16/5, axis.text.y = theme_blank(), axis.title.y=theme_blank() )


     scatter <- qplot(x,y, data=xy)  + scale_x_continuous(limits=c(min(x),max(x))) + scale_y_continuous(limits=c(min(y),max(y)))
none <- qplot(x,y, data=xy) + geom_blank()

и упорядочивая их с размещенной функцией здесь. Но коротко сделать короткую историю: есть ли способ создания этих графиков?

Ответ 1

Пакет gridExtra должен работать здесь. Начните с создания каждого из объектов ggplot:

hist_top <- ggplot()+geom_histogram(aes(rnorm(100)))
empty <- ggplot()+geom_point(aes(1,1), colour="white")+
         theme(axis.ticks=element_blank(), 
               panel.background=element_blank(), 
               axis.text.x=element_blank(), axis.text.y=element_blank(),           
               axis.title.x=element_blank(), axis.title.y=element_blank())

scatter <- ggplot()+geom_point(aes(rnorm(100), rnorm(100)))
hist_right <- ggplot()+geom_histogram(aes(rnorm(100)))+coord_flip()

Затем используйте функцию grid.arrange:

grid.arrange(hist_top, empty, scatter, hist_right, ncol=2, nrow=2, widths=c(4, 1), heights=c(1, 4))

plot

Ответ 2

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

scatter <- qplot(x,y, data=xy)  + 
         scale_x_continuous(limits=c(min(x),max(x))) + 
         scale_y_continuous(limits=c(min(y),max(y))) + 
         geom_rug(col=rgb(.5,0,0,alpha=.2))
scatter

enter image description here

Ответ 3

Это может быть немного поздно, но я решил сделать для него пакет (ggExtra), поскольку он содержит немного кода и может быть утомительным для записи. Пакет также пытается решить некоторые распространенные проблемы, такие как обеспечение того, что даже если есть заголовок или текст увеличен, графики все равно будут встроены друг в друга.

Основная идея похожа на то, что здесь даны ответы, но она немного выходит за рамки этого. Вот пример того, как добавить маргинальные гистограммы в случайный набор из 1000 баллов. Надеюсь, это облегчит добавление гистограмм/графиков плотности в будущем.

Ссылка на пакет ggExtra

library(ggplot2)
df <- data.frame(x = rnorm(1000, 50, 10), y = rnorm(1000, 50, 10))
p <- ggplot(df, aes(x, y)) + geom_point() + theme_classic()
ggExtra::ggMarginal(p, type = "histogram")

enter image description here

Ответ 4

Одно дополнение, просто чтобы сохранить время поиска для людей, делающих это после нас.

Легенды, метки осей, тексты осей, тики делают участки смещены друг от друга, поэтому ваш сюжет будет выглядеть уродливым и непоследовательным.

Вы можете исправить это, используя некоторые из этих настроек темы,

+theme(legend.position = "none",          
       axis.title.x = element_blank(),
       axis.title.y = element_blank(),
       axis.text.x = element_blank(),
       axis.text.y = element_blank(), 
       plot.margin = unit(c(3,-5.5,4,3), "mm"))

и выровняйте масштаб,

+scale_x_continuous(breaks = 0:6,
                    limits = c(0,6),
                    expand = c(.05,.05))

поэтому результаты будут выглядеть нормально:

an example

Ответ 5

Просто очень незначительная вариация на BondedDust answer, в общем духе маргинальных показателей распределения.

Эдвард Туфте назвал это использование графиков ковриков "графиком пунктирной точки" и имеет пример в VDQI использования оси чтобы указать диапазон каждой переменной. В моем примере метки оси и линии сетки также указывают распределение данных. Этикетки расположены со значениями Tukey пять сводных номеров (минимальный, нижний шарнир, средний, верхний шарнир, максимум), что дает быстрое представление о разбросе каждой переменной.

Эти пять чисел являются, таким образом, численным представлением ящика. Это немного сложно, потому что неравномерно расположенные линии сетки предполагают, что оси имеют нелинейный масштаб (в этом примере они линейны). Возможно, было бы лучше опустить линии сетки или заставить их находиться в обычных местах и ​​просто позволить ярлыкам отображать пять сводок.

x<-rnorm(300)
y<-rt(300,df=10)
xy<-data.frame(x,y)

require(ggplot2); require(grid)
# make the basic plot object
ggplot(xy, aes(x, y)) +        
  # set the locations of the x-axis labels as Tukey five numbers   
  scale_x_continuous(limit=c(min(x), max(x)), 
                     breaks=round(fivenum(x),1)) +     
  # ditto for y-axis labels 
  scale_y_continuous(limit=c(min(y), max(y)),
                     breaks=round(fivenum(y),1)) +     
  # specify points
  geom_point() +
  # specify that we want the rug plot
  geom_rug(size=0.1) +   
  # improve the data/ink ratio
  theme_set(theme_minimal(base_size = 18))

enter image description here

Ответ 6

Поскольку для сравнения этих групп не было удовлетворительного решения, я написал функцию для этого.

Он работает как для сгруппированных, так и для негруппированных данных и принимает дополнительные графические параметры:

marginal_plot(x = iris$Sepal.Width, y = iris$Sepal.Length)

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

marginal_plot(x = Sepal.Width, y = Sepal.Length, group = Species, data = iris, bw = "nrd", lm_formula = NULL, xlab = "Sepal width", ylab = "Sepal length", pch = 15, cex = 0.5)

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

Ответ 7

Я нашел пакет (ggpubr), который, кажется, очень хорошо подходит для этой проблемы и рассматривает несколько возможностей для отображения данных.

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

Сначала я установил пакет (для этого требуется devtools)

if(!require(devtools)) install.packages("devtools")
devtools::install_github("kassambara/ggpubr")

В качестве конкретного примера отображения разных гистограмм для разных групп, он упоминает в связи с ggExtra: "Одно ограничение ggExtra состоит в том, что он не может справиться с несколькими группами на графике рассеяния и на маржинальных графиках. Ниже приведен код R, мы предлагаем решение с использованием пакета cowplot. " В моем случае мне пришлось установить последний пакет:

install.packages("cowplot")

И я следовал этой части кода:

# Scatter plot colored by groups ("Species")
sp <- ggscatter(iris, x = "Sepal.Length", y = "Sepal.Width",
            color = "Species", palette = "jco",
            size = 3, alpha = 0.6)+
border()                                         
# Marginal density plot of x (top panel) and y (right panel)
xplot <- ggdensity(iris, "Sepal.Length", fill = "Species",
               palette = "jco")
yplot <- ggdensity(iris, "Sepal.Width", fill = "Species", 
               palette = "jco")+
rotate()
# Cleaning the plots
sp <- sp + rremove("legend")
yplot <- yplot + clean_theme() + rremove("legend") 
xplot <- xplot + clean_theme() + rremove("legend")
# Arranging the plot using cowplot
library(cowplot)
plot_grid(xplot, NULL, sp, yplot, ncol = 2, align = "hv", 
      rel_widths = c(2, 1), rel_heights = c(1, 2))

Что у меня хорошо сработало:

Радужная оболочка рассеивает гистограммы

enter image description here

Ответ 8

Вы можете легко создать привлекательные диаграммы рассеяния с маргинальными гистограммами, используя ggstatsplot (он также подойдет и опишет модель):

data(iris)

library(ggstatsplot)

ggscatterstats(
  data = iris,                                          
  x = Sepal.Length,                                                  
  y = Sepal.Width,
  xlab = "Sepal Length",
  ylab = "Sepal Width",
  marginal = TRUE,
  marginal.type = "histogram",
  centrality.para = "mean",
  margins = "both",
  title = "Relationship between Sepal Length and Sepal Width",
  messages = FALSE
)

enter image description here

Или чуть более привлекательный (по умолчанию) ggpubr:

devtools::install_github("kassambara/ggpubr")
library(ggpubr)

ggscatterhist(
  iris, x = "Sepal.Length", y = "Sepal.Width",
  color = "Species", # comment out this and last line to remove the split by species
  margin.plot = "histogram", # I'd suggest removing this line to get density plots
  margin.params = list(fill = "Species", color = "black", size = 0.2)
)

enter image description here

ОБНОВИТЬ:

По предложению @aickley я использовал версию для разработки сюжета.

Ответ 9

Чтобы построить ответ @alf-pascu, настройте каждый график вручную и расположите их вместе с помощью cowplot дает большую гибкость как в отношении основного, так и маргинального графиков (по сравнению с некоторыми другими решениями). Распределение по группам является одним из примеров. Изменение основного графика на график 2D-плотности - это другое.

Следующее создает диаграмму рассеяния с (правильно выровненными) маргинальными гистограммами.

library("ggplot2")
library("cowplot")

# Set up scatterplot
scatterplot <- ggplot(iris, aes(x = Sepal.Length, y = Sepal.Width, color = Species)) +
  geom_point(size = 3, alpha = 0.6) +
  guides(color = FALSE) +
  theme(plot.margin = margin())


# Define marginal histogram
marginal_distribution <- function(x, var, group) {
  ggplot(x, aes_string(x = var, fill = group)) +
    geom_histogram(bins = 30, alpha = 0.4, position = "identity") +
    # geom_density(alpha = 0.4, size = 0.1) +
    guides(fill = FALSE) +
    theme_void() +
    theme(plot.margin = margin())
}

# Set up marginal histograms
x_hist <- marginal_distribution(iris, "Sepal.Length", "Species")
y_hist <- marginal_distribution(iris, "Sepal.Width", "Species") +
  coord_flip()

# Align histograms with scatterplot
aligned_x_hist <- align_plots(x_hist, scatterplot, align = "v")[[1]]
aligned_y_hist <- align_plots(y_hist, scatterplot, align = "h")[[1]]

# Arrange plots
plot_grid(
  aligned_x_hist
  , NULL
  , scatterplot
  , aligned_y_hist
  , ncol = 2
  , nrow = 2
  , rel_heights = c(0.2, 1)
  , rel_widths = c(1, 0.2)
)

scatterplot with marginal histograms

Чтобы построить график 2D-плотности, просто измените основной график.

# Set up 2D-density plot
contour_plot <- ggplot(iris, aes(x = Sepal.Length, y = Sepal.Width, color = Species)) +
  stat_density_2d(aes(alpha = ..piece..)) +
  guides(color = FALSE, alpha = FALSE) +
  theme(plot.margin = margin())

# Arrange plots
plot_grid(
  aligned_x_hist
  , NULL
  , contour_plot
  , aligned_y_hist
  , ncol = 2
  , nrow = 2
  , rel_heights = c(0.2, 1)
  , rel_widths = c(1, 0.2)
)

enter image description here

Ответ 10

Другое решение, использующее ggpubr и cowplot, но здесь мы создаем графики, используя cowplot::axis_canvas и добавляем их в исходный график с помощью cowplot::insert_xaxis_grob:

library(cowplot) 
library(ggpubr)

# Create main plot
plot_main <- ggplot(faithful, aes(eruptions, waiting)) +
  geom_point()

# Create marginal plots
# Use geom_density/histogram for whatever you plotted on x/y axis 
plot_x <- axis_canvas(plot_main, axis = "x") +
  geom_density(aes(eruptions), faithful)
plot_y <- axis_canvas(plot_main, axis = "y", coord_flip = TRUE) +
  geom_density(aes(waiting), faithful) +
  coord_flip()

# Combine all plots into one
plot_final <- insert_xaxis_grob(plot_main, plot_x, position = "top")
plot_final <- insert_yaxis_grob(plot_final, plot_y, position = "right")
ggdraw(plot_final)

enter image description here

Ответ 11

Это старый вопрос, но я подумал, что было бы полезно опубликовать здесь обновление, поскольку я недавно столкнулся с этой проблемой (спасибо Стефани Мюллер за помощь!).

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

#load packages
library(tidyverse) #for creating dummy dataset only
library(ggExtra)

#create dummy data
a = round(rnorm(1000,mean=10,sd=6),digits=0)
b = runif(1000,min=1.0,max=1.6)*a
b = b+runif(1000,min=9,max=15)

DummyData <- data.frame(var1 = b, var2 = a) %>% 
  filter(var1 > 0 & var2 > 0)

#plot
p = ggplot(DummyData, aes(var1, var2)) + geom_point(alpha=0.3)
ggMarginal(p, type = "histogram")

enter image description here

Ответ 12

В настоящее время существует по крайней мере один пакет CRAN, который составляет диаграмму рассеяния с ее маргинальными гистограммами.

library(psych)
scatterHist(rnorm(1000), runif(1000))

Sample plot from scatterHist

Ответ 13

Вы можете использовать интерактивную форму ggExtra::ggMarginalGadget(yourplot) и легко выбирать между коробочными диаграммами, графиками скрипки, плотностями и гистограммами.

как это