ゆるふわめも

東京か京都にいます。

matplotlibでの散布図・プロット・アニメーションなどのサンプル集

毎回ぐぐるのもあれだったので。 よく使うものでなるべくドキュメントのギャラリーになさそうなもの。

適当に追記するかもしれません。

マルチラベルデータのプロット

プロットするデータの作成

今回利用するデータを生成。 sklearn.datasetsにてダミーのデータを作成します。

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.datasets import make_multilabel_classification

X, Y = make_multilabel_classification(n_classes=3,
                                      n_labels=1,
                                      allow_unlabeled=True,
                                      random_state=1)

マルチラベル用のダミーデータを生成して、これをプロットします。

二次元で可視化

サンプルの分布を二次元に可視化。 生成したデータは20次元で本来はPCAなどで2次元にしたデータを渡すべきですが、面倒なので省略。

def plot(X, Y, model=None, title="", option={}):
    min_x = np.min(X[:, 0])
    max_x = np.max(X[:, 0])

    min_y = np.min(X[:, 1])
    max_y = np.max(X[:, 1])

    plt.title(title)
    
    class_0 = np.where(Y[:, 0])
    class_1 = np.where(Y[:, 1])
    class_2 = np.where(Y[:, 2])
    
    # 全サンプルのプロット
    plt.scatter(X[:, 0], X[:, 1], s=80, c='gray')
    
    # ラベルごとにマークをつける
    plt.scatter(X[class_0, 0], X[class_0, 1], s=220, edgecolors='g',
               facecolors='none', linewidths=2, label='Class0')
    plt.scatter(X[class_1, 0], X[class_1, 1], s=150, edgecolors='b',
               facecolors='none', linewidths=2, label='Class1')
    plt.scatter(X[class_2, 0], X[class_2, 1], s=80, edgecolors='r',
               facecolors='none', linewidths=2, label='Class2')
    
    # ラベル名を表示
    plt.legend(bbox_to_anchor=(1.2,0.5),)
    
    # その他
    plt.grid(True)
    plt.tight_layout(True)


plot(X, Y)

f:id:misos:20170731152629p:plain

三次元で可視化

3Dでのプロット。 正直わかりにくいので滅多に使わない。

from mpl_toolkits.mplot3d import Axes3D
def plot(X, Y, model=None, title="", option={}):
    min_x = np.min(X[:, 0])
    max_x = np.max(X[:, 0])

    min_y = np.min(X[:, 1])
    max_y = np.max(X[:, 1])

    fig = plt.figure()
    ax = Axes3D(fig)
    plt.title(title)
    
    class_0 = np.where(Y[:, 0])
    class_1 = np.where(Y[:, 1])
    class_2 = np.where(Y[:, 2])
    
    # 全サンプルのプロット
    ax.scatter(X[:,0], X[:,1], X[:,2])

    # ラベルごとにマークをつける
    ax.scatter(X[class_0,0], X[class_0,1], X[class_0,2], s=220, edgecolors='g',
               facecolors='none', linewidths=2, label='Class0')
    ax.scatter(X[class_1,0], X[class_1,1], X[class_1,2], s=150, edgecolors='b',
               facecolors='none', linewidths=2, label='Class1')
    ax.scatter(X[class_2,0], X[class_2,1], X[class_2,2], s=80, edgecolors='r',
               facecolors='none', linewidths=2, label='Class2')

    # ラベル名を表示
    plt.legend(bbox_to_anchor=(1.2,0.5),)
    
    # その他
    plt.grid(True)


plot(X, Y)

f:id:misos:20170801004153p:plain

三次元で可視化してそれを回転させるアニメーションを作成

3Dでプロットしたデータを回転させながら確認する。mp4ファイル作成時に一時ファイルが大量に生成されるので注意、mp4ファイル作成後はなくなります。

def animate(i)にて一度だけ回転させるごとに画像を生成して最後にmp4でアニメーションを出力します。

from matplotlib import animation
from mpl_toolkits.mplot3d import Axes3D

fig = plt.figure()
ax = Axes3D(fig)

