É possível criar plotagem de "conjuntos paralelos" usando R?

16

Graças à pergunta do Tormod (postada aqui ), me deparei com o enredo Parallel Sets . Aqui está um exemplo de como fica: insira a descrição da imagem aqui (É uma visualização do conjunto de dados do Titanic. Mostrando, por exemplo, como a maioria das mulheres que não sobreviveram pertencia à terceira classe ...)

Eu adoraria poder reproduzir esse enredo com R. Isso é possível?

Obrigado, Tal

Tal Galili
fonte
1
Para obter idéias sobre gráficos, eu sempre verifico a galeria de gráficos R. Aqui está algo parecido com o que você pede: R Graph Gallery paralelo . Encontrei-o clicando em paralelo na nuvem de tags, mas pode haver opções melhores.
Nick Sabbe
1
Obrigado Nick. Mas isso não funcionará para dados categóricos sem grandes ajustes no código (provavelmente também não é a melhor base de funções para construir isso). Espero que alguém poderia ter feito algo semelhante já ...
Tal Galili

Respostas:

25

Aqui está uma versão usando apenas gráficos básicos, graças ao comentário de Hadley. (Para a versão anterior, consulte o histórico de edições).

terceira tentativa

parallelset <- function(..., freq, col="gray", border=0, layer, 
                             alpha=0.5, gap.width=0.05) {
  p <- data.frame(..., freq, col, border, alpha, stringsAsFactors=FALSE)
  n <- nrow(p)
  if(missing(layer)) { layer <- 1:n }
  p$layer <- layer
  np <- ncol(p) - 5
  d <- p[ , 1:np, drop=FALSE]
  p <- p[ , -c(1:np), drop=FALSE]
  p$freq <- with(p, freq/sum(freq))
  col <- col2rgb(p$col, alpha=TRUE)
  if(!identical(alpha, FALSE)) { col["alpha", ] <- p$alpha*256 }
  p$col <- apply(col, 2, function(x) do.call(rgb, c(as.list(x), maxColorValue = 256)))
  getp <- function(i, d, f, w=gap.width) {
    a <- c(i, (1:ncol(d))[-i])
    o <- do.call(order, d[a])
    x <- c(0, cumsum(f[o])) * (1-w)
    x <- cbind(x[-length(x)], x[-1])
    gap <- cumsum( c(0L, diff(as.numeric(d[o,i])) != 0) )
    gap <- gap / max(gap) * w
    (x + gap)[order(o),]
  }
  dd <- lapply(seq_along(d), getp, d=d, f=p$freq)
  par(mar = c(0, 0, 2, 0) + 0.1, xpd=TRUE )
  plot(NULL, type="n",xlim=c(0, 1), ylim=c(np, 1),
       xaxt="n", yaxt="n", xaxs="i", yaxs="i", xlab='', ylab='', frame=FALSE)
  for(i in rev(order(p$layer)) ) {
     for(j in 1:(np-1) )
     polygon(c(dd[[j]][i,], rev(dd[[j+1]][i,])), c(j, j, j+1, j+1),
             col=p$col[i], border=p$border[i])
   }
   text(0, seq_along(dd), labels=names(d), adj=c(0,-2), font=2)
   for(j in seq_along(dd)) {
     ax <- lapply(split(dd[[j]], d[,j]), range)
     for(k in seq_along(ax)) {
       lines(ax[[k]], c(j, j))
       text(ax[[k]][1], j, labels=names(ax)[k], adj=c(0, -0.25))
     }
   }           
}

data(Titanic)
myt <- subset(as.data.frame(Titanic), Age=="Adult", 
              select=c("Survived","Sex","Class","Freq"))
myt <- within(myt, {
  Survived <- factor(Survived, levels=c("Yes","No"))
  levels(Class) <- c(paste(c("First", "Second", "Third"), "Class"), "Crew")
  color <- ifelse(Survived=="Yes","#008888","#330066")
})

with(myt, parallelset(Survived, Sex, Class, freq=Freq, col=color, alpha=0.2))
Aaron - Restabelecer Monica
fonte
Aaron, uau, resposta fantástica - eu gostaria de poder marcar V duas vezes. Obrigado!
precisa
2
Estou feliz por ter gostado. Foi divertido. :) A única parte complicada é obter os locais onde as barras devem começar e terminar (que está na getpsubfunção); o resto é apenas desenhar polígonos.
Aaron - Restabelece Monica
1
Apenas outra panel.textlinha. Veja editar.
Aaron - Restabelece Monica
1
Você também pode fazer transparência nos gráficos básicos.
Hadley
2
Você está certo. Eu tinha esquecido completamente disso, estando tão acostumada com a maneira de fazer as coisas da estrutura. Para outros que estão interessados, você adiciona mais um par de personagens em sua seqüência de cor, por exemplo, #FF000080. ?rgbtem detalhes.
Aaron - Restabelece Monica