Como empilho verticalmente dois gráficos com a mesma escala x, mas uma escala y diferente em R?

9

Saudações,

Atualmente, estou fazendo o seguinte em 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
...

As duas últimas linhas plotam as informações necessárias e o resultado se assemelha ao seguinte: texto alternativo Linha azul é a entropia em bytes do artefato que me interessa. Linhas verdes representam a entropia das mudanças.

Agora, neste gráfico, funciona bem porque não há uma grande diferença de escalas. Mas tenho outros gráficos em que as linhas verdes se tornam tão pequenas que não se pode ver.

A solução que eu procurava envolvia duas coisas:

  1. Para mover as linhas verticais verdes para um segundo gráfico, logo abaixo do primeiro, com seu próprio eixo y, mas com o eixo x compartilhado.
  2. Para fornecer uma escala logarítmica, já que estou mais interessado na "magnitude" do que nos valores específicos.

Desde já, obrigado!

PS Se alguém também pode me dizer como eu poderia colocar "ticks menores" na escala x referente aos meses, eu aprecio :-) Se essas são perguntas demais para um único post, posso dividi-las ainda mais.

Hugo Sereno Ferreira
fonte

Respostas:

15

Você pode usar par(new=TRUE)para plotar no mesmo gráfico usando dois eixos y diferentes! Isso também deve resolver seu problema.

A seguir, você encontrará um exemplo simples que plota duas variáveis ​​normais aleatórias, uma na média 0 e outra na média 100 (ambos sd s = 1) no mesmo gráfico. O primeiro em vermelho no eixo y esquerdo, o segundo em azul no eixo y direito. Em seguida, os rótulos dos eixos são adicionados.

Aqui está:

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)

fica assim (lembre-se de vermelho no eixo esquerdo, azul no eixo direito): texto alternativo

ATUALIZAÇÃO:
Com base nos comentários, produzi uma versão atualizada do meu gráfico. Agora, vou me aprofundar um pouco mais na funcionalidade do gráfico base, usando par(mar=c(a,b,c,d))para criar uma margem maior ao redor do gráfico (necessária para o rótulo do eixo direito), mtextpara mostrar os rótulos dos eixos e o uso avançado da axisfunção:

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 você vê, é bem direto. Você pode definir a posição dos seus dados ylimna plotfunção e, em seguida, usar atna axisfunção para selecionar quais marcações do eixo você deseja ver. Além disso, você pode até fornecer os rótulos para as marcações dos eixos (bastante úteis para o eixo x nominal) labelsna axisfunção (feita aqui no eixo direito). Para adicionar etiquetas de eixo, use mtextcom atpara posicionamento vertical ( linepara posicionamento horizontal).

Certifique-se de verificar ?plot, ?par, ?axis, e ?mtextpara mais informações.
Os excelentes recursos da Web são: Quick-R para gráficos: 1 , 2 e 3 .

Henrik
fonte
Isso é interessante, mas como podemos dizer ao leitor qual escala corresponde a qual linha?
Hugo Sereno Ferreira
Veja este gráfico: imgur.com/K8BCr.png Aqui, apresentamos rótulos e marcações do eixo y somente onde eles se aplicam aos dados (ou seja, para o eixo esquerdo na parte superior do gráfico, como os dados correspondentes, e para o eixo direito na parte inferior do gráfico, como os dados correspondentes). Além disso, usamos cores diferentes (como no exemplo acima) e tipos de linha e explicamos na legenda. Você também pode usar um gráfico de linhas à esquerda e um gráfico de barras no eixo direito para tornar a distinção mais clara.
Henrik
O exemplo que você deu é muito bom ... Como você conseguiu deslocar verticalmente cada eixo?
Hugo Sereno Ferreira
2
Realmente bom exemplo. O único problema com seu gráfico é que os nomes de variáveis ​​Y estão sobrepostos. Nesse caso, você deseja um à esquerda e outro à direita (possivelmente até na posição vertical). Para atualizar seu exemplo de "muito bom" para "perfeito", você pode querer usar a função mtext de R fazer os nomes de variáveis
Dave Kellen
@Hugo @Dave: Veja minha atualização para uma incorporação de ambos os comentários.
Henrik
12

Eu acho que você pode conseguir o que deseja usando ggplot2. Usando o código abaixo, eu posso produzir:

texto alternativo

Obviamente, coisas como cores de linha podem ser alteradas para o que você quiser. No eixo x, especifiquei linhas principais em anos e linhas menores em 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
fonte
Tentei configurar df = data.frame (t = dias, valores = c (dados2, cum), tipo = rep (c ("Bytes", "Alterações"), cada um = 1001)), mas fornece um Erro no rbind.zoo (...): os índices se sobrepõem
Hugo Sereno Ferreira
Isso porque data2 e cum são objetos de zoológico. Use as.vector (data2) para obter os valores brutos. Além disso, usei 1001 porque tinha 1001 observações. Você precisará de algo diferente.
precisa saber é o seguinte
Usuário Noob R aqui: Erro no data.frame (t = dias, valores = c (como.vector (dados2), como.vector (cum)),: argumentos implicam número diferente de linhas: 1063, 1300, 2
Hugo Sereno Ferreira
Digite "days", "data2" e "cum" para ver seus dados. Em seguida, observe "duração (dias)", etc. Você precisa combinar os pontos de tempo com os valores.
Csgillespie