Asymmetric Expansion of Ggplot Axis Limits

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)))

Sample Image

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:
Sample Image

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)")

Sample Image

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)")

Sample Image

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.

Sample Image

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:

Sample Image

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"))

ggplot2, with bars starting at 1 instead of 0



Related Topics



Leave a reply



Submit