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()
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 ...
How to change the limits and divisions of the axes of each facet using ggplot2? Dealing with error in x$clone() attempt to apply non-function
I think I found the reason it doesn't work,
in facet_grid
the scales
parameter was used to indicate if each panel would have similar or different scales with c("free","free_x","free_y")
. But having free_x
on facet_grid
is only free in the horizontal direction, and all vertical groupings have the same scale range.
When specifying facet_grid_sc
, the scales
parameter is used to distinguish how each scale will be rendered, specifically scales = list(x = scale_x)
where scale_x
matches cols = vars(Range)
library(ggplot2)
library(facetscales)
#Constructing data frame
Source <- c(rep("Water", 12), rep("Oil", 12))
Range <- rep((c(rep("First", 4), rep("Second", 8))),2)
Xaxis <- c(0,1,2,5,0,1,2,5,10,20,30,40,
0,1,2,5,0,1,2,5,10,20,30,40)
Yaxis <- c(0,1,2,5,0,1,2,5,10,20,30,40,
0,1,2,5,0,1,2,5,10,20,30,40)
DF <- data.frame(Source, Range, Xaxis, Yaxis)
p <- ggplot(data = DF, aes(x = Xaxis, y = Yaxis)) +
geom_smooth(method = "lm",
formula = y ~ x) +
geom_point()
#old plot without facet_grid_sc
p + facet_grid(rows = vars(Range),
cols = vars (Source))
You see how if you facet by Range
on rows, they are split vertically instead of horizontality? I dont think facet_grid_sc
supports a free_x
while also specifiying the x element of scales
scale_x <- list(
First = scale_x_continuous(limits = c(0, 10), breaks = c(0, 2, 10)),
Second= scale_x_continuous(limits = c(0, 40), breaks = c(0, 5, 40))
)
#new plot where scale_x matches cols argument
p + facet_grid_sc(cols = vars(Range),
rows = vars (Source),
scales = list(x = scale_x))
Created on 2021-03-16 by the reprex package (v1.0.0)
EDIT
It should be noted that facet_grid_sc
is probably more useful if you want to control the range or labels of each panel cols/rows individually. Using scales = "free_x"
in facet_grid
is actually pretty sufficient in this example.
p + facet_grid(cols = vars(Range),
rows = vars (Source),
scales = "free_x")
Created on 2021-03-16 by the reprex package (v1.0.0)
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)))
How do you set different scale limits for different facets?
I don't think this is possible yet in ggplot2. This discussion from January suggests the issue is under consideration.
How to specify different scales format for different facets?
The function scale_y_continuous
allows for functions to be used for the labels
argument. We can create a custom labeler that uses the minimum big
value (or any other) as a threshold.
dollar <- function(x) {
ifelse(x >= min(df$value[df$variable == "big"]),
paste0("$", prettyNum(x, big.mark=",")), x)
}
ggplot(df) + geom_line(aes(x, value)) + facet_wrap(~ variable, scales = "free_y") +
scale_y_continuous(labels = dollar)
Different scale for faceted plots: scale_y_continuous()
Answer is simple: use scale_y_continuous(labels = abs)
. Final code looks as follows:
country <- c(1, 1, 1, 1, 2, 2, 2, 2)
age.range <- c("0-4", "0-4", "5-9", "5-9", "0-4", "0-4", "5-9", "5-9")
sex <- rep(c("M", "F"), times = 4)
pop <- c(-8, 9, -9, 8, -88, 99, -99, 88)
pop.pyr <- data.frame(country, age.range, sex, pop)
library(ggplot2)
ggplot(pop.pyr, aes(x = age.range, y = pop, fill = sex)) +
geom_col() +
coord_flip() +
scale_y_continuous(labels = abs)
facet_wrap(~ country, scales = "free_x")
That was a long way around. Thanks @Z.Lin.
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")
Related Topics
Replace Nas with Mean of the Same Column of a Data.Table
Rbindlist Two Data.Tables Where One Has Factor and Other Has Character Type for a Column
How to Draw Half-Filled Points in R (Preferably Using Ggplot)
Applying Gsub to Various Columns
Order Categorical Data in a Stacked Bar Plot with Ggplot2
Boxplot of Table Using Ggplot2
Draw Multiple Squares with Ggplot
How Does R's Ifelse Work with Character Data
Group_By() into Fill() Not Working as Expected
Retain Attributes When Using Gather from Tidyr (Attributes Are Not Identical)
Getting File Path from Shiny UI (Not Just Directory) Using Browse Button Without Uploading the File
Package Domc Not Available for R Version 3.0.0 Warning in Install.Packages
Find Elements Not in Smaller Character Vector List But in Big List
Converting a Data.Frame to a List of Lists
Downloading Files from Ftp with R
List and Description of All Packages in Cran from Within R
Generate Random Integers Between Two Values with a Given Probability Using R