admin管理员组

文章数量:1356582

I have 2 different dataframes :

# Factor levels
species_order <- c("AMPI","LALO", "HOLA","BASA","SNBU", "WRSA", "REPH","BBSA","CRPL", "PESA", "RUTU","REKN","AMGP","BBPL","LTJA", "PAJA", "ROPT", "PEFA","LTDU", "CORA", "RLHA", "RTLO", "GLGU", "KIEI","SNOW","PALO","SNGO", "CAGO", "ARFO","SACR", "ARHA","TUSW") 
# Dataframe Bylot
n <- 192
bylot <- data.frame(sp_code=rep(species_order, times = n/32),
                    ind_km2=sample(1:100, n, replace=TRUE),
                    site_code=factor(paste("BYLO")))

# Dataframe density
n <- 384
densityy <- data.frame(sp_code=rep(species_order, times = n/32),
                      ind_km2=sample(1:100, n, replace=TRUE),
                      site_code=rep(LETTERS, length.out = n))

I am making a plot like this one :

ggplot(densityy, aes(x=factor(sp_code, level = species_order), y=ind_km2, fill=sp_code, colour = sp_code)) +
  geom_violin(scale = "width", show.legend = FALSE) +
  stat_summary(fun=mean, geom="point", fill = "#FF8247", shape=23, size=3, show.legend = FALSE)+
  stat_summary(aes(x = sp_code, y = ind_km2), data = bylot, fun=mean, geom="point", fill = "#BBFFFF", shape=23, size=3, show.legend = FALSE)+
  scale_y_continuous(breaks = seq(0,400,25), expand = c(0, 0))+
  scale_fill_viridis_d(option = "D", begin = 0.2, direction = -1)+
  scale_color_viridis_d(option = "D", begin = 0.2, direction = -1)+
  labs(x = "Espèces", y = "Densité (individus/km2)")

I would like to add a legend that indicates that the orange points are the mean density for all sites, and the blue points are the mean for the site BYLO :

I've looked for solutions, and I've seen mostly aes(shape). Since I'm using 2 dataframes, I couldn't use aes(shape) for the bylot mean. Is there a way for me to add this legend without changing aes() ?

Here is something I tried, which didn't work :

ggplot(densityy, aes(x=factor(sp_code, level = species_order), y=ind_km2, fill=sp_code, colour = sp_code)) +
  geom_violin(scale = "width", show.legend = FALSE) +
  stat_summary(aes(shape = "Mean"), fun=mean, geom="point", fill = "#FF8247", shape=23, size=3, show.legend = FALSE)+
  stat_summary(aes(x = sp_code, y = ind_km2), data = Bylot, fun=mean, geom="point", fill = "#BBFFFF", shape=23, size=3, show.legend = FALSE)+
  scale_shape_manual("", values=c("Mean"="x"))+
  scale_y_continuous(breaks = seq(0,400,25), expand = c(0, 0))+
  scale_fill_viridis_d(option = "D", begin = 0.2, direction = -1)+
  scale_color_viridis_d(option = "D", begin = 0.2, direction = -1)+
  labs(x = "Espèces", y = "Densité (individus/km2)")+
  annotate("text",
           x = 1:length(table(density$sp_code)),
           y = aggregate(ind_km2 ~ sp_code, density, median)[ , 2],
           label = table(density$sp_code),
           col = "black",
           vjust = - 3)

# Message from the console
Warning messages:
3: No shared levels found between `names(values)` of the manual scale and the data's
shape values. 

Thank you!

I have 2 different dataframes :

# Factor levels
species_order <- c("AMPI","LALO", "HOLA","BASA","SNBU", "WRSA", "REPH","BBSA","CRPL", "PESA", "RUTU","REKN","AMGP","BBPL","LTJA", "PAJA", "ROPT", "PEFA","LTDU", "CORA", "RLHA", "RTLO", "GLGU", "KIEI","SNOW","PALO","SNGO", "CAGO", "ARFO","SACR", "ARHA","TUSW") 
# Dataframe Bylot
n <- 192
bylot <- data.frame(sp_code=rep(species_order, times = n/32),
                    ind_km2=sample(1:100, n, replace=TRUE),
                    site_code=factor(paste("BYLO")))

# Dataframe density
n <- 384
densityy <- data.frame(sp_code=rep(species_order, times = n/32),
                      ind_km2=sample(1:100, n, replace=TRUE),
                      site_code=rep(LETTERS, length.out = n))

I am making a plot like this one :

