Диаграмма рассеяния с маргинальными гистограммами в ggplot2 - PullRequest
126 голосов
/ 17 декабря 2011

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

scatterplot with marginal histograms

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

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

Ответы [ 12 ]

110 голосов
/ 17 декабря 2011

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

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

87 голосов
/ 17 декабря 2011

Пакет 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

83 голосов
/ 30 марта 2015

Это может быть немного поздно, но я решил сделать пакет (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

44 голосов
/ 26 марта 2013

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

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

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

+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

28 голосов
/ 01 декабря 2013

Лишь очень незначительное отклонение от Ответа BondedDust , в общем духе предельных показателей распределения.

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

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

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

10 голосов
/ 19 августа 2016

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

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

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

enter image description here

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)

enter image description here

7 голосов
/ 18 января 2018

Я нашел пакет (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

5 голосов
/ 25 мая 2018

Вы можете легко создавать привлекательные диаграммы рассеяния с маргинальными гистограммами, используя 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

UPDATE:

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

2 голосов
/ 08 июня 2019

Другое решение с использованием 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

2 голосов
/ 04 июня 2019

Чтобы построить ответ @ 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

...