Seabornのオブジェクト・インターフェイスのガイド

# Seabornのオブジェクト・インターフェイスのガイド

seabornは、matplotlibをベースとしたグラフ描画ライブラリで、特に複雑な統計情報を視覚的に示すことに特化している。

https://seaborn.pydata.org/

バージョン0.12より`seaborn.objects`を用いた新しい描画方法が導入され、[公式ドキュメント](https://seaborn.pydata.org/tutorial/objects_interface.html)も整備されているが、特に日本語で書かれた解説記事はごくわずかであり、多くの場合表面的か、APIを全て翻訳した煩雑なものである。

この記事では`seaborn.objects`について一通り学ぶことを目的とする。各クラス・メソッドに関して公式APIへのリンクを貼っているので、より細かい設定はそちらを参照。

## 0. はじめに

ライブラリのインポートを行おう。

```python:インポート
import seaborn as sns
import seaborn.objects as so
```

本記事では説明のために`sns.load_dataset()`から取得できる各種データフレームを用いる。例えば変数`df_iris`は`sns.load_dataset("iris")`に等しい。

```python:Irisデータセットのロード
df_iris = sns.load_dataset("iris")
print(df_iris)
#      sepal_length  sepal_width  petal_length  petal_width    species
# 0             5.1          3.5           1.4          0.2     setosa
# 1             4.9          3.0           1.4          0.2     setosa
# 2             4.7          3.2           1.3          0.2     setosa
# 3             4.6          3.1           1.5          0.2     setosa
# 4             5.0          3.6           1.4          0.2     setosa
# ..            ...          ...           ...          ...        ...
# 145           6.7          3.0           5.2          2.3  virginica
# 146           6.3          2.5           5.0          1.9  virginica
# 147           6.5          3.0           5.2          2.0  virginica
# 148           6.2          3.4           5.4          2.3  virginica
# 149           5.9          3.0           5.1          1.8  virginica
#
# [150 rows x 5 columns]
```

## 1. `Plot()`

[`Plot()`](https://seaborn.pydata.org/generated/seaborn.objects.Plot.html#seaborn-objects-plot)ではグラフの基礎設定、全レイヤーに共通する設定を行う。


まずx軸とy軸のデータを与える。サブグループ化する場合は続いてそれを指定する。

### 1.1. データの指定

`x=`引数に横軸のデータ、`y=`引数にy軸のデータを与える。それぞれのデータは一次元配列でなければならず、また互いに同じ長さでなければならない。

```python:配列からデータを指定する例
so.Plot(x=[0, 1, 2, 3], y=[0, 2, 4, 8])
```

元データがデータフレーム（pandasでもpolarsでも）の列として格納されている場合、第一引数にデータフレームオブジェクトを与えることで、各引数は列名の文字列を使って指定することができる。

```python:データフレームからデータを指定する例
so.Plot(df_iris, x="sepal_length", y="sepal_width")

# もちろんこれでも良い
so.Plot(x=df_iris["sepal_length"], y=df_iris["sepal_width"])

# こういうことをしても良い
so.Plot(df_iris, x="sepal_length", y=df_iris["sepal_width"])
```

この段階ではグラフの枠のみは描画されるが、マーカーは描画されない。

```python
so.Plot(
    df_iris,
    x="sepal_length",
    y="sepal_width",
)
```

> ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394333/709f66b9-b668-ddc1-05d7-632ae30d9aca.png)

後に説明する`.add()`などでレイヤーを追加することで描画される。

```python
so.Plot(
    df_iris,
    x="sepal_length",
    y="sepal_width",
).add(so.Dot())
```

> ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394333/9271d1bf-4af1-1060-3852-c7e0e6bc86af.png)

### 1.2. プロパティ（マーカースタイル）によるサブグルーピング

以下に説明する各引数によって、マーカースタイルをサブグループによって異なるものにすることができる。これらは`Plot()`に与えると全てのレイヤーに共通となる。

プロパティの詳細は[こちら](https://seaborn.pydata.org/tutorial/properties.html)。

`color=`にデータを与えると、それに基づいて色分けがなされる。図右の凡例に注目して欲しい。（サンプルコードでは例を図示するため、後に説明する`.add()`を用いる。）

なお、縁の色だけが変わる`edgecolor=`や塗りの色だけが変わる`fillcolor=`もあるようだが、視覚的にわかりづらいため、使うことはほとんどないだろう。

```python:colors=
plot = so.Plot(
    df_iris,
    x="sepal_length",
    y="sepal_width",
    color="species",  # ←
).add(so.Dot())
```

> ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394333/e6ce0ce7-dbfb-bba2-0f85-f244c060e69f.png)

`alpha=`にデータを与えると透明度が変わる。

```python:alpha=
plot = so.Plot(
    df_iris,
    x="sepal_length",
    y="sepal_width",
    alpha="species",  # ←
).add(so.Dot())
```

> ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394333/7e37a382-2fab-3ef8-ecaa-e7de0a847b44.png)

`marker=`にデータを与えると、ドットの種類が変わる。

