Définition des limites des axes individuels avec facet_wrap et scale = "free" dans ggplot2

116

Je crée un graphique à facettes pour afficher les valeurs prévues par rapport aux valeurs réelles côte à côte avec un graphique de la valeur prédite par rapport aux résidus. J'utiliserai shinypour aider à explorer les résultats des efforts de modélisation en utilisant différents paramètres d'entraînement. J'entraîne le modèle avec 85% des données, je teste sur les 15% restants et je le répète 5 fois, collectant à chaque fois les valeurs réelles / prévues. Après avoir calculé les résidus, mon data.frameressemble à ceci:

head(results)
       act     pred       resid
2 52.81000 52.86750 -0.05750133
3 44.46000 42.76825  1.69175252
4 54.58667 49.00482  5.58184181
5 36.23333 35.52386  0.70947731
6 53.22667 48.79429  4.43237981
7 41.72333 41.57504  0.14829173

Ce que je veux:

  • Graphique côte à côte de predvs. actet predvs.resid
  • La plage / limites x / y pour predvs actêtre la même, idéalement de min(min(results$act), min(results$pred))àmax(max(results$act), max(results$pred))
  • La plage / limites x / y pour predvs resid ne pas être affectée par ce que je fais à l'intrigue réelle vs prévue. Tracer xuniquement les valeurs prédites et yuniquement la plage résiduelle est très bien.

Afin de visualiser les deux graphiques côte à côte, je fusionne les données:

library(reshape2)
plot <- melt(results, id.vars = "pred")

Maintenant, tracez:

library(ggplot2)
p <- ggplot(plot, aes(x = pred, y = value)) + geom_point(size = 2.5) + theme_bw()
p <- p + facet_wrap(~variable, scales = "free")

print(p)

C'est assez proche de ce que je veux:

entrez la description de l'image ici

Ce que j'aimerais, c'est que les plages x et y pour les valeurs réelles et prévues soient identiques, mais je ne suis pas sûr de savoir comment le spécifier, et je n'ai pas besoin de cela pour le graphique prévu par rapport au résidu puisque le les gammes sont complètement différentes.

J'ai essayé d'ajouter quelque chose comme ça pour les deux scale_x_continouset scale_y_continuous:

min_xy <- min(min(plot$pred), min(plot$value))
max_xy <- max(max(plot$pred), max(plot$value))

p <- ggplot(plot, aes(x = pred, y = value)) + geom_point(size = 2.5) + theme_bw()
p <- p + facet_wrap(~variable, scales = "free")
p <- p + scale_x_continuous(limits = c(min_xy, max_xy))
p <- p + scale_y_continuous(limits = c(min_xy, max_xy))

print(p)

Mais cela reprend min()les valeurs résiduelles.

entrez la description de l'image ici

Une dernière idée que j'ai eue est de stocker la valeur du minimum actet des predvariables avant la fusion, puis de les ajouter au bloc de données fondu afin de dicter dans quelle facette elles apparaissent:

head(results)
       act     pred       resid
2 52.81000 52.86750 -0.05750133
3 44.46000 42.76825  1.69175252
4 54.58667 49.00482  5.58184181
5 36.23333 35.52386  0.70947731

min_xy <- min(min(results$act), min(results$pred))
max_xy <- max(max(results$act), max(results$pred))

plot <- melt(results, id.vars = "pred")

plot <- rbind(plot, data.frame(pred = c(min_xy, max_xy),
  variable = c("act", "act"), value = c(max_xy, min_xy)))

p <- ggplot(plot, aes(x = pred, y = value)) + geom_point(size = 2.5) + theme_bw()
p <- p + facet_wrap(~variable, scales = "free")

print(p)

Cela fait ce que je veux, à l'exception que les points apparaissent aussi:

entrez la description de l'image ici

Des suggestions pour faire quelque chose comme ça?


J'ai vu cette idée à ajouter geom_blank(), mais je ne sais pas comment spécifier le aes()bit et le faire fonctionner correctement, ni quel est l' geom_point()équivalent de l'utilisation de l'histogramme aes(y = max(..count..)).


Voici les données avec lesquelles jouer (mes valeurs réelles, prévues et résiduelles avant la fusion):

