Search code examples
rggplot2plotcolorsfill

Problem with seperating fill from color in ggplot2's geom_rect


I'm making a plot using ggplot2, when I try to separate between the fill and the color I just get the color overriding the fill.

The code for my data frame is as follows:

set.seed(42)

# Create the data frame
mydata <- data.frame(
  Species = rep(letters[1:5], each = 2),
  Community = rep(c("mono", "mix"), times = 5),
  mean_start = runif(10, min = 5, max = 10),
  mean_end = runif(10, min = 20, max = 30)
)

The code for my plot (and color vectors) is:

#Color vectors
color_palette <- c("a" = "#E69F00", "b" = "#D55E00", "c" = "#56B4E9",
                   "d" = "#009E73", "e" = "#CC79A7")
Com_color_palette <- c("mono" = "black", "mix" = "gray")

#Plot code
plot <- ggplot(data = mydata) +
  geom_rect(aes(xmin = Species,
                xmax = Species,
                ymin = mean_start,
                ymax = mean_end,
                group = Community,
                fill = Community,
                color = Species),
            position = position_dodge(width = 0.7),
            linewidth = 7) +
  labs(x = "Species", y = "Weeks") +
  ggtitle("try plot") +
  theme(plot.title = element_text(hjust = 0.5)) +
  theme(panel.background = element_rect(fill = "white")) +
  theme(axis.line = element_line(colour = 'black', linewidth = 0.5, linetype = 'solid')) +
  theme(axis.text = element_text(size = 32),
        axis.title = element_text(size = 34), 
        plot.title = element_text(size = 36)) +
  theme(panel.grid.minor = element_line(color = "gray", linetype = "dashed")) +
  scale_y_continuous(limits = c(3, 40)) +
  scale_fill_manual(name = "Community", values = Com_color_palette) +
  scale_color_manual(name = "Species", values = color_palette) +
  guides(size = "none", alpha = "none", color = "none") +
  guides(fill = guide_legend(nrow = 1, title.position = "top", title.hjust = 0.5)) +
  theme(legend.position = "bottom",
        legend.box = "horizontal",
        legend.box.just = "center",
        legend.margin = margin(1, 10, 10, 10),
        legend.text = element_text(size = 25),
        legend.title = element_text(size = 25)) +
  coord_flip()

The plot I get looks like this: Current plot

Ideally, the fill will be black/gray (per Community - mix / mono) and the border (color) will be separated by Species (a/b/c/d/e).

Thanks in advance!


Solution

  • The problem is that each of your geom_rect objects has the same xmin and xmax. They are therefore zero-width (effectively just lines) and have no interior space to fill.

    You are clearly compensating for this in your code by setting linewidth = 7, to make these lines appear wider, but this only makes the line around each zero-width rectangle thicker. Since these lines' color is controlled purely by the colour aesthetic, this is all you see. Effectively, you are just making a geom_linerange.

    The solution is to give your rectangles a non-zero width. It is tricky to do this with geom_rect when you have discrete variables. You will need to convert the Species from character to factor to numeric, perform calculations on this value, and specify you want a scale_x_discrete:

    ggplot(data = mydata, aes(x = Species)) +
      geom_rect(aes(xmin = as.numeric(factor(Species)) + 0.25,
                    xmax = as.numeric(factor(Species)) - 0.25,
                    ymin = mean_start,
                    ymax = mean_end,
                    group = Community,
                    fill = Community,
                    color = Species),
                linewidth = 2, position = position_dodge(0.75)) +
      scale_fill_manual(name = "Community", values = Com_color_palette) +
      scale_color_manual(name = "Species", values = color_palette, guide = "none") +
      scale_y_continuous(name = "Weeks", limits = c(3, 40)) +
      scale_x_discrete() +
      ggtitle("try plot") +
      guides(fill = guide_legend(title.position = "top", title.hjust = 0.5)) +
      theme(panel.background = element_rect(fill = "white"),
            axis.line = element_line(linewidth = 0.5),
            axis.text = element_text(size = 32),
            axis.title = element_text(size = 34), 
            plot.title = element_text(size = 36, hjust = 0.5),
            panel.grid.minor = element_line(color = "gray", linetype = "dashed"),
            legend.position = "bottom",
            legend.box = "horizontal",
            legend.box.just = "center",
            legend.margin = margin(1, 10, 10, 10),
            legend.text = element_text(size = 25),
            legend.title = element_text(size = 25)) +
      coord_flip()
    

    enter image description here