こんな人にオススメ
plotly
の時系列のグラフで特定の特定の期間をうまく表現できないかね。
全体の中でこの期間はこんな感じっていうグラフが作りたい。
ということで、今回はplotly
のrangeslider
とrangeselector
を使用して横軸の範囲を明示する方法を解説する。現状は横軸にしか対応していないが、期間を見たい時には重宝する。
横軸の移動や拡大などは特に設定しなくても可能だが、rangeslider
を使用することで全体の中で拡大した部分はどんな感じなのかが分かりやすい。
また、1年や10年など特定の期間を自動で拡大してくれるrangeselector
も便利。こちらを使用すると丁度10年とかを選択できる。
基本はPlotly公式の「Range Slider and Selector in Python」をベースに、噛み砕きながら解説する。
python環境は以下。
- Python 3.10.1
- pandas 1.3.5
- plotly 5.4.0
- plotly-orca 3.4.2
作成したコード全文
下準備(import
)
import pandas as pd import plotly.graph_objects as go import plotly.express as px import plotly.io as pio
まずは下準備としてのimport
関連。グラフ化するデータをpandas
のデータフレームで扱い、それを[go](<https://megatenpa.com/category/python/plotly/go/>)
でグラフ化、pio
で保存する。pio
でのグラフ保存については以下。
-
-
【plotly&orca】plotlyで静止画保存(orca)
続きを見る
[px](<https://megatenpa.com/category/python/plotly/px/>)
は最後にpx
でもレンジスライダー・レンジセレクターを追加できることを示すために使用。
レンジスライダー・セレクターなしのグラフ
まずはレンジスライダーもレンジセレクターもないグラフを作成。データが線のグラフとなっているだけ。
今回はAppleの株価っぽいデータを使用する。データフレームの中身は以下。
import pandas as pd # データの読み込み file = '<https://raw.githubusercontent.com/plotly/datasets/master/finance-charts-apple.csv>' df = pd.read_csv(file) print(df) # Date AAPL.Open AAPL.High ... mavg up direction # 0 2015-02-17 127.489998 128.880005 ... 117.927667 129.114281 Increasing # 1 2015-02-18 127.629997 128.779999 ... 118.940333 130.038244 Increasing # 2 2015-02-19 128.479996 129.029999 ... 119.889167 130.884089 Decreasing # 3 2015-02-20 128.619995 129.500000 ... 120.763500 131.741551 Increasing # 4 2015-02-23 130.020004 133.000000 ... 121.720167 133.067817 Increasing # .. ... ... ... ... ... ... ... # 501 2017-02-10 132.460007 132.940002 ... 124.498666 134.503328 Decreasing # 502 2017-02-13 133.080002 133.820007 ... 125.205166 135.589534 Increasing # 503 2017-02-14 133.470001 135.089996 ... 125.953499 136.731280 Increasing # 504 2017-02-15 135.520004 136.270004 ... 126.723499 137.901963 Decreasing # 505 2017-02-16 135.669998 135.899994 ... 127.504333 138.805366 Decreasing # [506 rows x 11 columns] # 列の一覧 print(df.columns.values) # ['Date' 'AAPL.Open' 'AAPL.High' 'AAPL.Low' 'AAPL.Close' 'AAPL.Volume' # 'AAPL.Adjusted' 'dn' 'mavg' 'up' 'direction']
列の一覧の中に「AAPL
」という文字が入っているのでこれを削除する。削除にはstr.replace(「対象の文字」, 「変更後の文字」)
の置き換えを使う。
# データ列のAAPLという文字を削除 df.columns = [col.replace('AAPL.', '') for col in df.columns] print(df) # Date Open High ... mavg up direction # 0 2015-02-17 127.489998 128.880005 ... 117.927667 129.114281 Increasing # 1 2015-02-18 127.629997 128.779999 ... 118.940333 130.038244 Increasing # 2 2015-02-19 128.479996 129.029999 ... 119.889167 130.884089 Decreasing # 3 2015-02-20 128.619995 129.500000 ... 120.763500 131.741551 Increasing # 4 2015-02-23 130.020004 133.000000 ... 121.720167 133.067817 Increasing # .. ... ... ... ... ... ... ... # 501 2017-02-10 132.460007 132.940002 ... 124.498666 134.503328 Decreasing # 502 2017-02-13 133.080002 133.820007 ... 125.205166 135.589534 Increasing # 503 2017-02-14 133.470001 135.089996 ... 125.953499 136.731280 Increasing # 504 2017-02-15 135.520004 136.270004 ... 126.723499 137.901963 Decreasing # 505 2017-02-16 135.669998 135.899994 ... 127.504333 138.805366 Decreasing # [506 rows x 11 columns]
あとはこれをグラフ化するだけ。ここではgo
の散布図作成であるgo.Scatter
を使用。go.Scatter
の描き方とfig.update_layout
などのグラフ更新の方法については以下の記事参照。
-
-
【plotly&go.Scatter】plotlyの散布図グラフの描き方
続きを見る
-
-
【plotly&fig作成と更新】add_traceやupdate_layoutの使い方
続きを見る
import plotly.graph_objects as go import plotly.io as pio # figureの作成 fig = go.Figure() # プロットを追加 fig.add_trace(go.Scatter(x=list(df.Date), y=list(df.High))) # グラフタイトルの追加 fig.update_layout(title_text='Time series') # グラフ全体とホバーのフォントサイズ変更 fig.update_layout(font_size=20, hoverlabel_font_size=20) fig.show() # グラフ保存 prefix = 'rangeselector_slider' # 保存ファイル名の接頭辞 save_name = f"{prefix}_simple" pio.orca.config.executable = '/Applications/orca.app/Contents/MacOS/orca' pio.write_html(fig, f"{save_name}.html") pio.write_image(fig, f"{save_name}.png")
ここでのコード全文を以下に書いておく。一括で見たい方は見ていただきたい。
レンジスライダーを追加
続いてはレンジスライダーを追加。レンジスライダーは上のグラフでわかるように、横軸に範囲を指定できるバーのことを言う。左右の橋の縦の棒を動かすことで、簡単に表示を制限することが可能。
一応、横軸にマウスを持っていってスライドすることで、表示範囲は変更できる。んだけど、レンジスライダーを使うことで全体の中でどこを拡大しているのかがわかりやすい。スライダーの記事は以下。
-
-
【plotly&スライダー】plotlyのslidersにスライダーを追加
続きを見る
追加は簡単でfig.update_layout
でxaxis_rangeslider
もしくはxaxis=dict(rangeslider=
というように書き、visible=True
とするだけ。お手軽。
# レンジスライダーを追加 # データの用意と修正 file = '<https://raw.githubusercontent.com/plotly/datasets/master/finance-charts-apple.csv>' df = pd.read_csv(file) df.columns = [col.replace('AAPL.', '') for col in df.columns] # figureの作成 fig = go.Figure() # プロットを追加 fig.add_trace( go.Scatter(x=list(df.Date), y=list(df.High)) ) # グラフタイトルとレンジスライダーの追加 fig.update_layout( # グラフタイトル title_text='Time series with range slider', # レンジスライダー xaxis_rangeslider=dict( visible=True, ), # グラフ全体とホバーのフォントサイズ変更 fig.update_layout(font_size=20, hoverlabel_font_size=20) fig.show() # グラフ保存 prefix = 'rangeselector_slider' # 保存ファイル名の接頭辞 save_name = f"{prefix}_rangeslider" pio.orca.config.executable = '/Applications/orca.app/Contents/MacOS/orca' pio.write_html(fig, f"{save_name}.html") pio.write_image(fig, f"{save_name}.png")
レンジスライダーで縦軸の拡大も可能に
レンジスライダー便利なんだけど、 visible=True
だけだとconfig
のzoom機能では横軸の範囲変更しかできない。不便。
config
のズーム機能はグラフ右上の虫眼鏡のマークで、プロット領域をドラッグすることで拡大できるというもの。config
については以下参照。
-
-
【plotly&config】グラフのツールバーを編集する
続きを見る
ただ、これはy
軸の設定を変更することで解決する。yaxis
でfixedrange=False
とすることで縦軸の範囲固定を解除することが可能。
ドラッグでグラフの拡大ができるし、拡大した範囲でレンジスライダーも自動で拡大領域の色分けをしてくれる。ありがたい。
# レンジスライダーで縦軸の拡大も可能にする # データの用意と修正 file = '<https://raw.githubusercontent.com/plotly/datasets/master/finance-charts-apple.csv>' df = pd.read_csv(file) df.columns = [col.replace('AAPL.', '') for col in df.columns] # figureの作成 fig = go.Figure() # プロットを追加 fig.add_trace( go.Scatter(x=list(df.Date), y=list(df.High)) ) # グラフタイトルとレンジスライダーの追加 fig.update_layout( # グラフタイトル title_text='Time series with range slider', # レンジスライダー xaxis_rangeslider=dict(visible=True,), yaxis=dict( # y軸のズームを可能にする fixedrange=False ), ) # グラフ全体とホバーのフォントサイズ変更 fig.update_layout(font_size=20, hoverlabel_font_size=20) fig.show() # グラフ保存 prefix = 'rangeselector_slider' # 保存ファイル名の接頭辞 save_name = f"{prefix}_rangeslider_fixedrange" pio.orca.config.executable = '/Applications/orca.app/Contents/MacOS/orca' pio.write_html(fig, f"{save_name}.html") pio.write_image(fig, f"{save_name}.png")# レンジスライダーを追加 # データの用意と修正 file = '<https://raw.githubusercontent.com/plotly/datasets/master/finance-charts-apple.csv>' df = pd.read_csv(file) df.columns = [col.replace('AAPL.', '') for col in df.columns] # figureの作成 fig = go.Figure() # プロットを追加 fig.add_trace( go.Scatter(x=list(df.Date), y=list(df.High)) ) # グラフタイトルとレンジスライダーの追加 fig.update_layout( # グラフタイトル title_text='Time series with range slider', # レンジスライダー xaxis_rangeslider=dict( visible=True, ),
レンジスライダーの見た目を変更
レンジスライダーは通常のグラフ同様、色やサイズの変更が可能。上のグラフでは4つの変更を行った。他の引数含め詳しくは公式の「Python Figure Reference: layout.xaxis」を参照。
bgcolor='black'
: 背景を黒に(デフォルトは"#fff”
)bordercolor='violet'
: 枠線をヴァイオレットに(デフォルトは"#444”
)borderwidth=6
: 枠線の太さを6に(デフォルトは0=枠線なし)thickness=0.3
: スライダーの厚さを0.3に(デフォルトは0.15)
変更はvisible
と同じxaxis_rangeslider
で指定するだけ。簡単。
# レンジスライダーの見た目を編集 # データの用意と修正 file = '<https://raw.githubusercontent.com/plotly/datasets/master/finance-charts-apple.csv>' df = pd.read_csv(file) df.columns = [col.replace('AAPL.', '') for col in df.columns] # figureの作成 fig = go.Figure() # プロットを追加 fig.add_trace( go.Scatter(x=list(df.Date), y=list(df.High)) ) # グラフタイトルとレンジスライダーの追加 fig.update_layout( # グラフタイトル title_text='Time series with range slider', # レンジスライダー xaxis_rangeslider=dict( visible=True, bgcolor='black', # 背景色 bordercolor='violet', # 枠線の色 borderwidth=6, # 枠線の太さ thickness=0.3, # レンジスライダーの厚さ ), ) # グラフ全体とホバーのフォントサイズ変更 fig.update_layout(font_size=20, hoverlabel_font_size=20) fig.show() # グラフ保存 prefix = 'rangeselector_slider' # 保存ファイル名の接頭辞 save_name = f"{prefix}_rangeslider_arrange" pio.orca.config.executable = '/Applications/orca.app/Contents/MacOS/orca' pio.write_html(fig, f"{save_name}.html") pio.write_image(fig, f"{save_name}.png")
レンジセレクターを追加
続いてはレンジセレクター。こちらはボタンの一種で、ボタンを押すと該当する期間に自動で絞られると言うもの。ボタンについては以下の記事参照。
-
-
【plotly&ボタン】plotlyのupdatemenusにbuttonsを追加
続きを見る
レンジスライダーのように自分で期間を変更するのではなく、予め決められた期間を指定するだけなので正確。しかも上のグラフでもわかるように複数期間をボタンとして登録できる。
使用した期間は以下。
- 1ヶ月
- 半年(6ヶ月)
- 年初来(year-to-date)
- 1年
年初来ってにが分かりにくいが、要するに表示範囲の最新の日付の年の最初の日=1月1日までを表示すると言うもの。例えば表示されている最新の日付(右端)が2022年2月14日なら一番古い日付(左端)は2022年1月1日になる。
もちろんYTDじゃなくてMTDにすることも可能。1ヶ月のMTDなら最新の月の初め、すなわち○月1日が左端に来る。2ヶ月なら前の月なので○-1月1日が左端に来る。
なお、rangeselector
で使用できる単位は以下。週単位がないので1週間にしたい時は7days換算にする必要がある。また、全期間表示はall
一択。
'month'
: 月単位'year'
:年単位'day'
: 日単位'hour'
: 時間単位'minute'
: 分単位'second'
: 秒単位'all'
: 全期間
# レンジセレクターを追加 # データの用意と修正 file = '<https://raw.githubusercontent.com/plotly/datasets/master/finance-charts-apple.csv>' df = pd.read_csv(file) df.columns = [col.replace('AAPL.', '') for col in df.columns] # figureの作成 fig = go.Figure() # プロットを追加 fig.add_trace( go.Scatter(x=list(df.Date), y=list(df.High)) ) # グラフタイトルとレンジスライダーの追加 fig.update_layout( # グラフタイトル title_text='Time series with range selector', # レンジセレクターの追加 xaxis=dict( rangeselector=dict( buttons=list([ dict(count=1, label='1m', # ボタンラベル step='month', # 1ヶ月 stepmode='backward'), dict(count=6, label='6m', step='month', # 半年 stepmode='backward'), dict(count=1, label='YTD', # 表示範囲の最新の日付まで、その年の年初から step='year', stepmode='todate'), dict(count=1, label='1y', step='year', # 1年 stepmode='backward'), dict(step='all') # 全期間表示 ]) )) ) # グラフ全体とホバーのフォントサイズ変更 fig.update_layout(font_size=20, hoverlabel_font_size=20) fig.show() # グラフ保存 prefix = 'rangeselector_slider' # 保存ファイル名の接頭辞 save_name = f"{prefix}_rangeselector" pio.orca.config.executable = '/Applications/orca.app/Contents/MacOS/orca' pio.write_html(fig, f"{save_name}.html") pio.write_image(fig, f"{save_name}.png")
なお、レンジセレクターのレイアウトの編集はレンジスライダーやボタンと似ているので割愛する。詳しい引数などは公式の「Python Figure Reference: layout.xaxis」参照。
go.Layout
にレンジスライダー(セレクター)を設定
ここまではfig.update_layout
でレンジスライダーもしくはレンジセレクターを設定したが、もちろんgo.Layout
で設定することも可能。個人的にはupdate
するよりもgo.Layout
で書く方好き。
- プロットとレイアウトを一元管理できる
- いちいちアップデートしなくても一気に書ける
- 最後に
fig
に入れるので頭の中でまとめやすい
要するにプロット・レイアウト・フィギュアを切り分けて考えられる点で好みってこと。
基本的なコードの書き方はfig.update
シリーズと同じ。もちろん出来るグラフもfig.update_layout
などを使用した時と同じ。
# go.Layoutにレンジスライダー(セレクター)を設置 # データの用意と修正 file = '<https://raw.githubusercontent.com/plotly/datasets/master/finance-charts-apple.csv>' df = pd.read_csv(file) df.columns = [col.replace('AAPL.', '') for col in df.columns] # プロットの作成 plot = [go.Scatter(x=list(df.Date), y=list(df.High))] # レイアウトの作成 layout = go.Layout( title_text='Time series with range slider', # レンジスライダー xaxis=dict( rangeslider=dict( visible=True, ), ) ) # figureの作成 # ここでプロットとレイアウトを入れる fig = go.Figure(data=plot, layout=layout) # グラフ全体とホバーのフォントサイズ変更 fig.update_layout(font_size=20, hoverlabel_font_size=20) fig.show() # グラフ保存 prefix = 'rangeselector_slider' # 保存ファイル名の接頭辞 save_name = f"{prefix}_rangeslider_ini" pio.orca.config.executable = '/Applications/orca.app/Contents/MacOS/orca' pio.write_html(fig, f"{save_name}.html") pio.write_image(fig, f"{save_name}.png")
レンジスライダーとセレクターを同時に使う
レンジスライダーとレンジセレクターを同時に使用することももちろん可能。このグラフは公式の「Range Slider and Selector in Python」の「Basic Range Slider and Range Selectors」のグラフ。
レンジセレクターで期間を指定するとレンジスライダーに反映さることがわかる。
# レンジスライダーとレンジセレクターを追加 # データの用意と修正 file = '<https://raw.githubusercontent.com/plotly/datasets/master/finance-charts-apple.csv>' df = pd.read_csv(file) df.columns = [col.replace('AAPL.', '') for col in df.columns] # figureの作成 fig = go.Figure() # プロットを追加 fig.add_trace( go.Scatter(x=list(df.Date), y=list(df.High)) ) # グラフタイトルとレンジスライダーの追加 fig.update_layout( # グラフタイトル title_text='Time series with range slider and selectors', # レンジスライダー xaxis_rangeslider=dict(visible=True,), yaxis=dict( # y軸のズームを可能にする fixedrange=False ), # レンジセレクターの追加 xaxis=dict( rangeselector=dict( buttons=list([ dict(count=1, label='1m', # ボタンラベル step='month', # 1ヶ月 stepmode='backward'), dict(count=6, label='6m', step='month', # 半年 stepmode='backward'), dict(count=1, label='YTD', # 表示範囲の最新の日付まで、その年の年初から step='year', stepmode='todate'), dict(count=1, label='1y', step='year', # 1年 stepmode='backward'), dict(step='all') # 全期間表示 ]) )) ) # グラフ全体とホバーのフォントサイズ変更 fig.update_layout(font_size=20, hoverlabel_font_size=20) fig.show() # グラフ保存 prefix = 'rangeselector_slider' # 保存ファイル名の接頭辞 save_name = f"{prefix}_rangeslider_rangeselector" pio.orca.config.executable = '/Applications/orca.app/Contents/MacOS/orca' pio.write_html(fig, f"{save_name}.html") pio.write_image(fig, f"{save_name}.png")
積み重なったグラフでレンジスライダー
続いては公式の「Range Slider with Vertically Stacked Subplots」のグラフ。コードの量が半端ないが、分解してみると同じことの繰り返し。落ち着いて。
分解して解説していく。なお、全文は以下。クソ長いから注意。
figure
の作成
# figureの作成 fig = go.Figure()
まずはfigure
の作成。これは簡単。
add_trace
でプロットの追加
# プロットの追加 fig.add_trace(go.Scatter( # xの値 x=['2013-01-15', '2013-01-29', '2013-02-26', '2013-04-19', '2013-07-02', '2013-08-27', '2013-10-22', '2014-01-20', '2014-05-05', '2014-07-01', '2015-02-09', '2015-04-13', '2015-05-13', '2015-06-08', '2015-08-05', '2016-02-25'], # yの値 y=['8', '3', '2', '10', '5', '5', '6', '8', '3', '3', '7', '5', '10', '10', '9', '14'], name='var0', # プロットの名称 # ホバーに表示する内容 text=['8', '3', '2', '10', '5', '5', '6', '8', '3', '3', '7', '5', '10', '10', '9', '14'], # どのy軸にプロットするか yaxis='y', ))
次は各データのプロット。いきなりややこしくなっているが、分解してみると以下の構造。シンプル。なお、上のコードはvar0
を示している。
fig.add_trace
でfigure
にプロットを追加go.Scattrer
で散布図を指定x
は横軸、y
は縦軸name
はプロット名text
はホバーに表示する内容yaxis
で縦軸をどの軸にするか(2軸グラフ的な)- 上記を
var0
からvar4
まで繰り返す
同じ構造が続くので、x
やy
をdict
でまとめてfor
文で回しコードを短くすることも可能。
var0
からvar4
は以下。
# プロットの追加 fig.add_trace(go.Scatter( # xの値 x=['2013-01-15', '2013-01-29', '2013-02-26', '2013-04-19', '2013-07-02', '2013-08-27', '2013-10-22', '2014-01-20', '2014-05-05', '2014-07-01', '2015-02-09', '2015-04-13', '2015-05-13', '2015-06-08', '2015-08-05', '2016-02-25'], # yの値 y=['8', '3', '2', '10', '5', '5', '6', '8', '3', '3', '7', '5', '10', '10', '9', '14'], name='var0', # プロットの名称 # ホバーに表示する内容 text=['8', '3', '2', '10', '5', '5', '6', '8', '3', '3', '7', '5', '10', '10', '9', '14'], # どのy軸にプロットするか yaxis='y', )) fig.add_trace(go.Scatter( x=['2015-04-13', '2015-05-13', '2015-06-08', '2015-08-05', '2016-02-25'], y=['53.0', '69.0', '89.0', '41.0', '41.0'], name='var1', text=['53.0', '69.0', '89.0', '41.0', '41.0'], yaxis='y2', )) fig.add_trace(go.Scatter( x=['2013-01-29', '2013-02-26', '2013-04-19', '2013-07-02', '2013-08-27', '2013-10-22', '2014-01-20', '2014-04-09', '2014-05-05', '2014-07-01', '2014-09-30', '2015-02-09', '2015-04-13', '2015-06-08', '2016-02-25'], y=['9.6', '4.6', '2.7', '8.3', '18', '7.3', '3', '7.5', '1.0', '0.5', '2.8', '9.2', '13', '5.8', '6.9'], name='var2', text=['9.6', '4.6', '2.7', '8.3', '18', '7.3', '3', '7.5', '1.0', '0.5', '2.8', '9.2', '13', '5.8', '6.9'], yaxis='y3', )) fig.add_trace(go.Scatter( x=['2013-01-29', '2013-02-26', '2013-04-19', '2013-07-02', '2013-08-27', '2013-10-22', '2014-01-20', '2014-04-09', '2014-05-05', '2014-07-01', '2014-09-30', '2015-02-09', '2015-04-13', '2015-06-08', '2016-02-25'], y=['6.9', '7.5', '7.3', '7.3', '6.9', '7.1', '8', '7.8', '7.4', '7.9', '7.9', '7.6', '7.2', '7.2', '8.0'], name='var3', text=['6.9', '7.5', '7.3', '7.3', '6.9', '7.1', '8', '7.8', '7.4', '7.9', '7.9', '7.6', '7.2', '7.2', '8.0'], yaxis='y4', )) fig.add_trace(go.Scatter( x=['2013-02-26', '2013-07-02', '2013-09-26', '2013-10-22', '2013-12-04', '2014-01-02', '2014-01-20', '2014-05-05', '2014-07-01', '2015-02-09', '2015-05-05'], y=['290', '1078', '263', '407', '660', '740', '33', '374', '95', '734', '3000'], name='var4', text=['290', '1078', '263', '407', '660', '740', '33', '374', '95', '734', '3000'], yaxis='y5', ))
update_traces
で全プロット共通の修正
# 全プロットで共通の修正部分 fig.update_traces( hoverinfo='name+x+text', # ホバーに表示する項目 line={'width': 0.5}, # 線の太さ marker={'size': 8}, # マーカーのサイズ mode='lines+markers', # プロットの種類 showlegend=False # 凡例を表示しない )
続いてはfig.update_traces
で作成したgo.Scatterのプロットの内容を修正する。以下の項目を修正している。
hoverinfo='name+x+text'
: マウスオーバー時の内容をプロット名+横軸の値+引数text
line={'width': 0.5}
: プロット線の太さを0.5にmarker={'size': 8}
: マーカーのサイズを8にmode='lines+markers'
: プロットを線+マーカーにshowlegend=False
: 凡例は非表示
var0
からvar4
まで毎回、上の設定を書いてもいいんだけど共通事項ならfig.add_trace
でプロットを作成してからfig.update_traces
で修正した方が楽。
fig.add_trace
やfig.update_traces
については以下の記事で解説している。
-
-
【plotly&fig作成と更新】add_traceやupdate_layoutの使い方
続きを見る
グラフ中にstate1, state2の文字を追加
# グラフ中に文字(テキスト)を追加 fig.update_layout( annotations=[ dict( x='2013-06-01', # xの位置 y=0, # yの位置 arrowcolor='rgba(63, 81, 181, 0.2)', # テキストの上の線(矢印)の色 arrowsize=0.3, # テキストの上の線(矢印)の色 ax=0, # 線(矢印)のx方向の長さ ay=30, # 線(矢印)のy方向の長さ text='state1', # 表示するテキスト xref='x', # xの基準はx軸 yanchor='bottom', # yの基準位置 yref='y' # yの基準はy軸 ), dict( x='2014-09-13', y=0, arrowcolor='rgba(76, 175, 80, 0.1)', arrowsize=0.3, ax=0, ay=30, text='state2', xref='x', yanchor='bottom', yref='y' ) ], )
続いてはグラフ中にstate1
, state2
の文字を追加。レイアウトの中の引数annotation
を使用することで実現可能。
annotation
は矢印を作成するのに使うが、テキストも追加できるので矢印を消してしまえばグラフ中にテキストを追加することが可能。以下の項目を指定。
x
:x
の位置y
:y
の位置arrowcolor
: テキストの上の線(矢印)の色arrowsize
: テキストの上の線(矢印)の色ax
: 線(矢印)のx方向の長さay
: 線(矢印)のy方向の長さtext
: 表示するテキストxref
:x
の基準はx軸yanchor
:y
の基準位置yref
:y
の基準はy軸
詳しい解説や引数はPlotly公式の「Text and Annotations in Python」や「Python Figure Reference: layout.annotations」参照。
グラフに塗りつぶしを追加
# グラフ上に四角形の両機を追加 fig.update_layout( shapes=[ dict( fillcolor='rgba(63, 81, 181, 0.2)', # 塗りつぶしの色 line={'width': 0}, # 枠線の色 type='rect', # 図形のタイプ x0='2013-01-15', # xのスタート位置 x1='2013-10-17', # xのエンド位置 xref='x', # xの基準はx軸 y0=0, # yのスタート位置 y1=0.95, # yのエンド位置 yref='paper' # yの基準はプロット面上 ), dict( fillcolor='rgba(76, 175, 80, 0.1)', line={'width': 0}, type='rect', x0='2013-10-22', x1='2015-08-05', xref='x', y0=0, y1=0.95, yref='paper' ) ] )
続いてはさっきのstate1
, 2
の領域に塗りつぶしを追加。塗りつぶしについては色んな方法があるが、ここではレイアウトを使ったshapes
で使用。他にもgo.Scatter
でも可能。詳しくは以下。
-
-
【plotly&fill】goで領域を塗りつぶし
続きを見る
-
-
【plotly&shapes】レイアウトとしてグラフ内に図形を配置する
続きを見る
引数はこれまで同じようなものが並ぶ。line_width
で枠線の太さを指定し、type
で図形の種類を指定。x0
, y0
でx
, y
のそれぞれの開始位置を指定、x1
, y1
で終了位置を指定している。
xref
, yref
はそれぞれx
, y
の位置をどこに基準にするか。xref=’x’
とすることでx
軸の値=x0
, x1
の値となる。すなわちx0
, x1
の値はx軸の日付と連動する。
一方でpaper
にするとグラフ全体の相対位置となる。y
はyref='paper’
としているが、これはプロット領域の下端を0、上端を1とした相対位置。なのでy1=0.95
は上端から0.05
下の位置って意味。
fig.update_layout
でレイアウトの編集(xaxis
)
# x軸 xaxis=dict( autorange=True, # 自動で範囲調節 # 表示範囲 range=['2012-10-31 18:36:37.3129', '2016-05-10 05:23:22.6871'], # レンジスライダーの追加 rangeslider=dict( autorange=True, # 自動範囲調節 # 表示範囲 range=['2012-10-31 18:36:37.3129', '2016-05-10 05:23:22.6871'] ), type='date' # x軸の軸タイプ ),
fig.update_layout
のxaxis
について。ここでは以下の項目を設定。
autorange
: 表示範囲の自動調節range
: グラフ作成時の表示範囲- rangeslider: レンジスライダー
- autorange: 表示範囲の自動調節
- range: グラフ作成時の表示範囲
- type: 軸の型(タイプ、形式)
レンジスライダーは追加だけしたい時はvisible=True
にする必要があるが、autorange
など他の引数を設定したいときはvisibleの指定は必要ない。
fig.update_layout
でレイアウトの編集(yaxis
)
# y軸 yaxis=dict( anchor='x', # x軸に固定 autorange=True, # 自動範囲調節 domain=[0, 0.2], # プロット位置を相対位置(0-1)のどこに置くか linecolor='#673ab7', # 軸の色 mirror=True, # 反対側にも軸の色を反映 range=[-60.0858369099, 28.4406294707], # 軸の範囲 showline=True, # 軸の線を表示 side='right', # 軸を表示するサイド tickfont={'color': '#673ab7'}, # 軸のフォントカラー tickmode='auto', # 目盛のモード ticks='', # 目盛を降らない titlefont={'color': '#673ab7'}, # 軸ラベルの色 type='linear', # 軸タイプ zeroline=False # 0の線は引かない ),
続いてはy
軸について。こちらも長いのでy2
軸などは省略してy
軸だけ表示した。yaxis
の場合の設定項目は以下。
anchor='x'
: x軸に固定autorange=True
: 自動範囲調節domain=[0, 0.2]
: プロット位置を相対位置(0-1)のどこに置くかlinecolor='#673ab7'
: 軸の色mirror=True
: 反対側にも軸の色を反映range=[-60.0858369099, 28.4406294707]
: 軸の範囲showline=True
: 軸の線を表示side='right'
: 軸を表示するサイドtickfont={'color': '#673ab7'}
: 軸のフォントカラーtickmode='auto'
: 目盛のモードticks=''
: 目盛を振らないtitlefont={'color': '#673ab7'}
: 軸ラベルの色type='linear'
: 軸タイプzeroline=False
: 0の線は引かない
これらの項目を各軸ごとに設定しているだけ。例えばvar1
の場合はgo.Scatter
の引数yaxis=’y2’
だったのでレイアウトでもyaxis2=
で引数を設定すればいい。
update_layout
で各レイアウト全般の設定
# レイアウト全般の設定 fig.update_layout( dragmode='zoom', # ドラッグした時の挙動はズームに hovermode='x', # ホバー時にxの値を表示 legend=dict(traceorder='reversed'), # 凡例の向きは逆転(いらん気がする) height=600, # グラフの高さ template='plotly_white', # グラフのテンプレート # 余白の設定 margin=dict( t=100, b=100 ), )
最後の設定はレイアウト全般の設定。以下の項目を設定している。
dragmode='zoom'
: ドラッグした時の挙動はズームにhovermode='x'
: ホバー時にx
の値を表示legend=dict(traceorder='reversed')
: 凡例の向きは逆転(いらん気がする)height=600
: グラフの高さtemplate='plotly_white'
: グラフのテンプレートmargin=dict(t=100, b=100)
: 余白の設定
dragmode
はデフォルトでzoom
な気がするが一応設定している。hovermode=’x
’でホバー時にその点の情報以外にxの値もx
軸に表示。
legend
のtraceorder
はいらん気がするが設定している。height
でグラフの高さを固定、幅width
はレスポンシブルのまま。
template
でグラフのベースを指定。ここでは背景が白くなるなどシンプルな見た目の’plotly_white’
を指定。テンプレートについては以下の記事参照。
-
-
【plotly&グラフテーマ】plotly既存のthemasをグラフ化
続きを見る
グラフ表示と保存
# グラフ全体とホバーのフォントサイズ変更 fig.update_layout(font_size=20, hoverlabel_font_size=20) fig.show() # グラフ保存 prefix = 'rangeselector_slider' # 保存ファイル名の接頭辞 save_name = f"{prefix}_stacked" pio.orca.config.executable = '/Applications/orca.app/Contents/MacOS/orca' pio.write_html(fig, f"{save_name}.html") pio.write_image(fig, f"{save_name}.png")
最後はグラフの表示と保存。ブログ上に載せるためにフォントサイズの変更はしているがそこはお好み。
長いけど分解したら簡単
と言うことでここまで公式の「Range Slider with Vertically Stacked Subplots」のコードを分解してきた。長いんだけ分解したら結構シンプル。
できるグラフは上の通り。積み重ねでもレンジスライダーを追加可能。レンジセレクターももちろん追加可能。
px
でレンジスライダー・レンジセレクター
最後にpxでレンジスライダーとレンジセレクターを追加する方法を解説する。
と言っても特別なことはせず、fig
を作成した後にfig.update_layout
でxaxis
のrangeslider
, rangeselector
を設定するのみ。
今回はpx.data.stocks
で株価のデータを取得、Google(GOOG)からMicrosoft(MSFT)のデータをグラフ化。pxについては pxのカテゴリーから色んな記事を閲覧可能。
# pxでレンジスライダーとレンジセレクター df = px.data.stocks() print(df) # date GOOG AAPL AMZN FB NFLX MSFT # 0 2018-01-01 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 # 1 2018-01-08 1.018172 1.011943 1.061881 0.959968 1.053526 1.015988 # 2 2018-01-15 1.032008 1.019771 1.053240 0.970243 1.049860 1.020524 # 3 2018-01-22 1.066783 0.980057 1.140676 1.016858 1.307681 1.066561 # 4 2018-01-29 1.008773 0.917143 1.163374 1.018357 1.273537 1.040708 # .. ... ... ... ... ... ... ... # 100 2019-12-02 1.216280 1.546914 1.425061 1.075997 1.463641 1.720717 # 101 2019-12-09 1.222821 1.572286 1.432660 1.038855 1.421496 1.752239 # 102 2019-12-16 1.224418 1.596800 1.453455 1.104094 1.604362 1.784896 # 103 2019-12-23 1.226504 1.656000 1.521226 1.113728 1.567170 1.802472 # 104 2019-12-30 1.213014 1.678000 1.503360 1.098475 1.540883 1.788185 # [105 rows x 7 columns] # pxで折れ線グラフを作成 fig = px.line(df, x='date', y=df.columns[1:6], markers=True) # レンジセレクターとレンジスライダーを追加 fig.update_layout( xaxis=dict( rangeselector=dict( buttons=list([ dict(count=1, label='1ヶ月', step='month', stepmode='backward'), dict(count=6, label='半年', step='month', stepmode='backward'), dict(count=1, label='year-to-date', step='year', stepmode='todate'), dict(count=1, label='1年', step='year', stepmode='backward'), dict(step='all') ]) ), rangeslider=dict( visible=True ), type='date' ) ) # グラフ全体とホバーのフォントサイズ変更 fig.update_layout(font_size=20, hoverlabel_font_size=20) fig.show() # グラフ保存 prefix = 'rangeselector_slider' # 保存ファイル名の接頭辞 save_name = f"{prefix}_px_rangeslider_range_selector" pio.orca.config.executable = '/Applications/orca.app/Contents/MacOS/orca' pio.write_html(fig, f"{save_name}.html") pio.write_image(fig, f"{save_name}.png")
レンジスライダー・セレクターで俯瞰と拡大
ということで、今回はplotlyのrangesliderとrangeselectorの解説だった。どちらも自分で範囲を絞れば手動で実現可能だけど、レンジスライダーがあると全体を俯瞰しながら局所的に確認可能。レンジセレクターがあるといちいち自分で範囲を狭める必要がない。
レンジスライダーやレンジセレクターを使いこなせば、横軸の範囲指定に無駄な労力を割かずに済む。なのでグラフの中身に集中できる。
今回の記事をきっかけによりplotlyのレンジスライダー・レンジセレクター、ひいてはレイアウトへの理解を深めていただけると幸いだ。
関連記事
-
-
【plotly&go.Scatter】plotlyの散布図グラフの描き方
続きを見る
-
-
【plotly&ボタン】plotlyのupdatemenusに2回押し対応のbuttonsを追加
続きを見る
-
-
【plotly&スライダー】plotlyのslidersにスライダーを追加
続きを見る
-
-
【plotly&fill】goで領域を塗りつぶし
続きを見る
-
-
【plotly&3D】goで3Dグラフを作成
続きを見る
-
-
【plotly&ボタン】plotlyのupdatemenusにbuttonsを追加
続きを見る
-
-
【plotly&add_vrect, hrect】グラフに垂直・水平の塗りつぶし
続きを見る
-
-
【plotly&px.scatter】pxでの散布図の描き方
続きを見る
-
-
【plotly&fill】px.areaで積み上げ塗りつぶし
続きを見る
-
-
【plotly&legendまとめ】凡例の引数一覧
続きを見る
-
-
【plotly&heatmap】go.Heatmapで2次元配列をマップ化
続きを見る