0

I have a data frame and I wonder how to plot a line using "max" (in red) with a filled area (in blue), and then add a second line using "min" (in green). Thanks a lot. The x-axis is "x".

df <- data.frame(
    x = c("Jan","Feb","Mar","April","May","June","July"),
    max = c(100,150,200,300,80,130,50),
    min = c(30,20,40,25,15,10,8))

I have tried the following code:

df$x = 1:7
ggplot(df, aes(x)) + 
    geom_line(aes(y = max), color="red") + 
    geom_area() + 
    geom_line(aes(y = min), color = "blue")

But an error occurs: Error in eval(expr, envir, enclos) : object 'y' not found

alistaire
  • 42,459
  • 4
  • 77
  • 117
Yang Yang
  • 858
  • 3
  • 26
  • 49

2 Answers2

2

One option is to turn x into a factor with the levels in the correct order and set a group aesthetic:

library(ggplot2)

df = data.frame(x = c("Jan","Feb","Mar","April","May","June","July"),
                max = c(100,150,200,300,80,130,50), 
                min = c(30,20,40,25,15,10,8))

df$x <- factor(df$x, df$x, ordered = TRUE)

ggplot(df, aes(x, ymin = min, ymax = max, group = 1)) + 
  geom_ribbon(fill = 'steelblue3', alpha = 0.5) + 
  geom_line(aes(y = min), color = 'green3') + 
  geom_line(aes(y = max), color = 'red2')

A more robust option is to parse x to Date class so x-axis labels get generated automatically:

df = data.frame(x = c("Jan","Feb","Mar","April","May","June","July"),
                max = c(100,150,200,300,80,130,50), 
                min = c(30,20,40,25,15,10,8))

df$x <- as.Date(paste(substr(df$x, 1, 3), '01 2017'), format = '%b %d %Y')

ggplot(df, aes(x, ymin = min, ymax = max)) + 
  geom_ribbon(fill = 'steelblue3', alpha = 0.5) + 
  geom_line(aes(y = min), color = 'green3') + 
  geom_line(aes(y = max), color = 'red2')

Further breaks or alternative formatting can be added with scale_x_date.

alistaire
  • 42,459
  • 4
  • 77
  • 117
1

Maybe you are looking for geom_ribbon:

df <- data.frame(
    x = c("Jan","Feb","Mar","April","May","June","July"),
    max = c(100,150,200,300,80,130,50),
    min = c(30,20,40,25,15,10,8))

df$xpos <- seq_len(nrow(df))

ggplot(df, aes(x = xpos)) +
    geom_ribbon(aes(ymin = min, ymax = max), fill = 'blue') +
    geom_line(aes(y = max), color = 'red') +
    geom_line(aes(y = min), color = 'green') +
    scale_x_continuous(breaks = df$xpos, labels = df$x)

If you want to start first data point and remove extra space from left end, you can set expand = c(0, 0). However, you would also need to expand right limit manually to avoid the x label from being cropped.

ggplot(df, aes(x = xpos)) +
    geom_ribbon(aes(ymin = min, ymax = max), fill = 'blue') +
    geom_line(aes(y = max), color = 'red') +
    geom_line(aes(y = min), color = 'green') +
    scale_x_continuous(breaks = df$xpos, labels = df$x,
                       expand = c(0, 0), limits = c(1, 7.2))

enter image description here

mt1022
  • 16,834
  • 5
  • 48
  • 71
  • Thank you so much for your help. I have one more question: how to make the plot start from 0, there is a gap on the plot now. – Yang Yang Apr 25 '17 at 04:00
  • 1
    @YangYang That is expansions of x range. You can suppress the expansion from both with `expand = c(0, 0)` : `scale_x_continuous(breaks = df$xpos, labels = df$x, expand = c(0, 0))`, but the last label will be also cropped too. – mt1022 Apr 25 '17 at 04:46
  • Thank you for your help. – Yang Yang Apr 25 '17 at 22:04