Comment puis-je empiler verticalement deux graphiques avec la même échelle x, mais une échelle y différente dans R?

9

Salutations,

Actuellement, je fais ce qui suit dans R:

require(zoo)
data <- read.csv(file="summary.csv",sep=",",head=TRUE)
cum  = zoo(data$dcomp, as.Date(data$date))
data = zoo(data$compressed, as.Date(data$date))
data <- aggregate(data, identity, tail, 1)
cum  <- aggregate(cum, identity, sum, 1)
days = seq(start(data), end(data), "day")
data2 = na.locf(merge(data, zoo(,days)))

plot(data2,xlab='',ylab='compressed bytes',col=rgb(0.18,0.34,0.55))
lines(cum,type="h",col=rgb(0,0.5,0))

Snip de summary.csv:

date,revision,file,lines,nclass,nattr,nrel,bytes,compressed,diff,dcomp
2007-07-25,16,model.xml,96,11,22,5,4035,991,0,0
2007-07-27,17,model.xml,115,16,26,6,4740,1056,53,777
2007-08-09,18,model.xml,106,16,26,7,4966,1136,47,761
2007-08-10,19,model.xml,106,16,26,7,4968,1150,4,202
2007-09-06,81,model.xml,111,16,26,7,5110,1167,13,258
...

Les deux dernières lignes tracent les informations dont j'ai besoin, et le résultat ressemble à ceci: texte alternatif La ligne bleue est l'entropie en octets de l'artefact qui m'intéresse. Les lignes vertes représentent l'entropie des changements.

Maintenant, dans ce graphique, cela fonctionne bien car il n'y a pas une énorme différence d'échelles. Mais j'ai d'autres graphiques où les lignes vertes deviennent si petites qu'on ne peut pas voir.

La solution que je cherchais impliquait deux choses:

  1. Pour déplacer les lignes verticales vertes vers un deuxième graphique, juste en dessous du premier, avec son propre axe y, mais un axe x partagé.
  2. Pour lui fournir une échelle logarithmique, puisque je suis plus intéressé par la "magnitude" que par les valeurs spécifiques.

Merci d'avance!

PS Si quelqu'un peut aussi me dire comment pourrais-je mettre des "graduations mineures" dans l'échelle x en référence aux mois, j'apprécie :-) Si ce sont trop de questions pour un seul post, je peux les diviser davantage.

Hugo Sereno Ferreira
la source

Réponses:

15

Vous pouvez utiliser par(new=TRUE)pour tracer dans le même graphique en utilisant deux axes Y différents! Cela devrait également résoudre votre problème.

Ensuite, vous trouverez un exemple simple qui trace deux variables normales aléatoires, l'une sur la moyenne 0 l'autre sur la moyenne 100 (les deux sd s = 1) dans le même graphique. Le premier en rouge sur l'axe y gauche, le second en bleu sur l'axe y droit. Ensuite, les étiquettes d'axe sont ajoutées.

Voici:

x <- 1:10
y1 <- rnorm(10)
y2 <- rnorm(10)+100

plot(x,y1,pch=0,type="b",col="red",yaxt="n",ylim=c(-8,2))
par(new=TRUE)
plot(x,y2,pch=1,type="b",col="blue",yaxt="n",ylim=c(98,105))

axis(side=2)
axis(side=4)

ressemble alors à ceci (rappelez-vous le rouge sur l'axe gauche, le bleu sur l'axe droit): texte alternatif

MISE À JOUR:
Sur la base des commentaires, j'ai produit une version mise à jour de mon graphique. Maintenant, je fouille un peu plus dans la fonctionnalité de graphique de base en utilisant par(mar=c(a,b,c,d))pour créer une plus grande marge autour du graphique (nécessaire pour l'étiquette de l'axe droit), mtextpour afficher les étiquettes des axes et et une utilisation avancée de la axisfonction:

x <- 1:100
y1 <- rnorm(100)
y2 <- rnorm(100)+100

par(mar=c(5,5,5,5))

plot(x,y1,pch=0,type="b",col="red",yaxt="n",ylim=c(-8,2),ylab="")
axis(side=2, at=c(-2,0,2))
mtext("red line", side = 2, line=2.5, at=0)

