Ajouter une courbe au dessus d'un boxplot, avec ggplot2

Postez ici vos questions, réponses, commentaires ou suggestions - Les sujets seront ultérieurement répartis dans les archives par les modérateurs

Modérateur : Groupe des modérateurs

Olivier Vinet
Messages : 9
Enregistré le : 26 Oct 2017, 14:45

Ajouter une courbe au dessus d'un boxplot, avec ggplot2

Messagepar Olivier Vinet » 07 Fév 2019, 16:19

Bonjour,

Je n'ai pas un gros niveau sur R, mais j'essaye de décortiquer un peu mes données.
En l'occurrence je creuse le package ggplot2, et je rencontre des problèmes.

Dans un premier temps, j'ai mis en forme mon tableau de données ('minposgg') qui se compose d'une 1ere colonne avec des noms d'espèces animales et d'une seconde colonne avec des activités biologiques, exprimées en "minutes positives".

Code : Tout sélectionner

    Espece Minutes_pos
1   Barbar          15
2   Barbar           8
3   Barbar          11
4   Barbar           1
5   Hypsav          11
6   Hypsav           0
7   Hypsav          19
8   Hypsav          42
9   Myosp          193
10  Myosp           49
11  Myosp          144
12  Myosp           11


Avec ggplot2, j'ai produit un boxplot de cette activité pour chaque espèce. Ca, c'est bon.

Code : Tout sélectionner

base <- ggplot(minposgg, aes(x = Espece, y = Minutes_pos))
basebox <- base + geom_boxplot() + stat_boxplot(geom = 'errorbar') + geom_boxplot(fill = "lightgrey") + stat_summary(fun.y=mean, geom="point", shape=17, size=3) + xlab("Groupes d'espèces") + ylab("Minutes positives")


Maintenant, j'aimerais afficher les valeurs seuils pour ces espèces, en fond.
Pour cela, j'ai un autre tableau de données ('quant')

Code : Tout sélectionner

   Espece Q25haquart Q75haquart Q98haquart
1  Barbar          2         12         69
2  Hypsav          2         11         96
3   Myosp          2         21        237


A partir de cet autre data.frame, j'aimerais que s'affiche, sur mon précédent boxplot, une courbe reliant les valeurs Q25 de référence (donc 2, 2 et 2), puis une autre courbe reliant les Q75 de référence (12, 11 et 21) et enfin une dernière courbe sur les Q98 de référence, ce qui me permettrait de voir où mon jeu de données se situe en comparaison des seuils de référence nationale
J'ai essayé de creuser les fonctions geom_path(), geom_line(), etc. Mais comme il s'agit d'un autre data.frame, je ne suis même pas sûr d'avoir le droit de le faire sur mon premier boxplot issu du premier data.frame.

Merci d'avance !

Mickael Canouil
Messages : 1315
Enregistré le : 04 Avr 2011, 08:53
Contact :

Re: Ajouter une courbe au dessus d'un boxplot, avec ggplot2

Messagepar Mickael Canouil » 07 Fév 2019, 16:48

Bonjour,

on ne peut pas (et il ne faut pas) utiliser geom_line/path avec une échelle discrète (enfin sans bidouille comme ci-après).
En pure visualisation, on ne relie pas des mesures discrètes (non numériques) par des lignes.

voici une proposition (légère modification de votre code):

Les données:

Code : Tout sélectionner

