LoginSignup
6
9

More than 3 years have passed since last update.

【可視化】Plotlyで綺麗なグラフが描きたい

Last updated at Posted at 2020-10-08

これは

Plotlyは少ないコードで綺麗なグラフがかけますが, matplotlibばかり使っていてあまりよく知らなかったので調べながら入門してみた人の備忘録です

環境

Google colaboratory

インストール

colabであればインストールはありませんが、必要な場合はpipでインストールできます

pip install plotly

データの準備

seabornですぐ使える時系列データがあったのでそれを使ってみます. 以下はデータの準備なので飛ばしてください

import seaborn as sns
import pandas as pd
from calendar import month_name

month_name_mappings = {name[:3]: n for n, name in enumerate(month_name)}

# ただのデータの準備
df = sns.load_dataset('flights')
df["month"] = df.month.apply(lambda x: month_name_mappings[x])
df["year-month"] = pd.to_datetime(df.year.astype(str) + "-" + df.month.astype(str))
ts_data = df[["passengers", "year-month"]].set_index("year-month")["passengers"]
ts_data
year-month
1949-01-01    112
1949-02-01    118
1949-03-01    132
1949-04-01    129
1949-05-01    121
             ... 
1960-08-01    606
1960-09-01    508
1960-10-01    461
1960-11-01    390
1960-12-01    432
Name: passengers, Length: 144, dtype: int64

月ごとの乗客数のシンプルなデータです.

基本操作

グラフを作成してみます

import plotly.graph_objects as go

fig = go.Figure()
fig.show()

image.png

グラフができた. ここに色々追加していくのですね

# 折れ線グラフ
fig = go.Figure()
fig.add_trace(go.Scatter(x=ts_data.index, y=ts_data.values, name="passengers"))
fig.show()

image.png

メモリを対数表示にしてみる

# 折れ線グラフ
fig = go.Figure()
fig.add_trace(go.Scatter(x=ts_data.index, y=ts_data.values, name="passengers"))

# 見た目のカスタマイズはlayoutをいじる
fig.update_layout(yaxis_type="log")
fig.show()

image.png

豪華なグラフを描きたい

もっと豪華にしたくなってきたので, 無理やり色々可視化してみます

  • 月ごとにデータを分割?して, 各データの変化を折れ線グラフにする
  • 年ごとの合計乗客数を棒グラフにしてみる
# 少しデータをこねこねする
ts_data_monthly = df.groupby("month")["passengers"].apply(list)
ts_sum_yearly = df.groupby("year")["passengers"].sum()
# 複数の折れ線グラフにしたい
ts_data_monthly
month
1     [112, 115, 145, 171, 196, 204, 242, 284, 315, ...
2     [118, 126, 150, 180, 196, 188, 233, 277, 301, ...
3     [132, 141, 178, 193, 236, 235, 267, 317, 356, ...
4     [129, 135, 163, 181, 235, 227, 269, 313, 348, ...
5     [121, 125, 172, 183, 229, 234, 270, 318, 355, ...
6     [135, 149, 178, 218, 243, 264, 315, 374, 422, ...
7     [148, 170, 199, 230, 264, 302, 364, 413, 465, ...
8     [148, 170, 199, 242, 272, 293, 347, 405, 467, ...
9     [136, 158, 184, 209, 237, 259, 312, 355, 404, ...
10    [119, 133, 162, 191, 211, 229, 274, 306, 347, ...
11    [104, 114, 146, 172, 180, 203, 237, 271, 305, ...
12    [118, 140, 166, 194, 201, 229, 278, 306, 336, ...
Name: passengers, dtype: object
# 棒グラフにしたい
ts_sum_yearly
year
1949    1520
1950    1676
1951    2042
1952    2364
1953    2700
1954    2867
1955    3408
1956    3939
1957    4421
1958    4572
1959    5140
1960    5714
Name: passengers, dtype: int64
# ラベル(x軸)
ts_labels = ts_sum_yearly.index
ts_labels
Int64Index([1949, 1950, 1951, 1952, 1953, 1954, 1955, 1956, 1957, 1958, 1959,
            1960],
           dtype='int64', name='year')

可視化してみます. layoutを少しいじってみました

fig = go.Figure()

# 月ごとの時系列データは折れ線グラフにする
for month, passengers in ts_data_monthly.iteritems():
    fig.add_trace(go.Scatter(x=ts_labels, y=passengers, name=str(month)+"月", yaxis='y2'))

# 年ごとの合計は棒グラフにする
fig.add_trace(go.Bar(x=ts_labels, y=ts_sum_yearly.values, name="合計", yaxis="y1"))

# 見た目のカスタマイズはlayoutをいじる
# 軸が2つあるのでメモリは無しにする
fig.update_layout(
    title={
        "text": "乗客数時系列データ",
        "x":0.5,
        "y": 0.9
    },
    legend={
        "orientation":"h",
        "x":0.5,
        "xanchor":"center"
    },
    yaxis1={
        "title": "乗客数(合計)",
        "side": "left",
        "showgrid":False
    },
    yaxis2={
        "title": "乗客数(月ごと)",
        "side": "right",
        "overlaying": "y",
        "showgrid":False
    }
)
fig.show()

image.png

凡例をぽちぽちしたりできます. こんな少ないコードでちょっと動かせるグラフが書けるのは感動です...

その他

ドーナッツ(かわいい)

import numpy as np

ts_sum_monthly = df.groupby("month")["passengers"].sum()
# 一番乗客が多い月を切ったピザみたいにする
pull=[0]*12
pull[np.argmax(ts_sum_monthly.values)] = 0.2

fig = go.Figure()
fig.add_trace(go.Pie(
    labels=[str(month) + "月" for month in ts_sum_monthly.index],
    values=ts_sum_monthly.values,
    hole=.3,
    pull=pull
    )
)
fig.update_layout(
    title={
        "text": "乗客数の割合(1949~1960年の合計)",
        "x":0.5,
        "y": 0.9
    }
)
fig.show()

image.png

年ごとに合計乗客数求めて円グラフを作成

from plotly.subplots import make_subplots

specs = [[{'type':'domain'}, {'type':'domain'}, {'type':'domain'}, {'type':'domain'}] for _ in range(3)]
# 3*4のグリッドにグラフを分割する
fig = make_subplots(rows=3, cols=4, specs=specs)

# ラベルの各円グラフのラベルのタイトルの位置
pos_x = [0.09, 0.37, 0.63, 0.91]
pos_y = [0.9, 0.5, 0.1]
annotations = []  

# (row, col)の位置に円グラフを載せる
row = 0
for i, (year, df_yearly) in enumerate(df.groupby(["year"])[["month","passengers"]]):
    pull=[0]*12
    pull[np.argmax(df_yearly.passengers.values)] = 0.2
    col = i%4+1
    if col == 1:
        row += 1
    annotations.append({
        "text": str(year)+"年",
        "x": pos_x[col-1],
        "y": pos_y[row-1],
        "font_size": 10,
        "showarrow":False
    })
    fig.add_trace(go.Pie(
        labels=[str(month) + "月" for month in df_yearly.month.values],
        values=df_yearly.passengers.values,
        name=str(year)+"年",
        hole=.3,
        pull=pull
    ),
    row, col
    )

fig.update_layout(
    title={
        "text": "乗客数の割合(年ごと)",
        "x":0.5,
        "y": 0.9
    },
    annotations=annotations
)
fig.show()

image.png

終わり

グラフが動くと嬉しいのは私だけでしょうか. 次回はplotlyでダッシュボードが作れるdashというWebフレームワークについてまとめたいと思います.

参考にさせていただいたサイト

6
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
9