Diagrammes de Sankey dans R?


87

J'essaie de visualiser mon flux de données avec un diagramme de Sankey dans R.

J'ai trouvé ce billet de blog lié à un script R qui produit un diagramme de Sankey, malheureusement il est assez brut et quelque peu limité (voir ci-dessous pour un exemple de code et des données).

Quelqu'un connaît-il d'autres scripts - ou peut-être même un package - plus développé? Mon objectif final est de visualiser à la fois le flux de données et les pourcentages par taille relative des composants du diagramme, comme dans ces exemples de diagrammes de Sankey .

J'ai posté une question un peu similaire sur la liste r-help , mais après deux semaines sans aucune réponse, je tente ma chance ici sur stackoverflow.

Merci, Eric

PS. Je connais le tracé des ensembles parallèles , mais ce n'est pas ce que je recherche.

# 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")

Diagramme de Sankey produit avec le code ci-dessus, Diagramme de Sankey produit avec le code ci-dessus


2
Les flèches me semblent correctes, on dirait qu'il vous reste un réglage fin du texte et que vous y êtes
Roman Luštrik

@Roman Luštrik, je suis d'accord, ce diagramme n'est pas mauvais du tout, mais mes compétences en R sont toujours limitées, donc je ne peux pas vraiment faire autant de réglages en R, si c'était ce que vous vouliez dire? Je pourrais bien sûr le faire dans Adobe Illustrator, ou quelque chose comme ça, mais cela briserait le principe de la recherche reproductible, qui pour moi est un élément central de tout travail (académique). Avez-vous regardé les exemples auxquels j'ai fait un lien dans l'article ?
Eric Fail

Je me rends compte que ma question n'est pas une bonne question dans le sens où ce n'est pas un problème de programmation spécifique et pas directement pratique, mais une question quelque peu ouverte ( de la FAQ ). Pour répondre à cette question, il faudrait soit surveiller les différentes options graphiques de R et, sur cette base, répondre à ma question par un non, il n'y a pas de scripts ou de packages plus développés , soit il faudrait connaître un méthode plus développée pour produire des diagrammes de Sankey dans R et y pointer. Peut-être y a-t-il un meilleur endroit pour poster cette question?
Eric Fail

1
Le seul endroit où je peux trouver est peut-être crossvalidated.com.
Roman Luštrik

Et la liste de diffusion R-help? r-project.org/mail.html
Alex Reynolds

Réponses:


63

Ce tracé peut être créé via le networkD3package. Il vous permet de créer des diagrammes de Sankey interactifs. Ici vous pouvez trouver un exemple . J'ai également ajouté une capture d'écran pour que vous ayez une idée de ce à quoi cela ressemble.

# 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)

entrez la description de l'image ici


4
exemple de lien cassé
rmstmppr

1
En effet. Une meilleure alternative depuis l'introduction de htmlwidgetsest l'intrigue sankey du networkD3package. J'ai mis à jour le message.
Jonas Tundo

1
Est-il possible d'avoir des valeurs numériques comme légende au lieu d'un entier? Les valeurs sont prises correctement, mais la légende semble être arrondie. Par exemple: valeur = 0,8 et valeur = 0,2 ont des largeurs de ligne différentes, mais la légende dit «0» pour les deux.
Naveen Mathew

si vous essayez de reproduire ceci avec un échantillon de vos propres données, assurez-vous que le premier identifiant source commence par 0 et que les identifiants source et cible sont successifs
Richard

43

J'ai créé un package ( riverplot ) qui a une fonctionnalité légèrement différente, mais se chevauchant par rapport à la fonction Sankey, et peut produire des graphiques comme celui-ci:

entrez la description de l'image ici


Cela a l'air vraiment impressionnant! Je vais y jeter un œil dès que possible.
Eric Fail

39

Si vous voulez le faire avec R, votre meilleure offre semble être la suggestion @Roman - pirater la fonction SankeyR . Par exemple - ci-dessous est ma solution très rapide - orientez simplement les étiquettes verticalement, décalez-les légèrement et diminuez la police pour les références d'entrée pour lui donner une apparence un peu meilleure. Cette modification ne modifie que les lignes 171 et 223 de la fonction 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)

entrez la description de l'image ici

Je ne suis pas un as en trigonométrie, mais c'est vraiment ce dont vous avez besoin pour changer la direction des flèches. Ce serait idéal à mon avis - si vous pouviez ajuster les flèches perdues pour qu'elles soient orientées horizontalement plutôt que verticalement. Sinon, pourquoi ma solution résout le problème d'orientation des étiquettes, cela ne rend pas le diagramme beaucoup plus lisible ...


1
c'est un bon hack, merci. Je l'ai déjà fait beaucoup mieux. Vous avez mon vote positif et si rien de mieux ne vient, je serai heureux de vous transférer la prime lorsque le temps sera écoulé. Aussi, j'aime votre nom d'utilisateur.
Eric Fail

24

En plus des rCharts , les diagrammes de Sankey peuvent désormais également être générés en R avec googleVis (version> = 0.5.0). Par exemple, cet article décrit la génération du diagramme suivant à l'aide de googleVis: entrez la description de l'image ici


15

R package fera également cela (à partir de ?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") )

entrez la description de l'image ici



6

A en juger par ces définitions, cette fonction, comme le graphique des ensembles parallèles, n'a pas la capacité de diviser et de combiner des flux (c'est-à-dire à travers plus d'une transition).

Puisque les diagrammes de Sankey sont des graphes pondérés dirigés , un paquet comme qgraph pourrait être utile.

La SankeyRfonction fournit des étiquettes plus claires si vous triez les pertes par ordre décroissant car le texte est placé plus près des pointes de flèche sans se chevaucher.


1
Le tri des pertes par ordre décroissant briserait la qualité directionnelle du diagramme. Si vous regardez attentivement le diagramme que j'ai soumis, vous verrez que l' heure est sur l'axe des x, d'où l'ordre actuel. Je connais sankey-diagrams.com et ses articles, ma première pensée quand j'ai vu ce site Web a été d'ouvrir op R et de produire un joli diagramme de Sankey dans ggplot2 .
Eric Fail

5

jetez un œil à //sankeybuilder.com car il offre une solution prête à l'emploi où vous pouvez télécharger vos données et lire les variations au fil du temps. La transition fonctionne bien (similaire à la démo youtube de votre question). Si vous chargez la démo SankeyTrend, elle comprend de nombreux créneaux horaires (années de données). Une fois chargé (construit automatiquement les sankeys), cliquez sur le bouton de lecture dans le coin supérieur droit de la page pour la lecture des plages horaires, vous pouvez même faire une pause et reprendre le temps. L'URL de démonstration est ici: SankeyTrend J'espère que cela vous aidera dans votre quête du diagramme de Sankey parfait.


4

Par souci d'exhaustivité, il existe également le ggalluvialpackage qui est unggplot2 extension pour les diagrammes alluviaux / Sankey.

Voici un exemple tiré de la documentation du package

# 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")

Créé le 13/11/2018 par le package reprex (v0.2.1.9000)


En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.