M. Beausoleil
M. Beausoleil

Reputation: 3557

How to fill points from 2 different sets of colours in ggplot?

I have this data:

structure(list(band.fct = structure(c(1L, 1L, 1L, 1L, 1L, 2L, 
2L, 2L, 2L, 2L, 3L, 3L, 3L, 3L, 4L, 4L, 4L, 4L, 4L, 5L, 5L, 5L, 
5L), .Label = c("id1", "id2", "id3", "id4", "id5"), class = "factor"), 
    Habitat = structure(c(1L, 2L, 3L, 4L, 5L, 1L, 2L, 3L, 4L, 
    5L, 2L, 3L, 4L, 5L, 1L, 2L, 3L, 4L, 5L, 1L, 3L, 4L, 5L), .Label = c("hab1", 
    "hab2", "hab3", "hab4", "hab5"), class = "factor"), indices = c(0.161144048214651, 
    -1, -0.689801153717231, 0.692829786903339, -1, 0.149024000501955, 
    -1, 0.477510693697384, -0.642600531465182, -1, -0.0286086971625589, 
    -0.6272579243597, 0.649130601630324, -1, -1, -1, -0.367988698543796, 
    0.473751285757837, -1, -1, 0.062409468983144, 0.0164070894341967, 
    -1), dir.selection = structure(c(2L, 3L, 3L, 1L, 3L, 2L, 
    3L, 1L, 3L, 3L, 2L, 3L, 1L, 3L, 3L, 3L, 2L, 1L, 3L, 3L, 2L, 
    2L, 3L), .Label = c("Preferred", "-", "Avoided"), class = "factor")), row.names = c(NA, 
-23L), class = c("tbl_df", "tbl", "data.frame"))

with which I'm drawing a bar plot like this:

col.dir.sel = c("#2D3D50","#E74D3C","#26AE61") shape.dir.sel = c(21,25,24) text.size =14

my.dat %>% 
  ggplot(aes(x = Habitat,
             y = indices, 
             fill = band.fct)) +
  geom_hline(yintercept = 0)+ 
  geom_bar(#position = position_dodge(width=0.85), 
    position = "dodge", 
    stat = "identity", width = .7, size =2) +
  geom_point(data = my.dat,
             position = position_dodge(width = .7), 
             aes(x = Habitat, 
                 y = position.point,
                 fill = band.fct,
                 col = dir.selection,
                 shape = dir.selection), 
             size = 6) + 
  ylim(range(c(-1.2,hstab.long.fil$indices,1.2))) +
  theme(axis.line = element_line(linetype = "solid"), 
        axis.ticks = element_line(colour = "black", size = 1),
        axis.title = element_text(size = text.size), 
        axis.title.x=element_blank(),
        axis.text = element_text(size = c(text.size-2), colour = "black"), 
        plot.title = element_text(size = text.size, hjust = 0.05, vjust = -7), 
        plot.tag = element_text(face = "bold", colour = "black", size = 20),
        plot.tag.position = c(0.01, 0.98),
        plot.background = element_rect(fill = "transparent", color = NA), # bg of the plot
        panel.grid.major = element_line(colour = col.grid, size = 0.3, linetype = "dotted"), 
        panel.grid.minor = element_line(colour = col.grid, size = 0.0, linetype = "dotted"), 
        panel.background = element_rect(fill = "transparent"),
        legend.title = element_text(colour="black", size=text.size, 
                                    face="bold"),
        legend.text = element_text(colour="black", size=(text.size-2))
  ) +
  labs(y = "Index", size = c(text.size)) + 
  scale_x_discrete(drop=FALSE) + 
  scale_fill_brewer(palette="Set1",drop=FALSE) + 
  scale_color_manual(values = col.dir.sel[c(3,1,2)],drop=FALSE) +
  scale_shape_manual(values = c(24,21,25),drop=FALSE,
                     guide = guide_legend(override.aes = list(fill = col.dir.sel[c(3,1,2)]))) +
  labs(fill="Individuals", 
       color = "Direction of\nselection", 
       shape = "Direction of\nselection") + 
  guides(fill = guide_legend(override.aes = list(shape = rep(NA, 5) ) ) )

So far it gives me this: enter image description here

Which is what I want except only one thing: the colour of the legend "Direction of selection" is the correct one, but the points above and below the bars have the fill of the bars and not the one in the legends.

How then it would be possible to plot the points with the correct colours? (i.e., the colours in the legend)? I really want to use the up and down arrow and in R, it seems that the down arrow is the one that needs to be filled...

Upvotes: 2

Views: 1185

Answers (1)

teunbrand
teunbrand

Reputation: 38063

The problem here is that you're trying to map two variables to two fill scales, whereas vanilla ggplot2 only accepts one fill scale per plot. You can use the ggnewscale package to create additional fill scales. Your example data + code didn't work for me due to missing environment variables, so I've mocked up some data for the example below. The order of operations matter, so I've commented at places you should be a bit careful.

library(ggplot2)
library(ggnewscale)
#> Warning: package 'ggnewscale' was built under R version 4.0.3

# Making dummy data
df <- data.frame(
  individual = rep(paste0("id", 1:5), each = 5),
  habitat = rep(paste0("hab", 1:5), 5),
  y = rnorm(25)
)
df$dir.selection <- factor(ifelse(
  df$y > 0.5, "Preferred",
  ifelse(df$y < -0.5, "Avoided", "-")
), levels = c("Preferred", "-", "Avoided"))

ggplot(df, aes(habitat, y)) +
  # First make the layer with the first fill scale
  geom_col(aes(fill = individual),
           position = "dodge") +
  # Apply the fill scale
  scale_fill_brewer(palette = "Set1") +
  # Then set the new scale. Every fill after this will be mapped to the new fill scale
  new_scale_fill() +
  # Make the second layer with the second fill
  geom_point(
    aes(fill  = dir.selection,
        shape = dir.selection,
        y = y + sign(y) * 0.2,
        group = individual),
    size = 5,
    position = position_dodge(width = 0.9)
  ) +
  scale_shape_manual(values = c(24, 21, 25),
                     name = "Direction of\nSelection") +
  # Set the second fill scale parallel to the shape scale
  scale_fill_manual(values = c("green", "blue", "red"),
                    name = "Direction of\nSelection")

Created on 2021-03-30 by the reprex package (v1.0.0)

Upvotes: 3

Related Questions