```python:marker=
plot = so.Plot(
    df_iris,
    x="sepal_length",
    y="sepal_width",
    marker="species",  # ←
).add(so.Dot())
```

> ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394333/eec75e4f-faa5-8d77-4db1-fc9adca7cb16.png)

`pointsize=`にデータを与えると、ドットの大きさが変わる。

```python:pointsize=
plot = so.Plot(
    df_iris,
    x="sepal_length",
    y="sepal_width",
    pointsize="species",  # ←
).add(so.Dot())
```

> ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394333/0753e6e9-f7e9-c1f9-af09-b82746ecafcc.png)

`linewidth=`にデータを与えると、線の太さが変わる。

```python:linewidth=
so.Plot(
    df_iris,
    x="sepal_length",
    y="sepal_width",
    linewidth="species",  # ←
).add(so.Line())
```

> ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394333/a1fc8688-25ae-718c-b92b-e62900c659fd.png)

`linestyle=`にデータを与えると、線の種類が変わる。

```python:linestyle=
so.Plot(
    df_iris,
    x="sepal_length",
    y="sepal_width",
    linestyle="species",  # ←
).add(so.Line())
```

> ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394333/5a88b482-d75c-bc76-80fb-bd7c796608b6.png)

### 1.3. Plotのメソッド

