Ajout de couches ggplot avec une boucle for

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

Fred Santos
Messages : 233
Enregistré le : 11 Avr 2009, 10:00
Contact :

Ajout de couches ggplot avec une boucle for

Messagepar Fred Santos » 04 Jan 2018, 14:56

Bonjour (et joyeuse année à tous les stateux),

J'aurais besoin de créer (dans le cadre d'une appli shiny) des graphiques ggplot, avec la particularité que je ne connais pas d'avance le nombre de couches qui devront être ajoutées : cela dépendra du choix de l'utilisateur à travers l'interface, des données qui seront uploadées, etc.
J'essaie naïvement d'ajouter des couches avec une boucle for, mais je constate qu'en procédant ainsi, seule la dernière couche de la boucle est réellement tracée : les autres semblent se perdre dans la nature.

Un exemple bête reproductible avec les données des iris de Fisher : on essaie ici de tracer les barycentres de chaque espèce d'iris pour les variables x=Sepal.Length, y=Sepal.Width, puis d'y ajouter des ellipses de confiance, ainsi que des "moustaches" de longueur 1 écart-type autour des barycentres. Chaque "tour" de boucle for correspond à une espèce d'iris.

Code : Tout sélectionner

data(iris)

# On calcule les barycentres pour chaque espèce :
iris.summary <- aggregate(iris[,1:2], list(iris$Species), mean)
names(iris.summary)[1] <- "Species"

p <- ggplot(data=iris, mapping=aes_string(x="Sepal.Length", y="Sepal.Width", color="Species"))

# On ajoute les barycentres et les ellipses :         
p <- p + geom_point(data=iris.summary, mapping=aes_string(x="Sepal.Length", y="Sepal.Width", color="Species"), shape=15, size=5)
p <- p + stat_ellipse()

# On essaie d'ajouter les "moustaches" pour chaque espèce :
for (k in 1:nlevels(iris$Species)) {
   espece <- subset(iris, iris$Species==levels(iris$Species)[k]) # on ne considère que l'espèce numéro "k"
   p <- p + geom_segment(aes(y=mean(espece[,2]), yend=mean(espece[,2]), x=mean(espece[,1])-sd(espece[,1]), xend=mean(espece[,1])+sd(espece[,1])))
   p <- p + geom_segment(aes(x=mean(espece[,1]), xend=mean(espece[,1]), y=mean(espece[,2])-sd(espece[,2]), yend=mean(espece[,2])+sd(espece[,2])))
}

p

On voit bien ci-dessus que seule l'espèce virginica (la dernière) a eu droit à ses moustaches. Pourquoi ce comportement de ggplot ? Et comment procéder pour ajouter un nombre indéterminé de couches si une boucle for n'est pas la bonne solution ?

Merci !

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

Re: Ajout de couches ggplot avec une boucle for

Messagepar Mickael Canouil » 04 Jan 2018, 16:10

Bonjour,

la raison du comportement "bizarre" (qui ne l'est pas):
ici vous fournissez à "aes" du code non évaluer, que ggplot va donc évaluer, d'abord dans les objets inclus dans le champ "data", puis l’environnement supérieur pour finir dans le "global". Or comme dans le petit exemple ci-dessous, vous changer l'environnement global du plot, et comme ggplot réavalue "p" à chaque print, il va chercher l'information dans l’environnement global et donc la dernière version de "dta"

Code : Tout sélectionner

dta  <- data.frame(x = seq(10), y = exp(seq(10)))
p <- ggplot() + geom_point(aes(x = dta[, "x"], y =  dta[, "y"]))
p
dta  <- data.frame(x = seq(100), y = log(seq(100)))
p


pour ne pas avoir ce problème, il faut fournir à ggplot toute l'information:

Code : Tout sélectionner

dta  <- data.frame(x = seq(10), y = exp(seq(10)))
p <- ggplot() + geom_point(data = dta, aes(x = x, y = y))
p
dta  <- data.frame(x = seq(100), y = log(seq(100)))
p



Enfin une proposition pour votre problématique, avec k étant l'input de votre app Shiny:

Code : Tout sélectionner

k <- c(1, 2, 3)

working.data <- subset(iris, iris$Species%in%levels(iris$Species)[k])

centroids <- working.data %>%
                group_by(Species) %>%
                summarise(
                    x = mean(Sepal.Length),
                    y = mean(Sepal.Width),
                    xmin = mean(Sepal.Length)-sd(Sepal.Length),
                    xmax = mean(Sepal.Length)+sd(Sepal.Length),
                    ymin = mean(Sepal.Width)-sd(Sepal.Width),
                    ymax = mean(Sepal.Width)+sd(Sepal.Width)
                ) %>%
                ungroup

ggplot(data = working.data, aes(x = Sepal.Length, y = Sepal.Width, fill = Species, colour = Species)) +
        # geom_point(shape = 21, size = 1) +
        stat_ellipse() +
        geom_errorbar(
            data = centroids,
            aes(x = x, ymin = ymin, ymax = ymax, colour = Species),
            inherit.aes = FALSE,
            width = 0
        ) +
        geom_errorbarh(
            data = centroids,
            aes(x = x, y = y, xmin = xmin, xmax = xmax, colour = Species),
            inherit.aes = FALSE,
            height = 0
        ) +
        geom_point(data = centroids, aes(x = x, y = y, colour = Species), shape = 15, size = 4, inherit.aes = FALSE)

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

Fred Santos
Messages : 233
Enregistré le : 11 Avr 2009, 10:00
Contact :

Re: Ajout de couches ggplot avec une boucle for

Messagepar Fred Santos » 05 Jan 2018, 16:54

Bonjour Mickaël,

Merci beaucoup pour ces détails techniques (très clairs !) et cette solution ! C'est parfait !

Cordialement


Retourner vers « Questions en cours »

Qui est en ligne

Utilisateurs parcourant ce forum : Aucun utilisateur enregistré et 1 invité