par(new=TRUE)
plot(x,y2,pch=1,type="b",col="blue",yaxt="n",ylim=c(98,108), ylab="")
axis(side=4, at=c(98,100,102), labels=c("98%","100%","102%"))
mtext("blue line", side=4, line=2.5, at=100)

texte alternatif

Comme vous le voyez, c'est assez simple. Vous pouvez définir la position de vos données ylimdans la plotfonction, puis utiliser atdans la axisfonction pour sélectionner les axes que vous souhaitez voir. De plus, vous pouvez même fournir les étiquettes pour les graduations des axes (assez utiles pour l'axe des x nominal) via labelsdans la axisfonction (fait ici sur l'axe de droite). Pour ajouter des étiquettes d'axe, utilisez mtextavec atpour le positionnement vertical ( linepour le positionnement horizontal).

Assurez - vous de vérifier ?plot, ?par, ?axiset ?mtextpour plus d' infos.
Les excellentes ressources Web sont: Quick-R pour les graphiques: 1 , 2 et 3 .

Henrik
la source
C'est intéressant, mais comment dire au lecteur quelle échelle correspond à quelle ligne?
Hugo Sereno Ferreira
Jetez un œil à ce graphique: imgur.com/K8BCr.png Là, nous présentons les étiquettes et les graduations de l' axe y uniquement là où elles s'appliquent aux données (c'est-à-dire pour l'axe gauche en haut du graphique, en tant que données correspondantes, et pour l'axe droit en bas du graphique, comme les données de correspondance). De plus, nous avons utilisé différentes couleurs (comme dans l'exemple ci-dessus) et types de lignes et l'avons expliqué dans la légende. Vous pouvez également utiliser un graphique linéaire à gauche et un graphique à barres sur l'axe droit pour rendre la distinction plus claire.
Henrik
L'exemple que vous avez donné est très bon ... Comment avez-vous réussi à décaler verticalement chaque axe?
Hugo Sereno Ferreira
2
Très bon exemple. Le seul problème avec votre graphique, c'est que les deux noms de variables Y se chevauchent. Dans ce cas, vous en voudriez un à gauche et l'autre à droite (éventuellement même en position verticale). Pour mettre à niveau votre exemple de "vraiment bon" à "parfait", vous voudrez peut-être utiliser la fonction mtext de R pour faire les noms des variables
Dave Kellen
@Hugo @Dave: Voir ma mise à jour pour une incorporation des deux commentaires.
Henrik
12

Je pense que vous pouvez obtenir ce que vous voulez en utilisant ggplot2. En utilisant le code ci-dessous, je peux produire:

texte alternatif

Évidemment, des choses comme les couleurs des lignes peuvent être changées en ce que vous voulez. Sur l'axe des x, j'ai spécifié des lignes majeures sur les années et des lignes mineures sur les mois.

require(ggplot2)
t = as.Date(0:1000, origin="2008-01-01")  
y1 = rexp(1001)
y2 = cumsum(y1)
df = data.frame(t=t, values=c(y2,y1), type=rep(c("Bytes", "Changes"), each=1001))

g = ggplot(data=df, aes(x=t, y=values)) +
  geom_line() +
  facet_grid(type ~ ., scales="free") +
  scale_y_continuous(trans="log10") +
  scale_x_date(major="years", minor="months") +
  ylab("Log values")
g
csgillespie
la source
Euh, j'ai essayé de configurer df = data.frame (t = jours, values ​​= c (data2, cum), type = rep (c ("Bytes", "Changes"), each = 1001)), mais cela donne une Erreur dans rbind.zoo (...): les index se chevauchent
Hugo Sereno Ferreira
C'est parce que data2 et cum sont des objets de zoo. Utilisez as.vector (data2) pour obtenir les valeurs brutes. De plus, j'ai utilisé 1001 parce que j'avais 1001 observations. Vous aurez besoin de quelque chose de différent.
csgillespie
Utilisateur Noob R ici: Erreur dans data.frame (t = jours, valeurs = c (as.vector (data2), as.vector (cum)),: les arguments impliquent un nombre de lignes différent: 1063, 1300, 2
Hugo Sereno Ferreira
Tapez "jours", "données2" et "cum" pour consulter vos données. Ensuite, regardez "durée (jours)", etc. Vous devez faire correspondre les points de temps avec les valeurs.
csgillespie