RとPythonで良さげなラベル付き散布図を書く
今回は、RとPythonで良さげなラベル付き散布図を書く方法についてまとめます。
良さげ=プロットした点とラベルの位置が重ならないよう、適当にズラして表示してくれる
R/ggplot2 にはggrepelというラベルの位置を自動調整してくれるパッケージがあったのですが、下記のツイートを見るまでPythonで同様のパッケージがあると知らなかったので、自分用まとめです。
A small library for automatically adjusting text position in matplotlib plots to minimize overlaps. https://t.co/FUYXYKOCA7 Inspired by ggrepel package for R/ggplot2 おお、Pythonで散布図のラベルをいい感じに調整してくれるやつや。
— SKUE (@Mr_Sakaue) July 4, 2018
可視化するデータセット
以下の記事で作成したデータセットを利用します。ちなみにGFは「1試合平均の得点数」、GAは「1試合平均の失点数」を示します。Groupは色分けのための列です。
urawa.csv
Name | GF | GA | Group |
---|---|---|---|
斉藤 和夫 | 2.21 | 1.12 | 1 |
ブッフバルト | 2.08 | 1.06 | 1 |
ペトロヴィッチ | 1.7 | 1.2 | 0 |
原 博実 | 1.69 | 1.49 | 1 |
ホルガー オジェック | 1.62 | 1.14 | 1 |
ホルスト・ケッペル | 1.59 | 1.41 | 1 |
ハンス オフト | 1.58 | 1.33 | 1 |
チッタ | 1.56 | 1.56 | 1 |
ゲルト エンゲルス | 1.52 | 1.21 | 1 |
フォルカー フィンケ | 1.34 | 1.24 | 1 |
ピッタ | 1.33 | 1.5 | 1 |
横山 謙三 | 1.33 | 1.9 | 1 |
ア・デモス | 1.2 | 1.67 | 1 |
ゼリコ・ペトロヴィッチ | 1.07 | 1.21 | 1 |
堀 孝史 | 1 | 1.6 | 1 |
森 孝慈 | 0.72 | 2.17 | 1v |
Rでの実装
上述した通り、R/ggplot2 ではggrepelというパッケージを用いることで、良さげなラベル付き散布図を出力できます。
data <- read.csv("urawa.csv", row.names = 1, fileEncoding="CP932") library(ggplot2) library("ggrepel") g <- ggplot( data, aes ( x = data[,1], y = data[,2], colour = data[,3], label = rownames(data) ) ) g <- g + geom_point( size = 3 ) g <- g + geom_text_repel(family = "HiraKakuPro-W3") g <- g + xlab("Goal For per Game") g <- g + ylab("Goal Against per Game") plot(g)
Pythonでの実装
adjustText というパッケージを利用します。使い方はREADMEやWikiが整備されています。
データの読み込み
import matplotlib.pyplot as plt plt.rcParams['font.family'] = 'IPAPGothic' import pandas as pd df = pd.read_csv('urawa.csv', encoding="shift-jis") x = df['GF per game'] y = df['GA per game'] text = df['Name']
通常の場合
プロットした点とラベルが重なってしまっています。
fig, ax = plt.subplots() plt.plot(x, y, 'bo') texts = [plt.text(x[i], y[i], text[i], ha='center', va='center') for i in range(len(x))]
adjustTextを使った場合
importして、adjust_text()するだけです。
from adjustText import adjust_text fig, ax = plt.subplots() plt.plot(x, y, 'bo') texts = [plt.text(x[i], y[i], text[i], ha='center', va='center') for i in range(len(x))] adjust_text(texts)