Search code examples
rggplot2

How to keep the limits of primary and secondary y-axis consistent between 2 figures in ggplot?


The original plot was created as below:

library(forcats)
library(tidyr)
library(ggplot2)

mydata<-data.frame(id=c(1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12),
                   mean=c(80,80,53,53,46,46,42,42,37,37,33,33,
                          28,28,22,22,20,20,17,17,10,10,8,8),
                   type=rep(c("dead","survived"),12),
                   value=c(46,130,220,980,20,840,13,452,8,350,5,69,
                           4,536,16,141,0,55,38,168,12,95,42,170))

mydata%>%
  ggplot(aes(x=factor(id),
             y=value, fill=factor(type,levels=c("dead","survived"))))+
  geom_bar(position=position_stack(),stat="identity") + 
  geom_text(data=subset(mydata,value != 0),
            aes(label = value), position=position_stack(vjust=0.5),size=4) +
  geom_line(color='grey30', linewidth=0.5, aes(x = id, y = mean*30, group=1)) +
  geom_point(aes(x=id,y=mean*30)) + 
  geom_text(aes(label = mean,y=mean*30+60),size=3.5) + 
  theme(legend.position = c(0.90,0.85)) +
  labs(x="Site ID",y="",fill="Num of pts") +  
  scale_y_continuous(
    breaks = seq (0, 1200, 60), name="num of pts",
    sec.axis = sec_axis(~.*1/30, name="mean events",breaks = seq (0, 90, 10))
  )

enter image description here

Now I want to break the figure into 2 halves (because the real data contain too many sites, making the figure too wide and bars too narrow):

mydata1<-mydata[which(mydata$id %in% c(1:6)),]
mydata2<-mydata[which(mydata$id %in% c(7:12)),]

mydata1%>%
  ggplot(aes(x=factor(id),
             y=value, fill=factor(type,levels=c("dead","survived"))))+
  geom_bar(position=position_stack(),stat="identity") + 
  geom_text(data=subset(mydata1,value != 0),
            aes(label = value),position=position_stack(vjust=0.5),size=4) +
  geom_line(color='grey30', linewidth=0.5, aes(x = id, y = mean*30, group=1)) +
  geom_point(aes(x=id,y=mean*30)) + 
  geom_text(aes(label = mean,y=mean*30+60),size=3.5) + 
  theme(legend.position = c(0.90,0.85)) +
  labs(x="Site ID",y="",fill="Num of pts") +  
  scale_y_continuous(
    breaks = seq (0, 1200, 60), name="num of pts",
    sec.axis = sec_axis(~.*1/30, name="mean events",breaks = seq (0, 90, 10))
  )

mydata2%>%
  ggplot(aes(x=factor(id),
             y=value, fill=factor(type,levels=c("dead","survived"))))+
  geom_bar(position=position_stack(),stat="identity") + 
  geom_text(data=subset(mydata2,value != 0),
            aes(label = value),position=position_stack(vjust=0.5),size=4) +
  geom_line(color='grey30', linewidth=0.5, aes(x = factor(id), y = mean*30, group=1)) +
  geom_point(aes(x=factor(id),y=mean*30)) + 
  geom_text(aes(label = mean,y=mean*30+60),size=3.5) + 
  theme(legend.position = c(0.90,0.85)) +
  labs(x="Site ID",y="",fill="Num of pts") +  
  scale_y_continuous(
    breaks = seq (0, 1200, 60), name="num of pts",
    sec.axis = sec_axis(~.*1/30, name="mean events",breaks = seq (0, 90, 10))
  )

The figures were shown as below: enter image description here

enter image description here

As you can see, the limits of primary and secondary y-axis between 2 figures were not the same. In the second figure, I'd like to keep the limit of primary y-axis from 0 to 1200, and secondary y-axis from 0 to 90 just as the first one. How to modify the code?


Solution

  • To ensure that both charts have the same limits for the y-scale, set it to explicitly refer to the maximum value of the mean from the original data, multiplied by the scaling factor you applied to the y of the geom_line, 30.

    simply add

    limits = c(0, max(mydata$mean)*30),
    

    to each scale_y_continuous()