Pythonでデータの挙動を見やすくする可視化ツールを作成してみた

# 概要
Pythonのグラフ描画ライブラリ「**seaborn**」をベースにして、
相関係数や散布図などを一括で確認できる可視化ツールを作ってみました。
![ggpairs_titanic_box_huesurvived.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/610167/aa6b10c7-bb4d-f2be-cce3-81fd50028744.png)
試行錯誤の結果、**様々なデータパターンに対応した、汎用性の高いツール**が出来た！
と感じています

## 2021/7 修正：pipでインストールできるよう改良しました
下記コマンドでインストール可能となりました

```
$ pip install seaborn-analyzer
```

**※[関連ツールを1つの記事にまとめました](https://qiita.com/c60evaporator/items/8cb774e65d4423fd93ee)！よければこちらもご覧ください**
![image](https://user-images.githubusercontent.com/59557625/126887193-ceba9bdd-3653-4d58-a916-21dcfe9c38a0.png)
もしこのツールを良いと思われたら、**[GitHubにStar頂けるとありがたいです！](https://github.com/c60evaporator/seaborn_analyzer)**

## 2021/8 注意点
~最新のseaborn 0.11.1では以下のように正しく表示されません~
→最新版の0.11.2でも正しく表示されるよう修正しました（2021/10/31）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/610167/162b612d-34ad-9c97-ac17-10c86c66bd53.png)


# 背景と機能
本ツールの機能と、作成した背景を解説します
## seabornとは？
Pythonのグラフ描画ライブラリで、ベースとなっているライブラリmatplotlibよりも、簡単なコードで綺麗なグラフを描くことができます

中でも、散布図とヒストグラムを組み合わせた「**pairplot**」は、
多変数の関係性を一度に可視化することができるため、
データ分析の初期段階で非常によく使われています。
![pairplot_iris_huespecies.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/610167/6e9d2596-192b-b6e5-6447-3218f51c5c5b.png)

## pairplotの課題
とても便利なpairplotですが、下記のようにいくつか課題があります。

### 課題1：右上の散布図が情報量ゼロ
pairplotの左下（下の図の赤枠）と右上（青枠）の散布図を見比べてください
![diag_pairplot_iris_huespecies.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/610167/f65d9d36-d155-bd8f-c847-aa3a395a6c5e.png)

よく見ると右上の散布図は左下の散布図の軸を反転させただけで、表示している情報は全く同じです。

**右上の散布図は情報量ゼロ**‥むしろ分析者に意味のない情報を見せている分、マイナスの効果すら生み出していると言えます。
（一応、縦軸横軸どちらの要素からスタートしても目的の2変数に辿り着けるというメリットはありますが‥）

### 課題2：離散的な変数は、散布図だと挙動が分かりずらい
今まで扱ってきた「iris」データセットは全て連続的な変数なので散布図がフィットしますが、
「titanic」データセットではどうでしょう？
![under2_pairplot_titanic_nohue.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/610167/c126c465-dd7c-3069-f974-ce8f7f67e0ee.png)
"adult_male"、"alone"などの、離散的でとる値の少ない変数（赤枠で囲った部分）では、
点が重なってしまって挙動がよく分からないですね。

しかも、このような離散的な変数こそ実際のデータ分析では重要な場面も多い（[下の「余談」を参照ください](https://qiita.com/c60evaporator/items/20f11b6ee965cec48570#%E4%BD%99%E8%AB%87)）ので、無視できる課題ではありません。

## 追加した機能
上記課題1、2をクリアするため、
R言語の可視化ライブラリ「GGally」等を参考にしつつ、
下記の2つの機能を加えてデータの傾向を見やすくしたメソッド

**pairanalyzer**

を作成しました

### 機能1：相関係数の表示
「課題1：右上の散布図の情報量がゼロ」をクリアするため、意味のある情報を載せたいと思い、
**右上には相関係数を表示する**こととしました
![ggpairs_iris_box_huespecies.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/610167/d718e7e1-2d25-9379-5e14-8b72b7224f2c.png)

相関係数の大小を直感的に分かりやすくするため、下記の機能も付け加えました
**・相関係数の大小に応じて文字サイズを変更**
**・全体の相関係数を黒で、hue(後で解説します)ごとの相関係数を色分けして表示**

### 機能2：箱ひげ図、バブルチャートへの自動表示変更
課題2で問題となっていた離散的な変数の傾向を把握しやすいよう、

・X,Yいずれかの変数の取る値が2種類以下のとき、**箱ひげ図で表示**
・もう1つの変数が4種類以下のとき箱ひげ図が作れないので、**バブルチャートの大きさでデータの重複数を表示**

に自動で表示変更する機能を追加し、データの挙動を見やすくしました
![ggpairs_titanic_box_huesurvived.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/610167/aa6b10c7-bb4d-f2be-cce3-81fd50028744.png)
hueによる色分け機能もあるので、元のpairplotとそう変わらない感覚で使えると思います

# 使用に必要なもの
・Python本体 (動作確認時は3.7.7を使用)
・Matplotlibで表示可能な環境 (Jupyter等)
・下記ライブラリ (参考として動作確認時のライブラリバージョンも記載)
　seaborn (0.10.1)
　numpy (1.18.5)
　pandas (1.0.5)
　matplotlib (3.2.2)
　scipy (1.5.0)

# インストール方法
下記コマンドでインストール可能です

```
$ pip install seaborn-analyzer
```
※アンダースコアの`pip install seaborn_analyzer`でもインストール可能です。
インポート時はアンダースコアの`import seaborn_analyzer`や`from seaborn_analyzer`
となるのでご注意ください

# コード
モジュールcustom_pair_plot.py内のクラスCustomPairPlotに、必要な処理をまとめました。
[GitHubにもアップロードしています](https://github.com/c60evaporator/seaborn_analyzer)
## モジュール本体

```custom_pair_plot.py
import seaborn as sns
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from scipy import stats

class CustomPairPlot():
    #初期化
    def __init__(self):
        self.df = None
        self.hue = None
        self.hue_names = None
        self.corr_mat = None
    
    #hueごとに相関係数計算
    def _corrfunc(self, x, y, **kws):
        if self.hue_names is None:
            labelnum=0
            hue_num = 0
        else:
            labelnum=self.hue_names.index(kws["label"])
            hue_num = len(self.hue_names)
        #xまたはyがNaNの行を除外
        mask = ~np.logical_or(np.isnan(x), np.isnan(y))
        x, y = x[mask], y[mask]
        #相関係数算出＆0.4ごとにフォントサイズ拡大
        r, _ = stats.pearsonr(x, y)
        fsize = min(9, 45/hue_num) + min(4.5, 22.5/hue_num) * np.ceil(abs(r)/0.4)
        fsize = min(9, 45/hue_num) if np.isnan(fsize) else fsize
        #該当マスのaxを取得
        ax = plt.gca()
        #既に表示したhueの分だけ下にさげて相関係数表示
        ax.annotate("r={:.2f}".format(r), xy=(.1, .65-min(.15,.75/hue_num)*labelnum), xycoords=ax.transAxes, size=fsize, color=kws["color"])
    
    #hueを分けない相関係数計算して上半分に表示
    def _corrall_upper(self, g):
        #右上を1マスずつ走査
        for i, j in zip(*np.triu_indices_from(g.axes, 1)):
            #該当マスのaxesを取得
            ax = g.axes[i, j]
            plt.sca(ax)
            #フィールド名を取得
            x_var = g.x_vars[j]
            y_var = g.y_vars[i]
            #相関係数
            r = self.corr_mat[x_var][y_var]
            #相関係数0.2ごとにフォントサイズ拡大
            fsize = 10 + 5 * np.ceil(abs(r)/0.2)
            fsize = 10 if np.isnan(fsize) else fsize
            #一番上に表示
            ax.annotate("r={:.2f}".format(r), xy=(.1, .85), xycoords=ax.transAxes, size=fsize, color="black")

    #重複数に応じたバブルチャート
    def _duplicate_bubblescatter(self, data, x, y, hue=None, hue_names=None, hue_slide="horizontal", palette=None):
        #hueの要素数および値を取得
        if hue is not None:
            #hue_nameを入力していないとき、hueの要素から自動生成
            if hue_names is None:
                hue_names = data[hue].dropna().unique()
            hue_num = len(hue_names)
            hue_vals = data[hue]
        #hueを入力していないときも、groupby用にhue関係変数生成
        else:
            hue_names = ["_nolegend_"]
            hue_num = 0
            hue_vals = pd.Series(["_nolegend_"] * len(data),
                                      index=data.index)
        #hueで区切らない全データ数（NaNは除外）をカウント
        ndata = len(data[[x,y]].dropna(how="any"))

        ######hueごとにGroupByして表示処理######
        hue_grouped = data.groupby(hue_vals)
        for k, label_k in enumerate(hue_names):
            try:
                data_k = hue_grouped.get_group(label_k)
            except KeyError:
                data_k = pd.DataFrame(columns=data.columns,
                                      dtype=np.float)
            #X,Yごとに要素数をカウント
            df_xy = data_k[[x,y]].copy()
            df_xy["xyrec"] = 1
            df_xycount = df_xy.dropna(how="any").groupby([x,y], as_index=False).count()
            #hueが2個以上存在するとき、表示位置ずらし量（対象軸のユニーク値差分最小値÷4に収まるよう設定）を計算
            if hue_num >=2:
                if hue_slide == "horizontal":
                    x_distinct_sort = sorted(data[x].dropna().unique())
                    x_diff_min = min(np.diff(x_distinct_sort))
                    x_offset = k * (x_diff_min/4)/(hue_num - 1) - x_diff_min/8
                    y_offset = 0
                else:
                    y_distinct_sort = sorted(data[y].dropna().unique())
                    y_diff_min = min(np.diff(y_distinct_sort))
                    x_offset = 0
                    y_offset = k * (y_diff_min/4)/(hue_num - 1) - y_diff_min/8
            else:
                x_offset = 0
                y_offset = 0
            #散布図表示（要素数をプロットサイズで表現）
            ax = plt.gca()
            ax.scatter(df_xycount[x] + x_offset, df_xycount[y] + y_offset, s=df_xycount["xyrec"]*1000/ndata, color=palette[k])

    #plotter=scatterかつ要素数が2以下なら箱ひげ図、それ以外ならscatterplotを使用
    def _boxscatter_lower(self, g, **kwargs):
        #kw_color = kwargs.pop("color", None)
        kw_color = g.palette
        #左下を走査
        for i, j in zip(*np.tril_indices_from(g.axes, -1)):
            ax = g.axes[i, j]
            plt.sca(ax)
            #軸表示対象のフィールド名を取得
            x_var = g.x_vars[j]
            y_var = g.y_vars[i]
            #XY軸データ抽出
            x_data = self.df[x_var]
            y_data = self.df[y_var]
            #XY軸のユニーク値
            x_distinct = x_data.dropna().unique()
            y_distinct = y_data.dropna().unique()
            
            #箱ひげ図(x方向)
            if len(x_distinct) ==2 and len(y_distinct) >= 5:
                sns.boxplot(data=self.df, x=x_var, y=y_var, orient="v",
                     hue=self.hue, palette=g.palette, **kwargs)
            #重複数に応じたバブルチャート(x方向)
            elif len(x_distinct) ==2 and len(y_distinct) < 5:
                self._duplicate_bubblescatter(data=self.df, x=x_var, y=y_var, hue=self.hue, hue_names=g.hue_names, hue_slide="horizontal", palette=g.palette)
            #箱ひげ図(y方向)
            elif len(y_distinct) ==2 and len(x_distinct) >= 5:
                sns.boxplot(data=self.df, x=x_var, y=y_var, orient="h",
                     hue=self.hue, palette=g.palette, **kwargs)
            #重複数に応じたバブルチャート(y方向)
            elif len(y_distinct) ==2 and len(x_distinct) < 5:
                self._duplicate_bubblescatter(data=self.df, x=x_var, y=y_var, hue=self.hue, hue_names=g.hue_names, hue_slide="vertical", palette=g.palette)
            #散布図
            else:
                if len(g.hue_kws) > 0 and "marker" in g.hue_kws.keys():#マーカー指定あるとき
                    markers = dict(zip(g.hue_names, g.hue_kws["marker"]))
                else:#マーカー指定ないとき
                    markers = True
                sns.scatterplot(data=self.df, x=x_var, y=y_var, hue=self.hue,
                     palette=g.palette, style=self.hue, markers=markers)
            #凡例を追加
            g._clean_axis(ax)
            g._update_legend_data(ax)

        if kw_color is not None:
            kwargs["color"] = kw_color
        #軸ラベルを追加
        g._add_axis_labels()

    #メイン関数
    def pairanalyzer(self, df, hue=None, palette=None, vars=None,
             lowerkind="boxscatter", diag_kind="kde", markers=None,
             height=2.5, aspect=1, dropna=True,
             lower_kws={}, diag_kws={}, grid_kws={}):
        #メンバ変数入力
        if diag_kind=="hist":#ヒストグラム表示のとき、bool型の列を除外してデータ読込
            self.df = df.select_dtypes(exclude=bool)
        else:#kde表示のとき、bool型を含めデータ読込
            self.df = df
        self.hue = hue
        self.corr_mat = df.corr(method="pearson")
        #文字サイズ調整
        sns.set_context("notebook")

        #PairGridインスタンス作成
        plt.figure()
        diag_sharey = diag_kind == "hist"
        g = sns.PairGrid(self.df, hue=self.hue,
                 palette=palette, vars=vars, diag_sharey=diag_sharey,
                 height=height, aspect=aspect, dropna=dropna, **grid_kws)

        #マーカーを設定
        if markers is not None:
            if g.hue_names is None:
                n_markers = 1
            else:
                n_markers = len(g.hue_names)
            if not isinstance(markers, list):
                markers = [markers] * n_markers
            if len(markers) != n_markers:
                raise ValueError(("markers must be a singleton or a list of "
                                "markers for each level of the hue variable"))
            g.hue_kws = {"marker": markers}

        #対角にヒストグラム or KDEをプロット
        if diag_kind == "hist":
            g.map_diag(plt.hist, **diag_kws)
        elif diag_kind == "kde":
            diag_kws.setdefault("shade", True)
            diag_kws["legend"] = False
            g.map_diag(sns.kdeplot, **diag_kws)

        #各変数のユニーク数を計算
        nuniques = []
        for col_name in g.x_vars:
            col_data = self.df[col_name]
            nuniques.append(len(col_data.dropna().unique()))

        #左下に散布図etc.をプロット
        if lowerkind == "boxscatter":
            if min(nuniques) <= 2: #ユニーク数が2の変数が存在するときのみ、箱ひげ表示
                self._boxscatter_lower(g, **lower_kws)
            else: #ユニーク数が2の変数が存在しないとき、散布図(_boxscatter_lowerを実行すると凡例マーカーが消えてしまう)
                g.map_lower(sns.scatterplot, **lower_kws)
        elif lowerkind == "scatter":
            g.map_lower(sns.scatterplot, **lower_kws)
        else:
            g.map_lower(sns.regplot, **lower_kws)

        #色分け（hue）有無で場合分けしてプロット＆相関係数表示実行
        #hueなし
        if self.hue is None:
            #右上に相関係数表示
            self.hue_names = None
            self._corrall_upper(g)
        #hueあり
        else:
            #右上に相関係数表示(hueごとに色分け＆全体の相関係数を黒表示)
            self.hue_names = g.hue_names
            g.map_upper(self._corrfunc)
            self._corrall_upper(g)
            g.add_legend()
```

## 各メソッドの解説
・pairanalyzer()：メインの処理。外部から呼び出すのはこのメソッド
・_boxscatter_lower()：変数の取る値に応じ、散布図・箱ひげ図・バブルチャートを切り替えるメソッド（上記「機能2」）
・_duplicate_bubblescatter()：バブルチャート表示メソッド
・_corrall_upper()：hueを分けない相関係数計算して上半分に表示
・_corrfunc()：hueごとに相関係数計算して表示

# 使用方法
実行方法と引数の解説をします
## 実行方法
実行元スクリプトと同フォルダにcustom_pair_plot.pyを置き、下記のように実行します

```python
#参考としてtitanicデータを読み込んでいます
import seaborn as sns
titanic = sns.load_dataset("titanic")

#ここから実行部分
from seaborn_analyzer import CustomPairPlot
gp = CustomPairPlot()
gp.pairanalyzer(titanic, hue='survived')
```

## 引数の解説
hue、lowerkind以外の引数は、
ベースとしたseabornのクラス「PairGrid」の引数と同仕様なので、
[こちら](https://seaborn.pydata.org/generated/seaborn.PairGrid.html)もご参照ください

### 引数を指定しないとき
下記の引数が自動入力されます
(df, hue=None, palette=None, vars=None, lowerkind="boxscatter", diag_kind="kde", markers=None, height=2.5, aspect=1, dropna=True, lower_kws={}, diag_kws={}, grid_kws={})

**・表示例**

```python
gp.pairanalyzer(titanic)
```
![ggpairs_titanic_box_nohue.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/610167/6177531d-abb5-b9e3-9c37-3e0fef7ff040.png)

### hue
ここで指定した列名で色分け表示します。相関係数もhueごとに計算されます。
離散変数以外を指定するととんでもない事になるので、注意してください‥(笑)

```python
gp.pairanalyzer(titanic, hue='survived')
```
![ggpairs_titanic_box_huesurvived.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/610167/aa6b10c7-bb4d-f2be-cce3-81fd50028744.png)

### palette
hueによる色分け用のカラーパレットを指定します

```python
gp.pairanalyzer(titanic, hue='survived', palette='Blues')
```
![ggpairs_titanic_box_hueblue.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/610167/f49df0bf-9996-f2f0-6d3e-543d49222257.png)

### vars
グラフ化する列を選択する(指定しなければ全ての数値型＆Boolean型の列を使用)

```python
gp.pairanalyzer(titanic, hue='survived', vars=['pclass', 'age', 'adult_male'])
```
![ggpairs_titanic_box_vars.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/610167/6e9612e1-3047-8ad9-17a6-635b9d501f1e.png)

### lowerkind
左下に表示するグラフを下記3種類から選択します(指定しなければ、'boxscatter'を選択)

'boxscatter'：前記「機能2」に従い、散布図・箱ひげ図・バブルチャートを自動切替
'scatter'：散布図（通常のpairplotと同じ）
'reg'：回帰直線

**boxscatter**

```python
gp.pairanalyzer(titanic, hue='survived', lowerkind='boxscatter')
```
![ggpairs_titanic_box_huesurvived.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/610167/aa6b10c7-bb4d-f2be-cce3-81fd50028744.png)

**scatter**

```python
gp.pairanalyzer(titanic, hue='survived', lowerkind='scatter')
```
![ggpairs_titanic_scatter.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/610167/8da18ec6-02e8-37de-7333-21a83af7eab4.png)

**reg**

```python
gp.pairanalyzer(titanic, hue='survived', lowerkind='reg')
```
![ggpairs_titanic_reg.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/610167/35350ddc-1f04-4994-065e-2793e21530d8.png)

### diag_kind
対角に表示するグラフを下記2種類から選択します(指定しなければ、'kde'を選択)

'hist'：ヒストグラム
'kde'：ヒストグラムをカーネル密度推定で円滑化

**hist**

```python
gp.pairanalyzer(titanic, hue='survived', diag_kind='hist')
```
![ggpairs_titanic_hist.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/610167/040cb515-942d-fe4c-af9e-5467d0ea2641.png)

※pairplotおよびベースとなるseabornのクラスPairGridには、bool型をヒストグラム表示するとエラーを吐くバグがあるので、pairanalyzerではbool型の列（titanicでは'adult_male','alone'）を事前に削除する処理を加えています

**kde**

```python
gp.pairanalyzer(titanic, hue='survived', lowerkind='kde')
```
![ggpairs_titanic_box_huesurvived.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/610167/aa6b10c7-bb4d-f2be-cce3-81fd50028744.png)

### markers
hueにより色分けしたデータの、散布図プロット形状を指定します
指定方法は[こちらを参照ください](https://pythondatascience.plavox.info/matplotlib/%E3%83%9E%E3%83%BC%E3%82%AB%E3%83%BC%E3%81%AE%E5%90%8D%E5%89%8D)

```python
gp.pairanalyzer(titanic, hue='survived', markers='+')
```
![ggpairs_titanic_marker.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/610167/7615be7d-161b-5dc5-a422-8ad40054f475.png)

List指定することで、hueごとに形状を変えることもできます。

```python
gp.pairanalyzer(titanic, hue='survived', markers=['s','X'])
```
![ggpairs_titanic_manymarker.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/610167/1bade18c-60b4-3a42-b985-cefdeab0c96e.png)

### height, aspect
グラフの高さと縦横比を指定します

```python
gp.pairanalyzer(titanic, hue='survived', height=2, aspect=2)
```
![ggpairs_titanic_heightaspect.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/610167/e130bf01-fd1d-6988-e062-709e64020a4d.png)

### その他の引数（dropna, lower_kws, diag_kws, grid_kws）
ベースとしたPairGridの仕様をそのまま使用していますが、
使いどころが分からなかったので本ページでは割愛します。
[仕様はこちら参照ください](https://seaborn.pydata.org/generated/seaborn.PairGrid.html?highlight=pairgrid#seaborn.PairGrid)
※その他の引数は動作テストも実施していないので、もしバグ等見つけた場合はコメント頂けるとありがたいです。

# 余談
本題とは直接関係ありませんが、タイタニック号のデータを本ツールで分析して面白い事実が可視化できたので、記載します
## タイタニック号生還率と相関係数
titanicのデータで、生還を表す"survived"との相関係数を見てみます（下の図の赤枠）
![titanic_corr_survived.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/610167/8434e574-e755-861c-059c-dca5b52482d6.png)

相関係数の絶対値順位は下記のようになります

|順位|変数名|相関係数|
|:-:|:-:|:-:|
|1|adult_male|-0.56|
|2|pclass|-0.34|
|3|fare|0.26|

### ・2位のpclass（等級）、3位のfare（運賃）
どちらも乗船に支払った金額と関係するもので、

**「金持ちの生還率が高い」**
という結果が読み取れます（1等室はデッキが近く、避難距離が短く済んだそうです）
やはり世の中カネなのか‥というやるせない気分になります‥

### ・1位のadult_male（成人男性かどうか）
R = -0.56と生還率と強い相関がありそうです。
これは一見「成人男性は体力があるので生存率が高い」という、これまた当たり前の結論に見えます

しかしよく見ると、相関係数にマイナスがついています。
すなわち「**体力のある成人男性の生存率が有意に低い**」という、
感覚と矛盾した結果が導き出されます。
このことは**上図緑枠で囲ったバブルチャート**でもはっきりと確認できます

### 英国紳士はダテではなかった
気になって調べてみたところ、下のような記事が見付かりました。
https://www.afpbb.com/articles/fp/2564918

どうやら多くの乗客が、
**女性や子供を優先して助ける**
という行動をとった結果が、上記の相関として現れたようです。

驚くべきは、極限状況で数百人もの成人男性が、このような理性的な行動を取った事です。
下の記事のように、船長を始めとしたクルーの指揮が的確だったことも、秩序だった行動の理由として挙げられていますが、
いずれにせよ、英国紳士の自己犠牲の精神には頭が下がりますね
http://blog.livedoor.jp/science_q/archives/1652343.html

### おわりに
以上のように**分析からドラマが生まれる**事もあるのだと、データの価値を再認識することができました。
私も100年後の分析者から後ろ指を差されないよう、清く正しく生きたいと思います…(笑)

## 追記：2020/11/8 凡例マーカが表示されないバグ修正
lowerkinde="boxscatter"を指定して箱ひげが存在しない時、凡例マーカが表示されないバグがあったので、修正いたしました（[トップのGitHubにPush済みです](https://github.com/c60evaporator/seaborn_analyzer)）

【修正前】
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/610167/360f5498-dc1c-1112-4b91-9eef8d73421b.png)

【修正後】
![b.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/610167/a64eaa4e-ff2c-720e-0376-6c84bdd28e63.png)

見ての通り、割と重大なバグです‥‥
今まで放置していてスミマせんでした‥

ひとまずこれで、使い勝手は向上したかと思います！

## 修正：2021/3/20 seaborn.scatterplotクラスの仕様変更対応
"markers"引数未指定時、seaborn.scatterplotクラスの引数"markers"にNoneを入れておりましたが、これでは動作しなくなる仕様変更があったようなので、Trueを入れるよう修正しました。
（本ライブラリの使用法自体は変化ありません）

seabornは開発が活発で仕様変更も多いライブラリなので、適宜対応していこうと思います。

他にも動作しない引数等ございましたら、コメント頂けると有難いです

## 修正：2022/7/12 新パーサー導入に伴い本記事にうまく表示できない部分が生じていたので、修正いたしました