棒グラフ#

準備#

Import#

Hide code cell content
# warningsモジュールのインポート
import warnings

# データ解析や機械学習のライブラリ使用時の警告を非表示にする目的で警告を無視
# 本書の文脈では、可視化の学習に議論を集中させるために選択した
# ただし、学習以外の場面で、警告を無視する設定は推奨しない
warnings.filterwarnings("ignore")
Hide code cell content
# pathlibモジュールのインポート
# ファイルシステムのパスを扱う
from pathlib import Path

# typingモジュールからの型ヒント関連のインポート
# 関数やクラスの引数・返り値の型を注釈するためのツール
from typing import Any, Dict, List, Optional, Union

# numpy:数値計算ライブラリのインポート
# npという名前で参照可能
import numpy as np

# pandas:データ解析ライブラリのインポート
# pdという名前で参照可能
import pandas as pd

# plotly.expressのインポート
# インタラクティブなグラフ作成のライブラリ
# pxという名前で参照可能
import plotly.express as px

# plotly.graph_objectsからFigureクラスのインポート
# 型ヒントの利用を主目的とする
from plotly.graph_objects import Figure

変数#

Hide code cell content
# マンガデータ保存ディレクトリのパス
DIR_CM = Path("../../../data/cm/input")
# アニメデータ保存ディレクトリのパス
DIR_AN = Path("../../../data/an/input")
# ゲームデータ保存ディレクトリのパス
DIR_GM = Path("../../../data/gm/input")

# マンガデータの分析結果の出力先ディレクトリのパス
DIR_OUT_CM = (
    DIR_CM.parent / "output" / Path.cwd().parts[-2] / Path.cwd().parts[-1] / "bar"
)
# アニメデータの分析結果の出力先ディレクトリのパス
DIR_OUT_AN = (
    DIR_AN.parent / "output" / Path.cwd().parts[-2] / Path.cwd().parts[-1] / "bar"
)
# ゲームデータの分析結果の出力先ディレクトリのパス
DIR_OUT_GM = (
    DIR_GM.parent / "output" / Path.cwd().parts[-2] / Path.cwd().parts[-1] / "bar"
)
Hide code cell content
# 読み込み対象ファイル名の定義

# Comic CollectionとCReaTor関連のファイル名
FN_CC_CRT = "cm_cc_crt.csv"

# Anime Episode関連のファイル名
FN_AE = "an_ae.csv"

# PacKaGeとPlatForm関連のファイル名
FN_PKG_PF = "gm_pkg_pf.csv"
Hide code cell content
# 可視化に関する設定値の定義

# 可視化対象のマンガ作者数
N_CRT = 20

# 可視化対象のアニメ作品数
N_AC = 20

# 可視化対象のゲームプラットフォーム数
N_PF = 20
Hide code cell content
# plotlyの描画設定の定義

# plotlyのグラフ描画用レンダラーの定義
# Jupyter Notebook環境のグラフ表示に適切なものを選択
RENDERER = "plotly_mimetype+notebook"
Hide code cell content
# 質的変数の描画用のカラースケールの定義

# Okabe and Ito (2008)基準のカラーパレット
# 色の識別性が高く、多様な色覚の人々にも見やすい色組み合わせ
# 参考URL: https://jfly.uni-koeln.de/color/#pallet
OKABE_ITO = [
    "#000000",  # 黒 (Black)
    "#E69F00",  # 橙 (Orange)
    "#56B4E9",  # 薄青 (Sky Blue)
    "#009E73",  # 青緑 (Bluish Green)
    "#F0E442",  # 黄色 (Yellow)
    "#0072B2",  # 青 (Blue)
    "#D55E00",  # 赤紫 (Vermilion)
    "#CC79A7",  # 紫 (Reddish Purple)
]

関数#

Hide code cell source
def show_fig(fig: Figure) -> None:
    """
    所定のレンダラーを用いてplotlyの図を表示
    Jupyter Bookなどの環境での正確な表示を目的とする

    Parameters
    ----------
    fig : Figure
        表示対象のplotly図

    Returns
    -------
    None
    """

    # 図の周囲の余白を設定
    # t: 上余白
    # l: 左余白
    # r: 右余白
    # b: 下余白
    fig.update_layout(margin=dict(t=25, l=25, r=25, b=25))

    # 所定のレンダラーで図を表示
    fig.show(renderer=RENDERER)
