'How ggplot2 seperate the legend of line and point and seperate the color manual of line and point?

I'm trying to plot a graph using ggplot2. And I'm having trouble with the several problems:

  1. I want to separate the legend of point and line
  2. I want to manually add color of the line and the point, if I use scale_colour_manual function, I found it can not separate the legend of line and point.

My data is

sec_dt <- data.table::data.table(
        DATE = c("2021/10/11","2021/10/12","2021/10/13",
                 "2021/10/14","2021/10/15","2021/10/18","2021/10/19",
                 "2021/10/20","2021/10/21","2021/10/22","2021/10/25","2021/10/26",
                 "2021/10/27","2021/10/28","2021/10/29","2021/10/31",
                 "2021/11/1","2021/11/2","2021/11/3","2021/11/4","2021/11/5",
                 "2021/11/8","2021/10/11","2021/10/12","2021/10/13","2021/10/14",
                 "2021/10/15","2021/10/18","2021/10/19","2021/10/20",
                 "2021/10/21","2021/10/22","2021/10/25","2021/10/26","2021/10/27",
                 "2021/10/28","2021/10/29","2021/10/31","2021/11/1",
                 "2021/11/2","2021/11/3","2021/11/4","2021/11/5","2021/11/8",
                 "2021/10/11","2021/10/12","2021/10/13","2021/10/14","2021/10/15",
                 "2021/10/18","2021/10/19","2021/10/20","2021/10/21",
                 "2021/10/22","2021/10/25","2021/10/26","2021/10/27","2021/10/28",
                 "2021/10/29","2021/10/31","2021/11/1","2021/11/2",
                 "2021/11/3","2021/11/4","2021/11/5","2021/11/8","2021/10/11",
                 "2021/10/12","2021/10/13","2021/10/14","2021/10/15","2021/10/18",
                 "2021/10/19","2021/10/20","2021/10/21","2021/10/22",
                 "2021/10/25","2021/10/26","2021/10/27","2021/10/28","2021/10/29",
                 "2021/10/31","2021/11/1","2021/11/2","2021/11/3",
                 "2021/11/4","2021/11/5","2021/11/8"),
        LINE = c("QUANTITY","QUANTITY","QUANTITY",
                 "QUANTITY","QUANTITY","QUANTITY","QUANTITY","QUANTITY","QUANTITY",
                 "QUANTITY","QUANTITY","QUANTITY","QUANTITY","QUANTITY",
                 "QUANTITY","QUANTITY","QUANTITY","QUANTITY","QUANTITY",
                 "QUANTITY","QUANTITY","QUANTITY","PRICE","PRICE","PRICE",
                 "PRICE","PRICE","PRICE","PRICE","PRICE","PRICE","PRICE",
                 "PRICE","PRICE","PRICE","PRICE","PRICE","PRICE","PRICE",
                 "PRICE","PRICE","PRICE","PRICE","PRICE","BUY_POINT",
                 "BUY_POINT","BUY_POINT","BUY_POINT","BUY_POINT","BUY_POINT",
                 "BUY_POINT","BUY_POINT","BUY_POINT","BUY_POINT","BUY_POINT",
                 "BUY_POINT","BUY_POINT","BUY_POINT","BUY_POINT","BUY_POINT",
                 "BUY_POINT","BUY_POINT","BUY_POINT","BUY_POINT","BUY_POINT",
                 "BUY_POINT","SELL_POINT","SELL_POINT","SELL_POINT",
                 "SELL_POINT","SELL_POINT","SELL_POINT","SELL_POINT","SELL_POINT",
                 "SELL_POINT","SELL_POINT","SELL_POINT","SELL_POINT",
                 "SELL_POINT","SELL_POINT","SELL_POINT","SELL_POINT","SELL_POINT",
                 "SELL_POINT","SELL_POINT","SELL_POINT","SELL_POINT",
                 "SELL_POINT"),
       POINT = c("QUANTITY","QUANTITY","QUANTITY",
                 "QUANTITY","QUANTITY","QUANTITY","QUANTITY","QUANTITY","QUANTITY",
                 "QUANTITY","QUANTITY","QUANTITY","QUANTITY","QUANTITY",
                 "QUANTITY","QUANTITY","QUANTITY","QUANTITY","QUANTITY",
                 "QUANTITY","QUANTITY","QUANTITY","PRICE","PRICE","PRICE",
                 "PRICE","PRICE","PRICE","PRICE","PRICE","PRICE","PRICE",
                 "PRICE","PRICE","PRICE","PRICE","PRICE","PRICE","PRICE",
                 "PRICE","PRICE","PRICE","PRICE","PRICE","BUY_POINT",
                 "BUY_POINT","BUY_POINT","BUY_POINT","BUY_POINT","BUY_POINT",
                 "BUY_POINT","BUY_POINT","BUY_POINT","BUY_POINT","BUY_POINT",
                 "BUY_POINT","BUY_POINT","BUY_POINT","BUY_POINT","BUY_POINT",
                 "BUY_POINT","BUY_POINT","BUY_POINT","BUY_POINT","BUY_POINT",
                 "BUY_POINT","SELL_POINT","SELL_POINT","SELL_POINT",
                 "SELL_POINT","SELL_POINT","SELL_POINT","SELL_POINT","SELL_POINT",
                 "SELL_POINT","SELL_POINT","SELL_POINT","SELL_POINT",
                 "SELL_POINT","SELL_POINT","SELL_POINT","SELL_POINT","SELL_POINT",
                 "SELL_POINT","SELL_POINT","SELL_POINT","SELL_POINT",
                 "SELL_POINT"),
       VALUE = c(12500,12500,12500,12500,12500,12500,
                 12500,12500,12500,12500,10100,10100,10100,10100,10100,
                 10100,10100,10100,10100,10100,10100,0,49.63,50.36,50.06,
                 52.8,52.5,50.9,50.99,50.91,50.71,50.06,49.71,50.8,
                 51.09,51.27,52.8,52.8,51.07,50.35,50.25,49.24,49.03,
                 52.91,49.63,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,
                 NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,
                 NA,NA,49.71,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,52.91)
)

