【Dash Plotlyの使い方 基本編】Plotlyで描く円グラフ徹底まとめ

皆さん、こんにちは!

今回は、Pythonのデータ可視化ライブラリの1つである、Dash Plotlyを学んでいきます。

この記事では、Plotlyで描画出来る円グラフをまとめています。

Plotyの関連記事はこちらです。今後もコンテンツを増やしていく予定ですのでお楽しみに!

【Dash Plotlyの使い方 基本編】Plotlyで描く折れ線グラフ徹底まとめ

Plotlyとは?

Plotlyはインタラクティブなオープンソースのデータ可視化ライブラリで、統計、財務、地理、科学、3次元データなど幅広いタイプの可視化をカバーする40種類上のグラフタイプが実装可能です。

Plotlyは元々はJavaScriptライブラリ(plotly.js)上に構築されているため、基本的にはPythonコードのみでデータがヌルヌル動くようなダッシュボードを構築できます。

JupyterNotebook上や、Webアプリケーションの一部としてWebベースの可視化も可能です。

Webベースの可視化を行うためには、Dash(中身はFlask)を使う必要があるため、PlotlyとDashはセットで扱われることも多いです。

https://plotly.com/dash/industry-app-catalog/

基本の円グラフ

まずは基本的な円グラフを作成していきます。

Plotly Expressを使えば、インポートを含め数行で描画可能です。

まずはPlotly Expressとサンプルデータをインポートします。

# ライブラリをインポート
import plotly.express as px
# サンプルデータセットを読み込む
df = px.data.tips()
df

支払額とそのチップを誰がいつ支払ったか(?)のようなデータセットだと思います。

このデータを簡単に円グラフにしていきます。

Plotlyは上記のような生データから1行でグラフ化が可能です。

Matplotlibで円グラフを描こうと思うと、あらかじめ各曜日でのTip支払額の合計を集計しておく必要があり、描画までひと手間掛かってしまいます。
Plotlyでは、この集計を裏側で行ってくれるので、生のデータフレームがあればOKです。

円グラフの定義は、px.pie()で完了です。namesでグルーピングして、valuesの値を足し合わせるようなイメージです。

fig = px.pie(df, values='tip', names='day')
fig.show()

デフォルトで、各要素が占める割合と、namesとvaluesが表示されます。

画像の保存にも対応しており、この辺はBokehと似ています。

円グラフの色を変更

円グラフの色味は、デフォルトで決まっているカラースケールから設定するのが簡単です。

Plotlyで使えるカラースケースは以下の公式ドキュメントにまとまっています。

カラースケールを一括表示することも可能です。

Built-In Sequential Color scales

import plotly.express as px

# あらかじめ利用できるカラースケールたちを一括表示
fig = px.colors.sequential.swatches_continuous()
fig.show()
import plotly.express as px
df = px.data.tips()
fig = px.pie(df, values='tip', names='day', color_discrete_sequence=px.colors.sequential.Magma)
fig.show()

試しに、色を変えてみます。

color_discrete_sequence引数に色をセットし、

Plotlyが備えているカラースケールを呼び出すときは、px.colors.sequential.Magma のように書きます。

円グラフのスタイルを変更

特にこだわりがなければ、PlotlyExpressで良いと思いますが、よりグラフをカスタムしたい場合、glaph objectsを用いる必要がでてきます。

詳しくは別記事にまとめたいと思いますが、Plotly Expressは、内部にgraph objectsを持っているため、Expressで作成したグラフに後からgraphobjectsを充てることはできません。

Expressでは1行で円グラフを作成できるのに対し、grahp objectsでは、最低でも5行、6行と必要になってくるので、よほどのことがない限り、Expressで良いでしょう。

以下の例では、HTMLカラーを手動で当てています。

カラーパレットがまとまっているサイトを張っておくので参考にしてください。

HTML Color Names

import plotly.graph_objects as go
# 色を自分で設定することも可能
colors = ['Coral', 'CornflowerBlue', 'DarkCyan', 'DarkGoldenRod']

# data引数に円グラフ要素を定義する
fig = go.Figure(data=[go.Pie(labels=['Oxygen','Hydrogen','Carbon_Dioxide','Nitrogen'],
                             values=[2200,1900,1053,500])])