Hide code cell content
def save_df_to_csv(df: pd.DataFrame, dir_save: Path, fn_save: str) -> None:
    """
    DataFrameをCSVファイルとして指定されたディレクトリに保存する関数

    Parameters
    ----------
    df : pd.DataFrame
        保存対象となるDataFrame
    dir_save : Path
        出力先ディレクトリのパス
    fn_save : str
        保存するCSVファイルの名前(拡張子は含めない)
    """
    # 出力先ディレクトリが存在しない場合は作成
    dir_save.mkdir(parents=True, exist_ok=True)

    # 出力先のパスを作成
    p_save = dir_save / f"{fn_save}.csv"

    # DataFrameをCSVファイルとして保存する
    df.to_csv(p_save, index=False, encoding="utf-8-sig")

    # 保存完了のメッセージを表示する
    print(f"DataFrame is saved as '{p_save}'.")
Hide code cell content
def format_cols(df: pd.DataFrame, cols_rename: Dict[str, str]) -> pd.DataFrame:
    """
    指定されたカラムのみをデータフレームから抽出し、カラム名をリネームする関数

    Parameters
    ----------
    df : pd.DataFrame
        入力データフレーム
    cols_rename : Dict[str, str]
        リネームしたいカラム名のマッピング(元のカラム名: 新しいカラム名)

    Returns
    -------
    pd.DataFrame
        カラムが抽出・リネームされたデータフレーム
    """

    # 指定されたカラムのみを抽出し、リネーム
    df = df[cols_rename.keys()].rename(columns=cols_rename)

    return df

可視化例#

マンガデータ#

Hide code cell content
# pandasのread_csv関数でCSVファイルの読み込み
df_cc_crt = pd.read_csv(DIR_CM / FN_CC_CRT)
Hide code cell content
# 'crtname'を基に'n_ce'の合計を計算
df_cm = df_cc_crt.groupby("crtname")["n_ce"].sum().reset_index()

# 'n_ce'で降順ソートし、上位N_CRT件を選択
df_cm = df_cm.sort_values("n_ce", ascending=False, ignore_index=True).head(N_CRT)

# 描画に適したカラム名に変更
df_cm = df_cm.rename(columns={"crtname": "マンガ作者名", "n_ce": "合計話数"})
Hide code cell content
# 可視化手法のDataFrameを確認
df_cm.head()
マンガ作者名 合計話数
0 水島新司 2798
1 秋本治 1979
2 梶原一騎 1873
3 高橋留美子 1736
4 浜岡賢次 1384
Hide code cell content
# 可視化対象DataFrameを保存
save_df_to_csv(df_cm, DIR_OUT_CM, "cm")
DataFrame is saved as '../../../data/cm/output/vol2/01/bar/cm.csv'.
Hide code cell source
# plotly.expressのbar関数で棒グラフ作成
# x軸: 'マンガ作者名', y軸: '合計話数'
fig = px.bar(df_cm, x="マンガ作者名", y="合計話数")

# 先に定義したshow_fig関数でグラフ表示
show_fig(fig)
Hide code cell source
# '作者名'のアルファベット順でソートし棒グラフを作成
# x軸: 'マンガ作者名', y軸: '合計話数'
fig = px.bar(df_cm.sort_values("マンガ作者名"), x="マンガ作者名", y="合計話数")

# show_fig関数でグラフ表示
show_fig(fig)

アニメデータ#

Hide code cell content
# pandasのread_csv関数でCSVファイルをデータフレームとして読み込み
df_ae = pd.read_csv(DIR_AN / FN_AE)
Hide code cell content
# 'acname' を基準にグループ化し、'aeid' のユニークな値の数を計算
# 各アニメ作品の合計話数を取得
df_an = df_ae.groupby("acname")["aeid"].nunique().reset_index(name="n_ae")

# 'n_ae' の値で降順ソートし、上位 N_AC 件をデータ取得
df_an = df_an.sort_values("n_ae", ascending=False, ignore_index=True).head(N_AC)

# 可視化用にカラム名を変更
df_an = df_an.rename(columns={"acname": "アニメ作品名", "n_ae": "合計話数"})
Hide code cell content
# 可視化対象のDataFrameを確認
df_an.head()
アニメ作品名 合計話数
0 クレヨンしんちゃん 1926
1 親子クラブ 1363
2 サザエさん 1175
3 ちびまる子ちゃん[新] 994
4 それいけ!アンパンマン 958
Hide code cell content
# 可視化対象DataFrameを保存
save_df_to_csv(df_an, DIR_OUT_AN, "an")
DataFrame is saved as '../../../data/an/output/vol2/01/bar/an.csv'.
Hide code cell source
# plotly.expressのbar関数で棒グラフを作成
# x軸は'アニメ作品名'、y軸は'合計話数'
fig = px.bar(df_an, x="アニメ作品名", y="合計話数")

