高度な対話型の可視化が可能なPlotlyを紹介する。

インストール方法

本家サイト参照

https://plotly.com/python/getting-started/

図の構成要素

Plotlyにおける図は、以下のように構成される。

  • トレース:基本描画単位(散布図 Scatter, 線グラフ Line, 棒グラフ Bar などのオブジェクト)
  • データ:トレースのリスト(複数のトレースをひとつの画面に描画)
  • レイアウト:図のレイアウト.タイトル,軸などを定義.
  • 図:データとレイアウトから構成されるオブジェクト

データ以外は,辞書(の辞書)から成るデータ構造で保管される.

描画

  • オフラインの場合 plotly.offline.plot() でhtmlファイルを出力(と同時にブラウザで表示)
  • 図オブジェクト.show()でも同様にノートに出力 (Jupyter Notebookのみ)
import plotly
import plotly.graph_objs as go

# Google Colab.でプロットするためには, 以下を実行する.
# import plotly.io as pio
# pio.renderers.default = "colab"

最初の例

最初の例題として、簡単な散布図 (scatter plot)を描画する。グラフオブジェクト goScatter クラスを用いる.

引数は以下の通り.

  • $x$: $x$ 軸の要素を表すリスト
  • $y$: $y$ 軸の要素を表すリスト
  • mode: マーカー(点) 'markers' か,線 'lines'か,両方かを指定する.
  • text: マウスオーバー時のテキストを指定
  • marker: マーカーの属性を指定した辞書.大きさ size,線の属性を表す辞書 line,色 color,透過度 opacity などを指定する.
trace = go.Scatter(
    x=[1, 2, 3, 4, 5],
    y=[10, 20, 30, 20, 10],
    mode="markers + lines",
    text=["A", "B", "C", "D", "E"],
    marker=dict(size=14, line=dict(width=1), color="red", opacity=0.3),
)

data = [trace]

fig = go.Figure(data)
# plotly.offline.plot(fig); # Jupyterlabのとき
# fig.show() # Jupyter Notebookのとき

2つ以上のトレースをもつ図も、同様に作ることができる。

trace1 = go.Scatter(
    x=[1, 2, 3, 4, 5],
    y=[10, 20, 30, 20, 10],
    mode="markers + lines",
)

trace2 = go.Scatter(
    x=[1, 2, 3, 4, 5],
    y=[20, 20, 20, 20, 20],
    mode="markers + lines",
)

data = [trace1, trace2]

layout = go.Layout(
    title="2つのトレース",
)

fig = go.Figure(data, layout)
#plotly.offline.plot(fig)
# fig.show()

棒グラフの例

次の例として,2つのトレースをもつ棒グラフを描画してみよう.

1つの棒には身長を,もう1つの棒には体重のデータを表示する.これには2つのトレースを作成し,それを入れたデータリストを作ればよい.

トレースの名称は,引数 name で指定する.

trace1 = go.Bar(x=["Sara", "Kitty", "Mickey"], y=[160, 64, 83], name="Height")
trace2 = go.Bar(x=["Sara", "Kitty", "Mickey"], y=[60, 12, 20], name="Weight")

data = [trace1, trace2]

fig = go.Figure(data)
# plotly.offline.plot(fig);
# fig.show()

レイアウト

上で作成した棒グラフにレイアウト情報を付加しよう.

ここでは積み上げ棒グラフにして,さらに表題を追加する.

layout = go.Layout(
    barmode="stack",
    title="身長と体重",
)
fig = go.Figure(data=data, layout=layout)
# plotly.offline.plot(fig);
# fig.show()

ヒストグラム

データフレームに保管されているデータをヒストグラムとして描画してみよう.

例題として用いるのはiris(アヤメ)のデータである.

まずはpandasを用いてデータを読んでおく.

import pandas as pd

iris = pd.read_csv(
    "http://logopt.com/data/iris.data",
    names=["sepal length", "sepal width", "petal length", "petal width", "class"],
)
iris.head()
sepal length sepal width petal length petal width class
0 5.1 3.5 1.4 0.2 Iris-setosa
1 4.9 3.0 1.4 0.2 Iris-setosa
2 4.7 3.2 1.3 0.2 Iris-setosa
3 4.6 3.1 1.5 0.2 Iris-setosa
4 5.0 3.6 1.4 0.2 Iris-setosa

アヤメのデータのヒストグラム(histgram, 度数分布表)を描画する.

ヒストグラムは数値データの分布の概要を知る際に便利である.

