Diagrammi di Sankey in R?


86

Sto cercando di visualizzare il mio flusso di dati con un diagramma di Sankey in R.

Ho trovato questo post sul blog che si collega a uno script R che produce un diagramma di Sankey, sfortunatamente è piuttosto grezzo e alquanto limitato (vedi sotto per codice e dati di esempio).

Qualcuno conosce altri script, o forse anche un pacchetto, più sviluppato? Il mio obiettivo finale è visualizzare sia il flusso di dati che le percentuali in base alla dimensione relativa dei componenti del diagramma, come in questi esempi di diagrammi di Sankey .

Ho pubblicato una domanda in qualche modo simile nell'elenco di r-help , ma dopo due settimane senza risposte sto tentando la fortuna qui su stackoverflow.

Grazie, Eric

PS. Sono a conoscenza del Parallel Sets Plot , ma non è quello che sto cercando.

# thanks to, https://tonybreyal.wordpress.com/2011/11/24/source_https-sourcing-an-r-script-from-github/
  sourc.https     <- function(url, ...) {
# install and load the RCurl package 
if (match('RCurl', nomatch=0, installed.packages()[,1])==0) {
  install.packages(c("RCurl"), dependencies = TRUE)
  require(RCurl)  
} else require(RCurl)    

# parse and evaluate each .R script
  sapply(c(url, ...), function(u) {
    eval(parse(text = getURL(u, followlocation = TRUE, 
    cainfo  = system.file("CurlSSL", "cacert.pem", 
    package = "RCurl"))), envir = .GlobalEnv)
 } )
 }

# from https://gist.github.com/1423501
sourc.https("https://raw.github.com/gist/1423501/55b3c6f11e4918cb6264492528b1ad01c429e581/Sankey.R")

# My example (there is another example inside Sankey.R):
inputs = c(6, 144)
losses = c(6,47,14,7, 7, 35, 34)
unit = "n ="

labels = c("Transfers",
           "Referrals\n",
           "Unable to Engage",
           "Consultation only",
           "Did not complete the intake",
           "Did not engage in Treatment",
           "Discontinued Mid-Treatment",
           "Completed Treatment",
           "Active in \nTreatment")

SankeyR(inputs,losses,unit,labels)

# Clean up my mess
rm("inputs", "labels", "losses", "SankeyR", "sourc.https", "unit")

Diagramma Sankey prodotto con il codice sopra, Diagramma di Sankey prodotto con il codice sopra


2
Le frecce mi stanno bene, sembra che ti sia rimasta la regolazione fine del testo e che tu sia dentro?
Roman Luštrik

@Roman Luštrik, sono d'accordo, questo diagramma non è affatto male, ma le mie abilità R sono ancora limitate, quindi non posso davvero fare così tante regolazioni in R, se era quello che intendevi? Ovviamente potrei farlo in Adobe Illustrator, o qualcosa di simile, ma ciò infrangerebbe il principio della ricerca riproducibile, che per me è un elemento centrale in qualsiasi lavoro (accademico). Hai guardato gli esempi che ho linkato nel post ?
Eric Fail

Mi rendo conto che la mia domanda non è una buona domanda nel senso che non è un problema di programmazione specifico e non direttamente pratico, ma una domanda piuttosto aperta ( dalle FAQ ). Per rispondere a questa domanda si dovrebbe avere una supervisione sulle diverse opzioni di rappresentazione grafica in R e su questa base rispondere alla mia domanda con un no, non ci sono script o pacchetti là fuori che sono più sviluppati , o si dovrebbe conoscere un metodo più sviluppato per produrre diagrammi di Sankey in R e indicarli. Forse c'è un posto migliore per pubblicare questa domanda?
Eric Fail

1
L'unico posto che posso trovare è forse crossvalidated.com.
Roman Luštrik

Che ne dici della mailing list di R-help? r-project.org/mail.html
Alex Reynolds

Risposte:


63

Questo grafico può essere creato tramite il networkD3pacchetto. Ti permette di creare diagrammi Sankey interattivi. Qui puoi trovare un esempio . Ho anche aggiunto uno screenshot in modo da farti un'idea di come appare.

# Load package
library(networkD3)

# Load energy projection data
# Load energy projection data
URL <- paste0(
        "https://cdn.rawgit.com/christophergandrud/networkD3/",
        "master/JSONdata/energy.json")
Energy <- jsonlite::fromJSON(URL)
# Plot
sankeyNetwork(Links = Energy$links, Nodes = Energy$nodes, Source = "source",
             Target = "target", Value = "value", NodeID = "name",
             units = "TWh", fontSize = 12, nodeWidth = 30)

inserisci qui la descrizione dell'immagine


4
il collegamento di esempio è interrotto
rmstmppr

1
Infatti. Un'alternativa migliore dall'introduzione di htmlwidgetsè la trama di sankey dal networkD3pacchetto. Ho aggiornato il post.
Jonas Tundo

1
È possibile avere valori numerici come didascalia anziché interi? I valori sono presi correttamente, ma la didascalia sembra essere arrotondata. Ad esempio: valore = 0,8 e valore = 0,2 hanno linee di larghezza diverse, ma la didascalia dice "0" per entrambi.
Naveen Mathew

se provi a riprodurlo con un campione dei tuoi dati, assicurati che il primo ID di origine inizi con 0 e che gli ID di origine e di destinazione siano successivi
Richard

43

Ho creato un pacchetto ( riverplot ) che ha una funzionalità leggermente diversa, ma sovrapposta rispetto alla funzione Sankey, e può produrre grafici come questo:

inserisci qui la descrizione dell'immagine


Questo sembra davvero impressionante! Lo darò il prima possibile.
Eric Fail

