godines
godines

Reputation: 359

How to highlight specific lines in specific groups with ggplot2?

I'm trying to highlight (change the color) specific lines in a plot.

The input data looks like this:

dt <- data.frame(Marker = paste0('m', rep(seq(1,10), 10)),
                 Year = rep(1990:1999, each = 10),
                 Ahat = rnorm(100, 0.5, 0.1)) %>% 
  mutate(Group = if_else(Marker %in% c("m1", "m2", "m3"), "A", 
                         if_else(Marker %in% c("m4", "m5", "m6"), "B", 
                         if_else(Marker %in% c("m7", "m8"), "C", "D")) ) )

And the general plot can be created by:

ggplot(dt, aes(x = Year, y = Ahat, group = interaction(as.factor(Group), Marker), color = as.factor(Group) ) ) + 
  geom_line(alpha = 0.5, size = 0.5) +
  theme_classic() +
  scale_y_continuous(name = "Predicted Value", breaks = pretty_breaks()) +
  scale_colour_manual(name = "Groups", values = c("black", "red", "blue", "orange")) +
  facet_wrap(~Group)

enter image description here

What I'd like to do is to highlight (e.g. make some lines black) some specific lines in specific groups (e.g. "m1" and "m9"). I've tried using something like this gghighlight(Marker %in% c("m1", "m9")), but it doesn't work.

I'd like to have something like this (sorry for my poor drawing skills): enter image description here

Any suggestion?

P.S: My real data has 50K markers.

Thank you!

Upvotes: 1

Views: 1103

Answers (2)

abreums
abreums

Reputation: 196

One option would be to first group data in subgroups (nesting in the dataframe) and then build the plots...

library(tidyverse)
library(scales)
library(patchwork)

# 1. Create dataframe ----
dt <- data.frame(Marker = as.factor(paste0('m', rep(seq(1,10), 10))),
                 Year = rep(1990:1999, each = 10),
                 Ahat = rnorm(100, 0.5, 0.1)) %>% 
  mutate(Group = case_when(
    Marker %in% c("m1", "m2", "m3") ~ "A", 
    Marker %in% c("m4", "m5", "m6") ~ "B", 
    Marker %in% c("m7", "m8")       ~ "C",
    TRUE ~ "D"))


# 2. Function to choose which Market of sub_df should be Highlight
getHighlightMarketBasedOntAhatValue <- function(sub_dt) {
  sub_dt <- sub_dt %>% 
    group_by(Marker) %>% 
    mutate(mean_Ahat = mean(Ahat))
  # using mean to choose Ahat is just a doomed example... also instead of a single value you could get an array of values.
# Here I am not using the index...1, 2... any more (as was in first solution), but the factor itself.
  highlightMarket <- first(sub_dt$Marker[sub_dt$mean_Ahat == max(sub_dt$mean_Ahat)])
}

# 3. Function to build plot for sub_df
my_plot <- function(sub_dt, highlighted_one) {
  custom_pallete = rep("grey", length(levels(sub_dt$Marker)))
  names(custom_pallete) <- levels(sub_dt$Marker)
  custom_pallete[highlighted_one] = "blue"
  
  dt %>% ggplot(aes(x = Year, 
                    y = Ahat, 
                    color = as.factor(Marker))) + 
    geom_line(alpha = 0.5, size = 0.5) +
    theme_classic() +
    scale_y_continuous(name = "Predicted Value", breaks = pretty_breaks()) +
    scale_colour_manual(name = "Marker", values = custom_pallete)
}

# 4. Main ----

# 4.1 Nesting ----
nested_dt <- dt %>% 
  group_by(Group) %>% 
  nest()

# 4.2 Choosing highlight Market for each subgroup ----
nested_dt <- nested_dt %>% 
  mutate(highlighted_one = getHighlightMarketBasedOntAhatValue(data[[1]]))

# 4.3 Build plots ----
nested_dt <- nested_dt %>% 
  mutate(plot = map2(.x = data,
                     .y = highlighted_one,
                     .f = ~ my_plot(.x, .y)))

# 4.4 Use patchwork ... ----
# to combine plots ... see patchwork help to find out how to 
# manage titles, labels, etc.
nested_dt %>% pull(plot) %>% patchwork::wrap_plots()

```

Upvotes: 1

TarJae
TarJae

Reputation: 78927

One way could be to set color as Marker. Then you can change the color of the Marker in this line

scale_colour_manual(name = "Groups", values = c("black", "red", "blue", "orange", "green", "black", "red", "blue", "orange", "green")) +

Change the colors as you like:

ggplot(dt, aes(x = Year, y = Ahat, group = interaction(as.factor(Group), Marker), color = Marker ) ) + 
  geom_line(alpha = 0.5, size = 0.5) +
  theme_classic() +
  scale_y_continuous(name = "Predicted Value", breaks = pretty_breaks()) +
  scale_colour_manual(name = "Groups", values = c("black", "red", "blue", "orange", "green",
                                                  "black", "red", "blue", "orange", "green")) +
  facet_wrap(~Group)

enter image description here

Upvotes: 1

Related Questions