- [`.add()`](https://seaborn.pydata.org/generated/seaborn.objects.Plot.add.html#seaborn-objects-plot-add): プロットを描画するレイヤーの追加。

    - 第一引数にマークオブジェクト（[§2](#2-プロットの種類)）を与える。
    - 任意で第二引数以降にスタッツオブジェクト（[§3](#3-統計処理)）とムーブオブジェクト（[§4](#4-ムーブオブジェクト)）を与える。
    - 通常は自動で決定されるが、任意で`orient=`引数にベースライン（一部のグラフの描画方法に影響する）を`x`軸か`y`軸にするかを指定することができる。日付時刻型や離散型・カテゴリー型が有る場合はそちらがベースラインと考えて良い。

- [`.scale()`](https://seaborn.pydata.org/generated/seaborn.objects.Plot.scale.html#seaborn-objects-plot-scale): x/y軸やサブグルーピングのスケールの変更・詳細設定（[§5](#5-xy軸やサブグルーピングのスケール--scale)）
- [`.facet()`](https://seaborn.pydata.org/generated/seaborn.objects.Plot.facet.html#seaborn-objects-plot-facet): サブプロットの設定（x/y軸が同一で、異なるサブグループのグラフを並べる場合）
- [`.pair()`](https://seaborn.pydata.org/generated/seaborn.objects.Plot.pair.html#seaborn-objects-plot-pair): サブプロットの設定（x/y軸が異なる、同一データのグラフを並べる場合）
- [`.share()`](https://seaborn.pydata.org/generated/seaborn.objects.Plot.share.html#seaborn-objects-plot-share): サブプロット時のx/y軸の共有に関する設定
- [`.layout()`](https://seaborn.pydata.org/generated/seaborn.objects.Plot.layout.html#seaborn-objects-plot-layout): グラフレイアウトの設定
- [`.label()`](https://seaborn.pydata.org/generated/seaborn.objects.Plot.label.html#seaborn-objects-plot-label): グラフのラベルの設定
- [`.limit()`](https://seaborn.pydata.org/generated/seaborn.objects.Plot.limit.html#seaborn-objects-plot-limit): x/y軸の範囲の設定
- [`.theme()`](https://seaborn.pydata.org/generated/seaborn.objects.Plot.theme.html#seaborn-objects-plot-theme): 視覚テーマに関する設定

## 2. プロットの種類

[`.add()`メソッド](https://seaborn.pydata.org/generated/seaborn.objects.Plot.add.html#seaborn-objects-plot-add)の第一引数`mark=`には、マークオブジェクトと通称される、プロットの種類を与える。

### 2.1. 散布図 — `so.Dot()`

散布図（あるいはそれに類する、データを点で表現する図）は[`so.Dot()`](https://seaborn.pydata.org/generated/seaborn.objects.Dot.html#seaborn-objects-dot)である。

```python:散布図1: Dot
so.Plot(df_iris, x="sepal_length", y="sepal_width", color="species").add(so.Dot())
```

> ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394333/29ba986f-d027-6ee1-bdf6-302e048eaa18.png)

[`so.Dots()`](https://seaborn.pydata.org/generated/seaborn.objects.Dots.html#seaborn-objects-dots)を使うこともできる。これは`so.Dot()`においてプロットの数が多すぎるために重なっていて見づらい場合に特に有用である。各プロパティの（デフォルトの）値が異なり、サイズがやや小さく、かつ半透明となっている。

```python:散布図2: Dots
so.Plot(df_iris, x="sepal_length", y="sepal_width", color="species").add(so.Dots())
```

> ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394333/f4c0b3fa-b76f-292b-47eb-9262aa341816.png)

また、ドットを描画する`so.Dot()`に対して、ベースラインと平行な短い線を描画する[`so.Dash()`](https://seaborn.pydata.org/generated/seaborn.objects.Dash.html#seaborn-objects-dash)もある。

```python:散布図3: Dash
so.Plot(df_iris, x="sepal_length", y="sepal_width", color="species").add(so.Dash())
```

> ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394333/c8572e9f-ffd4-5601-a12b-5b73c577fb8a.png)

### 2.2. 折れ線グラフ — `so.Path()`, `so.Line()`

折れ線グラフの類は[`so.Path()`](https://seaborn.pydata.org/generated/seaborn.objects.Path.html#seaborn-objects-path)または[`so.Line()`](https://seaborn.pydata.org/generated/seaborn.objects.Line.html#seaborn-objects-line)を用いる。

`so.Path()`は与えられたデータを順番に線で結ぶが、`so.Line()`はソートした状態で線が引かれる。

```python:折れ線グラフ1: Path
# 折れ線は元の配列通り (x, y) = (1, 10) → (3, 20) → (2, 30) →  (4, 40) を通る
so.Plot(x=[1, 3, 2, 4], y=[10, 20, 30, 40]).add(so.Path())
```

> ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394333/d3083bf0-def9-58a7-b3d7-1959b2b11708.png)

```python:折れ線グラフ2: Line
# 折れ線はx軸がソートされて (x, y) = (1, 10) → (2, 30) → (3, 20) →  (4, 40) を通る
so.Plot(x=[1, 3, 2, 4], y=[10, 20, 30, 40]).add(so.Line())
```

> ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394333/e574c088-cc38-fd3e-f23c-e1833ab518ab.png)

`so.Line()`においてソートされる軸は自動で決定されるが、`.add()`（`so.Plot()`ではない）に`orient="x"`または`orient="y"`を渡すことで制御できる。

ドットありの折れ線グラフは、①`marker=`引数を指定する、②`so.Dot()`のレイヤーと重ねる、の2つの方法がある。

```python:折れ線グラフ3
# 1. `marker=`引数を指定する
so.Plot(
    df_flights, x="month", y="passengers", color=df_flights["year"].astype("string")
).add(so.Line(marker="o"))

# 2. `so.Dot()`のレイヤーと重ねる
so.Plot(
    df_flights, x="month", y="passengers", color=df_flights["year"].astype("string")
).add(so.Line()).add(so.Dot())
```

> ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394333/9461f2f0-c3b3-6673-4074-fe19aa9c21f9.png)
>
> ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394333/b97d0eef-f061-7879-183e-457a213f5f68.png)

`so.Dot()`に対してデータ数が多い場合のための`so.Dots()`があったように、`so.Path()`, `so.Line()`にも対応する[`so.Paths()`](https://seaborn.pydata.org/generated/seaborn.objects.Paths.html#seaborn-objects-paths), [`so.Lines()`](https://seaborn.pydata.org/generated/seaborn.objects.Lines.html#seaborn-objects-lines)がある。

### 2.2.1. 折れ線グラフ＋塗りつぶし — `so.Area()`, `so.Band()`

[`so.Area()`](https://seaborn.pydata.org/generated/seaborn.objects.Area.html#seaborn-objects-area)は折れ線とベースラインで挟まれた領域を塗りつぶす。`.add()`に`orient="x"`または`orient="y"`を渡すことで制御できる。ここで`orient=`は`so.Line()`と同様にソートされる軸も決定する。

```python:折れ線グラフ4: Area
so.Plot(x=[1, 3, 2, 4], y=[10, 20, 30, 40]).add(so.Area())

# y軸ベースの Area (枠線無し) + Line の例
so.Plot(x=[1, 3, 2, 4], y=[10, 20, 30, 40]).add(so.Area(edgewidth=0), orient="y").add(
    so.Line(), orient="y"
)
```

> ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394333/948b5ad8-44a4-6c01-ad82-30b3865b8303.png)
>
> ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394333/150ceac1-bf51-5a64-58a6-4dca920b00ee.png)

[`so.Band()`](https://seaborn.pydata.org/generated/seaborn.objects.Band.html#seaborn-objects-band)はいくつかの使い方がある（以下の文章は`orient="x"`の場合で説明する）。

①元データの`x=`配列が全ユニークではない場合、すなわちy→xが単射でない場合、すなわち1つのxに対して2つ以上のyの値が対応する場合、その最大yと最小yの間を塗りつぶす。

```python:折れ線グラフ5: Band1
so.Plot(df_flights, x="month", y="passengers").add(so.Band())
```

> ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394333/943c2442-b23d-f363-5267-e63f51cd2608.png)

②`Plot()`に`y=`ではなく`ymin=`と`ymax=`が与えられている場合、2つの折れ線グラフ（`ymin=`と`ymax=`）の間を塗りつぶす。

```python:折れ線グラフ5: Band2
so.Plot(
    x=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
    ymax=[0, 2, 4, 9, 16, 25, 36, 49, 64, 81, 100],
    ymin=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
).add(so.Band())
```

> ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394333/fa0560bd-037e-581c-3caa-a459e336ed97.png)

③`so.Est()`を使って信頼区間の図示に用いる。[§3.2](#32-%E4%BF%A1%E9%A0%BC%E5%8C%BA%E9%96%93%E6%A8%99%E6%BA%96%E8%AA%A4%E5%B7%AE%E3%81%AA%E3%81%A9--soest)参照。

### 2.3. 棒グラフ — `so.Bar()`

棒グラフの類は[`so.Bar()`](https://seaborn.pydata.org/generated/seaborn.objects.Bar.html#seaborn-objects-bar)を用いる。

```python:棒グラフ1: Bar
so.Plot(df_flights[df_flights["year"] == 1960], x="month", y="passengers").add(so.Bar())
```

> ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394333/4aef2ec7-2952-b2f5-a36c-868653880e1a.png)

棒の向きは自動で決定されるが、`.add()`（`so.Bar()`ではない）に`orient="x"`（縦棒）または`orient="y"`（横棒）を渡すことで制御できる。

```python
so.Plot(x=[1, 3, 2, 4], y=[10, 20, 30, 40]).add(so.Bar(), orient="y")
```

> ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394333/71695c39-43d2-3252-f68e-44af0c0fe342.png)

`so.Dot()`に対してデータ数が多い場合のための`so.Dots()`があったように、`so.Bar()`にも対応する[`so.Bars()`](https://seaborn.pydata.org/generated/seaborn.objects.Bars.html#seaborn-objects-bars)がある。

### 2.4. `so.Range()`

[`so.Range()`](https://seaborn.pydata.org/generated/seaborn.objects.Range.html#seaborn-objects-range)は、`so.Band()`の棒グラフ（というか線）版だが、実用的にはほぼ`so.Est()`を用いたエラーバーやデータ範囲の図示にしか使われないと思われる。[§3.2](#32-%E4%BF%A1%E9%A0%BC%E5%8C%BA%E9%96%93%E6%A8%99%E6%BA%96%E8%AA%A4%E5%B7%AE%E3%81%AA%E3%81%A9--soest)参照。

### 2.5. 文字 – `so.Text`

[`so.Text()`](https://seaborn.pydata.org/generated/seaborn.objects.Text.html#seaborn-objects-text)は、散布図のドットの代わりに文字を描画する。`color=`引数で文字色、`valign=`/`halign=`引数で文字揃え（描画方向）を指定できる。

## 3. 統計処理

データを直接xy座標としてプロットするのではなく何らかの統計処理を通した形で表現するには、[`.add()`メソッド](https://seaborn.pydata.org/generated/seaborn.objects.Plot.add.html#seaborn-objects-plot-add)の第二引数`transforms=`にスタッツオブジェクトと通称されるものを渡す。

### 3.1. 集計（平均・合計など） — `so.Agg()`

[`so.Agg()`](https://seaborn.pydata.org/generated/seaborn.objects.Agg.html#seaborn-objects-agg)により、ベースラインと垂直方向のデータ（`add.(orient="x")`のときはy）を集計することができる。pandasでいうと、`df.groupby(x列)[y列].agg()`が行われると考えて良い。

第一変数`func=`で集計の種類を指定する。デフォルトは平均値`func="mean"`となっており、それ以外によく使うのは合計値`func="sum"`と中央値`func="median"`だろう。

例えば次のような時系列データを

```python:複数の折れ線グラフ
(
    so.Plot(df_flights, x="month", y="passengers", color="year")
    .scale(color=so.Nominal())
    .add(so.Line())
)
```

> ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394333/5c737f9d-b252-c17b-e750-eec12157b387.png)

月ごとに平均する。

```python:集計1: Agg
(
    so.Plot(df_flights, x="month", y="passengers")
    .scale(color=so.Nominal())
    .add(so.Line(), so.Agg("mean"))  # ←
    .add(so.Band())
)
```

> ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394333/6319ffe3-9121-55c3-393d-183a3aaf8f05.png)

また、以下のような観察データを

```python:複数の観察データ
so.Plot(df_iris, x="species", y="sepal_length").add(so.Dots(), so.Jitter())
```

> ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394333/e58b53e5-dee9-7bcf-e925-08a5abae1159.png)

種類ごとに平均する。

```python:集計2: Agg
so.Plot(df_iris, x="species", y="sepal_length").add(so.Bar(), so.Agg("mean"))
```

> ![temp.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394333/15243928-b53a-3020-e996-d96a041d6f3a.png)

#### 3.1.1. データの個数 — `so.Count()`

データ数をカウントする場合は[`so.Count()`](https://seaborn.pydata.org/generated/seaborn.objects.Count.html#seaborn-objects-count)を用いる（`so.Agg("count")`を使っても良い）。`so.Count()`を使う場合は`Plot()`引数の`x=`または`y=`を省略できる。

```python:集計3: Count
so.Plot(df_iris, x="species").add(so.Bar(), so.Count()).label(y="Count")
```

> ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394333/d0b17a7e-d7de-78ef-ce81-5e5291a7804a.png)

#### 3.1.2. パーセンタイル値 — `so.Perc()`

パーセンタイル値を計算する場合は[`so.Perc()`](https://seaborn.pydata.org/generated/seaborn.objects.Perc.html#seaborn-objects-perc)を用いる。2つの指定方法がある。

①第一引数`k=`に0～100の数値のリストを与える。

```python:集計4: Perc
(
    so.Plot(df_iris, x="species", y="sepal_length")
    .add(so.Dots(), so.Jitter())
    .add(so.Dash(), so.Perc([0, 50, 100]))  # = 最小値・中央値・最大値
)
```

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394333/ab78e7e2-5936-56f1-cee4-aa968d13058c.png)

②第一引数`k=`にパーセンタイルの個数を与える。

```python:集計5: Perc
(
    so.Plot(df_iris, x="species", y="sepal_length")
    .add(so.Dots(), so.Jitter())
    .add(so.Dash(), so.Perc(5))  # = 0%, 25%, 50%, 75%, 100%
)
```

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394333/921924f8-17db-ab9f-b856-33fa1032e2b6.png)

### 3.2. 信頼区間・標準誤差など — `so.Est()`

[`so.Est()`](https://seaborn.pydata.org/generated/seaborn.objects.Est.html#seaborn-objects-est)は信頼区間・標準誤差等を計算する。`so.Band()`あるいは`so.Range()`と組み合わせて、データ範囲やエラーバー等を図示する場合に用いる。

`errorbar=`引数で計算方法を指定する。デフォルトでは`("ci", 95)`というタプルが指定されており、これはブートストラップ法による95%信頼区間を意味する。`("pi", 数値)`でパーセンタイル区間、`("se", スケール)`で標準偏差、`("se", スケール)`で標準誤差となる（数値・スケールは省略可能）。[エラーバーに関する公式チュートリアル](https://seaborn.pydata.org/tutorial/error_bars.html#statistical-estimation-and-error-bars)も参照。

```python:信頼区間: Est
(
    so.Plot(df_flights, x="month", y="passengers")
    .add(so.Line(), so.Agg("mean"))
    .add(so.Band(), so.Est())
)
```

> ![temp.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394333/58e61653-ffb0-359f-0b3b-f4bd14a3a776.png)

```python:エラーバー: Est
(
    so.Plot(df_iris, x="species", y="sepal_length")
    .add(so.Dot(), so.Agg("median"))
    .add(so.Range(linestyle=":"), so.Est(errorbar=("pi", 95)))  # 95%tile区間（点線）
    .add(so.Range(), so.Est(errorbar="sd"))  # 1σ区間（実線）
)
```

> ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394333/6969c679-7f6f-811b-8bd5-b939c3689b9d.png)

### 3.3. ヒストグラム — `so.Hist()`

[`so.Hist()`](https://seaborn.pydata.org/generated/seaborn.objects.Hist.html#seaborn-objects-hist)でヒストグラムを計算する。マークオブジェクトは`so.Bars()`を用いることが推奨されている。

- `stat=`: 統計処理方法を文字列で指定。棒グラフの形は変わらないが縦軸（y軸）の意味が変わる。

    - `stat="count"`: 縦軸はデータ数
    - `stat="percent"`: 縦軸は母集団に占める割合（0%～100%）
    - `stat="probability"`: 縦軸は母集団に占める割合（0～1）
    - `stat="density"`: 密度（ビン面積合計が1）

- `bins=`: にビン（柱）の本数または各階級区間（境界）のリスト
- `binwidth=`: ビンの幅
- `binrange=`: 集計対象区間をタプル`(min, max)`で指定
- `cumulative=True`: グラフを累積分布に

```python:ヒストグラム1: Hist
so.Plot(df_iris, x="sepal_length").add(
    so.Bars(), so.Hist("frequency", binwidth=0.5, binrange=(4, 8))
)
```

> ![temp.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394333/c08f96e7-6325-f374-9afd-5c8e0296bf46.png)

### 3.4. カーネル密度分布 — `so.KDE()`

[`so.KDE()`](https://seaborn.pydata.org/generated/seaborn.objects.KDE.html#seaborn-objects-kde)でカーネル密度推定を行う。

```python:カーネル密度分布1: KDE
so.Plot(df_iris, x="sepal_length", color="species").add(so.Area(), so.KDE())
```

> ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394333/a0a4a0c6-5846-aa9c-9fec-51963182ff3b.png)

ヒストグラムと重ねる例。

```python:カーネル密度分布2: KDE
(
    so.Plot(df_iris, x="sepal_length")
    .add(so.Bars(alpha=0.3), so.Hist("density", binwidth=0.5, binrange=(4, 8)))
    .add(so.Line(), so.KDE())
)
```

> ![temp.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394333/5a2f9b60-4405-48e4-794f-9ad6d440867c.png)

### 3.5. 直線・曲線近似 — `so.PolyFit()`

分布の直線・曲線近似は[`so.PolyFit()`](https://seaborn.pydata.org/generated/seaborn.objects.PolyFit.html#seaborn-objects-polyfit)を用いる。

デフォルトでは2次曲線で近似される（下の例はわかりづらいかもしれないが）。

```python:2次曲線近似: PolyFit
(
    so.Plot(df_tips, x="total_bill", y="tip", color="time")
    .add(so.Dot())
    .add(so.Line(), so.PolyFit())
)
```

> ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394333/eeb385ab-1399-259f-d8bb-ef97f421584d.png)


第一引数`order=`に`1`を指定すると1次曲線（つまり直線）、`3`を指定すると3次曲線、という具合になる。

```python:直線近似: PolyFit
(
    so.Plot(df_tips, x="total_bill", y="tip", color="time")
    .add(so.Dot())
    .add(so.Line(), so.PolyFit(1))
)
```

> ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394333/288b16b7-c36d-2360-2bf4-64c2dd7162b1.png)

## 4. ムーブオブジェクト

[`.add()`メソッド](https://seaborn.pydata.org/generated/seaborn.objects.Plot.add.html#seaborn-objects-plot-add)の第二引数`transforms=`（スタッツオブジェクトを渡している場合はその後）にムーブオブジェクトと通称されるものを渡すことで、グラフの描き方の調整ができる。このあたりは言葉で説明するより図を見てもらったほうが早い。

### 4.1. サブグループの分割 — `so.Dodge()`

サブグループ化（[§1.2](#12-%E3%83%97%E3%83%AD%E3%83%91%E3%83%86%E3%82%A3%E3%83%9E%E3%83%BC%E3%82%AB%E3%83%BC%E3%82%B9%E3%82%BF%E3%82%A4%E3%83%AB%E3%81%AB%E3%82%88%E3%82%8B%E3%82%B5%E3%83%96%E3%82%B0%E3%83%AB%E3%83%BC%E3%83%94%E3%83%B3%E3%82%B0)）している場合、デフォルトでは重なってプロットされるが、[`so.Dodge()`](https://seaborn.pydata.org/generated/seaborn.objects.Dodge.html#seaborn-objects-dodge)を与えると、ベースライン方向で分割される。離散型の場合に使う。

```python:Dodge
# 重なっている棒グラフ
so.Plot(df_tips, "day", "total_bill", color="sex").add(so.Bar(), so.Count())

# `so.Dodge()`を与えると横に分割される
so.Plot(df_tips, "day", "total_bill", color="sex").add(so.Bar(), so.Count(), so.Dodge())
```

> ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394333/2a06785a-6a05-72f6-42bd-228116f99bbc.png)
>
> ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394333/02d26cf8-d3d0-7a5a-f4c0-c638fae40b93.png)

### 4.2. サブグループの積み上げ — `so.Stack()`

サブグループ化（[§1.2](#12-%E3%83%97%E3%83%AD%E3%83%91%E3%83%86%E3%82%A3%E3%83%9E%E3%83%BC%E3%82%AB%E3%83%BC%E3%82%B9%E3%82%BF%E3%82%A4%E3%83%AB%E3%81%AB%E3%82%88%E3%82%8B%E3%82%B5%E3%83%96%E3%82%B0%E3%83%AB%E3%83%BC%E3%83%94%E3%83%B3%E3%82%B0)）している場合、デフォルトでは重なってプロットされるが、[`so.Stack()`](https://seaborn.pydata.org/generated/seaborn.objects.Stack.html#seaborn-objects-stack)を与えると、ベースラインと垂直方向に積み上げられる。

```python:Stack1
# 重なっている棒グラフ
so.Plot(df_tips, "day", "total_bill", color="sex").add(so.Bar(), so.Count())

# `so.Stack()`を与えると積み上げられる
so.Plot(df_tips, "day", "total_bill", color="sex").add(so.Bar(), so.Count(), so.Stack())
```

> ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394333/2a06785a-6a05-72f6-42bd-228116f99bbc.png)
>
> ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394333/062a8076-99cd-ac34-d581-d62a50bbd63f.png)

```python:Stack2
# 重なっている分布図（サブグループごとの分布がわかりやすい）
so.Plot(df_iris, x="sepal_length", color="species").add(so.Area(), so.KDE())

# `so.Stack()`を与えると積み上げられる（データ全体の分布とサブグループの割合がわかりやすい）
so.Plot(df_iris, x="sepal_length", color="species").add(so.Area(), so.KDE(), so.Stack())
```

> ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394333/a0a4a0c6-5846-aa9c-9fec-51963182ff3b.png)
>
> ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394333/0872d963-4dd7-92f0-5ed8-4938f0c7907a.png)

### 4.3. データに揺れを与える — `so.Jitter()`

[`so.Jitter()`](https://seaborn.pydata.org/generated/seaborn.objects.Jitter.html#seaborn-objects-jitter)はデータに揺れを与える。多くの場合、次の例のような離散型散布図に使う。

```python:Jitter1
# x軸が離散的でドットが重なっている散布図
so.Plot(df_iris, x="species", y="sepal_length").add(so.Dots())

# `so.Jitter()`を与えて横に散らすと分布がわかりやすくなる
so.Plot(df_iris, x="species", y="sepal_length").add(so.Dots(), so.Jitter())
```

> ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394333/1d1f0363-3631-102a-b5db-c45a2b45b6a5.png)
>
> ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394333/b1990e8c-36dd-bcfe-cf5d-7f69887e2444.png)

第一引数`width=`で振れ幅を指定できる。

```python:Jitter2
so.Plot(df_iris, x="species", y="sepal_length").add(so.Dots(), so.Jitter(0.8))
```

> ![temp.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394333/99300629-6382-5eb4-2c50-39a6b3369965.png)

### 4.4. データを平行移動 — `so.Shift()`

[`so.Shift(x, y)`](https://seaborn.pydata.org/generated/seaborn.objects.Shift.html#seaborn-objects-shift)で`x`/`y`分だけデータをずらすことができる。

```python:Shift
# データ点と標準偏差を示す縦棒が重なっている状態
(
    so.Plot(df_iris, x="species", y="sepal_length")
    .add(so.Dots(), so.Jitter())
    .add(so.Range(), so.Est(errorbar="sd"))
)

# `so.Shift()`を用いてデータ点を左に、標準偏差を示す縦棒を右に移動
(
    so.Plot(df_iris, x="species", y="sepal_length")
    .add(so.Dots(), so.Jitter(), so.Shift(-0.1))
    .add(so.Range(), so.Est(errorbar="sd"), so.Shift(0.1))
)
```

> ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394333/31f49fa9-d8e2-f129-876c-f378e5e3dc99.png)
>
> ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394333/9c1dd7bf-6c2e-2d6b-f68e-3af2e4aadb47.png)

## 5. x/y軸やサブグルーピングのスケール — `.scale()`

プロットの[`.scale()`メソッド](https://seaborn.pydata.org/generated/seaborn.objects.Plot.scale.html#seaborn-objects-plot-scale)でx/y軸やサブグルーピングのスケールを設定する。

### 5.1. 対数軸

`x=`/`y=`引数に`"log"`を指定すると対数軸となる。

```python:対数軸
# 通常
so.Plot(df_planets, x="orbital_period", y="mass").add(so.Dot())

# x軸を対数スケールに変更
so.Plot(df_planets, x="orbital_period", y="mass").add(so.Dot()).scale(x="log")
```

> ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394333/45774382-6996-247c-69ff-2d8fdcc1a5b0.png)
>
> ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394333/2e091582-e521-195b-fec7-e20c7cf1db54.png)

### 5.2. 軸・サブグループを離散化

数値データや時系列データは、デフォルトでは連続変数として扱われる。離散型変数として扱いたい場合は、`x=`/`y=`引数（もちろん`color=`等も可）に[`so.Nominal()`](https://seaborn.pydata.org/generated/seaborn.objects.Nominal.html#seaborn-objects-nominal)を与える。

```python:軸を離散化
# `df_glue["Year"]`列は整数型であるため連続量として図示されている。
(
    so.Plot(df_glue, x="Year", y="Score")
    .add(so.Dot(), so.Jitter())
)

# x軸を離散データとして扱う
(
    so.Plot(df_glue, x="Year", y="Score")
    .add(so.Dot(), so.Jitter())
    .scale(x=so.Nominal())
)
```

> ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394333/ac9dd2ab-5f3f-dc03-f566-58db65f60161.png)
>
> ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394333/c8da406e-398b-977b-e154-4743e42fea08.png)

```python:サブグループの配色を離散化
# `df_glue["Year"]`列は整数型であるため連続量として図示されている。
(
    so.Plot(df_glue, x="Encoder", y="Score", color="Year")
    .add(so.Dot(), so.Jitter())
)

# サブグループを離散データとして扱う
(
    so.Plot(df_glue, x="Encoder", y="Score", color="Year")
    .add(so.Dot(), so.Jitter())
    .scale(color=so.Nominal())
)
```

> ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394333/68a9a4d2-7f2a-203f-d6f6-0c99226ba9b2.png)
>
> ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394333/31c664e5-15a4-c226-23e2-a36a3605a2d2.png)

### 5.3. 配色の変更

`color=`引数にカラーパレットの名前（[参照1](https://matplotlib.org/stable/users/explain/colors/colormaps.html#choosing-colormaps), [参照2](https://seaborn.pydata.org/tutorial/color_palettes.html#choosing-color-palettes)）や色名（[参照](https://matplotlib.org/stable/gallery/color/named_colors.html#list-of-named-colors)）を与えるとサブグループの配色を変更できる。

```python:カラーパレットの変更
# デフォルト
(
    so.Plot(df_healthexp, x="Life_Expectancy", y="Spending_USD", color="Country")
    .add(so.Line(marker="."))
)

# パレットを変更
(
    so.Plot(df_healthexp, x="Life_Expectancy", y="Spending_USD", color="Country")
    .add(so.Line(marker="."))
    .scale(color="twilight")
)
```

> ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394333/28091d56-960e-954d-88c1-5d96ddf54653.png)
>
> ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394333/4219e0a6-d18f-24fd-b369-015d0d4b4a9c.png)