39

Se vuoi farlo con R, la tua migliore offerta sembra essere il suggerimento di @Roman: hackera la funzione SankeyR . Ad esempio, di seguito è riportata la mia soluzione molto rapida: basta orientare le etichette verticalmente, sfalsarle leggermente e diminuire il carattere per i riferimenti di input per farlo sembrare un po 'migliore. Questa modifica cambia solo le righe 171 e 223 nella funzione SankeyR :

    #line171 - change oversized font size of input label
    fontsize = max(0.5,frInputs[j]*1.5)#1.5 instead of 2.5 

    #line223 - srt changes from 35 to 90 to orient labels vertically, 
    #and offset adjusts them to get better alignment with arrows
    text(txtX, txtY, fullLabel, cex=fontsize, pos=4, srt=90, offset=0.1)

inserisci qui la descrizione dell'immagine

Non sono un asso in trigonometria, ma questo è davvero ciò di cui hai bisogno per cambiare la direzione delle frecce. Sarebbe l'ideale a mio avviso, se potessi regolare le frecce libere in modo che siano orientate orizzontalmente anziché verticalmente. Altrimenti, perché la mia soluzione risolve il problema con l'orientamento delle etichette, non rende il diagramma molto più leggibile ...


1
è un bel trucco, grazie. L'ho già migliorato molto. Hai il mio voto positivo e se non arriva niente di meglio sono felice di trasferirti la taglia quando il tempo sarà scaduto. Inoltre, mi piace il tuo nome utente.
Eric Fail

24

Oltre a rCharts , i diagrammi di Sankey possono ora essere generati anche in R con googleVis (versione> = 0.5.0). Ad esempio, questo post descrive la generazione del seguente diagramma utilizzando googleVis: inserisci qui la descrizione dell'immagine


15

R's package farà anche questo (da ?alluvial).

# install.packages(c("alluvial"), dependencies = TRUE)
require(alluvial)

# Titanic data
tit <- as.data.frame(Titanic)

# 4d
alluvial( tit[,1:4], freq=tit$Freq, border=NA,
     hide = tit$Freq < quantile(tit$Freq, .50),
     col=ifelse( tit$Class == "3rd" & tit$Sex == "Male", "red", "gray") )

inserisci qui la descrizione dell'immagine



6

A giudicare da queste definizioni, questa funzione, come il Parallel Sets Plot, manca della capacità di dividere e combinare i flussi (cioè attraverso più di una transizione).

Poiché i diagrammi di Sankey sono grafici pesati diretti , un pacchetto come qgraph potrebbe essere utile.

La SankeyRfunzione fornisce etichette più chiare se si ordinano le perdite in ordine decrescente poiché il testo viene posizionato più vicino alle punte delle frecce senza sovrapposizioni.


1
Ordinare le perdite in ordine decrescente spezzerebbe la qualità direzionale del diagramma. Se guardi attentamente il diagramma che ho presentato, vedrai che l' ora è sull'asse x, da cui l'ordine corrente. Conosco sankey-diagrams.com e gli articoli su di esso, il mio primo pensiero quando ho visto quel sito Web è stato quello di aprire op R e produrre un bel diagramma di Sankey in ggplot2 .
Eric Fail

5

dai un'occhiata a //sankeybuilder.com in quanto offre una soluzione pronta all'uso in cui puoi caricare i tuoi dati e riprodurre le variazioni nel tempo. La transizione funziona bene (simile alla demo di YouTube nella tua domanda). Se carichi la demo di SankeyTrend, include molti intervalli di tempo (anni di dati). Una volta caricato (crea sankeys automaticamente), fai clic sul pulsante di riproduzione nell'angolo in alto a destra della pagina per la riproduzione degli intervalli di tempo, puoi anche mettere in pausa e riprendere il tempo. L'URL della demo è qui: SankeyTrend Spero che questo aiuti la tua ricerca del diagramma Sankey perfetto.


4

Per completezza, c'è anche il ggalluvialpacchetto che è un ggplot2 extensiondiagramma alluvionale / Sankey.

Ecco un esempio tratto dalla documentazione del pacchetto

# devtools::install_github("corybrunson/ggalluvial", ref = "optimization")
library(ggalluvial)

titanic_wide <- data.frame(Titanic)
ggplot(data = titanic_wide,
       aes(axis1 = Class, axis2 = Sex, axis3 = Age,
           y = Freq)) +
  scale_x_discrete(limits = c("Class", "Sex", "Age"), expand = c(.1, .05)) +
  xlab("Demographic") +
  geom_alluvium(aes(fill = Survived)) +
  geom_stratum() + geom_text(stat = "stratum", label.strata = TRUE) +
  theme_minimal() +
  ggtitle("passengers on the maiden voyage of the Titanic",
          "stratified by demographics and survival") +
  theme(legend.position = 'bottom')

ggplot(titanic_wide,
       aes(y = Freq,
           axis1 = Survived, axis2 = Sex, axis3 = Class)) +
  geom_alluvium(aes(fill = Class),
                width = 0, knot.pos = 0, reverse = FALSE) +
  guides(fill = FALSE) +
  geom_stratum(width = 1/8, reverse = FALSE) +
  geom_text(stat = "stratum", label.strata = TRUE, reverse = FALSE) +
  scale_x_continuous(expand = c(0, 0), 
                     breaks = 1:3, labels = c("Survived", "Sex", "Class")) +
  scale_y_discrete(expand = c(0, 0)) +
  coord_flip() +
  ggtitle("Titanic survival by class and sex")

Creato il 13/11/2018 dal pacchetto reprex (v0.2.1.9000)


Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.