# show_fig関数で棒グラフを表示
show_fig(fig)
Hide code cell source
# 横棒グラフの可視化

# plotly.expressのbar関数で横棒グラフ作成
# y軸は'アニメ作品名'、x軸は'合計話数'、'orientation="h"'で「横向き」を指定
# グラフの高さを500ピクセルに指定することで全件余裕を持って表示
fig = px.bar(df_an, y="アニメ作品名", x="合計話数", orientation="h", height=500)

# show_fig関数で図を表示
show_fig(fig)
Hide code cell content
# 'acname'毎の'aeid'の数と'date'の最初・最後の日付集計
df_tmp = (
    df_ae.groupby("acname")
    .agg(n_ae=("aeid", "nunique"), start_date=("date", "min"), end_date=("date", "max"))
    .reset_index()
)

# 'acname'に「ドラえもん」を含むデータの抽出
df_tmp[df_tmp["acname"].str.contains("ドラえもん")]
acname n_ae start_date end_date
1914 ドラえもん[新・第2期] 608 2005-04-15 2016-12-31
1915 ドラえもん[新] 224 1999-12-03 2005-03-18
Hide code cell content
# 'acname'に「ちびまる子ちゃん」を含むデータの抽出
df_tmp[df_tmp["acname"].str.contains("ちびまる子ちゃん")]
acname n_ae start_date end_date
1029 ちびまる子ちゃん[新] 994 1999-12-05 2016-12-25
Hide code cell content
# df_aeデータフレームを'date'列で昇順に並び替えて、'asid'でグループ化
# 各グループにおける'aeid'のユニークな値の数と、最初の'acname'を集計
# acnameを用いるのは、asname相当のデータが存在しないため
df_an2 = (
    df_ae.sort_values("date")
    .groupby("asid")
    .agg({"aeid": "nunique", "acname": "first"})
).reset_index()

# 集計したデータフレームdf_an2を'aeid'(つまりシリーズ合計話数)で降順に並び替え、
# 上位N_AC件を取得して新たなdf_an2に更新
# ignore_index=Trueにより、インデックスを新しい連番にリセット
df_an2 = df_an2.sort_values("aeid", ascending=False, ignore_index=True).head(N_AC)

# 列名をより分かりやすい名称に変更
df_an2 = df_an2.rename(
    columns={
        "acname": "代表的なアニメ作品名",
        "aeid": "シリーズ合計話数",
        "asid": "アニメシリーズID",
    }
)
Hide code cell content
# 可視化対象とするDataFrameを確認
df_an2.head()
アニメシリーズID シリーズ合計話数 代表的なアニメ作品名
0 C1462 2084 忍たま 乱太郎[第1期]
1 C1327 1926 クレヨンしんちゃん
2 C2158 1653 おじゃる丸
3 C1640 1363 親子クラブ
4 C4102 1245 いない いない ばあっ![第4期]
Hide code cell content
# 可視化対象DataFrameを保存
save_df_to_csv(df_an2, DIR_OUT_AN, "an2")
DataFrame is saved as '../../../data/an/output/vol2/01/bar/an2.csv'.
Hide code cell source
# 横棒グラフの可視化

# plotly.expressのbar関数で横棒グラフ作成
# y軸は'アニメ作品名'、x軸は'合計話数'、'orientation="h"'で「横向き」を指定
# グラフの高さを500ピクセルに指定することで全件余裕を持って表示
fig = px.bar(
    df_an2, y="代表的なアニメ作品名", x="シリーズ合計話数", orientation="h", height=500
)

# show_fig関数で図を表示
show_fig(fig)

ゲームデータ#

Hide code cell content
# pandasのread_csv関数でCSVファイルをデータフレームとして読み込み
df_pkg_pf = pd.read_csv(DIR_GM / FN_PKG_PF)
Hide code cell content
# 'pfname'に基づき、'pkgid'のユニークな値の数の集計
df_gm = df_pkg_pf.groupby("pfname")["pkgid"].nunique().reset_index(name="n_pkg")

