Jude
Jude

Reputation: 193

How to create a corresponding and merged legend in ggplot?

I created this scatter plot with ggplot and as you can see I don't manage to create a corresponding legend to the plot:

I would have like as well, if possible, to put the legend for the dashed line "Seuil" closer to these points.

Here is my code:

ggplot(tst_formule, aes(x=nom_graph, y = value, shape = BRI_type, col = factor(BRI_type))) + 
  geom_point(size = 4) + 
  scale_shape_manual("", values = c( 15, 17)) +
  scale_colour_manual(values=c("grey20", "gray54"),  # légende
                      name  ="Légende",
                      breaks=c("BRI_adi_moy_guide", "BRI_adi_moy_Sandrine"),
                      labels=c("Méthode par transects", "Méthode par sous-transects")) +
  geom_text(aes(label = value, vjust = -0.5, hjust= -0.1), show.legend = FALSE) + # etiquettes
  geom_hline(aes(yintercept = 0.004, linetype = "Seuil"), colour= 'black') + 
  scale_linetype_manual("", values = c(2),  guide = guide_legend(override.aes = list(color = c("black")))) + 
  scale_x_discrete("\nTronçons\n") + 
  scale_y_continuous("\nValeur du BRI*\n", limits = c(0,0.025)) + 
  theme(axis.text.x = element_text(size = 11),
        axis.text.y = element_text(size = 11),
        legend.text = element_text(size = 11),
        plot.margin = unit(c(0.2,0.2,0.2,0.2), "cm"))

I read several posts and tried different solutions but it doesn't work, I'm still new to ggplot and I think my syntax may be wrong for the legend...

Here is a dput() of my data:

structure(list(Riviere = c("Durance", "Durance", "Roya", "Drac", 
"Drac", "Durance", "Durance", "Roya", "Drac", "Drac"), Troncon = c("La Brillanne", 
"Les Mées", "Basse vallée", "St Bonnet", "St Bonnet", "La Brillanne", 
"Les Mées", "Basse vallée", "St Bonnet", "St Bonnet"), Annee = c(2017, 
2017, 2018, 2011, 2018, 2017, 2017, 2018, 2011, 2018), nom_graph = c("La Brillane 2017 \nDurance", 
"Les Mées 2017 \nDurance", "Roya 2018", "St Bonnet 2011 \nDrac", 
"St Bonnet 2018 \nDrac", "La Brillane 2017 \nDurance", "Les Mées 2017 \nDurance", 
"Roya 2018", "St Bonnet 2011 \nDrac", "St Bonnet 2018 \nDrac"
), BRI_type = c("BRI_adi_moy_Sandrine", "BRI_adi_moy_Sandrine", 
"BRI_adi_moy_Sandrine", "BRI_adi_moy_Sandrine", "BRI_adi_moy_Sandrine", 
"BRI_adi_moy_guide", "BRI_adi_moy_guide", "BRI_adi_moy_guide", 
"BRI_adi_moy_guide", "BRI_adi_moy_guide"), value = c(0.0037, 
0.0024, 0.0013, 0.0239, 0.0038, 0.0028, 0.0017, 0.0009, 0.02, 
0.0031)), row.names = c(NA, -10L), class = "data.frame")

Any help is welcomed!

Upvotes: 0

Views: 308

Answers (1)

chemdork123
chemdork123

Reputation: 13863

First of all: Thanks so much for posting your dataset via dput. It really helps to answer your question and is really appreciated.

The basic idea is to let ggplot create and combine legends, which it tries to do intelligently. To create a legend in the first place, you put the parameter into an aesthetic (aes()), which you've done already. In your case, you want to combine the shape= and color= aesthetic.

First of all, make sure they are pointing to the right thing. In your case, the references are not the same (shape= BRI_type, whereas color= factor(BRI_type)), but to ggplot, this is the same thing. The character vector tst_formule$BRI_type will be converted to a factor during the creation of the plot in order to separate shape= based on the levels of that factor. Bottom line, you can remove factor(BRI_type) and just use BRI_type; however, the end result is the same. It's just better practice.

