¿Cómo apilo verticalmente dos gráficos con la misma escala x, pero una escala y diferente en R?

9

Saludos,

Actualmente estoy haciendo lo siguiente en 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))

Recorte 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
...

Las dos últimas líneas trazan la información que necesito, y el resultado se parece al siguiente: texto alternativo La línea azul es la entropía en bytes del artefacto que me interesa. Las líneas verdes representan la entropía de los cambios.

Ahora, en este gráfico, funciona bien porque no hay una gran diferencia en las escalas. Pero tengo otros gráficos donde las líneas verdes se vuelven tan pequeñas que uno no puede ver.

La solución que estaba buscando implicaba dos cosas:

  1. Para mover las líneas verticales verdes a un segundo gráfico, justo debajo del primero, con su propio eje y, pero compartido x eje.
  2. Para proporcionarle una escala logarítmica, ya que estoy más interesado en la "magnitud" que en los valores específicos.

¡Gracias por adelantado!

PD: Si alguien también puede decirme cómo puedo poner "marcas menores" en la escala x en referencia a los meses, agradezco :-) Si estas son demasiadas preguntas para una sola publicación, puedo dividirlas aún más.

Hugo Sereno Ferreira
fuente

Respuestas:

15

¡Puede usar par(new=TRUE)para trazar en el mismo gráfico usando dos ejes y diferentes! Esto también debería resolver tu problema.

A continuación, encontrará un ejemplo simple que traza dos variables normales aleatorias, una en la media 0 y la otra en la media 100 (ambas sd s = 1) en la misma gráfica. El primero en rojo en el eje y izquierdo, el segundo en azul en el eje y derecho. Luego, se agregan etiquetas de eje.

Aqui tienes:

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)

entonces se ve así (recuerde rojo en el eje izquierdo, azul en el eje derecho): texto alternativo

ACTUALIZACIÓN:
Basado en comentarios, produje una versión actualizada de mi gráfico. Ahora profundizo un poco más en la funcionalidad del gráfico base usando par(mar=c(a,b,c,d))para crear un margen mayor alrededor del gráfico (necesario para la etiqueta del eje derecho), mtextpara mostrar las etiquetas del eje y el uso avanzado de la axisfunción:

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)

texto alternativo

Como ves, es bastante sencillo. Puede definir la posición de sus datos con ylimen la plotfunción, luego usar aten la axisfunción para seleccionar qué marcas de eje desea ver. Además, incluso puede proporcionar las etiquetas para los ticks del eje (bastante útil para el eje x nominal) a través labelsde la axisfunción (hecho aquí en el eje derecho). Para agregar etiquetas de eje, use mtextcon atpara posicionamiento vertical ( linepara posicionamiento horizontal).

Asegúrese de revisar ?plot, ?par, ?axis, y ?mtextpara más información.
Los mejores recursos web son: Quick-R para gráficos: 1 , 2 y 3 .

Henrik
fuente
Eso es interesante, pero ¿cómo le decimos al lector qué escala corresponde a qué línea?
Hugo Sereno Ferreira
Eche un vistazo a este gráfico: imgur.com/K8BCr.png Allí, presentamos etiquetas y marcas del eje y solo donde se aplican a los datos (es decir, para el eje izquierdo en la parte superior del gráfico, como los datos correspondientes, y para el eje derecho en la parte inferior del gráfico, como los datos correspondientes). Además, utilizamos diferentes colores (como en el ejemplo anterior) y tipos de línea y lo explicamos en el título. También puede usar un gráfico de líneas a la izquierda y un gráfico de barras en el eje derecho para aclarar la distinción.
Henrik
El ejemplo que ha dado es muy bueno ... ¿Cómo logró compensar verticalmente cada eje?
Hugo Sereno Ferreira
2
Muy buen ejemplo. El único problema con su gráfico es que ambos nombres de variables Y se superponen. En este caso, querrá uno a la izquierda y el otro a la derecha (posiblemente incluso en posición vertical). Para actualizar su ejemplo de "realmente bueno" a "perfecto", es posible que desee utilizar la función mtext de R para hacer los nombres de las variables
Dave Kellen,
@Hugo @Dave: Vea mi actualización para una incorporación de ambos comentarios.
Henrik
12

Creo que puedes obtener lo que quieres usando ggplot2. Usando el siguiente código, puedo producir:

texto alternativo

Obviamente, cosas como los colores de línea se pueden cambiar a lo que quieras. En el eje x especifiqué líneas mayores en años y líneas menores en meses.

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
fuente
Uh, intenté configurar df = data.frame (t = días, valores = c (data2, cum), type = rep (c ("Bytes", "Changes"), each = 1001)), pero da un Error en rbind.zoo (...): solapamiento de índices
Hugo Sereno Ferreira
Eso es porque data2 y cum son objetos del zoológico. Use as.vector (data2) para obtener los valores sin formato. Además, usé 1001 porque tenía 1001 observaciones. Necesitarás algo diferente.
csgillespie
Usuario Noob R aquí: Error en data.frame (t = días, valores = c (as.vector (data2), as.vector (cum)),: los argumentos implican un número diferente de filas: 1063, 1300, 2
Hugo Sereno Ferreira
Escriba "días", "datos2" y "cum" para ver sus datos. Luego mire "duración (días)", etc. Debe hacer coincidir los puntos de tiempo con los valores.
csgillespie