```python:色を直接指定
# デフォルト（データが示す色と図の配色が一致していないのでわかりづらい）
(
    so.Plot(df_taxis, x="distance", color="color")
    .add(so.Area(), so.KDE())
)

# 色を指定
(
    so.Plot(df_taxis, x="distance", color="color")
    .add(so.Area(), so.KDE())
    .scale(color=["goldenrod", "forestgreen"])
)
```

> ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394333/5c066f7c-1cb7-55ad-268e-b865e7bfa75c.png)
>
> ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394333/62673cb3-8a53-e69d-6629-2607db7fa0ab.png)

## 6. サブプロットの設定

### 6.1. サブグループ別のサブプロット — `.facet()`

プロットの[`.facet()`メソッド](https://seaborn.pydata.org/generated/seaborn.objects.Plot.facet.html#seaborn-objects-plot-facet)にサブグループ配列を与えると、グラフがサブグループごとに分割される。それぞれのサブプロットのx軸とy軸は共通である。

第一変数`col=`は横に分割され、第二変数`row=`は縦に分割される。

```python:サブプロット1: facet
# 元
(
    so.Plot(df_iris, x="sepal_length", y="sepal_width", color="species")
    .add(so.Dot())
)

# 種類に基づいて横分割
(
    so.Plot(df_iris, x="sepal_length", y="sepal_width", color="species")
    .add(so.Dot())
    .facet(col="species")
)

# 種類に基づいて縦分割
(
    so.Plot(df_iris, x="sepal_length", y="sepal_width", color="species")
    .add(so.Dot())
    .facet(row="species")
)
```

> ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394333/326fd847-33ac-958a-e1b2-6305ccf0a851.png)
>
> ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394333/d0c82ef4-9064-1065-bf79-ab466af6c586.png)
>
> ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394333/7ea722e8-abe3-3219-bf04-7dfa07c783fb.png)

