Plotting correct colors and ordered factors with missing values

Viewed 388

I'm working with several dataframes that have a few categorical values and creating charts from them.

For example the data may look like this. Notice that "Marcus" is not in friends_2

friends <- data.frame(
  name = factor(c("Nicole", "Sara", "Marcus", "Derek", "Conor", "Anna")),
  number = c(.4, .8, 1, .1, .2, .2)
)

friends_2 <- data.frame(
  name = factor(c("Nicole", "Sara", "Derek", "Conor", "Anna")),
  score = c(50, 10, 20, 90, 15)
)

Here are some code for plots. I have a color palette that is intended to match the names but because "Marcus" isn't on friends_2, the colors don't match up anymore.

cbp1 <- c("#1B9E77", "#D95F02", "#7570B3", "#E7298A", "#66A61E", "#E6AB02")

ggplot(friends, aes(x=name, y=number)) +
  scale_fill_manual(values = cbp1) +
  geom_bar(
    stat = "identity",
    width = 0.5,
    aes(fill = name)
  )

ggplot(friends_2, aes(x=name, y=score)) +
  scale_fill_manual(values = cbp1) +
  geom_bar(
    stat = "identity",
    width = 0.5,
    aes(fill = name)
  )

What is the best way to make it so the colors are aligned with my names? Thank you!

1 Answers

Two options, simple and possibly a more visually attractive version using facet_wrap


library(ggplot2)
library(tidyr)
library(dplyr)


f_levs <- c("Nicole", "Sara", "Marcus", "Derek", "Conor", "Anna")

friends <- data.frame(
  name = factor(c("Nicole", "Sara", "Marcus", "Derek", "Conor", "Anna"), levels = f_levs, ordered = TRUE),
  number = c(.4, .8, 1, .1, .2, .2)
)


friends_2 <- data.frame(
  name = factor(c("Nicole", "Sara", "Derek", "Conor", "Anna"), levels = f_levs, ordered = TRUE),
  score = c(50, 10, 20, 90, 15)
)



cbp1 <- c("#1B9E77", "#D95F02", "#7570B3", "#E7298A", "#66A61E", "#E6AB02")

p1 <- ggplot(friends, aes(x=name, y=number)) +
  scale_fill_manual(values = cbp1, breaks = f_levs) +
  geom_bar(
    stat = "identity",
    width = 0.5,
    aes(fill = name)
  ) +
  ggtitle("p1 - friends")


p2 <- ggplot(friends_2, aes(x=name, y=score)) +
  scale_fill_manual(values = cbp1, breaks = f_levs) +
  geom_bar(
    stat = "identity",
    width = 0.5,
    aes(fill = name)
  ) +
  ggtitle("p2 - friends_2")


with facet_wrap

Combine the data into "long" format for plotting.


f <- 
  friends %>%
  bind_rows(friends_2) %>% 
  mutate(df = case_when(is.na(score) ~ "friends",
                        TRUE ~ "friends_2")) %>% 
  pivot_longer(-c(name, df), names_to = "var", values_to = "val", values_drop_na = TRUE)


p3 <- 
  ggplot(f, aes(name, val, fill = name))+
  geom_col()+
  facet_wrap(~var, scales = "free_y", ncol = 1) +
  ggtitle("p3 - facet_wrap all friends")

enter image description here

Created on 2020-05-13 by the reprex package (v0.3.0)

enter image description here

Related