Scatterplot With Marginal Histograms in Ggplot2

Scatterplot with marginal histograms in ggplot2

The gridExtra package should work here. Start by making each of the ggplot objects:

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

Then use the grid.arrange function:

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

plot

How to create marginal/histogram plot along with a geom_count plot in R?

You can do that with cowplot package instead of ggExtra package.

library(tidyverse)
library(cowplot)

g <-
ggplot(mpg, aes(cty, hwy)) +
geom_count(show.legend = F)

xhist <-
axis_canvas(g, axis = "x") +
geom_histogram(data = mpg,
aes(x = cty),
binwidth = 1,
color = 'lightgray')
yhist <-
axis_canvas(g, axis = "y", coord_flip = TRUE) +
geom_histogram(data = mpg,
aes(x = hwy),
binwidth = 1,
color = 'lightgray') +
coord_flip()

g %>%
insert_xaxis_grob(xhist, grid::unit(1, "in"), position = "top") %>%
insert_yaxis_grob(yhist, grid::unit(1, "in"), position = "right") %>%
ggdraw()

Sample Image

Plotting marginal histograms (as factors) and scatterplot (as numeric) from the same variable in R

If you are willing to give baseplotting a try, here is a function:

plots$scatterWithHists <- function(x, y, histCols=c("lightblue","lightblue"), lhist=20, xlim=range(x), ylim=range(y), ...){
## set up layout and graphical parameters
layMat <- matrix(c(1,4,3,2), ncol=2)
layout(layMat, widths=c(5/7, 2/7), heights=c(2/7, 5/7))
ospc <- 0.5 # outer space
pext <- 4 # par extension down and to the left
bspc <- 1 # space between scatter plot and bar plots
par. <- par(mar=c(pext, pext, bspc, bspc), oma=rep(ospc, 4)) # plot parameters

## barplot and line for x (top)
xhist <- hist(x, breaks=seq(xlim[1], xlim[2], length.out=lhist), plot=FALSE)
par(mar=c(0, pext, 0, 0))
barplot(xhist$density, axes=FALSE, ylim=c(0, max(xhist$density)), space=0, col=histCols[1])

## barplot and line for y (right)
yhist <- hist(y, breaks=seq(ylim[1], ylim[2], length.out=lhist), plot=FALSE)
par(mar=c(pext, 0, 0, 0))
barplot(yhist$density, axes=FALSE, xlim=c(0, max(yhist$density)), space=0, col=histCols[2], horiz=TRUE)

## overlap
dx <- density(x)
dy <- density(y)
par(mar=c(0, 0, 0, 0))
plot(dx, col=histCols[1], xlim=range(c(dx$x, dy$x)), ylim=range(c(dx$y, dy$y)),
lwd=4, type="l", main="", xlab="", ylab="", yaxt="n", xaxt="n", bty="n"
)
points(dy, col=histCols[2], type="l", lwd=3)

## scatter plot
par(mar=c(pext, pext, 0, 0))
plot(x, y, xlim=xlim, ylim=ylim, ...)
}

Just do:

scatterWithHists(x,y, histCols=c("lightblue","orange"))

And you get:

marginalHists

If you absolutely want to use ggMargins then look up xparams and yparams. It says you can send additional arguments to x-margin and y-margin using those. I was only successful in sending trivial things like color. But maybe sending something like xlim would help.

Align another object with scatterplot+marginal boxplots

You could:

  1. Change element_blank to axis.text.x = element_text(colour = "white") so axis text is the same colour as the plot background so not visible, forcing the axis label to be on the vertical position as the main plot.
  2. Include a dummy plot with NULL in the call to plot_grid

    And, in response to additional question in comments...
  3. use grid::nullGrob to make the right hand side plot panel the same height as the main plot panel.
library(ggplot2)
library(cowplot)
# Main plot
pmain <- ggplot(iris, aes(x = Sepal.Length, y = Sepal.Width, color = Species))+
geom_point()+
ggpubr::color_palette("jco")+
theme(legend.position = c(0.8, 0.8))
# Marginal densities along x axis
xdens <- axis_canvas(pmain, axis = "x")+
geom_boxplot(data = iris, aes(x = Sepal.Length, fill = Species),
alpha = 0.7, size = 0.2)+
ggpubr::fill_palette("jco")
# Marginal densities along y axis
# Need to set coord_flip = TRUE, if you plan to use coord_flip()
ydens <- axis_canvas(pmain, axis = "y", coord_flip = TRUE)+
geom_boxplot(data = iris, aes(x = Sepal.Width, fill = Species),
alpha = 0.7, size = 0.2)+
coord_flip()+
ggpubr::fill_palette("jco")
p1 <- insert_xaxis_grob(pmain, xdens, grid::unit(.2, "null"), position = "top")
p2<- insert_yaxis_grob(p1, ydens, grid::unit(.2, "null"), position = "right")
# ggdraw(p2)
# generate a separate bar chart to go alongside
petal.bar <- ggplot(data=iris, aes(y=Petal.Width, x=Species, fill = Species))+
geom_bar(stat="summary", fun="mean", position = "dodge")+
theme(axis.text.x = element_text(colour = "white"),
legend.position = "none")+
geom_point()+
ggpubr::fill_palette("jco")

p3 <- insert_xaxis_grob(petal.bar, grid::nullGrob(), grid::unit(.2, "null"), position = "top")
# place bar chart to the right
plot_grid(p2, NULL, p3, align = "h", axis = "b", nrow = 1, ncol = 3, rel_widths = c(1, 0.1, 0.6))

Sample Image

Created on 2022-01-20 by the reprex package (v2.0.1)



Related Topics



Leave a reply



Submit