Pythonでggplot2のプロットを作成する（plotnine）

Pythonには、[plotnine](https://plotnine.readthedocs.io/en/v0.12.4/)というデータ可視化ライブラリがあります。
plotnineは[ggplot2](https://ggplot2.tidyverse.org)をもとにしており、plotnineを用いることで、Pythonでggplot2のプロットを作成することができます。
今回は、irisデータセットの可視化を行います。
実行環境：MacBook Air M1, 2020

# Pythonのインストール
以下のサイトにアクセスし、Latest Python 3 Release - Python 3.12.1をクリックします。
https://www.python.org/downloads/macos/
![スクリーンショット 2023-12-09 1.58.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3569835/a99c13f0-63a0-26d8-d755-ddbd24cd2ea4.png)

開いたページを下にスクロールし、macOS 64-bit universal2 installerをクリックします。

![スクリーンショット 2023-12-09 1.59.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3569835/de2e9e8c-97fe-df1b-bf5b-7202e5691a42.png)

インストーラをダウンロードしたら、インストールを進めます。

![スクリーンショット 2023-12-09 2.00.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3569835/51bc1c2e-fbba-a468-09ac-b8722f983a3f.png)

ターミナルでPythonのバージョンを確認します。
```zsh
% python3 -V
Python 3.12.1
```
Python 3.12.1をインストールすることができました。

# 環境構築
今回は、仮想環境を構築し、データ可視化を行います。
ターミナルで以下のコマンドを実行します。
```zsh
% mkdir plotnine
% cd plotnine
% python3 -m venv .venv
% source .venv/bin/activate
```
plotnineディレクトリを作成し、仮想環境の構築と起動を行いました。
次回からは、以下のコマンドのみを実行します。
```zsh
% cd plotnine
% source .venv/bin/activate
```

# ライブラリのインストール
以下のコマンドを実行し、データ可視化に用いるライブラリをインストールします。
```zsh
% pip install ipykernel
% pip install pandas
% pip install plotnine
% pip install scikit-learn
```

# VSCodeのインストール
以下のURLからVSCodeをインストールしました。
https://code.visualstudio.com

# データ可視化
VSCodeを起動し、plotnineディレクトリを開き、iris.ipynbを作成しました。
## ライブラリの読み込み
```Python
import pandas as pd
from plotnine import *
```

## データの読み込み
[sklearn.datasets](https://scikit-learn.org/stable/datasets/toy_dataset.html)からirisデータセットを読み込みます。
```Python
from sklearn.datasets import load_iris
iris = load_iris()
data = pd.DataFrame(data = iris.data, columns = iris.feature_names)
data.head()
```

<div>
<style scoped>
    .dataframe tbody tr th:only-of-type {
        vertical-align: middle;
    }

    .dataframe tbody tr th {
        vertical-align: top;
    }

    .dataframe thead th {
        text-align: right;
    }
</style>
<table border="1" class="dataframe">
  <thead>
    <tr style="text-align: right;">
      <th></th>
      <th>sepal length (cm)</th>
      <th>sepal width (cm)</th>
      <th>petal length (cm)</th>
      <th>petal width (cm)</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>0</th>
      <td>5.1</td>
      <td>3.5</td>
      <td>1.4</td>
      <td>0.2</td>
    </tr>
    <tr>
      <th>1</th>
      <td>4.9</td>
      <td>3.0</td>
      <td>1.4</td>
      <td>0.2</td>
    </tr>
    <tr>
      <th>2</th>
      <td>4.7</td>
      <td>3.2</td>
      <td>1.3</td>
      <td>0.2</td>
    </tr>
    <tr>
      <th>3</th>
      <td>4.6</td>
      <td>3.1</td>
      <td>1.5</td>
      <td>0.2</td>
    </tr>
    <tr>
      <th>4</th>
      <td>5.0</td>
      <td>3.6</td>
      <td>1.4</td>
      <td>0.2</td>
    </tr>
  </tbody>
</table>
</div>

データフレームにアヤメの種類（target）を追加します。

```Python
data['target'] = iris.target
data.loc[data['target'] == 0, 'target'] = "setosa"
data.loc[data['target'] == 1, 'target'] = "versicolor"
data.loc[data['target'] == 2, 'target'] = "virginica"
data.head()
```

<div>
<style scoped>
    .dataframe tbody tr th:only-of-type {
        vertical-align: middle;
    }

    .dataframe tbody tr th {
        vertical-align: top;
    }

    .dataframe thead th {
        text-align: right;
    }
</style>
<table border="1" class="dataframe">
  <thead>
    <tr style="text-align: right;">
      <th></th>
      <th>sepal length (cm)</th>
      <th>sepal width (cm)</th>
      <th>petal length (cm)</th>
      <th>petal width (cm)</th>
      <th>target</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>0</th>
      <td>5.1</td>
      <td>3.5</td>
      <td>1.4</td>
      <td>0.2</td>
      <td>setosa</td>
    </tr>
    <tr>
      <th>1</th>
      <td>4.9</td>
      <td>3.0</td>
      <td>1.4</td>
      <td>0.2</td>
      <td>setosa</td>
    </tr>
    <tr>
      <th>2</th>
      <td>4.7</td>
      <td>3.2</td>
      <td>1.3</td>
      <td>0.2</td>
      <td>setosa</td>
    </tr>
    <tr>
      <th>3</th>
      <td>4.6</td>
      <td>3.1</td>
      <td>1.5</td>
      <td>0.2</td>
      <td>setosa</td>
    </tr>
    <tr>
      <th>4</th>
      <td>5.0</td>
      <td>3.6</td>
      <td>1.4</td>
      <td>0.2</td>
      <td>setosa</td>
    </tr>
  </tbody>
</table>
</div>

## データ可視化
### 棒グラフ
アヤメの種類（target）のカウントを示す棒グラフを作成します。
```Python
(ggplot(data, aes(x = 'target', fill = 'target'))
 + geom_bar())
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3569835/31e6585d-0bc6-8577-f3a7-0a5f4d2af157.png)

### 散布図
がく片の長さとがく片の幅の関係を示す散布図を作成します。
```Python
(ggplot(data, aes(x = 'sepal length (cm)', y = 'sepal width (cm)', color = 'target')) 
 + geom_point())
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3569835/a2f0fc9f-13cb-52f9-1524-d01f7ba864f2.png)

### ヒストグラム
がく片の長さの分布を示すヒストグラムを作成します。
```Python
(ggplot(data, aes(x = 'sepal length (cm)', fill = 'target')) 
 + geom_histogram(position = "identity", alpha = 0.5, bins = 10))
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3569835/82b4ada0-6951-c836-f174-cb4f00d8d64f.png)

### 密度曲線
がく片の長さの分布を示す密度曲線を作成します。
```Python
(ggplot(data, aes(x = 'sepal length (cm)', fill = 'target')) 
 + geom_density(alpha = 0.5))
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3569835/2e2d6d15-461e-8dee-2643-341ed5cc56dc.png)

### 箱ひげ図
がく片の長さの分布を示す箱ひげ図を作成します。
```Python
(ggplot(data, aes(x = 'target', y = 'sepal length (cm)', fill = 'target')) 
 + geom_boxplot())
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3569835/1a9ae237-78c6-fd33-2f09-955e733e09bf.png)

### バイオリンプロット
がく片の長さの分布を示すバイオリンプロットを作成します。
```Python
(ggplot(data, aes(x = 'target', y = 'sepal length (cm)', fill = 'target')) 
 + geom_violin())
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3569835/a1daab79-9def-39a6-fc0c-0e4c09c36956.png)

### 密度プロット
がく片の長さとがく片の幅の関係を示す密度プロットを作成します。
```Python
(ggplot(data, aes(x = 'sepal length (cm)', y = 'sepal width (cm)', color = 'target')) 
 + geom_point()
 + stat_density_2d())
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3569835/54db1cf1-fa13-a039-13be-e8c581495ec8.png)

plotnineを用いてデータ可視化を行うことができました。
Pythonでggplot2と同様のプロットを作成できることがすごいと思いました。

# 参考文献
https://biomedicalhacks.com/2020-08-07/python-ggplot2/
https://qiita.com/ao_log/items/fe9bd42fd249c2a7ee7a
https://plotnine.readthedocs.io/en/v0.12.4/
https://plotnine.readthedocs.io/en/v0.12.4/api.html