# 'n_pkg'の値で降順ソートし、上位N_PF件のデータを取得
df_gm = df_gm.sort_values("n_pkg", ascending=False).head(N_PF)

# カラム名を可視化に適したものに変更
df_gm = df_gm.rename(columns={"pfname": "プラットフォーム名", "n_pkg": "パッケージ数"})
Hide code cell content
# 可視化対象とするDataFrameを確認
df_gm.head()
プラットフォーム名 パッケージ数
40 プレイステーション2 4216
39 プレイステーション 3750
44 プレイステーション・ポータブル 3417
41 プレイステーション3 2501
43 プレイステーションVita 2348
Hide code cell content
# 可視化対象DataFrameを保存
save_df_to_csv(df_gm, DIR_OUT_GM, "gm")
DataFrame is saved as '../../../data/gm/output/vol2/01/bar/gm.csv'.
Hide code cell source
# plotly.expressのbar関数で棒グラフの作成
# x軸: プラットフォーム名、y軸: パッケージ数
fig = px.bar(df_gm, x="プラットフォーム名", y="パッケージ数")

# show_fig関数で図の表示
show_fig(fig)
Hide code cell content
# ゲームのプラットフォームとメーカーの対応辞書
# キー: プラットフォーム名、値: メーカー名の略称
pf2mk = {
    "プレイステーション2": "ソニー",
    "プレイステーション": "ソニー",
    "プレイステーション・ポータブル": "ソニー",
    "プレイステーション3": "ソニー",
    "プレイステーションVita": "ソニー",
    "ニンテンドー3DS": "任天堂",
    "ニンテンドーDS": "任天堂",
    "プレイステーション4": "ソニー",
    "Xbox360": "マイクロソフト",
    "Wii": "任天堂",
    "スーパーファミコン": "任天堂",
    "ゲームアーカイブス": "ソニー",
    "ゲームボーイ": "任天堂",
    "セガサターン": "セガ",
    "WiiU": "任天堂",
    "XboxOne": "マイクロソフト",
    "ゲームボーイアドバンス": "任天堂",
    "MicrosoftWindows": "マイクロソフト",
    "ドリームキャスト": "セガ",
    "メガドライブ": "セガ",
}
Hide code cell content
# 可視化用に新たなDataFrameを作成
df_gm2 = df_gm.copy()

# 'プラットフォーム名'をキーとして辞書'pf2mk'からメーカー名を取得
# 新たな'メーカー名'カラムに格納
df_gm2["メーカー名"] = df_gm2["プラットフォーム名"].map(pf2mk)
Hide code cell content
# 可視化対象とするDataFrameを確認
df_gm2.head()
プラットフォーム名 パッケージ数 メーカー名
40 プレイステーション2 4216 ソニー
39 プレイステーション 3750 ソニー
44 プレイステーション・ポータブル 3417 ソニー
41 プレイステーション3 2501 ソニー
43 プレイステーションVita 2348 ソニー
Hide code cell content
# 可視化対象DataFrameを保存
save_df_to_csv(df_gm2, DIR_OUT_GM, "gm2")
DataFrame is saved as '../../../data/gm/output/vol2/01/bar/gm2.csv'.
Hide code cell source
# 'プラットフォーム名'をx軸、'パッケージ数'をy軸として棒グラフ作成
# カラーは'メーカー名'に基づき、カラーパレットにはOKABE_ITOを使用
fig = px.bar(
    df_gm2,
    x="プラットフォーム名",
    y="パッケージ数",
    color="メーカー名",
    height=400,
    color_discrete_sequence=OKABE_ITO,
)

# show_fig関数で図の表示
show_fig(fig)
Hide code cell source
# 'パッケージ数'をx軸'プラットフォーム名'をy軸、として横棒グラフ作成
# カラーは'メーカー名'に基づき、カラーパレットにはOKABE_ITOを使用
fig = px.bar(
    df_gm2,
    x="パッケージ数",
    y="プラットフォーム名",
    color="メーカー名",
    orientation="h",
    height=400,
    color_discrete_sequence=OKABE_ITO,
)

# show_fig関数で図の表示
show_fig(fig)
Hide code cell source
# 'update_layout'でグラフの凡例の位置を調整
# 凡例の右上の角を図の右上に固定 (x=0.99, y=0.99)
fig.update_layout(legend=dict(yanchor="top", y=0.99, xanchor="right", x=0.99))

# show_fig関数で図の表示
show_fig(fig)