ggplot add ticks to each plot in a facet_wrap - r

I'd like to display x-axis ticks on plots in the upper rows in facet_wraps. For example:
library(ggplot2)
ggplot(diamonds, aes(carat)) + facet_wrap(~ cut, scales = "fixed") + geom_density()
generates this plot:
I'd like to have ticks as I've drawn in on this plot:
Is there a simple way to achieve this result?

Using scales = "free_x" adds x axes to each plot:
ggplot(diamonds, aes(carat)) +
geom_density() +
facet_wrap(~cut, scales = "free_x")
However, as you can see and the syntax suggests, it also frees the limits of each plot to adjust automatically, so if you want them all to be consistent, you'll need to set them with xlim, lims or scale_x_continuous:
ggplot(diamonds, aes(carat)) +
geom_density() +
xlim(range(diamonds$carat)) +
# or lims(x = range(diamonds$carat))
# or scale_x_continuous(limits = range(diamonds$carat))
facet_wrap(~cut, scales = "free_x")

Related

How to show the part of the errorbar lines which are within the plot margins using `ggplot2`?

I have a grid of plots, all with the same y and x-axis scale. The plots represent time in the x-axe and mean values in the y-axe with their standard errors. My problem is that some errorbars are not entirely within the plot margins, and I wonder if there is some way to represent the part of the errorlines that are within the plot margins. Below I give a fake example and code to play with:
df <- data.frame(time=seq(-15,15,1),
mean=c(0.49,0.5,0.53,0.55,0.57,0.59,0.61,0.63,0.65,0.67,0.69,0.71,0.73,0.75,0.77,0.79,0.77,0.75,0.73,0.71,0.69,0.67,0.65,0.63,0.61,0.59,0.57,0.55,0.53,0.51,0.49),
sd=c(0.09,0.087,0.082,0.08,0.023,0.011,0.010,0.009,0.008,0.007,0.006,0.005,0.004,0.003,0.002,0.001,0.002,0.003,0.004,0.005,0.006,0.007,0.008,0.009,0.010,0.011,0.023,0.08,0.084,0.087,0.09))
Plot <- ggplot(df, aes(x=time, y=mean)) +
geom_errorbar(aes(ymin=mean-sd, ymax=mean+sd), width=.3) +
geom_point(size=1) +
geom_line () +
theme_bw() +
scale_y_continuous(limits = c(0.49, 0.85), breaks = c(0.5, 0.65,0.8))
Plot
You need to set coord_cartesian limits rather than scale_y_continuous limits:
ggplot(df, aes(x=time, y=mean)) +
geom_errorbar(aes(ymin=mean-sd, ymax=mean+sd), width=.3) +
geom_point(size=1) +
geom_line () +
theme_bw() +
scale_y_continuous(breaks = c(0.5, 0.65,0.8)) +
coord_cartesian(ylim = c(0.49, 0.85))

ggplot Adding Tracking Colors Below X-Axis

I'd like to add a line below the x-axis where its color is dependant on a factor that is not plotted.
In this example, I'm creating a box plot and would like to add a line that indicates another variable.
Using the cars data set as an example and then physically dawing in what I'm trying to do:
ggplot(mtcars, aes(factor(cyl), mpg, fill=factor(am))) +
geom_boxplot()
My thought was to create a bar, column, or geom_tile plot and then arrange it below the boxplot. This is how I would do it in base R. Is there a way to add in these kinds of color labels in ggplot2?
The natural way in ggplot2 to do this sort of thing would to be facet on the categorical variable to create subplots. However if you want to keep everything on the same graph you could try using a geom_tile() layer something like this:
df <-data.frame(x = factor(c(4,6,8)), colour = factor(c(1,2,1)))
ggplot(mtcars, aes(factor(cyl), mpg, fill=factor(am))) +
geom_boxplot() +
geom_tile(data=df, aes(x = x, y = 8, fill = colour))
Alternatively as you suggest you could align an additional plot underneath it. You could use ggarrange() in the ggpubr package for this:
plot1 <- ggplot(mtcars, aes(factor(cyl), mpg, fill=factor(am))) +
geom_boxplot() +
geom_tile(data=df, aes(x = x, y = 10, fill = colour))
theme(legend.position = 'none')
plot2 <- ggplot(df, aes(x=x, y=1, fill = colour)) +
geom_tile() +
theme_void() +
scale_fill_manual(values=c('orange', 'green', 'orange')) +
theme(legend.position = 'none')
library(ggpubr)
ggarrange(plot1, plot2, nrow = 2, heights = c(10, 1), align = 'h')

Possible to put the (secondary) axis next to the plot (instead of the facet label)

When using facets and an axis on the same side of plot the facet label comes before the axis. While it makes sense for labels with dark background, it looks strange for white background labels. Here an MWE example:
library(tidyverse)
ggplot(diamonds, aes(x=carat)) +
facet_grid(cut~.) +
geom_histogram() +
scale_y_continuous(sec.axis = dup_axis()) +
theme_minimal()
Plot:
Is it possible to swap the facet labels and the secondary axis, so that the axis is next to the plot?
Mockup:
Does this work for you?
require(ggplot2)
library(tidyverse)
ggplot(diamonds, aes(x=carat)) +
geom_histogram() +
scale_y_continuous(sec.axis = dup_axis()) +
theme_minimal()+
theme(strip.placement = "outside",
plot.margin=margin(c(.1,.1,.1,.1),unit="pt"))+
facet_grid(cut~.)