And my code is

library(data.table)
library(ggplot2)

sec_dt <- sec_dt[, DATE := lubridate::ymd(DATE)]
x1 <- max(sec_dt[LINE == 'QUANTITY', VALUE]) * 2
y1 <- max(sec_dt[LINE == 'PRICE', VALUE])
x2 <- min(sec_dt[LINE == 'QUANTITY', VALUE])
y2 <- min(sec_dt[LINE == 'PRICE', VALUE])

k <- (y2 - y1) / (x2 - x1)
b <- y1 - k*x1
stopifnot(!is.na(k),  !is.na(b))

p <- ggplot(sec_dt, aes(x = DATE)) +
  geom_point(aes(y = VALUE, size = POINT, color = POINT), data = sec_dt[POINT %in% c('BUY_POINT', 'SELL_POINT')]) +
  geom_line(aes(y = VALUE, linetype = LINE, colour = LINE), data = sec_dt[LINE %in% c('PRICE')]) +
  geom_line(aes(y = VALUE * k + b, linetype = LINE, colour = LINE), data = sec_dt[LINE %in% c('QUANTITY')]) +
  scale_linetype_manual('', values = c('PRICE' = 'solid', 'QUANTITY' = 'dashed')) +
  scale_size_manual('', values = c('BUY_POINT' = 2, 'SELL_POINT' = 2)) +
  scale_colour_manual('', values = c('PRICE' = '#000000', 'QUANTITY' = '#CC0000', 'BUY_POINT' = '#FF0000', 'SELL_POINT' = '#31FF21')) +
  scale_y_continuous(
    name = 'price', limits = c(min(sec_dt[LINE == 'PRICE', VALUE]), max(sec_dt[LINE == 'PRICE', VALUE])),
    sec.axis = sec_axis(~ (. - b) / k , name = "quantity")
  ) +
  labs(x = NULL, y = NULL) +
  scale_x_date(
    labels = scales::date_format("%Y-%m"), expand = c(0, 12)
  ) +
  theme_minimal() +
  theme(
    plot.title = element_text(hjust = 0.5),
    panel.grid.minor = element_blank(),
    panel.border = element_blank(),
    axis.title.x = element_text(size = 12),
    axis.title.y = element_text(size = 12),
    legend.text = element_text(size = 8),
    legend.position = "top"
  )
p

And my graph is like this:

My plot

But I need the graph like this:

My needness plot

Does anyone know how to separate the legend of point and line? And how to add different color of line and point separately ?



Solution 1:[1]

One option to achieve your desired result would be the ggnewscale package which allows for multiple scales and legends for the same aesthetic. To this end:

  1. Duplicate your scale_colour_manual and add dirt straight after the geom_point
  2. Add a new color scale using ggnewscale::new_scale_color()

Note: I added limits=force to each scale_colour_manual to drop unused colors from the legend.

library(ggplot2)
library(ggnewscale)

ggplot(sec_dt, aes(x = DATE)) +
  geom_point(aes(y = VALUE, size = POINT, color = POINT), data = sec_dt[POINT %in% c('BUY_POINT', 'SELL_POINT')]) +
  scale_colour_manual('', values = c('PRICE' = '#000000', 'QUANTITY' = '#CC0000', 'BUY_POINT' = '#FF0000', 'SELL_POINT' = '#31FF21'), limits = force) +
  ggnewscale::new_scale_color() +
  geom_line(aes(y = VALUE, linetype = LINE, colour = LINE), data = sec_dt[LINE %in% c('PRICE')]) +
  geom_line(aes(y = VALUE * k + b, linetype = LINE, colour = LINE), data = sec_dt[LINE %in% c('QUANTITY')]) +
  scale_linetype_manual('', values = c('PRICE' = 'solid', 'QUANTITY' = 'dashed')) +
  scale_size_manual('', values = c('BUY_POINT' = 2, 'SELL_POINT' = 2)) +
  scale_colour_manual('', values = c('PRICE' = '#000000', 'QUANTITY' = '#CC0000', 'BUY_POINT' = '#FF0000', 'SELL_POINT' = '#31FF21'), limits = force) +
  scale_y_continuous(
    name = 'price', limits = c(min(sec_dt[LINE == 'PRICE', VALUE]), max(sec_dt[LINE == 'PRICE', VALUE])),
    sec.axis = sec_axis(~ (. - b) / k , name = "quantity")
  ) +
  labs(x = NULL, y = NULL) +
  scale_x_date(
    labels = scales::date_format("%Y-%m"), expand = c(0, 12)
  ) +
  theme_minimal() +
  theme(
    plot.title = element_text(hjust = 0.5),
    panel.grid.minor = element_blank(),
    panel.border = element_blank(),
    axis.title.x = element_text(size = 12),
    axis.title.y = element_text(size = 12),
    legend.text = element_text(size = 8),
    legend.position = "top"
  )
#> Warning: Removed 41 rows containing missing values (geom_point).

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 stefan