Merge and Perfectly Align Histogram and Boxplot Using Ggplot2

Merge and Perfectly Align Histogram and Boxplot using ggplot2

You can use either egg, cowplot or patchwork packages to combine those two plots. See also this answer for more complex examples.

library(dplyr)
library(ggplot2)

plt1 <- my_df %>% select(value) %>%
ggplot(aes(x="", y = value)) +
geom_boxplot(fill = "lightblue", color = "black") +
coord_flip() +
theme_classic() +
xlab("") +
theme(axis.text.y=element_blank(),
axis.ticks.y=element_blank())

plt2 <- my_df %>% select(id, value) %>%
ggplot() +
geom_histogram(aes(x = value, y = (..count..)/sum(..count..)),
position = "identity", binwidth = 1,
fill = "lightblue", color = "black") +
ylab("Relative Frequency") +
theme_classic()

egg

# install.packages("egg", dependencies = TRUE)
egg::ggarrange(plt2, plt1, heights = 2:1)

cowplot

# install.packages("cowplot", dependencies = TRUE)
cowplot::plot_grid(plt2, plt1,
ncol = 1, rel_heights = c(2, 1),
align = 'v', axis = 'lr')

patchwork

# install.packages("devtools", dependencies = TRUE)
# devtools::install_github("thomasp85/patchwork")
library(patchwork)
plt2 + plt1 + plot_layout(nrow = 2, heights = c(2, 1))

Sample Image

Combination Boxplot and Histogram using ggplot2

you can do that by coord_cartesian() and align.plots in ggExtra.

library(ggplot2)
library(ggExtra) # from R-forge

p1 <- qplot(x = 1, y = mpg, data = mtcars, xlab = "", geom = 'boxplot') +
coord_flip(ylim=c(10,35), wise=TRUE)
p2 <- qplot(x = mpg, data = mtcars, geom = 'histogram') +
coord_cartesian(xlim=c(10,35), wise=TRUE)

align.plots(p1, p2)

Here is a modified version of align.plot to specify the relative size of each panel:

align.plots2 <- function (..., vertical = TRUE, pos = NULL) 
{
dots <- list(...)
if (is.null(pos)) pos <- lapply(seq(dots), I)
dots <- lapply(dots, ggplotGrob)
ytitles <- lapply(dots, function(.g) editGrob(getGrob(.g,
"axis.title.y.text", grep = TRUE), vp = NULL))
ylabels <- lapply(dots, function(.g) editGrob(getGrob(.g,
"axis.text.y.text", grep = TRUE), vp = NULL))
legends <- lapply(dots, function(.g) if (!is.null(.g$children$legends))
editGrob(.g$children$legends, vp = NULL)
else ggplot2:::.zeroGrob)
gl <- grid.layout(nrow = do.call(max,pos))
vp <- viewport(layout = gl)
pushViewport(vp)
widths.left <- mapply(`+`, e1 = lapply(ytitles, grobWidth),
e2 = lapply(ylabels, grobWidth), SIMPLIFY = F)
widths.right <- lapply(legends, function(g) grobWidth(g) +
if (is.zero(g))
unit(0, "lines")
else unit(0.5, "lines"))
widths.left.max <- max(do.call(unit.c, widths.left))
widths.right.max <- max(do.call(unit.c, widths.right))
for (ii in seq_along(dots)) {
pushViewport(viewport(layout.pos.row = pos[[ii]]))
pushViewport(viewport(x = unit(0, "npc") + widths.left.max -
widths.left[[ii]], width = unit(1, "npc") - widths.left.max +
widths.left[[ii]] - widths.right.max + widths.right[[ii]],
just = "left"))
grid.draw(dots[[ii]])
upViewport(2)
}
}

usage:

# 5 rows, with 1 for p1 and 2-5 for p2
align.plots2(p1, p2, pos=list(1,2:5))
# 5 rows, with 1-2 for p1 and 3-5 for p2
align.plots2(p1, p2, pos=list(1:2,3:5))

align.plots2 second example

How do I align a histogram and boxplot so that they share x-axis?

Just add xlim(0,50) to each ggplot call.

The plot and boxplot (using package ggplot) give the different results

It's important to note that boxplot and plot are generic functions that behave differently based on what is passed to them. In this case, because you specify a factor as your x variable in the plot, it really comes down to comparing

boxplot(rad, crim, log='y')
boxplot(crim ~ as.factor(rad),log='y')

So you are either passing two different parmeters in the first case, or a formula in the second case. These behave very differently. If you don't use a formula, you just get a box plot for each variable you pass in. You can see what happens if you add other column names

boxplot(rad, crim, zn, dis, log='y')

There you can see that you just get a separate box plot for each of the variables you pass in. The "1" is the distribution of the rad variable for all observations, the "2" is the crim, and so on.

When you call

boxplot(crim ~ as.factor(rad),log='y')

You are getting a box plot for each unique value of rad. It's not really possible to add over variables when using the formula syntax.

See the ?boxplot help page for more details.

Also I should mention it's usually a bad idea to use attach(). It would be better to the data= parameter for functions that support it and with() for functions that do not. For example

with(Boston, boxplot(crim, rad, log="y"))
boxplot(crim~rad, log="y", data=Boston)

Control size of ggplot plot to match a second plot

As one of the comments mentioned, package cowplot has the functionality you need.

library(ggplot2)
library(cowplot)

df1 <- data.frame(a = as.factor(1:20), b = runif(20, 5, 9))
df2 <- data.frame(a = as.factor(1:20), b = runif(20, 50000, 90000))

plot1 <- ggplot(df1, aes(x = a, y =b)) + geom_bar(stat = "identity")
plot2 <- ggplot(df2, aes(x = a, y =b)) + geom_bar(stat = "identity")

#see ?plot_grid for more details
plot_grid(plot1,plot2,ncol = 1, align = "v", rel_heights = c(.7, .3))

Sample Image

Created on 2019-01-12 by the reprex package (v0.2.1)

Draw two plots in R with ggplot and par

use win.graph() to split the window into two.

Since you have not provided dataset, if you want to create a side by side plot try based on my example below

Try this:

library(cowplot)

iris1 <- ggplot(iris, aes(x = Species, y = Sepal.Length)) +
geom_boxplot() + theme_bw()

iris2 <- ggplot(iris, aes(x = Sepal.Length, fill = Species)) +
geom_density(alpha = 0.7) + theme_bw() +
theme(legend.position = c(0.8, 0.8))

plot_grid(iris1, iris2, labels = "AUTO")

How to adjust plot areas in ggplot?

Using patchwork package

# install.packages("devtools", dependencies = TRUE)
# devtools::install_github("thomasp85/patchwork")
library(patchwork)
p1 / p2 + plot_annotation(title = "Plot title",
subtitle = "Plot subtitle",
tag_levels = 'A',
tag_suffix = ')')

Sample Image

Created on 2018-11-20 by the reprex package (v0.2.1.9000)



Related Topics



Leave a reply



Submit