`ggplot2 - facet_grid`: Axes without ticks in interior facets

I would like to create facet_grid / facet_wrap plot with the x axis being repeated under each graph but with ticks present only on the lowest graph.
Here is an example of a plot with the x axis present only once using facet_grid
ggplot(mtcars, aes(y=mpg,x=cyl)) +
facet_grid(am~., scales="free") +
geom_point() +
theme_classic() +
theme(strip.background = element_rect(colour="white", fill="white"),
strip.text.y = element_blank())
Here is an example of a plot with the x axis present twice but with ticks both times using facet_wrap
ggplot(mtcars, aes(y=mpg, x=cyl)) +
facet_wrap(~am, ncol=1, scales="free") +
geom_point() +
theme_classic() +
theme(strip.background = element_rect(colour="white", fill="white"),
strip.text.x = element_blank())
I would like the same plot as the one just above but without the ticks on the x-axis of the upper graph. Or if you prefer, I would like the same plot as the first one but with an x-axis on the upper graph.
This is a very verbose solution, but I don't think you can get the plot you want using just the usual ggplot functions.
library(ggplot2)
library(grid)
Plot <- ggplot(mtcars, aes(y=mpg, x=cyl)) +
facet_wrap(~am, ncol=1, scales="free") +
geom_point() +
theme_classic() +
theme(strip.background = element_rect(colour="white", fill="white"),
strip.text.x = element_blank())
Switching off the top x-axis requires modifying the gtable object for the plot.
Plot.build <- ggplot_gtable(ggplot_build(Plot))
axis.pos <- grep("axis-b-1-1", Plot.build$layout$name)
num.ticks <- length(Plot.build$grobs[[axis.pos]]$children[2]$axis$grobs[[1]]$y)
This step removes the axis labels:
Plot.build$grobs[[axis.pos]]$children$axis$grobs[[2]]$children[[1]]$label <- rep("", num.ticks)
This step removes the tick marks:
Plot.build$grobs[[axes.pos]]$children[2]$axis$grobs[[1]]$y <- rep(unit(0, units="cm"), num.ticks)
Finally, the plot is generated using:
grid.draw(Plot.build)
The workaround I use to get just an axis line (no tick marks) is to use geom_hline() to fake an axis.
#make a dataframe with the y minimum for each facet
fake.axes <- data.frame(mpg = c(10, 15), #y minimum to use for axis location
am = c(0,1)) #facetting variable
#add an "axis" without ticks to upper graph using geom_hline()
ggplot(mtcars, aes(y=mpg,x=cyl)) +
facet_grid(am~., scales="free") +
geom_point() +
geom_hline(aes(yintercept = mpg), fake.axes, #dataframe with fake axes
linetype = c("solid", "blank")) + #line for top graph, blank for bottom graph
theme_classic() +
theme(strip.background = element_rect(colour="white", fill="white"),
strip.text.y = element_blank())
If you haven't used scales = "free", and all the axes are in the same location this is even simpler, you can skip making a dataframe with yintercepts for each facet and simply add
geom_hline(yintercept = 10) (or whatever your minimum is) to your plot code to add an axis line on each facet.

box plot in R with additional point

I have a dataframe of multiple columns (let's say n) with different range and a vector of length n. I want different x-axis for each variable to be shown below each box plot. I tried facet_grid and facet_wrap but it gives common x axis.
This is what I have tried:
d <- data.frame(matrix(rnorm(10000), ncol = 20))
point_var <- rnorm(20)
plot.data <- gather(d, variable, value)
plot.data$test_data <- rep(point_var, each = nrow(d))
ggplot(plot.data, aes(x=variable, y=value)) +
geom_boxplot() +
geom_point(aes(x=factor(variable), y = test_data), color = "red") +
coord_flip() +
xlab("Variables") +
theme(legend.position="none")
If you can live with having the text of the x axis above the plot, and having the order of the graphs a bit messed-up this could work:
library(grid)
p = ggplot(plot.data, aes(x = 0, y=value)) +
geom_boxplot() +
geom_point(aes(x = 0, y = test_data), color = "red") +
facet_wrap(~variable, scales = "free_y", switch = "y") +
xlab("Variables") +
theme(legend.position="none") + theme_bw() + theme(axis.text.x=element_blank())
print(p, vp=viewport(angle=270, width = unit(.75, "npc"), height = unit(.75, "npc")))
I'm actually just creating the graph without flipping coords, so that scales = 'free_y' works, swithcing the position of the strip labels, and then rotating the graph.
If you don't like the text above graph (which is understandable), I would consider creating a list of single plots and then putting them together with grid.arrange.
HTH,
Lorenzo

Resources