Setting individual axis limits with facet_wrap and scales = free in ggplot2
Here's some code with a dummy geom_blank
layer,
range_act <- range(range(results$act), range(results$pred))
d <- reshape2::melt(results, id.vars = "pred")
dummy <- data.frame(pred = range_act, value = range_act,
variable = "act", stringsAsFactors=FALSE)
ggplot(d, aes(x = pred, y = value)) +
facet_wrap(~variable, scales = "free") +
geom_point(size = 2.5) +
geom_blank(data=dummy) +
theme_bw()
Adjusting y axis limits in ggplot2 with facet and free scales
First, reproducibility with random data needs a seed. I started using set.seed(42)
, but that generated negative values which caused completely unrelated warnings. Being a little lazy, I changed the seed to set.seed(2021)
, finding all positives.
For #1, we can add limits=
, where the help for ?scale_y_continuous
says that
limits: One of:
• 'NULL' to use the default scale range
• A numeric vector of length two providing limits of the
scale. Use 'NA' to refer to the existing minimum or
maximum
• A function that accepts the existing (automatic) limits
and returns new limits Note that setting limits on
positional scales will *remove* data outside of the
limits. If the purpose is to zoom, use the limit argument
in the coordinate system (see 'coord_cartesian()').
so we'll use c(0, NA)
.
For Q2, we'll add expand=
, documented in the same place.
data %>%
gather(Gene, Levels, -Patient, -Treatment) %>%
mutate(Treatment = factor(Treatment, levels = c("Pre", "Post"))) %>%
mutate(Patient = as.factor(Patient)) %>%
ggplot(aes(x = Treatment, y = Levels, color = Patient, group = Patient)) +
geom_point() +
geom_line() +
facet_wrap(. ~ Gene, scales = "free") +
theme_bw() +
theme(panel.grid = element_blank()) +
scale_y_continuous(limits = c(0, NA), expand = expansion(mult = c(0, 0.1)))
ggplot2 change axis limits for each individual facet panel
preliminaries
Define original plot and desired parameters for the y-axes of each facet:
library(ggplot2)
g0 <- ggplot(mpg, aes(displ, cty)) +
geom_point() +
facet_grid(rows = vars(drv), scales = "free")
facet_bounds <- read.table(header=TRUE,
text=
"drv ymin ymax breaks
4 5 25 5
f 0 40 10
r 10 20 2",
stringsAsFactors=FALSE)
version 1: put in fake data points
This doesn't respect the breaks
specification, but it gets the bounds right:
Define a new data frame that includes the min/max values for each drv
:
ff <- with(facet_bounds,
data.frame(cty=c(ymin,ymax),
drv=c(drv,drv)))
Add these to the plots (they won't be plotted since x
is NA
, but they're still used in defining the scales)
g0 + geom_point(data=ff,x=NA)
This is similar to what expand_limits()
does, except that that function applies "for all panels or all plots".
version 2: detect which panel you're in
This is ugly and depends on each group having a unique range.
library(dplyr)
## compute limits for each group
lims <- (mpg
%>% group_by(drv)
%>% summarise(ymin=min(cty),ymax=max(cty))
)
Breaks function: figures out which group corresponds to the set of limits it's been given ...
bfun <- function(limits) {
grp <- which(lims$ymin==limits[1] & lims$ymax==limits[2])
bb <- facet_bounds[grp,]
pp <- pretty(c(bb$ymin,bb$ymax),n=bb$breaks)
return(pp)
}
g0 + scale_y_continuous(breaks=bfun, expand=expand_scale(0,0))
The other ugliness here is that we have to set expand_scale(0,0)
to make the limits exactly equal to the group limits, which might not be the way you want the plot ...
It would be nice if the breaks()
function could somehow also be passed some information about which panel is currently being computed ...
ggplot: limit axis limits/breaks of individual facet
Try this.
- I expanded the y axis.
- I adjusted the breaks. I borrowed the general idea from here. Function
my_breaks
returns pretty_breaks but removes the last value.
(Note: I also switched the aesthetics, y = nobs and x = cyl and used coord_flip, because running your code on my machine has not reproduced your plot (ggplot 3.3.0)):
library(tidyverse)
#> Warning: package 'forcats' was built under R version 3.6.3
my_breaks <- function(x, n = 5, drop = 2) {
breaks <- seq(x[[1]], x[[2]], length.out = n)
breaks <- scales::pretty_breaks()(breaks)
breaks <- breaks[1:(length(breaks) - drop)]
breaks
}
mtcars %>%
group_by(cyl, gear) %>%
summarise(n_obs = n()) %>%
mutate(n_obs = case_when(
gear == 4 ~ n_obs * 100,
TRUE ~ as.numeric(n_obs))) %>%
group_by(gear) %>%
mutate(n_obs_max = max(n_obs, na.rm=T)) %>%
ggplot(aes(x = cyl))+
geom_bar(aes(y = n_obs), stat="identity")+
geom_text(aes(y = n_obs_max * 1.2, label = n_obs))+
facet_wrap(vars(gear), scales = "free_x") +
scale_y_continuous(breaks = function(x) my_breaks(x, 5, 2),
expand = expand_scale(mult = c(0.05, .2))) +
coord_flip()
#> Warning: 'expand_scale()' is deprecated; use 'expansion()' instead.
Created on 2020-03-09 by the reprex package (v0.3.0)
How to increase the default y-axis limit in ggplot when scales in facet_wrap() are set to free
An option is to expand the axis limits.
ggplot(d, aes(id, mean)) +
geom_point() +
geom_errorbar(aes(ymin = mean - sd,
ymax = mean + sd)) +
geom_text(aes(
x = id,
y = mean + sd,
vjust = -2,
label = diff
)) +
facet_wrap( ~ var, scales = "free_y") +
scale_y_continuous(expand = expansion(mult = c(0.1, 0.2)))
This increases the top range by 20% and the bottom by 10%. AFAIK, the defaults are mult = c(0.05, 0)
.
How to set dynamic data limits across facets in ggplot2?
I agree with the comments, although I think this accomplishes the original goal. Based on this.
library(tidyverse)
location <- rep(c("1001", "1002", "1003", "1004"), c(3, 3, 3, 3))
period <- rep(c(2019, 2020, 2021), 4)
change <- c(-3.1, 5.4, -2.2, 190.8, 2.3, 150, 0.34, -0.44, -0.67, 1.2, 3, 4)
tot <- data.frame(location, period, change)
ggplot(data = tot, aes(x = period, y = change)) +
geom_blank(aes(y=-change)) +
geom_bar(stat = "identity", position = "dodge") +
coord_flip() +
facet_wrap(~location, ncol = 1, scales = "free")
Changing multiple y scales when using facet_wrap
The limits are automatically set based on the x
,y
values... but ignore the ymax
and ymin
values used for the error bar geoms, which is why the errorbars are outside the viewable area on the plot. One option could be to reset your own limits manually, but much better would be to use the expand=
argument with scale_y_continuous()
to expand the viewable area a bit past the automatically-set limits.
To use the argument, you assign expand=expansion(mult=c(lower,upper))
or expand=expansion(add=c(lower,upper))
. The numbers for upper
and lower
set the expansion on the high or low end of the axis, respectively. Using add
expands the axis by adding a discrete amount, whereas mult
expands the axis by adding a multiplier. mult
is more useful in this case, since the facets have different limits by default. Here's the some numbers that worked okay for me and the code:
ggplot(df, aes(x =time,y=mean)) +
geom_point(size = 3)+
geom_errorbar(ymax=df$mean+df$sd,ymin=df$mea-df$sd,width=0.1)+
scale_y_continuous(expand=expansion(mult=c(0.8,0.8))) +
facet_wrap(~df$var, scales="free_y", ncol = 1, strip.position = "left")+
theme_bw()+
theme(
axis.line=element_line(colour="black"),
axis.text.y= element_text(size=18),
axis.text.x=element_text(size=18,angle = 90,vjust=0.1),
axis.title=element_blank())
Related Topics
How to Remove Na from a Factor Variable (And from a Ggplot Chart)
Break Dataframe into Smaller Dataframe'S and Save Them
Remove Total Value for One Column in Powerbi
Removing Columns That Are All 0
Converting Year and Month ("Yyyy-Mm" Format) to a Date
What Are the Differences Between "=" and "≪-" Assignment Operators
How to Trim Leading and Trailing White Space
Why Is It Not Advisable to Use Attach() in R, and What Should I Use Instead
How to Use "≪≪-" (Scoping Assignment) in R
Removing Duplicate Combinations (Irrespective of Order)
How to Change the Default Colors in Plotly Chart
Duplicate Columns in Spark Dataframe
Coerce Multiple Columns to Factors At Once
Filter Data.Frame Rows by a Logical Condition
Evaluate Expression Given as a String
Add Count of Unique/Distinct Values by Group to the Original Data