Asymmetric expansion of ggplot axis limits
ggplot2 v3.0.0
released in July 2018 has expand_scale()
option (w/ mult
argument) to achieve OP's goal.
Edit: expand_scale()
will be deprecated in the future release in favor of expansion()
. See News for more information.
library(ggplot2)
### ggplot <= 3.2.1
ggplot(mtcars) +
geom_bar(aes(x = cyl, fill = factor(vs)), width = 1) +
facet_grid(vs ~ ., scales = "free_y") +
scale_y_continuous(expand = expand_scale(mult = c(0, .2)))
### ggplot >= 3.2.1.9000
ggplot(mtcars) +
geom_bar(aes(x = cyl, fill = factor(vs)), width = 1) +
facet_grid(vs ~ ., scales = "free_y") +
scale_y_continuous(expand = expansion(mult = c(0, .2)))
How to expand axis asymmetrically with ggplot2 without setting limits manually?
You can "extend" ggplot by creating a scale with a custom class and implementing the internal S3 method scale_dimension like so:
library("scales")
scale_dimension.custom_expand <- function(scale, expand = ggplot2:::scale_expand(scale)) {
expand_range(ggplot2:::scale_limits(scale), expand[[1]], expand[[2]])
}
scale_y_continuous <- function(...) {
s <- ggplot2::scale_y_continuous(...)
class(s) <- c('custom_expand', class(s))
s
}
This is also an example of overriding the default scale. Now, to get the desired result you specify expand like so
qplot(1:10, 1:10) + scale_y_continuous(expand=list(c(0,0.1), c(0,0)))
where the first vector in the list is the multiplicative factor, the second is the additive part and the first (second) element of each vector corresponds to lower (upper) boundary.
Adjust y axis limits in dual y axis ggplot
I think the challenge here is that geom_bar/geom_col
has a baseline of zero, so I don't know of a way to use that geom where your y-axis does not include 0 in it's range. So you could use geom_tile
in its place, specifying the center y point and the height.
Here's the original for reference:
As a first step, we can test the use of geom_tile
where the two axes use the same vertical distance for 1 unit. To do so, we shift the bar data up by 24 (so its baseline is 24), and shift the labeling down 24 (so that 24 on the primary axis appears as 0 on the secondary one). For geom_tile
, we define y as DHW/2 + 24
since we want the middle height of the tile.
ggplot() +
geom_tile(data = b, aes(Date, DHW/2 + 24, width = 7*0.9, height = DHW, fill = DHW)) +
geom_ribbon(data = a, aes(x = Date, ymin = Min2019, ymax = Max2019),
alpha = 0.2, linetype = "blank", color = "black", fill = "black") +
geom_line(data = a, aes(Date, Temp2019), color = "black") +
scale_y_continuous(sec.axis = sec_axis(~.-24, name = "Degree Heating Weeks")) +
scale_fill_gradient(high = "#DD6666", low = "#F8E1E1") +
scale_x_date(date_breaks = "1 week") + labs(y = "Temp (°C)")
If we want to stretch the bars to take up more space, say 1.5 dec C per Degree Heating Week, we add that scale to both the data and the scale transformation, in opposite directions.
ggplot() +
geom_tile(data = b, aes(Date, DHW/2*1.5 + 24, width = 7*0.9, height = DHW*1.5, fill = DHW)) +
geom_ribbon(data = a, aes(x = Date, ymin = Min2019, ymax = Max2019),
alpha = 0.2, linetype = "blank", color = "black", fill = "black") +
geom_line(data = a, aes(Date, Temp2019), color = "black") +
scale_y_continuous(sec.axis = sec_axis(~(.-24)/1.5, name = "Degree Heating Weeks")) +
scale_fill_gradient(high = "#DD6666", low = "#F8E1E1") +
scale_x_date(date_breaks = "1 week") + labs(y = "Temp (°C)")
Season to taste.
Setting axes limits based on variable values in ggplot
This is exactly what the expand
parameter in a scale is meant for. We can set a multiplicative axis expansion.
We can also simplify your code a bit:
sample_data %>%
filter(program == "Program1") %>%
ggplot(aes(x = forcats::fct_infreq(country))) +
geom_bar(fill = "salmon3") +
geom_text(aes(label = stat(count)), stat = 'count', size = 3, hjust = -0.2) +
labs(title = "Country for Program1 Applicants") +
scale_y_continuous(expand = expansion(c(0, 0.1))) +
coord_flip()
I also turned off expansion of the left side of the plot. See ?scale_y_continuous
and ?expansion
.
How do you set x axis limits for times of type hms?
One way to do this is to define end_time
as as.POSIXct
Sample code:
library(dplyr)
library(ggplot2)
df%>%
mutate(end_time = as.POSIXct(end_time),
end_time= if_else(end_time < as.POSIXct('1970-01-01 04:00:00', 'UTC'), end_time + 86400, end_time)) %>%
ggplot(aes(x=end_time, y=n)) +
geom_bar(stat="identity") +
labs(x="End time", y="Count")+
theme_bw()+
theme(axis.text.x = element_text(hjust = 1,family="Times", face="bold", size=12, color="black"),
axis.title.x = element_text(family="Times", face="bold", size=16, color="black"),
axis.text.y = element_text(family="Times", face="bold", size=12, color="black"),
axis.title.y = element_text(family="Times", face="bold", size=16, color="black"),
strip.text = element_text(size=10, face="bold"),
plot.title = element_text(size=20, face="bold"),
legend.title = element_blank(),
legend.text = element_text(family="Times", color = "black", size = 16,face="bold"),
legend.position="none")+
scale_y_continuous(expand = expansion(mult = c(0, .1))) +
scale_x_datetime(date_labels = '%H:%M',
limits = c(as.POSIXct('1970-01-01 04:00:00', tz = 'UTC'),
as.POSIXct('1970-01-02 03:50:00', tz = 'UTC')),
breaks = '2 hour')
Plot:
Changing y-axis limits in ggplot without cutting off graph or losing data
If your data starts at 1
instead of 0
, you can switch from geom_bar
to geom_rect
.
hwid <- 0.25
full %>%
ggplot(aes(x = order, y = mean, fill = type, width = 0.5)) +
scale_fill_manual(values = c("003900", "003901")) +
geom_rect(aes(xmin = order-hwid, xmax = order+hwid, ymin = 1, ymax = mean)) +
geom_errorbar(aes(ymin = mean - se, ymax = mean + se), width = .2, position = position_dodge(.9)) +
geom_text(aes(label = round(mean, digits =1)), position = position_dodge(width=1.0), vjust = -2.0, size = 3.5) +
theme(legend.position = "right") +
labs(title = "Behavioral intentions and expected convincingness for single-reason messages") +
ylim(1, 7) +
theme(axis.text = element_text(size = 7)) +
theme(legend.title = element_blank()) +
xlab("Single-Reason Message") +
ylab("Rating of intentions or expected convincngess") +
scale_x_continuous(breaks = c(1.5, 3.5, 5.5, 7.5), labels = c("Animals", "Environment", "Health", "Money"))
Related Topics
Use an Image as Area Fill in an R Plot
Subset Rows According to a Range of Time
How to Train a Ml Model in Sparklyr and Predict New Values on Another Dataframe
Dplyr Summarize with Subtotals
Trouble Passing on an Argument to Function Within Own Function
Using Dplyr Within a Function, Non-Standard Evaluation
Replace Value with the Name of Its Respective Column
Convert Month Year to a Date in R
Dplyr::N() Returns "Error: Error: N() Should Only Be Called in a Data Context "
Plotting a "Sequence Logo" Using Ggplot2
Nested If Else Statements Over a Number of Columns
The Perils of Aligning Plots in Ggplot
Increase Space Between Bars in Ggplot
Assign Names to Data Frame with As.Data.Frame Function
Reverse and Change Limit of Axis