# fig要素をアップデートしてマウスホバー時の表示や、色を変更する
fig.update_traces(hoverinfo='label+percent', textinfo='value', textfont_size=20,
                  marker=dict(colors=colors, line=dict(color='#000000', width=2)))
fig.show()

円グラフのテキストを変更

Plotly Expressでもグラフに表示するテキストを変えることが可能です。

まずはデータセットを読み込みます。

※.query はSQLのように、データフレーム内で一致検索をした結果を返してくれます。

import plotly.express as px
# gapminderのデータ(アメリカ大陸に絞り込み)
df = px.data.gapminder().query("continent == 'Americas'")
df

# 円グラフを設定
fig = px.pie(df, values='pop', names='country')
# グラフをアップデート(テキストの位置を内側に)
fig.update_traces(textposition='inside')
# グラフをアップデート(フォントの最小サイズを指定、最小サイズで書けないものは隠す)
fig.update_layout(uniformtext_minsize=12, uniformtext_mode='hide')
# グラフを描画
fig.show()

ちなみに、右側のレジェンドから、United Statesをクリックすると、”アメリカを除く”場合の集計結果を表示することも可能です。この辺りは、生のデータフレームを与えているPlotyならではの機動力かもしれません。

円グラフを複数配置(sub_plot)

1つのプロットの中に複数のグラフを描画することをサブプロットと言います。

サブプロットでは、内部のグラフが相互に連動して操作できるため、1つのデータセット内で、比較を行ったり、別のグラフ(折れ線+円グラフなど)を組み合わせて表示したい場合に用います。

Plotly Expressでは、残念ながらサブプロットは使えません。

変わりとして、Facetsオブジェクトを用いて、サブプロットに近いことはできます。

詳細は別の記事にまとめようと思いますが、データセットの周辺分布を出したい場合は以下のリンクから。

Facet and Trellis Plots in Python

データセットのユニーク変数を用いて、自動的に描画するFacetsは以下のリンクから可能です。

Marginal Distribution Plots in Python

2つの円グラフを同時に表示

サブプロットを用いるには、make_subplots関数を用います。

make_subplots(rows=行数, cols=列数)でプロットを定義可能です。

2つの円グラフを横並びに表示したい場合、以下のような記述で実施できます。

import plotly.graph_objects as go
from plotly.subplots import make_subplots

labels = ["US", "China", "European Union", "Russian Federation", "Brazil", "India",
          "Rest of World"]

# サブプロットを作成する
fig = make_subplots(rows=1, cols=2, specs=[[{'type':'domain'}, {'type':'domain'}]])
# 1,1 の場所にGHG Emissionsのグラフを挿入
fig.add_trace(go.Pie(labels=labels, values=[16, 15, 12, 6, 5, 4, 42], name="GHG Emissions"),
              1, 1)
# 1,2 の場所にCO2 Emissionsのグラフを挿入
fig.add_trace(go.Pie(labels=labels, values=[27, 11, 25, 8, 1, 3, 25], name="CO2 Emissions"),
              1, 2)

# ドーナツ状に変更し、マウスホバー時の表示を変更
fig.update_traces(hole=.4, hoverinfo="label+percent+name")

# グラフタイトルを追加。
fig.update_layout(
    title_text="Global Emissions 1990-2011",
    # サブプロットの位置と、ドーナツ内のテキストを変更
    annotations=[dict(text='GHG', x=0.18, y=0.5, font_size=20, showarrow=False),
                 dict(text='CO2', x=0.82, y=0.5, font_size=20, showarrow=False)])
fig.show()

円のサイズを変更する

サブプロットで描画したグラフのサイズを。任意の値に応じて変化させることが可能です。

values引数で指定するものに連動し、サブプロット内でも連動させるグラフをグルーピングで指定できます。

グラフサイズはscalegroupで定義しますが、値は任意で、TeseでもAでもOKです。

import plotly.graph_objects as go
from plotly.subplots import make_subplots

# データセットのラベルを定義する
labels = ["Asia", "Europe", "Africa", "Americas", "Oceania"]

# 1行2列のグラフを描画する
fig = make_subplots(1, 2, specs=[[{'type':'domain'}, {'type':'domain'}]],
                    subplot_titles=['1980', '2007'])
