概要
※【基礎編】からご覧になることをおすすめします。
本稿ではグラフ可視化ライブラリ Altair を用いた時系列データの可視化を紹介させていただきます。。
ハンズオン公開
GitHub Pages、.ipynbファイル、Google colabでハンズオンを公開しています。よろしければご活用ください。
各種インポート
import urllib
import json
import pandas as pd
import altair as alt
可視化用デモデータ読込
2000〜2010年の米国業種別失業者数(千人)count
および失業率rate
をデモデータとして使用します。
data_path = "https://cdn.jsdelivr.net/npm/vega-datasets@1.29.0/data/unemployment-across-industries.json"
with urllib.request.urlopen(data_path) as f:
unemployment_across_industries = f.read().decode("cp932").split("\n")[0]
dict_data = json.loads(unemployment_across_industries)
keys = list(dict_data[0].keys())
df = pd.DataFrame([[row[key]for key in keys] for row in dict_data], columns=keys)
df["date"] = pd.to_datetime(df["date"])
df
series year month count rate date
0 Government 2000 1 430 2.1 2000-01-01 08:00:00+00:00
1 Government 2000 2 409 2.0 2000-02-01 08:00:00+00:00
2 Government 2000 3 311 1.5 2000-03-01 08:00:00+00:00
3 Government 2000 4 269 1.3 2000-04-01 08:00:00+00:00
4 Government 2000 5 370 1.9 2000-05-01 07:00:00+00:00
... ... ... ... ... ... ...
1703 Self-employed 2009 10 610 5.9 2009-10-01 07:00:00+00:00
1704 Self-employed 2009 11 592 5.7 2009-11-01 07:00:00+00:00
1705 Self-employed 2009 12 609 5.9 2009-12-01 08:00:00+00:00
1706 Self-employed 2010 1 730 7.2 2010-01-01 08:00:00+00:00
1707 Self-employed 2010 2 680 6.5 2010-02-01 08:00:00+00:00
date
列のデータ型はdatetime64[ns, UTC]
です。
series object
year int64
month int64
count int64
rate float64
date datetime64[ns, UTC]
dtype: object
テーマの設定
【基礎編】と同様に全グラフ共通のテーマを設定します。
def font_config():
labelFont = "Yu Gothic UI"
labelFontSize = 15
labelAngle = 0
titleFont = "Yu Gothic UI"
titleFontSize = 18
titleAngle = 0
markFont = "Yu Gothic UI"
return {
"config": {
"axis": {
"ticks": True,
"grid": True,
"labelFont": labelFont,
"labelFontSize": labelFontSize,
"labelAngle": 0,
"titleFont": titleFont,
"titleFontSize": titleFontSize,
# "titleAngle": 0, # Axis のtitleAngleは encode がきかなくなる
},
# 色分けした際の項目
"legend": {
"labelFont": labelFont,
"labelFontSize": labelFontSize,
"labelAngle": labelAngle,
"titleFont": titleFont,
"titleFontSize": titleFontSize,
"titleAngle": titleAngle,
},
# グラフ上部の文字
"header": {
"labelFont": labelFont,
"labelFontSize": 20,
"labelAngle": labelAngle,
"titleFont": titleFont,
"titleFontSize": 25,
"titleAngle": titleAngle,
},
"mark": {"font": markFont},
"title": {"font": titleFont, "subtitleFont": titleFont},
# 図の大きさ
"view": {"width": 500, "height": 300},
# 図の背景
"background": "white",
}
}
alt.themes.register(name="font_config", value=font_config)
alt.themes.enable(name="font_config")
折れ線グラフ
時系列データはtype=temporal
で指定可能です。
(
alt.Chart(df)
.mark_line()
.encode(
x=alt.X(field="date",type="temporal"),
y=alt.Y(field="count",type="quantitative"),
color=alt.Color(
field="series",type="nominal",
scale=alt.Scale(scheme="category20b"), # デフォルトより色のバリエーション数が多いです。
legend=alt.Legend(labelFontSize=10)
),
tooltip=[
alt.Tooltip(field="count",type="temporal"),
alt.Tooltip(field="series",type="nominal"),
alt.Tooltip(field="date",type="temporal", format="%Y年%m月%d日 %H時%M分"),
],
)
)
マウスオーバーによるハイライト
Altair ではマウスに最も近いポイントをハイライトさせることができます。.alt_selection()
でマウスの位置に近いレコードの series
を表示させるために base
で detail="series"
としているところがポイントです。detail
がないと特定のレコードのみを抽出してハイライトさせることができません。
series_mouse_selection = alt.selection(
type="single", fields=["series"], on="mouseover", nearest=True, init={"series": "Agriculture"}
)
base = alt.Chart(df).encode(
x=alt.X(field="date",type="temporal"),
y=alt.Y(field="count",type="quantitative"),
detail=alt.Detail(field="series",type="nominal"),
tooltip=[
alt.Tooltip(field="count",type="temporal"),
alt.Tooltip(field="series",type="nominal"),
alt.Tooltip(field="date",type="temporal", format="%Y年%m月%d日 %H時%M分"),
],
)
points = (
base.mark_circle()
.encode(
opacity=alt.condition(
predicate=series_mouse_selection,
if_true=alt.value(1),
if_false=alt.value(0),
),
)
.add_selection(series_mouse_selection)
)
lines = base.mark_line().encode(
color=alt.condition(
predicate=series_mouse_selection,
if_true=alt.value("steelblue"),
if_false=alt.value("lightgray"),
),
opacity=alt.condition(
predicate=series_mouse_selection,
if_true=alt.value(1),
if_false=alt.value(0.5),
),
)
text = (
alt.Chart()
.mark_text(align="center", dx=0, dy=-170, fontSize=18)
.encode(text=alt.Text("series:N"))
.transform_filter(series_mouse_selection)
)
(points + lines + text).properties(width=500)
ドロップダウンによるハイライト
Altair ではドロップダウンで選択した項目のみをハイライトさせることができます。
series_dropdown = alt.binding_select(options=sorted(set(df["series"])))
series_selection = alt.selection_single(
fields=["series"], bind=series_dropdown, name="_", init={"series": "Construction"}
)
line_chart = (
alt.Chart(df)
.mark_line()
.encode(
x=alt.X(field="date",type="temporal"),
y=alt.Y(field="count",type="quantitative"),
detail=alt.Detail(field="series",type="nominal"),
color=alt.condition(
predicate=series_selection,
if_true=alt.value("steelblue"),
if_false=alt.value("lightgray"),
),
opacity=alt.condition(
predicate=series_selection,
if_true=alt.value(1),
if_false=alt.value(0.5),
),
)
)
line_chart.add_selection(series_selection)
全期間の平均を表示
複数のグラフを重ねて表示させることも可能です。
avg_line = (
alt.Chart(df)
.mark_rule(color="darkorange",size=2.5)
.encode(
y=alt.Y("mean(count):Q",axis=alt.Axis(title=None)),
strokeDash=alt.value([7, 7]), # dashed line: 7 pixels dash + 7 pixels space
)
)
text = (
alt.Chart(df)
.mark_text(align="left",dx=5,dy=-15,text="Average",color="darkorange")
.encode(y="mean(count):Q")
)
(
line_chart.add_selection(series_selection)
+ avg_line.transform_filter(series_selection)
+ text.transform_filter(series_selection)
)
ドラックした区間の平均を表示
2009年付近をドラックすると、その頃に失業者数が増加していたことがわかります。
date_brush = alt.selection(type="interval", encodings=["x"])
(
line_chart.add_selection(series_selection).add_selection(date_brush)
+ avg_line.transform_filter(series_selection).transform_filter(date_brush)
+ text.transform_filter(series_selection).transform_filter(date_brush)
)
回帰分析
trans_regression()
で回帰分析が可能です。method
で回帰方法を選べます。線形回帰はmethod=linear
です。
pr_line = (
line_chart
.transform_filter(series_selection)
.transform_regression(on="date", regression="count",method="poly")
.mark_line(size=3,opacity=1)
.encode(
strokeDash=alt.value([7, 7]), # dashed line: 7 pixels dash + 7 pixels space
color=alt.value("darkorange"),
)
)
line_chart.add_selection(series_selection) + pr_line
エラーバンド
ばらつきの大きさは.mark_errorband()
で表示可能です。.mark_errorbar()
と同様にでエラーバーで表示する統計量の種類は extent
で指定しましょう。引数はデフォルトでstderr(標準誤差)です。他にはstderv(標準偏差)、ci(95%信頼区間)、iqr(四分位範囲)がとれます。
以下のエラーバーは産業別失業者数の95%信頼区間を表示しています。
line = alt.Chart(df).mark_line().encode(x="date:T", y="mean(count):Q")
band = alt.Chart(df).mark_errorband(extent="ci").encode(x="date:T", y="count:Q")
band + line
スライダーで選択した年の可視化
特定の1年間を可視化する手法です。
year_slider = alt.binding_range(min=2000, max=2009, step=1)
year_selection = alt.selection_single(name="year", fields=["year"],
bind=year_slider, init={"year": 2000})
(
alt.Chart(df)
.mark_line()
.encode(
x=alt.X("yearmonth(date)",type="temporal",
axis=alt.Axis(title="Year Month",labelAngle=-45)
),
y=alt.Y(field="count",type="quantitative"),
color=alt.Color(
field="series",type="nominal",
scale=alt.Scale(scheme="category20b"),
legend=alt.Legend(labelFontSize=10)
),
tooltip=[
alt.Tooltip(field="count",type="temporal"),
alt.Tooltip(field="series",type="nominal"),
alt.Tooltip(field="date",type="temporal", format="%Y年%m月%d日 %H時%M分"),
],
)
.add_selection(year_selection)
.transform_filter(year_selection)
)
2008年を選択した例です。
正規化積みあげ面グラフ
棒グラフと同様に、面グラフも stack="normalize"
で正規化できます。
(
alt.Chart(df)
.mark_area()
.encode(
x="date:T",
y=alt.Y("count:Q", stack="normalize"),
color=alt.Color("series:N",
scale=alt.Scale(scheme="category20b"),
legend=alt.Legend(labelFontSize=10)
),
)
)
凡例で選択した項目のハイライト
凡例でクリックした項目がハイライトされます。2個目以降はshiftキーを押しながらクリックしてください。
series_multi_selection = alt.selection_multi(fields=["series"], bind="legend")
(
alt.Chart(df)
.mark_area()
.encode(
x="date:T",
y=alt.Y("count:Q", stack="normalize"),
color=alt.Color("series:N",
scale=alt.Scale(scheme="category20b"),
legend=alt.Legend(labelFontSize=10)
),
opacity=alt.condition(series_multi_selection, alt.value(1), alt.value(0.2))
)
.add_selection(series_multi_selection)
)
選択した項目だけで正規化
凡例でクリックした項目のみで正規化されます。2個目以降はshiftキーを押しながらクリックしてください。
base = (
alt.Chart(df)
.mark_area()
.encode(
x="date:T",
y=alt.Y("count:Q", stack="normalize"),
color=alt.Color("series:N",
scale=alt.Scale(scheme="category20b"),
legend=alt.Legend(labelFontSize=10)
),
)
)
background = base.mark_area(opacity=0)
foreground = base.add_selection(series_multi_selection).transform_filter(series_multi_selection)
background + foreground
選択期間の拡大
下の横長グラフでドラックした区間を上のグラフで表示させることが可能です。
base = (
alt.Chart(df)
.encode(
x=alt.X(field="date",type="temporal"),
y=alt.Y(field="count",type="quantitative"),
color=alt.Color(
field="series",type="nominal",
scale=alt.Scale(scheme="category20b"),
legend=alt.Legend(labelFontSize=10)
),
tooltip=[
alt.Tooltip(field="count",type="temporal"),
alt.Tooltip(field="series",type="nominal"),
alt.Tooltip(field="date",type="temporal", format="%Y年%m月%d日 %H時%M分"),
],
)
)
upper = (
base.mark_line()
.encode(alt.X("date:T",scale=alt.Scale(domain=date_brush)))
.properties(height=300)
)
lower = (
base
.mark_area()
.properties(height=100)
.add_selection(date_brush)
)
upper & lower
2007年以降を拡大させた場合、以下のようになります。