PythonでSankey Diagram
参考:
[2] やってみよう分析!第7章: Google Charts Sankey Diagramを使ってデータ可視化-Qiita
[3] pythonでsankeyダイアグラム – Qiita
[4] matplotlib.sankey – matplotlib 2.0.1 documentation
[5] A tutorial about drawing Sankey graphics using matplotlib – Frolian’s blog
[6] Connecting flows in matplotlib sankey diagram – StackOverflow
[7] 参議院の議席の流れをsankey-diagramで可視化する – 盆栽日記
PythonでSankey Diagramを描くならmatplotlibを使うのが一番楽なんだろうか.
(楽さだけで云えば,networkxを使って有向グラフで表現する方が楽そうだけど……)
やり方は簡単で,まず「流量(flows)」を設定,インプットがプラス,アウトプットがマイナス,
出入り口にラベル(labels)を貼る.流量に着目したネットワーク構造って感じで,目的と書き方がコンパチで分かり易い.
参考[7]を基に試しにmatplotlibで描いてみる.Rのグラフと比較してみたかったので,敢えてそのままのデータで(2016年のビジュアライゼーションはしない).
import matplotlib.pyplot as plt from matplotlib.sankey import Sankey %matplotlib inline fig = plt.figure(figsize=(8, 6)) ax = fig.add_subplot(111, title = "2013参議院選挙の議席の流れ") ax.axis('off') sankey = Sankey(ax = ax, scale=0.02, offset=0.3) sankey.add(flows = [242, -121, -121], pathlengths = [2, 1, 1], labels = ['葬儀席', '改選', '非改選'], label = '新勢力', orientations = [0, 0, 1] ) sankey.add(flows = [121, -65, -17, -11, -8, -8, -8, -1, -1, -2], fc = '#FFFF00', labels=['改選', '自民', '民主', '公明', 'みんな', '共産', '維新', '社民', '諸派', '無所属'], label='改選勢力', orientations = [0, 0, 1, -1, 1, -1, 1, -1, 1, -1], pathlengths = [2, 2, 2, 2, 2, 2, 2, 2, 2, 2], prior = 0, connect = (1, 0) ) diagrams = sankey.finish() plt.legend(loc='lower right') plt.show()
うーん.ダサい…….
[5]のコードを参考に描いてみると,
fig = plt.figure(figsize=(8, 12)) ax = fig.add_subplot(1, 1, 1, xticks=[], yticks=[], title="2013参議院選挙の議席の流れ") learners = [242, 121, 120, 119, 117, 109, 101, 93, 82, 65] labels = ['総議席', '改選', '残議席数', '残議席数', '残議席数', '残議席数', '残議席数', '残議席数', '残議席数', '自民'] out_labels = ['非改選', '社民', '諸派', '無所属', '共産', 'みんな', '維新', '公明', '民主'] colors = ['#FF0000', '#fc3f00', '#f79902', '#f7de00', '#baf202', '#83ed02', '#2eff00', '#00ff4c', '#00ffd8', '#009dff'] sankey = Sankey(ax=ax, scale=0.05, offset=0.3) for prior, (input_learner, output_learner, label, out_label, color) \ in enumerate(zip(learners[:-1], learners[1:], labels, out_labels, colors)): if prior != 8: sankey.add(flows=[input_learner, -output_learner, output_learner - input_learner], orientations=[0, 0, 1], patchlabel = label, labels=['', None, out_label], prior = prior - 1 if prior != 0 else None, connect=(1, 0), pathlengths=[0, 0, 2], trunklength=10., rotation=-90, facecolor=color) else: sankey.add(flows=[input_learner, -output_learner, output_learner - input_learner], orientations=[0, 0, 1], patchlabel=label, labels=['', labels[-1], out_label], prior=prior - 1, connect=(1, 0), pathlengths=[0, 5, 5], trunklength=10., rotation=-90, facecolor=color) diagrams = sankey.finish() for diagram in diagrams: diagram.text.set_fontweight('bold') diagram.text.set_fontsize('10') for text in diagram.texts: text.set_fontsize('10') ylim = plt.ylim() plt.ylim(ylim[0]*1.05, ylim[1])
うーん.自民党と愉快な仲間達,或いは自民党というメインストリームに対してハミゴになった存在,みたいなグラフ…….
「Sankey Diagram」でGoogle画像検索をすると,色々と綺麗でお洒落なグラフがある.
matplotlibでRのriverplotみたいな美しいグラフを描こうと思うと骨が折れそう.
というか,今更だけど,Google Chart[2]やR[7]の様なグラフを描くなら,[3]の方法の方が良かった.そもそも,それらはd3.jsからの移植な気がするので,似ているというか,同じだと思う.matplotlibのは,本当に本来の使い方のトラフィックの分析以外ではなかなか巧く表現するのが大変.
あまり,思った様なグラフを描けなかったので,
PAGE_BREAK: PageBreak
使い慣れたnetworkxで「2013参議院選挙の議席の流れ」を表してみると,
(コードの使い回しをする為に,かなり汚い(いい加減な)事をやっているのでソースは略)
(この程度のノード数なら,一つ一つ「add_node」と「add_edge」をしても良いと思う)
「参院選の流れ」ではないけど,細かい枝やノードをリムーブするとすっきり.
特に有向グラフの必要もないかと思ったので,無向グラフで表したけど.
有向グラフで表すとこんな感じに.
見易くするために,議席数5未満をリムーブ.
ピンバック: PythonでRiverplot(的なもの) | 粉末@それは風のように (日記)
ピンバック: Google Spread SheetでSankey Diagram(サンキーダイアグラム) | 粉末@それは風のように (日記)
ピンバック: Requests: 人間のためのHTTP | 粉末@それは風のように (日記)
ピンバック: Sankey Diagrams with matplotlib | Sankey Diagrams
ピンバック: networkx | 粉末@それは風のように (日記)