> dput(results)
structure(list(act = c(52.81, 44.46, 54.5866666666667, 36.2333333333333, 
53.2266666666667, 41.7233333333333, 35.2966666666667, 30.6833333333333, 
39.25, 35.8866666666667, 25.1, 29.0466666666667, 23.2766666666667, 
56.3866666666667, 42.92, 41.57, 27.92, 23.16, 38.0166666666667, 
61.8966666666667, 37.41, 41.6333333333333, 35.9466666666667, 
48.9933333333333, 30.5666666666667, 32.08, 40.3633333333333, 
53.2266666666667, 64.6066666666667, 38.5366666666667, 41.7233333333333, 
25.78, 33.4066666666667, 27.8033333333333, 39.3266666666667, 
48.9933333333333, 25.2433333333333, 32.67, 55.17, 42.92, 54.5866666666667, 
23.16, 64.6066666666667, 40.7966666666667, 39.0166666666667, 
41.6333333333333, 35.8866666666667, 25.1, 23.2766666666667, 44.46, 
34.2166666666667, 40.8033333333333, 24.5766666666667, 35.73, 
61.8966666666667, 62.1833333333333, 74.6466666666667, 39.4366666666667, 
36.6, 27.1333333333333), pred = c(52.8675013282404, 42.7682474758679, 
49.0048248585123, 35.5238560262515, 48.7942868566949, 41.5750416040131, 
33.9548164913007, 29.9787449128663, 37.6443975781139, 36.7196211666685, 
27.6043278172077, 27.0615724310721, 31.2073056885252, 55.0886903524179, 
43.0895814712768, 43.0895814712768, 32.3549865881578, 26.2428426737583, 
36.6926037128343, 56.7987490221996, 45.0370788180147, 41.8231642271826, 
38.3297859332601, 49.5343916620086, 30.8535641206809, 29.0117492750411, 
36.9767968381391, 49.0826677983065, 54.4678549541069, 35.5059204731218, 
41.5333417555995, 27.6069075391361, 31.2404889715121, 27.8920960978598, 
37.8505531149324, 49.2616631533957, 30.366837650159, 31.1623492639066, 
55.0456078770405, 42.772538591063, 49.2419293590535, 26.1963523976241, 
54.4080781796616, 44.9796700541254, 34.6996927469131, 41.6227713664027, 
36.8449646519306, 27.5318686661673, 31.6641793552795, 42.8198894266632, 
40.5769177148146, 40.5769177148146, 29.3807781312816, 36.8579132935989, 
55.5617033901752, 55.8097119335638, 55.1041728261666, 43.6094641699075, 
37.0674887276681, 27.3876960746536), resid = c(-0.0575013282403773, 
1.69175252413213, 5.58184180815435, 0.709477307081826, 4.43237980997177, 
0.148291729320228, 1.34185017536599, 0.704588420467079, 1.60560242188613, 
-0.832954500001826, -2.50432781720766, 1.98509423559461, -7.93063902185855, 
1.29797631424874, -0.169581471276786, -1.51958147127679, -4.43498658815778, 
-3.08284267375831, 1.32406295383237, 5.09791764446704, -7.62707881801468, 
-0.189830893849219, -2.38311926659339, -0.541058328675241, -0.286897454014273, 
3.06825072495888, 3.38653649519422, 4.14399886836018, 10.1388117125598, 
3.03074619354486, 0.189991577733821, -1.82690753913609, 2.16617769515461, 
-0.088762764526507, 1.47611355173427, -0.268329820062384, -5.12350431682565, 
1.5076507360934, 0.124392122959534, 0.147461408936991, 5.34473730761318, 
-3.03635239762411, 10.1985884870051, -4.18300338745873, 4.31697391975358, 
0.0105619669306023, -0.958297985263961, -2.43186866616734, -8.38751268861282, 
1.64011057333683, -6.36025104814794, 0.226415618518729, -4.80411146461488, 
-1.1279132935989, 6.33496327649151, 6.37362139976954, 19.5424938405001, 
-4.17279750324084, -0.467488727668119, -0.254362741320246)), .Names = c("act", 
"pred", "resid"), row.names = c(2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L, 
10L, 11L, 12L, 13L, 15L, 16L, 17L, 18L, 19L, 20L, 21L, 22L, 23L, 
24L, 25L, 26L, 28L, 29L, 30L, 31L, 32L, 33L, 34L, 35L, 36L, 37L, 
38L, 39L, 41L, 42L, 43L, 44L, 45L, 46L, 47L, 48L, 49L, 50L, 51L, 
52L, 54L, 55L, 56L, 57L, 58L, 59L, 60L, 61L, 62L, 63L, 64L, 65L
), class = "data.frame")
Hendy
la source
Juste curieux - pourquoi ne pas tracer réel et résiduel dans le même graphique?
Ricardo Saporta
2
Je créerais les parcelles séparément puis les utiliserais grid.arrange.
joran
@RicardoSaporta Y a-t-il une image google vers laquelle vous pourriez créer un lien à titre d'exemple? Est-ce que vous suggérez, en utilisant les données post-fondues, que je ferais simplement ggplot(plot, aes(x = pred, y = value)) + geom_point()sans facettage? Cela ne réduirait-il pas vraiment l'échelle des résidus pour rendre difficile la détection du non-aléatoire / asymétrie?
Hendy
1
Mon autre commentaire est que la facettisation est moins de code ... J'ai juste dû fondre, puis tracer et facette par la variablevaleur créée par melt(). Là encore, je suppose que je pourrais les stocker dans une liste créée par lapplypour tracer diverses combinaisons. Merci pour la contribution. Si vous souhaitez créer une gridsolution, je peux accepter la réponse, mais si c'est la voie que nous empruntons, cela pourrait tout aussi bien être un double des autres gridsolutions basées sur les autres .
Hendy
1
@joran et je trouve que je conseille régulièrement aux gens de ne pas utiliser grid.arrangece qui gâche presque invariablement la mise en page. Je souhaite que les bugs de longue date de gtable soient corrigés.
baptiste le

