大阪大学医学部 情報医科学研究会 (通称:Python会)

Now is better than never.

PtitPrinceによるPythonでのRaincloud plotの描画

2020-12-16(Wed) - Posted by 山本 in 技術ブログ    tag:Statistics

Contents

    Raincloud plotを描画するときにPtitPrinceを使うことがあるのですが、日本語のメモが無かったので書きました。

    Raincloud plotとは

    Raincloud plotは簡単に言えば生データ (strip plot), 箱ひげ図 (box plot), バイオリン図 (violin plot)を見やすく組み合わせたデータの描画手法である。Micah Allen氏のIntroducing Raincloud Plots!というブログで初めに提案され、その後論文にもなっている (Allen et al., Wellcome Open Res. 2019)。

    Allen M, Poggiali D, Whitaker K, Marshall TR, Kievit RA. Raincloud plots: a multi-platform tool for robust data visualization. Wellcome Open Res. 2019 Apr 1;4:63. doi: 10.12688/wellcomeopenres.15191.1. PMID: 31069261; PMCID: PMC6480976.

    この論文に付属して、以下のリポジトリにR, PythonおよびMatlabでRaincloud plotを描画するtutorialがまとめられている。

    上記のリポジトリを参考にして、Raincloud plotをseabornのviolin plotなどと同様に描画できるようなライブラリにしたのがPtitPrinceである。

    Setup

    PtitPrinceのinstall

    pipでinstallする場合はpip install ptitprinceを実行する。

    In [1]:
    # !pip install ptitprince
    
    In [2]:
    import ptitprince as pt
    

    ライブラリとサンプルデータセットのload

    ptitprinceの他にpandas, seaborn, matplotlibを用いる。

    In [3]:
    import pandas as pd
    import seaborn as sns
    import matplotlib.pyplot as plt
    tips = sns.load_dataset("tips")
    print(tips.shape)
    
    (244, 7)
    

    描画例のためにseabornのtips データセットを用いる。初めの5列を見てみよう。

    In [4]:
    tips.head()
    
    Out[4]:
    total_bill tip sex smoker day time size
    0 16.99 1.01 Female No Sun Dinner 2
    1 10.34 1.66 Male No Sun Dinner 3
    2 21.01 3.50 Male No Sun Dinner 3
    3 23.68 3.31 Male No Sun Dinner 2
    4 24.59 3.61 Female No Sun Dinner 4

    pt.RainCloud関数

    引数の概要

    以下はhelp(pt.RainCloud)で表示できる内容の一部を適宜訳したもの。

    RainCloud(x=None, y=None, hue=None, data=None, order=None, hue_order=None, orient='v', width_viol=0.7, width_box=0.15, palette='Set2', bw=0.2, linewidth=1, cut=0.0, scale='area', jitter=1, move=0.0, offset=None, point_size=3, ax=None, pointplot=False, alpha=None, dodge=False, linecolor='red', **kwargs)
    

    異なるカテゴリxの尺度yのRaincloud plotを描画する。ただし、xyはpandas dataframe のdataの異なる列である。

    主な入力:

    • x : categorical data. Iterable, np.array, or dataframe column name if data is specified
    • y : measure data. Iterable, np.array, or dataframe column name if data is specified
    • hue : a second categorical data. Use it to obtain different clouds and rainpoints
    • data : input pandas dataframe
    • order : list, order of the categorical data
    • hue_order : list, order of the hue
    • orient : string, vertical if "v" (default), horizontal if "h"
    • width_viol : float, width of the cloud
    • width_box : float, width of the boxplot
    • move : float, adjusts rain position to the x-axis (default value 0.)
    • offset : float, adjusts cloud position to the x-axis

    kwargsは、cloud (default), boxplot, rain/stripplot, pointplotのそれぞれについてキーワード引数の頭に [cloud_, box_, rain_, point_]を付けることで指定ができる。例えば stripplotはrainであり、edgecolorを変更したければ頭にrain_を付けてrain_edgecolor="gray"などとする。

    描画例とRaincloud plotについて

    pt.RainCloud関数を使ってRainCloud plotを描画してみよう。

    In [5]:
    pt.RainCloud(x="time", y="tip", data=tips, orient="h", pointplot=True)
    plt.tight_layout()
    

    ただし、"RainCloud"「雨雲」と呼ばれる理由が分かりやすいように描画方向を水平向きにした。RainCloud plotは以下の4つの構成要素から成る。

    1. 「雲」("Cloud"):カーネル密度推定 (あるいはhalf violinplot)
    2. 「雨」("Rain"):雲の下の stripplot
    3. 「傘」("Umberella"):箱ひげ図 (boxplot)
    4. 「雷」("Thunder"):異なる群の平均値を結ぶ pointplot (pointplot=Trueの場合)

    しかし、わざわざRainCloud plotを導入しなくても生データ(strip plot), 箱ひげ図(box plot), バイオリン図(violin plot)の組み合わせであればsns.violinplotsns.stripplotでも実現可能である。比較のために描画してみよう。

    In [6]:
    sns.violinplot(y="time", x="tip", data=tips, orient="h", color=".8", bw=0.2)
    sns.stripplot(y="time", x="tip", data=tips,  orient="h", alpha=.7)
    plt.tight_layout()
    

    箱ひげ図とstrip plotが被り見にくいことが分かる。violin plotは左右対称だがこれは冗長な表現とも言えるので、片側だけ表示し、箱ひげ図を横にずらして見やすくしたのがRainCloud plotである。

    描画向きを変える

    orient="v"とすれば垂直に、orient="h"とすれば水平に描画される。デフォルトは"v"である。

    In [7]:
    plt.figure(figsize=(10, 4))
    plt.subplot(1,2,1); plt.title("vertical")
    pt.RainCloud(x="day", y="total_bill", data=tips, orient="v")
    plt.subplot(1,2,2); plt.title("horizontal")
    pt.RainCloud(x="day", y="total_bill", data=tips, orient="h")
    plt.tight_layout()
    

    片側violin plot ("cloud") を調整する

    width_violで横幅、bwでカーネルのバンド幅、linewidthで輪郭線の太さが調整できる。

    In [8]:
    plt.figure(figsize=(12, 4))
    plt.subplot(1,3,1); plt.title("width_viol=0.3")
    pt.RainCloud(x="day", y="total_bill", data=tips, width_viol=0.3)
    plt.subplot(1,3,2); plt.title("width_viol=0.3, bw=1")
    pt.RainCloud(x="day", y="total_bill", data=tips, width_viol=0.3, bw=1)
    plt.subplot(1,3,3); plt.title("linewidth=3")
    pt.RainCloud(x="day", y="total_bill", data=tips, linewidth=3)
    plt.tight_layout()
    

    stripplot ("rain") を調整する

    point_sizeで点の大きさ、jitterで点のばらつきの大きさが調整できる。また、キーワード引数の頭にrain_を付けてrain_edgecolorで輪郭線の色, rain_linewidthで輪郭線の幅, rain_alphaで点の透過度が調整できる。

    In [9]:
    plt.figure(figsize=(12, 4))
    plt.subplot(1,3,1); plt.title("point_size=8")
    pt.RainCloud(x="day", y="total_bill", data=tips, point_size=8)
    plt.subplot(1,3,2); plt.title("jitter=.01")
    pt.RainCloud(x="day", y="total_bill", data=tips, jitter=.01)
    plt.subplot(1,3,3); plt.title("rain_edgecolor='gray', \n rain_linewidth=1, rain_alpha=0.5")
    pt.RainCloud(x="day", y="total_bill", data=tips, point_size=8,
                 rain_edgecolor='gray', rain_linewidth=1, rain_alpha=0.5)
    plt.tight_layout()
    

    箱ひげ図 ("umberella") を調整する

    width_boxで箱ひげ図の幅、box_linewidthで箱ひげ図の線の太さが調整できる。

    In [10]:
    plt.figure(figsize=(8, 4))
    plt.subplot(1,2,1); plt.title("width_box=0.3")
    pt.RainCloud(x="day", y="total_bill", data=tips, width_viol=0.5, width_box=0.3)
    plt.tight_layout()
    plt.subplot(1,2,2); plt.title("box_linewidth=3")
    pt.RainCloud(x="day", y="total_bill", data=tips, box_linewidth=3)
    plt.tight_layout()
    

    平均値を結ぶ線 ("thunder") を調整する

    pointplot=Trueとすれば平均値を結ぶ線が描画される。defaultの色は赤だが,linecolorの引数を指定することで色を変更できる。

    In [11]:
    plt.figure(figsize=(12, 4))
    plt.subplot(1,3,1); plt.title("pointplot=True")
    pt.RainCloud(x="day", y="total_bill", data=tips, pointplot=True)
    plt.subplot(1,3,2); plt.title("linecolor='tab:blue'")
    pt.RainCloud(x="day", y="total_bill", data=tips, pointplot=True, linecolor='tab:blue')
    plt.subplot(1,3,3); plt.title("point_linestyles='--'")
    pt.RainCloud(x="day", y="total_bill", data=tips, pointplot=True, point_linestyles='--')
    plt.tight_layout()
    

    各グループでの比較

    hueを指定することで2つ目のカテゴリについての比較もできる。ここでは同様のことが可能なviolin plotの場合との比較をしている。なお、alphaに[0, 1]の数字を与えることで全体の透過度を変更できる。右上図では箱ひげ図の位置が被っており見にくい。このような場合はdodge = True とすれば箱ひげ図の位置をずらすことができる。さらにpointplot=Trueとしたのが左下図である。

    In [12]:
    plt.figure(figsize=(12, 8))
    plt.subplot(2,2,1); plt.title("sns.violinplot")
    sns.violinplot(x="day", y="total_bill", hue="smoker", data=tips, palette='Set2', bw=.2)
    plt.subplot(2,2,2); plt.title("pt.RainCloud")
    pt.RainCloud(x="day", y="total_bill", hue="smoker", data=tips, alpha=.65)
    plt.subplot(2,2,3); plt.title("pt.RainCloud (dodge=True, pointplot=True)")
    pt.RainCloud(x="day", y="total_bill", hue="smoker", data=tips, alpha=.65, dodge=True, pointplot=True)
    plt.tight_layout()
    

    pt.half_violinplot関数

    恐らく使う機会はあまりないだろうが、pt.half_violinplotというviolin plotの片側のみを描画する関数も用意されている。

    half_violinplot(x=None, y=None, hue=None, data=None, order=None, hue_order=None, bw='scott', cut=2, scale='area', scale_hue=True, gridsize=100, width=0.8, inner='box', split=False, dodge=True, orient=None, linewidth=None, color=None, palette=None, saturation=0.75, ax=None, offset=0.15, **kwargs)
    
    In [13]:
    pt.half_violinplot(x="day", y="total_bill", data=tips, palette="Set2", width=0.5, bw=0.3)
    plt.tight_layout()
    

    まとめ

    • Raincloud plotは生データとその分布を描画するのに優れた手法である。
    • PtitPrinceというライブラリを用いればPythonでRaincloud plotを簡単に描画できる。