# グラフサイズはscalegroupで定義する(値は任意、TeseでもAでも)
fig.add_trace(go.Pie(labels=labels, values=[4, 7, 1, 7, 0.5], scalegroup='Test',
                     name="World GDP 1980"), 1, 1)
fig.add_trace(go.Pie(labels=labels, values=[21, 15, 3, 19, 1], scalegroup='Test',
                     name="World GDP 2007"), 1, 2)

fig.update_layout(title_text='World GDP')
fig.show()

様々な円グラフ

最後にPlotlyで描画できる様々な円グラフを試して終わりにします。

ドーナツ型 円グラフ

ドーナツ型の円グラフを作成するには、graph objectsが必要となります。

import plotly.graph_objects as go

labels = ['Oxygen','Hydrogen','Carbon_Dioxide','Nitrogen']
values = [4500, 2500, 1053, 500]

# ドーナツ型円グラフを描画、 hole 引数を使う
fig = go.Figure(data=[go.Pie(labels=labels, values=values, hole=.3)])
fig.show()

hole引数を0.8に設定した場合は、こんな感じ。

中心の穴の大きさが変わります。

一部が飛び出た 円グラフ

飛び出しグラフも、graph objectsを使います。

pull 引数に対して、円グラフの各要素の飛び出し比率を指定します。

import plotly.graph_objects as go

labels = ['Oxygen','Hydrogen','Carbon_Dioxide','Nitrogen']
values = [4500, 2500, 1053, 500]

# pull で飛び出しを表現する、円の半径に対する割合で、表現するのでMaxは1
fig = go.Figure(data=[go.Pie(labels=labels, values=values, pull=[0, 0, 0.2, 0])])
fig.show()

pullを1にすると、このような感じ。

サンバーストチャート

サンバーストチャートは、階層データを表現することが出来る円グラフです。

内側の縁が階層の最上位を示し、外側に行くにつれて、細かい分類になっていくイメージです。

import plotly.express as px
# データセットを作成
data = dict(
    character=["Eve", "Cain", "Seth", "Enos", "Noam", "Abel", "Awan", "Enoch", "Azura"],
    parent=["", "Eve", "Eve", "Seth", "Seth", "Eve", "Eve", "Awan", "Eve" ],
    value=[10, 14, 12, 10, 2, 6, 6, 4, 4])

# サンバーストチャートを作成
fig = px.sunburst(
    data,
    names='character',
    parents='parent',
    values='value',
)
fig.show()

サンバーストチャートは様々なバリエーションがあるので、詳細は別の記事で扱いたいと思います。

野球で言えば、内側が「NPB」、次の階層が「セリーグ・パリーグ」、最後が「チーム名」と言ったイメージでしょうか。

データに意味はありませんが、以下のように簡単に各チームが占める割合などを示すことが可能です。

NPB、セ、パのvaluesが全て0になっているのは、データがすべて一番下の階層(チーム名)に属しているからです。

# サンバーストチャートを作成
fig =go.Figure(go.Sunburst(
    labels =["NPB", "セ", "パ", "巨人", "阪神", "中日", "広島", "ヤクルト", "DeNA",
             "ソフト", "楽天", "ロッテ","オリックス", "西武", "日ハム"],
    parents=[""   , "NPB" , "NPB" , "セ", "セ", "セ" , "セ", "セ", "セ" ,
             "パ" , "パ" , "パ" , "パ" , "パ" , "パ"  ],
    values= [0,0,0,
             7,30,13,16,20,17,
             10,24,17,29,6,18]
))

# レイアウトを設定
fig.update_layout(margin = dict(t=0, l=0, r=0, b=0))

fig.show()

「パ」をクリックすると、グラフがヌルっと動いて、パリーグのみでグラフを描画することができます。

このグラフを更に改良して、チームの下に年齢のレンジ(19~25など)、更にしたに選手名を入れることで、1つのグラフに様々な情報を埋め込むことが可能になります。

まとめ

以上、Plotlyの円グラフについてまとめていきました。

最小で3行程度でインタラクティブなグラフを描くことが出来るPlotlyですが、その一方で、サンバーストグラフなど手の込んだグラフを描くことも可能です。

皆さんもぜひ試してみてください!

当ブログでは、Plotlyの使い方を様々解説しています。

他の記事もぜひ参考にしてみてください!

【Dash Plotlyの使い方 基本編】Plotlyで描く折れ線グラフ徹底まとめ