def plot(X, Y, model=None, title="", option={}, fig=fig, ax=ax):
    min_x = np.min(X[:, 0])
    max_x = np.max(X[:, 0])

    min_y = np.min(X[:, 1])
    max_y = np.max(X[:, 1])

    plt.title(title)
    
    class_0 = np.where(Y[:, 0])
    class_1 = np.where(Y[:, 1])
    class_2 = np.where(Y[:, 2])
    
    # 全サンプルのプロット
    ax.scatter(X[:,0], X[:,1], X[:,2])

    # ラベルごとにマークをつける
    ax.scatter(X[class_0,0], X[class_0,1], X[class_0,2], s=220, edgecolors='g',
               facecolors='none', linewidths=2, label='Class0')
    ax.scatter(X[class_1,0], X[class_1,1], X[class_1,2], s=150, edgecolors='b',
               facecolors='none', linewidths=2, label='Class1')
    ax.scatter(X[class_2,0], X[class_2,1], X[class_2,2], s=80, edgecolors='r',
               facecolors='none', linewidths=2, label='Class2')
    # ラベル名を表示
    plt.legend(bbox_to_anchor=(1.2,0.5),)
    
    # その他
    plt.grid(True)
    
    return fig, ax


def init():
    plot(X, Y, model=None, title="", option={})
    return fig,

def animate(i):
    ax.view_init(elev=10., azim=i)
    return fig,

anim = animation.FuncAnimation(fig, animate, 
                               init_func=init,
                               frames=280, 
                               interval=20, 
                               blit=True)
anim.save('3d_animation.mp4',
          fps=30,
          extra_args=['-vcodec', 'libx264'])

f:id:misos:20170801004841g:plain

※ファイルサイズが大きくならないように圧縮してます

分類問題データのプロット

Isomapで次元削減したものを可視化

散布図で教師データごとに色を変えてプロット。 ついでにマーカーやカラーマップも変えていろいろプロット。適当すぎる。

重要なのはplt.scatter(plot_data[:, 0], plot_data[:, 1], lw=0.2, c=digits.target, cmap=cmap, s=15.5, marker=marker) の箇所のみです。

from sklearn.datasets import load_digits
from sklearn.manifold import Isomap

from matplotlib import cm
from matplotlib import markers


digits = load_digits(n_class=6)
iso = Isomap(n_components=2)
plot_data = iso.fit_transform(digits.data)

cm_list = list(cm.cmap_d.keys())
mk_list = list(markers.MarkerStyle.markers.keys())
plt.figure(figsize=(10, 20))


for i, color_scheme_i in enumerate(cm_list):
    cmap = plt.cm.get_cmap(cm_list[i], 6)
    marker = mk_list[i]
    subplot_num = i+1
    
    # plot
    plt.subplot(6, 3, subplot_num)
    plt.title("Color Map:"+str(color_scheme_i)+" Maker:"+str(marker))
    plt.scatter(plot_data[:, 0], 
                plot_data[:, 1], 
                lw=0.2,
                c=digits.target, 
                cmap=cmap,
                s=15.5,
                marker=marker)

    # add color bar
    if subplot_num%3==0:
        plt.colorbar(ticks=range(6), label='color/digit_number')
    else:
        plt.colorbar(ticks=range(6))
        
    # options
    plt.clim(-0.7, 5.7)
    plt.grid(True)
    
    # break
    if 6*3==subplot_num:
        break
    
plt.tight_layout()
plt.show()

f:id:misos:20170731194243p:plain

プロットのマーカを変える+ランダムに色を生成する

('#%02X%02X%02X' % (r(),r(),r()))でランダムに色を生成しています。mpl.markers.MarkerStyle.markers.keys()で利用可能なマーカを取得して、プロットしています。マーカーの形の指定部分はmarker=mk_iです。見栄えを確認してみたかったのでとりあえず全部プロットしました。

import matplotlib as mpl
import matplotlib.pyplot as plt
import random

# ダミーデータの作成
n_samples = 10
r = lambda: random.randint(0,255)
X = np.arange(n_samples)

# マーカーと色の取得
mk_list = list(mpl.markers.MarkerStyle.markers.keys())
color_list = [('#%02X%02X%02X' % (r(),r(),r())) for _ in range(len(mk_list))]

# プロット
plt.figure(figsize=(5, 10))
for i, mk_i in enumerate(mk_list):
    label_name = str(mk_i)
    label_color = color_list[i]
    
    if i < 20:
        plt.plot(X, X+i*5,'-.',marker=mk_i,ms=10,c=label_color,label=label_name)
    else:
        plt.plot(X+12, X+(i-20)*5,'-.',marker=mk_i,ms=10,c=label_color,label=label_name)
    
    
plt.legend(bbox_to_anchor=(1.1,0.7), ncol=2, title="marker str")
plt.grid()

f:id:misos:20170731215823p:plain

その他

矢印をプロットに追加

arrowstyle='<->'の箇所を変えることで他の矢印もできるはず。

import matplotlib.pyplot as plt
import matplotlib.patches as patches

