2012-10-17 99 views
29

到目前爲止,我一直無法找到可以創建類似於John Stasko的Sunburst情節的R庫。任何人都知道如何在R或Python中實現這個目標?如何在R或Python中創建一個sunburst圖?

Sunburst

+0

這些被稱爲「treemaps」的矩形等價物非常流行。如果您搜索「循環樹形圖」或類似搜索,您可能會有更好的運氣。 – fmark

回答

9
使用matplotlib棒極投影旭日圖的

Python版本:

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

例,該功能如何使用:

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

+2

這是最優雅的答案!喜歡遞歸。 – dmvianna

+1

處理簡單,可擴展,無需額外的庫;純粹的天才。這值得讚賞。 –

+0

https://bl.ocks.org/mbostock/4348373這種交互式可縮放的viz可以在R中完成嗎? –

3

只有一對夫婦,我知道圖書館是這樣做本身:

這些都不是在Python或R,但獲得一個Python/R腳本來寫出一個簡單的JSON文件,可以通過任何一個JavaScript庫加載應該是相當實現的。

+1

2年後有沒有更新這個答案? – Dror

11

您可以使用ggplot2包中的geom_tile沿着sunburst圖的線創建一些東西。我們首先創建一些隨機數據:

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

然後創建柵格圖。在這裏,圖中的x軸被耦合到dat中的x變量,y軸變爲y變量,並且將像素填充到z變量。這產生了以下情節:

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

enter image description here

ggplot2包支持各種座標變換,其中一個帶有一個軸和項目它在一個圓圈,即極座標:

p + coord_polar() 

enter image description here

這大致做你所需要的,現在你可以調整dat以獲得所需的結果。

+0

我承認它很有用,但它看起來並不完美。戒指之間有不規則的白色空間。但是,謝謝你的努力! – dmvianna

+0

我沒有不規則的空格,至少不在我上面發佈的png中。你有最新的ggplot2版本嗎? –

+0

我剛剛更新了它,當然,我仍然有。我正在使用Windows機器。 – dmvianna

21

你甚至可以很容易地有R現在建立一個互動版:

# 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

...當你移動你的鼠標在它上面時,奇蹟發生了:

enter image description here

編輯
這個包的官方網站可以在這裏找到(很多例子!):https://github.com/timelyportfolio/sunburstR

帽子提示@timelyportfolio創造了這段令人印象深刻的代碼!

+0

@Dror:這可能會讓你感興趣:-) – vonjd

+3

感謝您添加更新。我當然更喜歡交互式版本。任何人請隨時提供反饋意見,想法,批評,用例,例如https://github.com/timelyportfolio/sunburstR – timelyportfolio

+0

@timelyportfolio:謝謝,我添加了鏈接到答案:-) – vonjd

3

這裏有一個ggplot2兩層陽光。

其基本思想是爲每個圖層製作一個不同的條形,並且爲外層增加條形。我也與X軸混淆,以確保內部餅圖中間沒有洞。因此,您可以通過改變寬度和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

唯一的缺點這相比旭日專用軟件是它假設要外層是窮盡(即無缺口)。 「部分窮舉」的外層(如其他一些例子)肯定是可能的,但更復雜。

爲了完整起見,這裏已被清除,以更好的格式和標籤:

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