ggplot(densityy, aes(x=factor(sp_code, level = species_order), y=ind_km2, fill=sp_code, colour = sp_code)) +
  geom_violin(scale = "width", show.legend = FALSE) +
  stat_summary(fun=mean, geom="point", fill = "#FF8247", shape=23, size=3, show.legend = FALSE)+
  stat_summary(aes(x = sp_code, y = ind_km2), data = bylot, fun=mean, geom="point", fill = "#BBFFFF", shape=23, size=3, show.legend = FALSE)+
  scale_y_continuous(breaks = seq(0,400,25), expand = c(0, 0))+
  scale_fill_viridis_d(option = "D", begin = 0.2, direction = -1)+
  scale_color_viridis_d(option = "D", begin = 0.2, direction = -1)+
  labs(x = "Espèces", y = "Densité (individus/km2)")

I would like to add a legend that indicates that the orange points are the mean density for all sites, and the blue points are the mean for the site BYLO :

I've looked for solutions, and I've seen mostly aes(shape). Since I'm using 2 dataframes, I couldn't use aes(shape) for the bylot mean. Is there a way for me to add this legend without changing aes() ?

Here is something I tried, which didn't work :

ggplot(densityy, aes(x=factor(sp_code, level = species_order), y=ind_km2, fill=sp_code, colour = sp_code)) +
  geom_violin(scale = "width", show.legend = FALSE) +
  stat_summary(aes(shape = "Mean"), fun=mean, geom="point", fill = "#FF8247", shape=23, size=3, show.legend = FALSE)+
  stat_summary(aes(x = sp_code, y = ind_km2), data = Bylot, fun=mean, geom="point", fill = "#BBFFFF", shape=23, size=3, show.legend = FALSE)+
  scale_shape_manual("", values=c("Mean"="x"))+
  scale_y_continuous(breaks = seq(0,400,25), expand = c(0, 0))+
  scale_fill_viridis_d(option = "D", begin = 0.2, direction = -1)+
  scale_color_viridis_d(option = "D", begin = 0.2, direction = -1)+
  labs(x = "Espèces", y = "Densité (individus/km2)")+
  annotate("text",
           x = 1:length(table(density$sp_code)),
           y = aggregate(ind_km2 ~ sp_code, density, median)[ , 2],
           label = table(density$sp_code),
           col = "black",
           vjust = - 3)

# Message from the console
Warning messages:
3: No shared levels found between `names(values)` of the manual scale and the data's
shape values. 

Thank you!

Share Improve this question asked Mar 30 at 13:29 MagMag 335 bronze badges 1
  • 4 I believe this is an XY problem. Why not merge the two data frames, creating a column to indicate if the data is BYLOT or other, and then plot the merged data, using the new column to define the shape/colour of the points? That way, you're not making your life difficult by fighting against the expectations that ggplot has for your data. – Limey Commented Mar 30 at 13:58
Add a comment  | 

1 Answer 1

Reset to default 2

You can achieve your desired result by mapping on the fill aes instead of setting the colors as parameters. Additionally, as you are already mapping on the fill and color aes you could use the ggnewscale package which allows to have multiple scales and legends for the same aesthetic.

library(ggplot2)
library(ggnewscale)

ggplot(densityy, aes(
  x = factor(sp_code, level = species_order),
  y = ind_km2, fill = sp_code, colour = sp_code
)) +
  geom_violin(scale = "width", show.legend = FALSE) +
  scale_fill_viridis_d(option = "D", begin = 0.2, direction = -1) +
  scale_color_viridis_d(option = "D", begin = 0.2, direction = -1) +
  ggnewscale::new_scale_fill() +
  stat_summary(
    aes(fill = "other"),
    fun = mean, geom = "point", shape = 23, size = 3,
    show.legend = c(fill = TRUE, color = FALSE)
  ) +
  stat_summary(aes(x = sp_code, y = ind_km2, fill = "bylot"),
    data = bylot, fun = mean,
    geom = "point", shape = 23, size = 3,
    show.legend = c(fill = TRUE, color = FALSE)
  ) +
  scale_fill_manual(
    values = c(bylot = "#BBFFFF", other = "#FF8247"),
    labels = c(bylot = "Bylot", other = "Autres sites")
  ) +
  scale_y_continuous(breaks = seq(0, 400, 25), expand = c(0, 0)) +
  labs(x = "Espèces", y = "Densité (individus/km2)")

本文标签: rSet legend in ggplot with several factor levels without using aes()Stack Overflow