fig = plt.figure()
ax = fig.add_subplot(111)

# sample points
sample_1, sample_2 = (1.0, 2.0), (3.0, 4.0)

# add sample
plt.scatter(sample_1[0], sample_1[1], s=30, c="r")
plt.scatter(sample_2[0], sample_2[1], s=30, c="b")

# add arrow
arrow = patches.FancyArrowPatch(
        sample_1,
        sample_2,
        arrowstyle='<->',
        mutation_scale=30
    )

ax.add_patch(arrow)

plt.xlim(0, 5)
plt.ylim(0, 5)
plt.grid()

f:id:misos:20170731173523p:plain

棒グラフなどを模様で埋める(hatch)

色盲の方向けや白黒印刷でもグラフの区別がつくようにするため、しばしば使います。hatch=patterns[i]で模様を指定します。

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.patches as patches

patterns = ['-', '+', 'x', 'o', 'O', '.', '*'] 
n_patterns = len(patterns)

sample_data = np.random.rand(n_patterns)
sample_index = np.arange(n_patterns)

for i, d in zip(sample_index, sample_data):
    plt.bar([i], [d], hatch=patterns[i], label=patterns[i])
    
plt.legend(
    title="hatch pattern",
    bbox_to_anchor=(1.3,1.0),
)

f:id:misos:20170731174140p:plain

jupyter notebookでアニメーションを埋め込む

以下を参照してください。

長方形の枠をプロットする

特定の場所を囲ったりするのに使えるかもしれません。 ['solid', 'dashdot', 'dotted', 'dashed']でボーダの種類を指定します。 このあたりの図形は

ドキュメントのmatplotlib.patchesの項目をみればわかるので、他の図形をプロットしたい方はドキュメント参照。

import matplotlib.pyplot as plt
import matplotlib.patches as patches

fig = plt.figure()
ax = fig.add_subplot(111)

rect_index = [(np.random.rand(1), np.random.rand(1)) for _ in range(4)]
line_style = ['solid', 'dashdot', 'dotted', 'dashed']

for r, l in zip(rect_index, line_style):
    rect = patches.Rectangle(
        r,
        0.4, # width for rectangle
        0.4, # height for rectangle
        fill=False,
        linestyle=l
    )
    ax.add_patch(rect)
    
plt.xlim(0, 1.3)
plt.ylim(0, 1.3)

f:id:misos:20170731175127p:plain

ヒートマップのアニメーション

地図上での人の時系列データなどの可視化の時に使う気がします、必要最低限のコードのみ。

import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
from matplotlib import animation
from mpl_toolkits.mplot3d import Axes3D


x = np.arange(10)
fig, ax = plt.subplots()

def plot(i, fig=fig, ax=ax):
    data = x*x[:, np.newaxis]+np.random.rand(10,10)*i
    plt.imshow(data)

def init():
    plot(0)
    return fig,

def animate(i):
    plot(i)
    return fig,

anim = animation.FuncAnimation(fig, animate, 
                               init_func=init,
                               frames=100, 
                               interval=20, 
                               blit=True)

anim.save('heatmap_animation.mp4',
          fps=30,
          extra_args=['-vcodec', 'libx264'])

f:id:misos:20170731224020g:plain

利用可能なカラーマップの取得

他の色を試してみたくなった時に使う?

from matplotlib import cm
cm.cmap_d.keys()

実行結果

dict_keys(['bwr', 'rainbow',  ..., 'PuBuGn_r', 'Vega20b_r', 'YlOrBr_r', 'cool_r', 'YlGn_r', 'bone', 'Greys', 'Paired_r', 'RdPu_r', 'nipy_spectral', 'gnuplot2'])

利用可能なマーカー(点の形)の一覧の取得

from matplotlib import markers
markers.MarkerStyle.markers.keys()

実行結果

dict_keys([0, '+', 2, 3, '3', '1', 6, 1, 'D', 9, 10, 11, 'd', '4', '2', 'X', 7, 'p', 'v', '', 5, 'o', 'H', 's', '*', 'x', 'None', ',', '^', '8', None, 'P', '|', '>', '.', 8, 4, ' ', 'h', '<', '_'])

ラベルの位置の調整

その他のプロットのサンプルコード

宇宙工学・天文学など

JJ’s Matplotlib Gallery For Astronomy — Matplotlib Gallery For Astronomy v0.1.1 documentation

seaborn のギャラリー

Example gallery — seaborn 0.8.0 documentation

matplotlibのギャラリー

Thumbnail gallery — Matplotlib 2.0.2 documentation