縦横それぞれ別の属性でサブグループ化することも可能。

```python:サブプロット2: facet
(
    so.Plot(df_titanic, x="age", color="alive")
    .add(so.Bar(), so.Hist(binwidth=5, binrange=(0, 100)), so.Stack())
    .facet(col="class", row="sex")
)
```

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394333/da7ab1c1-eef8-7134-00e3-ae1702e6363f.png)

### 6.2. サブグループ別のサブプロット — `.pair()`

プロットの[`.pair()`メソッド](https://seaborn.pydata.org/generated/seaborn.objects.Plot.pair.html#seaborn-objects-plot-pair)は、`x=`/`y=`をリストで受け取ることができ、異なるx/y軸を持つサブプロットを作ることができる。`.pair()`を用いる場合は`so.Plot()`の`x=`/`y=`引数は空でいい。

```python:サブプロット3: pair
(
    so.Plot(df_iris, color="species")
    .add(so.Dot())
    .pair(x=["sepal_length", "sepal_width"], y=["petal_length"])
)
```

> ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394333/af247474-6847-2cb6-2e97-0a8176b5861f.png)

```python:サブプロット4: pair
(
    so.Plot(df_iris, color="species")
    .add(so.Dots())
    .pair(x=["sepal_length", "sepal_width"], y=["petal_length", "petal_width"])
)
```

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394333/1173c236-ef88-5f51-90e7-e63440519833.png)