library(tidyverse)
minposgg <- read.table(text = "    Espece Minutes_pos
1   Barbar          15
2   Barbar           8
3   Barbar          11
4   Barbar           1
5   Hypsav          11
6   Hypsav           0
7   Hypsav          19
8   Hypsav          42
9   Myosp          193
10  Myosp           49
11  Myosp          144
12  Myosp           11", header = TRUE)


Les "annotations" qu'on reformate un peu pour le rendre vraiment compatible avec ggplot2

Code : Tout sélectionner

annot <- read.table(text = "   Espece Q25haquart Q75haquart Q98haquart
1  Barbar          2         12         69
2  Hypsav          2         11         96
3   Myosp          2         21        237", header = TRUE)

annot <- annot %>%
  tidyr::gather(key = "quartiles", value = "value", -Espece)


Votre graphique de "base". A noter que ggplot2 fonctionne en couche, ainsi le second geom/stat se dessine par dessus le premier et ainsi de suite.

Code : Tout sélectionner

base <- ggplot(minposgg, aes(x = Espece, y = Minutes_pos))
basebox <- base +
  stat_boxplot(geom = "errorbar") + # pas convaincu de l’intérêt visuel
  geom_boxplot(fill = "lightgrey", ) +
  stat_summary(fun.y = mean, geom = "point", shape = 17, size = 3) +
  labs(x = "Groupes d'espèces", y = "Minutes positives")


Les seuil via 'geom_segment' et une petite bidouille pour permettre de tracer via des valeurs numérique sur un axe discret.

Code : Tout sélectionner

basebox +
  geom_segment(
    data = annot,
    mapping = aes(
      x = as.integer(factor(Espece))-0.375,
      xend = as.integer(factor(Espece))+0.375,
      y = value,
      yend = value,
      colour = quartiles
    ),
    inherit.aes = FALSE
  )

Image

Et si voulez vraiment une ligne

Code : Tout sélectionner

basebox +
  geom_line(
    data = annot,
    mapping = aes(
      x = as.integer(factor(Espece)),
      y = value,
      colour = quartiles
    ),
    inherit.aes = FALSE
  )

Image

Cordialement,
Mickaël
mickael.canouil.fr | rlille.fr

Olivier Vinet
Messages : 9
Enregistré le : 26 Oct 2017, 14:45

Re: Ajouter une courbe au dessus d'un boxplot, avec ggplot2

Messagepar Olivier Vinet » 07 Fév 2019, 16:58

Ca parait top !
Je vais transférer ça sur mon jeu de données complet et voir ce que ça donne, mais ça m'a l'air impeccable.

Par contre j'ai une question supplémentaire, pour un autre souci qui se voit déjà un peu sur l'extrait des données proposé ici.
J'aurais voulu disposer d'une échelle 'y' discontinue, pour "étendre" la partie entre 0 et 5 (voire 10).
J'ai fait des essais avec une échelle log, mais le fait qu'on soit à 1 en valeur min ça me pose un problème. Du coup ça ne me satisfait pas trop.
Si je pouvais rendre l'axe y discontinu, ça serait le top.
Mais j'ai lu pas mal de réponses qui déconseillent de le faire...

Merci en tout cas

Mickael Canouil
Messages : 1315
Enregistré le : 04 Avr 2011, 08:53
Contact :

Re: Ajouter une courbe au dessus d'un boxplot, avec ggplot2

Messagepar Mickael Canouil » 07 Fév 2019, 17:12

La transformation racine-carré est ce que vous cherchez, à un détail près ...

Code : Tout sélectionner

basebox +
  geom_segment(
    data = annot,
    mapping = aes(
      x = as.integer(factor(Espece))-0.375,
      xend = as.integer(factor(Espece))+0.375,
      y = value,
      yend = value,
      colour = quartiles
    ),
    inherit.aes = FALSE
  ) +
  scale_y_continuous(trans = "sqrt") # équivalent à scale_y_sqrt()

Image

Astuce pour récupérer le "zéro"

Code : Tout sélectionner

sqrt_zero_trans <- function() {
  scales::trans_new(
    name = "sqrt_zero",
    transform = base::sqrt,
    inverse = function(x) ifelse(x<0, 0, x^2),
    domain = c(0, Inf)
  )
}
basebox +
  geom_segment(
    data = annot,
    mapping = aes(
      x = as.integer(factor(Espece))-0.375,
      xend = as.integer(factor(Espece))+0.375,
      y = value,
      yend = value,
      colour = quartiles
    ),
    inherit.aes = FALSE
  ) +
  scale_y_continuous(trans = "sqrt_zero")

Image
Mickaël
mickael.canouil.fr | rlille.fr

Olivier Vinet
Messages : 9
Enregistré le : 26 Oct 2017, 14:45

Re: Ajouter une courbe au dessus d'un boxplot, avec ggplot2

Messagepar Olivier Vinet » 07 Fév 2019, 17:15

Intéressant, effectivement.
Je vais creuser et tester tout ça :)
Merci

Olivier Vinet
Messages : 9
Enregistré le : 26 Oct 2017, 14:45

Re: Ajouter une courbe au dessus d'un boxplot, avec ggplot2

Messagepar Olivier Vinet » 15 Mar 2019, 14:24

Bonjour,

Je reviens sur cette question.
Il y a un truc qui me chagrine sur le résultat.
En définitive, quand je fais tourner le script sur mon jeu de données, j'ai l'impression qu'avec le passage en échelle racine carrée, il y un bug sur le positionnement de la moyenne (triangle noir).

Regardez où se situe la moyenne sur ce plot, avec une échelle normale (la moyenne est bonne, ici):
Image

Alors que sur le graphe en échelle racine carrée, ça donne ça :
Image


C'est particulièrement net sur le groupe "Hypsav", cette différence, pour un même jeu de données.

Qqun aurait une idée ?


Retourner vers « Questions en cours »

Qui est en ligne

Utilisateurs parcourant ce forum : Google [Bot] et 1 invité