フューチャー技術ブログ

Plotly.pyによるデータ可視化のすすめ

Plotly.pyによるデータ可視化のすすめ

7月にキャリア採用していただいて、早3ヶ月が経とうとしています 。Futureの人はみんな自分の知見を積極的に発信していて、自分も乗るしかないこの波にという気持ちで一本書きました。

現在業務でいわゆるビッグデータを扱っていまして、アウトプットを可視化する機会が多くあります。Pythonでデータ可視化といえばmatplotlibが定番で、メンバー単位でのアウトプット共有なら特に不便は無いのですが、顧客への説明資料などに使い回すことを考えると、もう少し見栄え良く仕上げたくなる時があります。しかし、matplotlibはデフォルト設定だと素っ気無いグラフになるので、そこから見栄えを良くしようとするとかなり手間がかかります。

plotlyはデフォルトで作成できるグラフが既に美しいので、誰でも手間なく見栄えのいいグラフを作成できます(もちろん見栄えがいいだけでなく、見やすいです)。
しかも特別な設定をしなくても、インタラクティブな操作が可能となっていますので、作成したアウトプットを用いたディスカッションも捗ることでしょう。

Plotlyとは

plotly はデータ可視化のためのOSSで、MITライセンスなので自由に無料で利用することが可能です。アカウント登録なども不要です。手間をかけずに美しいグラフが作成できることと、インタラクティブな操作性を特徴としています。

概要

今回はPlotlyのインストールから簡単なグラフ作成方法までを紹介します。

ウェブサイト
https://plotly.com/python/

インストール

pipでインストールします

pip install plotly==5.10.0

Jupyter Labもサポートしているので、もし使用する場合はjupyterlabおよびipywidgets パッケージをインストールします。

pip install "jupyterlab>=3" "ipywidgets>=7.6"

動作確認

以下のコードを試してみます。

pythonで以下のコードを実行すると、ブラウザが起動してグラフが表示されます。

import plotly.express as px
fig = px.bar(x=["a", "b", "c"], y=[1, 3, 2])
fig.show()
plotly01.gif

グラフ操作

グラフ上にカーソルを置くとx, yの値が表示されたり、X方向にドラッグ&ドロップして範囲を指定するとその範囲のみが拡大表示されます。例えば1年間の推移を示す時系列のグラフを作成しつつ、 1ヶ月分だけを拡大して表示させるといったことができます。便利ですね。

グラフ保存

作成したグラフはhtmlで保存することで、インタラクティブな操作が可能なグラフをそのまま保存できます。また、右上のカメラアイコンでPNG画像として保存できます。この場合は静止画として保存されます。

もちろんグラフの保存はコード上で実行することも可能です(後述)。

グラフ作成手順

グラフ作成に使用するモジュール

plotlyは大きく分けて2種類のサブモジュールがあり、公式サイトでは以下のように説明されています。

  • Plotly Express: high-level interface for data visualization
  • Graph Objects: low-level interface to figures, traces and layout

plotly Expressの方がパラメーターがシンプルで少ないコードでグラフ作成が可能ですが、Graph Objectsの方が細やかなグラフ作成が可能です。Graph Objectsの方がmatplotlibの使い方に近いと思います。今回はGraph Objectsを使用します。

※最初はPlotly Expressで作成したけど、後になってやりたいことができなくてGraph Objectsで作り直すパターンが何度かあるので。。。

サブモジュールごとの比較

それぞれのサブモジュールをヒストグラムを作成します。見た目は全く同じになりますが、Plotly Expressの方がコードがややシンプルです。Graph Objectsは最初にgo.Figureでキャンバスを作成しておいて、そこにグラフを重ねていくというイメージです(matplotlibplt.Figureと同じような感じですね)

ちなみにPlotlyで作成したヒストグラムは拡大表示すると自動でbinが細分化されたりして面白いので、ぜひ試してみてください。

# Plotly Expressでヒストグラム作成
import plotly.express as px
df = px.data.tips()
fig = px.histogram(df, x="total_bill")
fig.show()
# Graph Objectsでヒストグラム作成
import plotly.graph_objects as go
df = px.data.tips()
fig = go.Figure(data=[go.Histogram(x=df['total_bill'])])
fig.show()

グラフを作成してみる

Graph Objectsを使ってグラフを作成します。大まかな流れは以下の通りです。

  • インスタンス作成:go.Figure()
  • グラフ追加:fig.add_trace()
  • グラフ周りの設定:fig.update_layout()
  • グラフ表示:fig.show()
  • グラフの保存:fig.write_html(), fig.write_image()
    ※グラフによってはもっと簡単に記述できますが、これが最も汎用的な手順だと思います。
import plotly.graph_objects as go

# データ準備(2グループ作成)
df = px.data.tips() # 今回はPlotlyのサンプルデータを利用
df1 = df[df['time']=='Lunch']
df2 = df[df['time']=='Dinner']

# インスタンス作成
fig = go.Figure()

# 料金とチップの散布図(Lunch)
fig.add_trace(
go.Scatter(
x=df1['total_bill'], y=df1['tip'],
name='Lunch', mode='markers', opacity=0.7,
)
)

# 料金とチップの散布図(Dinner)
fig.add_trace(
go.Scatter(
x=df2['total_bill'], y=df2['tip'],
name='Dinner', mode='markers', opacity=0.7,
)
)