# グラフオブジェクトの Histgram クラスを用いて,インスタンスを生成する.
trace1 = go.Histogram(x=iris["sepal length"], opacity=0.75, name="sepal length")
trace2 = go.Histogram(x=iris["sepal width"], opacity=0.75, name="sepal width")
trace3 = go.Histogram(x=iris["petal length"], opacity=0.75, name="petal length")
trace4 = go.Histogram(x=iris["petal width"], opacity=0.75, name="petal width")

# データはトレースのリストである.
data = [trace1, trace2, trace3, trace4]

# レイアウトでグラフのタイトルや軸名を設定する.
# レイアウトも辞書(の辞書)のような形式である.
layout = go.Layout(
    title="Iris Histgram", xaxis=dict(title="Length/Width"), yaxis=dict(title="Count")
)

# 図(Figure)はデータとレイアウトを合わせたオブジェクトである.
fig = go.Figure(data=data, layout=layout)
# plotly.offline.plot(fig);
# fig.show()

問題(ポケモン)

以下のように読み込んだポケモンのデータフレームを用いて,攻撃力(Attack),守備力(Defense)のヒストグラムを描画せよ. (ヒント:データフレームから一部の列を切り出す方法については,pandasの練習問題を参考にせよ.)

pokemon = pd.read_csv("http://logopt.com/data/poke.csv", encoding="utf-8", index_col=0)
pokemon.head()
Name Type 1 Type 2 Total HP Attack Defense Sp. Atk Sp. Def Speed Generation Legendary Japanese
#
1 Bulbasaur Grass Poison 318 45 49 49 65 65 45 1 False フシギダネ
2 Ivysaur Grass Poison 405 60 62 63 80 80 60 1 False フシギソウ
3 Venusaur Grass Poison 525 80 82 83 100 100 80 1 False フシギバナ
3 VenusaurMega Venusaur Grass Poison 625 80 100 123 122 120 80 1 False フシギバナ・メガ進化
4 Charmander Fire NaN 309 39 52 43 60 50 65 1 False ヒトカゲ

問題 (SAT,GPA)

http://logopt.com/data/SATGPA.csv データを読み込み,2種類のSATの成績とGPAのヒストグラムを描画せよ.

散布図

散布図(scatter plot)は,2つの数値データの関係を知る際に便利である.

グラフオブジェクトとしてはScatterクラスを用いる.

引数の x と y で $x,y$ 軸に使用するデータ(データフレームの列名)を指定する.

ここでは'がく片長 'sepal length'と花びら長 'petal length'の関係を図示してみる.

trace = go.Scatter(
    x=iris["sepal length"],
    y=iris["petal width"],
    mode="markers",
)

layout = go.Layout(
    title="Iris Scatter",
    xaxis=dict(title="sepal length"),
    yaxis=dict(title="petal width"),
)
data = [trace]
fig = go.Figure(data, layout)
# plotly.offline.plot(fig);
# fig.show()

問題(車)

http://logopt.com/data/auto-mpg.dataから車のデータを読み込み, 重さ "weight" と燃費 "mpg" の散布図を描け.

L = [
    "mpg",
    "cylinders",
    "displacement",
    "horsepower",
    "weight",
    "acceleration",
    "year",
    "origin",
    "name",
]
car = pd.read_csv(
    "http://logopt.com/data/auto-mpg.data", delim_whitespace=True, names=L
)

問題(ダイヤモンド)

http://logopt.com/data/Diamond.csv からダイアモンドの価格データを読み込み,カラット"carat"と価格 "price" の散布図を描け.

問題(ポケモン)

ポケモンのデータフレームに対して,攻撃力(Attack),守備力(Defense)の関係を散布図に描画せよ.

pokemon = pd.read_csv("http://logopt.com/data/poke.csv", encoding="utf-8", index_col=0)
pokemon.head()
Name Type 1 Type 2 Total HP Attack Defense Sp. Atk Sp. Def Speed Generation Legendary Japanese
#
1 Bulbasaur Grass Poison 318 45 49 49 65 65 45 1 False フシギダネ
2 Ivysaur Grass Poison 405 60 62 63 80 80 60 1 False フシギソウ
3 Venusaur Grass Poison 525 80 82 83 100 100 80 1 False フシギバナ
3 VenusaurMega Venusaur Grass Poison 625 80 100 123 122 120 80 1 False フシギバナ・メガ進化
4 Charmander Fire NaN 309 39 52 43 60 50 65 1 False ヒトカゲ

他にも色々なグラフが描画できる.

詳細については、本家サイト https://plot.ly/python/ を参照