web-dev-qa-db-fra.com

Comment faire un tracé sunburst en R ou Python?

Jusqu'à présent, je n'ai pas pu trouver une bibliothèque R qui puisse créer un tracé sunburst comme ceux-ci par John Stasko . Quelqu'un sait comment accomplir cela en R ou en Python?

Sunburst

39
dmvianna

Version Python du diagramme sunburst utilisant des barres matplotlib en projection polaire:

import numpy as np
import matplotlib.pyplot as plt

def sunburst(nodes, total=np.pi * 2, offset=0, level=0, ax=None):
    ax = ax or plt.subplot(111, projection='polar')

    if level == 0 and len(nodes) == 1:
        label, value, subnodes = nodes[0]
        ax.bar([0], [0.5], [np.pi * 2])
        ax.text(0, 0, label, ha='center', va='center')
        sunburst(subnodes, total=value, level=level + 1, ax=ax)
    Elif nodes:
        d = np.pi * 2 / total
        labels = []
        widths = []
        local_offset = offset
        for label, value, subnodes in nodes:
            labels.append(label)
            widths.append(value * d)
            sunburst(subnodes, total=total, offset=local_offset,
                     level=level + 1, ax=ax)
            local_offset += value
        values = np.cumsum([offset * d] + widths[:-1])
        heights = [1] * len(nodes)
        bottoms = np.zeros(len(nodes)) + level - 0.5
        rects = ax.bar(values, heights, widths, bottoms, linewidth=1,
                       edgecolor='white', align='Edge')
        for rect, label in Zip(rects, labels):
            x = rect.get_x() + rect.get_width() / 2
            y = rect.get_y() + rect.get_height() / 2
            rotation = (90 + (360 - np.degrees(x) % 180)) % 360
            ax.text(x, y, label, rotation=rotation, ha='center', va='center') 

    if level == 0:
        ax.set_theta_direction(-1)
        ax.set_theta_zero_location('N')
        ax.set_axis_off()

Exemple, comment cette fonction peut être utilisée:

data = [
    ('/', 100, [
        ('home', 70, [
            ('Images', 40, []),
            ('Videos', 20, []),
            ('Documents', 5, []),
        ]),
        ('usr', 15, [
            ('src', 6, [
                ('linux-headers', 4, []),
                ('virtualbox', 1, []),

            ]),
            ('lib', 4, []),
            ('share', 2, []),
            ('bin', 1, []),
            ('local', 1, []),
            ('include', 1, []),
        ]),
    ]),
]

sunburst(data)

python matplotlib sunburst diagram

32
sirex

Vous pouvez même créer une version interactive assez facilement avec R maintenant:

# devtools::install_github("timelyportfolio/sunburstR")

library(sunburstR)
# read in sample visit-sequences.csv data provided in source
# https://Gist.github.com/kerryrodden/7090426#file-visit-sequences-csv
sequences <- read.csv(
  system.file("examples/visit-sequences.csv",package="sunburstR")
  ,header=F
  ,stringsAsFactors = FALSE
)

sunburst(sequences)

enter image description here

... et lorsque vous déplacez votre souris dessus, la magie opère:

enter image description here

Modifier
Le site officiel de ce package peut être trouvé ici (avec de nombreux exemples!): https://github.com/timelyportfolio/sunburstR

Pointe du chapeau à @timelyportfolio qui a créé cet impressionnant morceau de code!

30
vonjd

Vous pouvez créer quelque chose comme un tracé sunburst en utilisant geom_tile du ggplot2 paquet. Créons d'abord des données aléatoires:

require(ggplot2); theme_set(theme_bw())
require(plyr)
dat = data.frame(expand.grid(x = 1:10, y = 1:10),
                 z = sample(LETTERS[1:3], size = 100, replace = TRUE))

Et puis créez le tracé raster. Ici, l'axe x dans le graphique est couplé à la variable x dans dat, l'axe y à la variable y, et le remplissage des pixels à la variable z. Cela donne le graphique suivant:

p = ggplot(dat, aes(x = x, y = y, fill = z)) + geom_tile() 
print(p)

enter image description here

Le ggplot2 le package prend en charge toutes sortes de transformations de coordonnées, dont l'une prend un axe et la projette sur un cercle, c'est-à-dire les coordonnées polaires:

p + coord_polar()

enter image description here

Cela fait à peu près ce dont vous avez besoin, vous pouvez maintenant Tweak dat pour obtenir le résultat souhaité.

12
Paul Hiemstra

Il y a un paquet appelé ggsunburst. Malheureusement, il n'est pas dans CRAN, mais vous pouvez l'installer en suivant les instructions du site Web: http://genome.crg.es/~didac/ggsunburst/ggsunburst.html .

enter image description here

J'espère que cela aide les personnes qui recherchent toujours un bon forfait comme celui-ci.

Cordialement,

5
jbkunst

Voici un ggplot2 sunburst avec deux couches.

L'idée de base est de simplement créer une barre différente pour chaque couche et d'agrandir les barres pour les couches externes. J'ai également joué avec l'axe des x pour m'assurer qu'il n'y a pas de trou au milieu du graphique à secteurs interne. Vous pouvez ainsi contrôler l'apparence du sunburst en modifiant les valeurs de largeur et d'axe des x.