# タイトル、軸ラベル、凡例
fig.update_layout(
title='料金とチップの関係 <br> 時間別:Lunch, Dinner', # htmlなので<br>で改行
xaxis=dict(title='料金($)'),
yaxis=dict(title='チップ($)'),
legend=dict(
yanchor="top", y=0.99, # 判例をいい感じの位置に置く
xanchor="left", x=0.01,
bgcolor='rgba(255,255,255,0.5)' # プロットが隠れないように半透明にする
)
)

fig.show()

それでは上記のコードを順番に説明します

インスタンス作成

plotly.graph_objectsimportして、Figureのインスタンスを作成します

import plotly.graph_objects as go

# データ準備(2グループ作成)
df = px.data.tips() # 今回はPlotlyのサンプルデータを利用
df1 = df[df['time']=='Lunch']
df2 = df[df['time']=='Dinner']

# インスタンス作成
fig = go.Figure()

グラフ追加

今回はtimeでグループ分けした散布図を描いてみます(LunchとDinner)

# 料金とチップの散布図(Lunch)
fig.add_trace(
go.Scatter(
x=df1['total_bill'], y=df1['tip'],
name='Lunch', mode='markers', opacity=0.7,
)
)

# 料金とチップの散布図(Dinner)
fig.add_trace(
go.Scatter(
x=df2['total_bill'], y=df2['tip'],
name='Dinner', mode='markers', opacity=0.7,
)
)

これでfig.show()するとこのようなグラフが作成できます。

newplot

グラフ周りの設定

続いてグラフタイトル、軸ラベル、凡例を追加します

# タイトル、軸ラベル、凡例
fig.update_layout(
title='料金とチップの関係 <br> 時間別:Lunch, Dinner', # htmlなので<br>で改行
xaxis=dict(title='料金($)'),
yaxis=dict(title='チップ($)'),
legend=dict(
yanchor="top", y=0.99, # 判例をいい感じの位置に置く
xanchor="left", x=0.01,
bgcolor='rgba(255,255,255,0.5)' # プロットが隠れないように半透明にする
)
)

完成したグラフ

グラフ表示

既に登場していますが、fig.show()で作成したグラフを表示します。Pythonファイルで実行するとブラウザが起動します。Jupyterファイルで実行すると出力セルに表示されます。

fig.show()

グラフ保存

ブラウザ上で保存できますが、もちろんコード上で保存することもできます。インタラクティブな操作をそのままにしたい場合はhtmlで保存します。パワポに使いたい等、静止画が欲しい場合は画像で保存します。

htmlで保存

 参考URL: https://plotly.github.io/plotly.py-docs/generated/plotly.io.write_html.html

write_html('output.html')
画像で保存

 参考URL: https://plotly.github.io/plotly.py-docs/generated/plotly.io.write_image.html

write_image('output.png') # 拡張子で自動的にフォーマットが変わります

画像で保存する場合の前準備
静的画像を生成する場合はKaleidoをインストールする必要があります。

参考URL: https://plotly.com/python/static-image-export/

pip install -U kaleido

グラフの紹介

Plotlyで作成したグラフを紹介します。画像をクリックするとhtmlが開くので、インタラクティブな操作を体験していただければと思います。この他にも色々なグラフが用意されているので、ぜひ公式サイトのグラフライブラリーを見てください。

グラフライブラリー(公式サイトTop)

色々な種類のグラフがソースコード付きで公開されているので、何かグラフ化したいデータがある時は、まずここを参考にするのがいいと思います。アウトプットのイメージを固めつつ、足りないところはリファレンスで補いましょう。見た目が綺麗で見やすいので、勉強になります。

APIリファレンス

様々な項目が設定可能で、一通り眺めるのも一苦労なのでグラフライブラリーで分からない設定をしたいときに参考にするのがいいと思います。凝り出すとコードが長くなりがちです😅

散布図+折れ線グラフ

go.Scatter()(線グラフもScatterで作成します)

時系列の折れ線グラフ

go.Scatter()

ヒストグラム

go.Histogram()

2次元ヒストグラム with 散布図

go.Histogram2d() & go.Scatter()

マップ

go.Scattermapbox

mapboxの地図を利用しています。

ウェブサイト
https://www.mapbox.jp/

使ってみての所感

何もせずともインタラクティブな操作ができることに感動しました。たとえば日次データで1年間の時系列に沿った推移を表すグラフを作成すると、どうしても週単位のデータがつぶれますが、Plotlyなら期間選択して拡大表示できます。客先でもも捗りますし、簡易的なダッシュボードとして使えるのではと思います。

マニュアルは用意されているのですが、項目が膨大過ぎて、目当ての項目を探すのに苦労しました。
幸い公式サイトでサンプルがコード付きで多数公開されているので、そこからイメージに合うグラフを探してコードを参考にするのがいいと思いました。

最後に

以上、Plotly.pyの紹介でした。

Plotlyは美しい見た目とインタラクティブな操作感を手軽に実現できる非常に有用なツールです。パワポ用だけではなく、インタラクティブな操作を生かした簡易的なダッシュボードのような利用方法も可能かと思います。今回紹介した以外にも様々な表現を美しくお手軽に実現できますので、ぜひ利用してみてください!