Réponses:

115

Voici du code avec une geom_blankcouche factice ,

range_act <- range(range(results$act), range(results$pred))

d <- reshape2::melt(results, id.vars = "pred")

dummy <- data.frame(pred = range_act, value = range_act,
                    variable = "act", stringsAsFactors=FALSE)

ggplot(d, aes(x = pred, y = value)) +
  facet_wrap(~variable, scales = "free") +
  geom_point(size = 2.5) + 
  geom_blank(data=dummy) + 
  theme_bw()

entrez la description de l'image ici

baptiste
la source
11
Une variante intéressante à cela est expand_limits(pred=range_act, value=range_act), qui utilise geom_blankmais est plus simple à utiliser.
eregon
6
Cela ne fait qu'étendre les limites (mais ne les contracte pas) Y a-t-il un moyen de raccourcir la portée? @baptiste
Indranil Gayen
32

Je ne suis pas sûr de comprendre ce que vous voulez, mais d'après ce que j'ai compris

l'échelle x semble être la même, c'est l'échelle y qui n'est pas la même, et c'est parce que vous avez spécifié scale = "free"

vous pouvez spécifier scale = "free_x" pour n'autoriser que x à être libre (dans ce cas, c'est le même que pred a la même plage par définition)

p <- ggplot(plot, aes(x = pred, y = value)) + geom_point(size = 2.5) + theme_bw()
p <- p + facet_wrap(~variable, scales = "free_x")

a travaillé pour moi, voir la photo

entrez la description de l'image ici

Je pense que vous rendiez les choses trop difficiles - je semble me souvenir une fois d'avoir défini les limites en fonction d'une formule avec min et max et si à facettes, je pense qu'il n'utilisait que ces valeurs, mais je ne trouve pas le code

user1617979
la source
7

Vous pouvez également spécifier la plage avec la commande coord_cartesian pour définir la plage de l'axe y que vous souhaitez, comme dans le post précédent, utilisez scale = free_x

p <- ggplot(plot, aes(x = pred, y = value)) +
     geom_point(size = 2.5) +
     theme_bw()+
     coord_cartesian(ylim = c(-20, 80))
p <- p + facet_wrap(~variable, scales = "free_x")
p

entrez la description de l'image ici

Luis Candanedo
la source