### 6.3. サブプロット軸の共有設定 ‒ `.share()`

プロットの[`.share()`メソッド](https://seaborn.pydata.org/generated/seaborn.objects.Plot.share.html#seaborn-objects-plot-share)の`x=`/`y=`引数に`True`を`False`を与えることでサブプロットの軸の共有設定を指定できる。

## 7. その他のグラフの調整

### 7.1. ラベルの設定 — `.label()`

プロットの[`.label()`メソッド](https://seaborn.pydata.org/generated/seaborn.objects.Plot.label.html#seaborn-objects-plot-label)で図のラベルを設定できる。引数の名前は直感通り。

```python:ラベルの設定: label
(
    so.Plot(df_iris, x="sepal_length", y="sepal_width", color="species", pointsize="petal_length")
    .add(so.Dot())
    .label(title="title", x="x", y="y", color="color", pointsize="pointsize")
)
```

> ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394333/3f25c922-8c4b-7b53-b9db-cabeaf57c411.png)

### 7.2. x/y軸の範囲設定 — `.limit()`

プロットの[`.limit()`メソッド](https://seaborn.pydata.org/generated/seaborn.objects.Plot.limit.html#seaborn-objects-plot-limit)でx軸/y軸の表示範囲を設定できる。

```python
(
    so.Plot(df_iris, x="sepal_length", y="sepal_width", color="species")
    .add(so.Dot())
    .limit(x=(5, 7), y=(2, 4))
)
```

> ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394333/0d692465-e53a-9685-d109-65a39edd95d9.png)