0

I'm trying to set the minimum y value for a dual axis chart. I understand having dual axis is not entirely best practices when plotting, but this is a requested item. I'd like to try and have the minimum set to anything above zero.

Looking online I have not found an answer other than adjusting or using expansion. The issue with this is, since it contracts, anything not in the area gets cut off. The plot was made using tenubrand's answer here. ggplot with 2 y axes on each side and different scales

I thought his use of y max values in his post could be changed to min but it didn't work. So I included expansion, but it's not dynamic and doesn't work well for varying data sets. Some graphs even cut of at some points.

library(scales)
library(ggplot2)
# Function factory for secondary axis transforms
train_sec <- function(primary, secondary, na.rm = TRUE) {
  from <- range(secondary, na.rm = na.rm)
  to   <- range(primary, na.rm = na.rm)
  forward <- function(x) {
    rescale(x, from = from, to = to)
  }
  reverse <- function(x) {
    rescale(x, from = to, to = from)
  }
  list(fwd = forward, rev = reverse)
}


sec <- with(economics, train_sec(unemploy, psavert))


ggplot(economics, aes(date)) +
  geom_col(aes(y = unemploy), colour = "blue") +
  geom_line(aes(y = sec$fwd(psavert)), colour = "red") +
  scale_y_continuous(name = NULL, 
                     expand = expansion(mult = c(-.2, .1)),
                     sec.axis = sec_axis(~sec$rev(.), name = "psavert"))
  • 2
    Initial thought — sounds like you might want to control the limits using coord_cartesian instead of scale_y_continuous if you don’t want any data excluded (but it’s ok if any of it is potentially out of view). See: https://stackoverflow.com/questions/28198613/r-ggplot-boxplot-change-y-axis-limit/28199268#28199268 – Jon Spring Aug 03 '23 at 23:50
  • What do you want the result to look like? – Jon Spring Aug 04 '23 at 16:10
  • I was just looking at your recommendation, I think I'm close. I have ``coord_cartesian`` set dynamically following this https://stackoverflow.com/questions/45555095/ggplot-modify-coord-cartesian-values-dynamically. It works, but it only adjusts the bar graph, the line graph on the same plot cuts out midway in the plot. If I can have them both adjusted, that would be my ideal output. @JonSpring thanks for the help by the way – wigglesthe3rd Aug 04 '23 at 16:16

1 Answers1

1

One simple option that works for some (many?) situations would be to hardcode the scaling min for both ranges as zero, so that the two series share a vertical origin.

train_sec <- function(primary, secondary, na.rm = TRUE) {
  from <- range(secondary, na.rm = na.rm)
  from[1] = 0
  to   <- range(primary, na.rm = na.rm)
  to[1] = 0
  forward <- function(x) {
    rescale(x, from = from, to = to) 
  }
  reverse <- function(x) {
    rescale(x, from = to, to = from)
  }
  list(fwd = forward, rev = reverse)
}

ggplot(economics, aes(date)) +
  geom_col(aes(y = unemploy), colour = "blue") +
  geom_line(aes(y = sec$fwd(psavert)), colour = "red") +
  scale_y_continuous(name = NULL, 
                     sec.axis = sec_axis(~sec$rev(.), name = "psavert")) 

enter image description here

Jon Spring
  • 55,165
  • 4
  • 35
  • 53
  • Assume I want the graph's y axis to begin at something other than '0', for both axis' (hence setting the y min). How would I do that? Is it even possible to set dynamically? – wigglesthe3rd Aug 04 '23 at 20:45
  • I am sure it is possible, but the algebra to correctly account for scale padding in the two scales is breaking my brain right now. – Jon Spring Aug 04 '23 at 20:48
  • haha i totally understand, i've been on this longer than i've hoped – wigglesthe3rd Aug 04 '23 at 20:49
  • 1
    I suspect the answer is something like "low end of secondary range = pmax(0, original_min of secondary range, expanded out 5% from median of secondary range)" – Jon Spring Aug 04 '23 at 20:52
  • i'll look into that, you've been more than helpful, thanks – wigglesthe3rd Aug 04 '23 at 20:58