library(ggplot2)

# make some fake data
df <- data.frame(
    'level1'=c('a', 'a', 'a', 'a', 'b', 'b', 'c', 'c', 'c'), 
    'level2'=c('a1', 'a2', 'a3', 'a4', 'b1', 'b2', 'c1', 'c2', 'c3'), 
    'value'=c(.025, .05, .027, .005, .012, .014, .1, .03, .18))

# sunburst plot
ggplot(df, aes(y=value)) +
    geom_bar(aes(fill=level1, x=0), width=.5, stat='identity') + 
    geom_bar(aes(fill=level2, x=.25), width=.25, stat='identity') + 
    coord_polar(theta='y')

enter image description here

Le seul inconvénient que cela a par rapport aux logiciels spécifiques à Sunburst est qu'il suppose que vous voulez que les couches externes soient collectivement exhaustives (c'est-à-dire sans lacunes). Des couches externes "partiellement exhaustives" (comme dans certains des autres exemples) sont sûrement possibles mais plus compliquées.

Pour être complet, ici, il est nettoyé avec un formatage et des étiquettes plus agréables:

library(data.table)

# compute cumulative sum for outer labels
df <- data.table(df)
df[, cumulative:=cumsum(value)-(value/2)]

# store labels for inner circle
inner_df <- df[, c('level1', 'value'), with=FALSE]
inner_df[, level1_value:=sum(value), by='level1']
inner_df <- unique(text_df[, c('level1', 'level1_value'), with=FALSE])
inner_df[, cumulative:=cumsum(level1_value)]
inner_df[, prev:=shift(cumulative)]
inner_df[is.na(prev), position:=(level1_value/2)]
inner_df[!is.na(prev), position:=(level1_value/2)+prev]

colors <- c('#6a3d9a', '#1F78B4', '#33A02C', '#3F146D', '#56238D', '#855CB1', '#AD8CD0', '#08619A', '#3F8DC0', '#076302', '#1B8416', '#50B74B')
colorNames <- c(unique(as.character(df$level1)), unique(as.character(df$level2)))
names(colors) <- colorNames

ggplot(df, aes(y=value, x='')) +
    geom_bar(aes(fill=level2, x=.25), width=.25, stat='identity') + 
    geom_bar(aes(fill=level1, x=0), width=.5, stat='identity') + 
    geom_text(data=inner_df, aes(label=level1, x=.05, y=position)) + 
    coord_polar(theta='y') + 
    scale_fill_manual('', values=colors) +
    theme_minimal() + 
    guides(fill=guide_legend(ncol=1)) +
    labs(title='') + 
    scale_x_continuous(breaks=NULL) + 
    scale_y_continuous(breaks=df$cumulative, labels=df$level2, 5) + 
    theme(axis.title.x=element_blank(), axis.title.y=element_blank(), panel.border=element_blank(), panel.grid=element_blank())

enter image description here

3
dmp

Il n'y a que quelques bibliothèques que je connais qui le font nativement:

Aucun de ces éléments n'est en Python ou R, mais obtenir un script python/R pour écrire un simple fichier JSON qui peut être chargé par l'une des bibliothèques javascript devrait être assez réalisable.

3
jozzas

Puisque jbkunst a mentionné ggsunburst, je poste ici un exemple de reproduction du sunburst par sirex.

Ce n'est pas exactement la même chose car dans ggsunburst, l'angle d'un nœud est égal à la somme des angles de ses nœuds enfants.

# install ggsunburst package
if (!require("ggplot2")) install.packages("ggplot2")
if (!require("rPython")) install.packages("rPython")
install.packages("http://genome.crg.es/~didac/ggsunburst/ggsunburst_0.0.9.tar.gz", repos=NULL, type="source")
library(ggsunburst)

# dataframe
# each row corresponds to a node in the hierarchy
# parent and node are required, the rest are optional attributes
# the attributes correspond to the node, not its parent
df <- read.table(header = T, sep = ",", text = "
parent,node,size,color,dist
,/,,B,1
/,home,,D,1
home,Images, 40,E,1
home,Videos, 20,E,1
home,Documents, 5,E,1
/,usr,,D,1
usr,src,,A,1
src,linux-headers, 4,C,1.5
src,virtualbox, 1,C,1.5
usr,lib, 4,A,1
usr,share, 2,A,1
usr,bin, 1,A,1
usr,local, 1,A,1
usr,include, 1,A,1
")

write.table(df, 'df.csv', sep = ",", row.names = F)

# compute coordinates from dataframe
# "node_attributes" is used to pass the attributes other than "size" and "dist", 
# which are special attributes that alter the dimensions of the nodes
sb <- sunburst_data('df.csv', sep = ",", type = "node_parent", node_attributes = "color")

# plot
sunburst(sb, node_labels = T, node_labels.min = 10, rects.fill.aes = "color") +
  scale_fill_brewer(palette = "Set1", guide = F)

enter image description here

2
didac