Remember I mentioned that ggplot tries to combine legends automatically? Well, since color= and shape= are pointed to the same factor (BRI_type, which gets factored before plotting), by default, you will get a combined legend. You can see this for yourself by removing scale_color_manual and scale_shape_manual from your original code:

ggplot(tst_formule, aes(x=nom_graph, y = value, shape = BRI_type, col = BRI_type)) + 
  geom_point(size = 4) + 
  geom_text(aes(label = value, vjust = -0.5, hjust= -0.1), show.legend = FALSE) + # etiquettes
  geom_hline(aes(yintercept = 0.004, linetype = "Seuil"), colour= 'black') + 
  scale_linetype_manual("", values = c(2),  guide = guide_legend(override.aes = list(color = c("black")))) + 
  scale_x_discrete("\nTronçons\n") + 
  scale_y_continuous("\nValeur du BRI*\n", limits = c(0,0.025)) + 
  theme(axis.text.x = element_text(size = 11),
        axis.text.y = element_text(size = 11),
        legend.text = element_text(size = 11),
        plot.margin = unit(c(0.2,0.2,0.2,0.2), "cm"))

enter image description here

The general rule is in order to preserve the legend combination, if you change one aspect of one legend, you have to make the same simultaneous change to the other legend. This concept is demonstrated well in this post. So in the solution, I'll change both legends concurrently.

Additionally, you will see I've done the following in order to adjust the spacing of the legends:

  • Changed both scale_shape_ and scale_color_ calls to use the same parameters for name=, and labels=. The values= parameters for both is sent a list item that contains the same named labels from your data, but with different values. Note that if you alter any one of these parameters, you will get two legends, so it's important to change all at the same time.

  • legend.spacing.y is used to adjust the spacing between the shape/color and linetype legends

  • legend.margin is used to set the margin around each legend (allows them to get closer without clipping).

  • legend.title A consequence to making the spacing smaller is that the title gets "squished" near the keys. I add a margin her to ensure there is space between the legend title and the keys.

  • I set the name= of the linetype legend to be NULL instead of "". If you use "", it's blank, but it's still a character, so still takes up space. That means that when you move the legend up, you start to get clipping of "" with the upper legend. it's better to remove it altogether by setting it to be NULL.

Here's the code and resulting plot:

ggplot(tst_formule, aes(x=nom_graph, y = value, shape = BRI_type, col = BRI_type)) + 
  geom_point(size = 4) + 
  scale_shape_manual(
    values=list("BRI_adi_moy_guide"=15, "BRI_adi_moy_Sandrine"=17),
    name  ="Légende",
    labels=c("Méthode par transects", "Méthode par sous-transects")) +
  scale_colour_manual(
    values=list("BRI_adi_moy_guide"="grey20", "BRI_adi_moy_Sandrine"="gray54"),
    name  ="Légende",
    labels=c("Méthode par transects", "Méthode par sous-transects")) +
  geom_text(aes(label = value, vjust = -0.5, hjust= -0.1), show.legend = FALSE) + # etiquettes
  geom_hline(aes(yintercept = 0.004, linetype = "Seuil"), colour= 'black') + 
  scale_linetype_manual(
    name=NULL, values = c(2),
    guide = guide_legend(override.aes = list(color = c("black")))) + 
  scale_x_discrete("\nTronçons\n") + 
  scale_y_continuous("\nValeur du BRI*\n", limits = c(0,0.025)) + 
  theme(axis.text.x = element_text(size = 11),
        axis.text.y = element_text(size = 11),
        legend.text = element_text(size = 11),
        plot.margin = unit(c(0.2,0.2,0.2,0.2), "cm"),
        legend.spacing.y = unit(0.1, 'cm'),
        legend.margin = margin(0,0,0,0, 'pt'),
        legend.title = element_text(margin=margin(0,0,0.1,0, 'cm'))
  )

enter image description here

Upvotes: 1

Related Questions