简体   繁体   中英

Set left and right limit ranges simultaneously for dual y-axis plot using ggplot2

Given a dataframe df :

df <- structure(list(date = c("2022-4-30", "2022-5-5", "2022-5-6", 
"2022-5-9", "2022-5-10", "2022-5-11", "2022-5-12", "2022-5-13", 
"2022-5-16", "2022-5-17", "2022-5-18", "2022-5-19", "2022-5-20"
), value1 = c(6, 6.1, 6.5, 6.9, 7.3, 7.7, 8.1, 8, 7.9, 7.8, 7.7, 
7.6, 7.5), value2 = c(-1L, -2L, 0L, 6L, 7L, 5L, 3L, 10L, 18L, 
16L, 12L, 19L, 20L), value3 = c(2.7, 2.4, 1.7, 0.5, -0.5, 0.2, 
-0.3, -0.2, 0.4, 0.9, 1.3, 1.1, 1)), class = "data.frame", row.names = c(NA, 
-13L))

Out:

        date value1 value2 value3
1  2022-4-30    6.0     -1    2.7
2   2022-5-5    6.1     -2    2.4
3   2022-5-6    6.5      0    1.7
4   2022-5-9    6.9      6    0.5
5  2022-5-10    7.3      7   -0.5
6  2022-5-11    7.7      5    0.2
7  2022-5-12    8.1      3   -0.3
8  2022-5-13    8.0     10   -0.2
9  2022-5-16    7.9     18    0.4
10 2022-5-17    7.8     16    0.9
11 2022-5-18    7.7     12    1.3
12 2022-5-19    7.6     19    1.1
13 2022-5-20    7.5     20    1.0

I use code below to plot dual y-axis (left side for value1 and value3 , right side for value2 ):

df_m <- melt(df, id.vars = 'date')
df_m <- df_m %>% 
  mutate(date=as.Date(date))

df_m1 <- df_m %>% 
  filter(variable %in% c("value1", 'value3')) 

df_m2 <- df_m %>% 
  filter(variable %in% c("value2")) %>%
  mutate(value = value * 0.6)


df_m2
coeff = 1/0.6

ggplot() +
  geom_line(data = df_m1[!is.na(df_m1$value), ], aes(x = date, y = value, col = variable), alpha = 1, size = 1) +
  geom_line(data = df_m2[!is.na(df_m2$value), ], aes(x = date, y = value, col = variable), alpha = 1, size = 1) +
  scale_y_continuous(
    name = '',
    # limits=c(-1, 9),
    sec.axis = sec_axis(~.*coeff, name = "")) 

Out:

在此处输入图像描述

Now I wondering if it's possible to set limits=c(-1, 9) for left y-axis and limits=c(-2, 20) for right y-axis simultaneously using ggplot2?

I try with code below, but right y-axis's changed to around limits=c(-2, 15) , not as figure above. Alternative solutions to plot a similar dual y-axis plot will be welcomed as well.

ggplot() +
  geom_line(data = df_m1[!is.na(df_m1$value), ], aes(x = date, y = value, col = variable), alpha = 1, size = 1) +
  geom_line(data = df_m2[!is.na(df_m2$value), ], aes(x = date, y = value, col = variable), alpha = 1, size = 1) +
  scale_y_continuous(
    name = '',
    limits=c(-1, 9),
    sec.axis = sec_axis(~.*coeff, name = ""))

在此处输入图像描述

Reference:

https://r-graph-gallery.com/line-chart-dual-Y-axis-ggplot2.html

This is one of the reasons ggh4x::help_secondary() was written. Essentially it figures out the transformation needed to get the secondary range to match the primary range and the inverse. We apply the transformation to secondary data and it's inverse is used as the trans argument of the secondary axis.

In your example, we can drop the mutate() bit, because that is handled in sec$proj() .

(Disclaimer: I wrote ggh4x)

# df <- structure(...) # omitted for brevity

library(ggplot2)
library(dplyr)
library(reshape2)

df_m <- melt(df, id.vars = 'date')
df_m <- df_m %>% 
  mutate(date=as.Date(date))

df_m1 <- df_m %>% 
  filter(variable %in% c("value1", 'value3')) 

df_m2 <- df_m %>% 
  filter(variable %in% c("value2"))

sec <- ggh4x::help_secondary(
  name = "",
  primary = c(-1, 9), secondary = c(-2, 20),
)

ggplot() +
  geom_line(data = df_m1[!is.na(df_m1$value), ], 
            aes(x = date, y = value, col = variable), alpha = 1, size = 1) +
  geom_line(data = df_m2[!is.na(df_m2$value), ], 
            aes(x = date, y = sec$proj(value), col = variable), alpha = 1, size = 1) +
  scale_y_continuous(
    limits = c(-1, 9),
    name = '',
    sec.axis = sec) 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM