ひろこま Hack Log

プログラミングや機械学習などの知識を記録・共有します

matplotlibで3次元配列を描画【Voxel使用】

f:id:twx:20190624225645p:plain
3次元配列の描画

3次元配列を上図のように描画してみる

matplotlibのvoxelという技を使います。これを使うと3次元配列(テンソル)を3D空間上に表示できます。

import colorsys
import collections
import numpy as np
from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

def int2hue(integer, in_max=255, out_max=255, is_alpha=False):
    if is_alpha:
        return tuple( float(v * out_max) for v in  colorsys.hsv_to_rgb(integer/in_max, 1, 1) ) + (out_max,)
    else:
        return tuple( float(v * out_max) for v in  colorsys.hsv_to_rgb(integer/in_max, 1, 1) )

def flatten(xs):
    result = []
    for x in xs:
        if isinstance(x, collections.Iterable) and not isinstance(x, dict)and not isinstance(x, str):
            result.extend(flatten(x))
        else:
            result.append(x)
    return result

def draw3d(tensor):
    tensor = tensor.transpose(2,0,1) # 軸を入れ替える。※ 機械学習で画像を扱うときによく使う軸の順番にしただけで、それ以外の深い意味は無い
    fig = plt.figure(figsize=(5, 5), dpi=100) # 図の大きさを変えられる
    ax = fig.gca(projection='3d')
    org_shape = tensor.shape

    tensor_min = tensor.min() # すべての要素が正になるように、もし負の値があったらその絶対値を全要素に加算する
    if tensor_min < 0:
        tensor = tensor - tensor_min

    eps = 1e-10
    tensor = tensor + eps # 要素の値が0だと表示できないことがあるので、それを回避するために微小な数を与える

    tensor_max = tensor.max()
    colors = [int2hue(x, in_max=tensor_max, out_max=1.0, is_alpha=True) for x in flatten(tensor)]
    colors = np.reshape(colors, org_shape + (4,)) # 各座標に、RGBAを表すサイズ4の配列を埋め込むためシェイプに4を追加する

    # 立方体になるように軸を調整
    xsize, ysize, zsize = tensor.shape
    max_range = np.array([xsize, ysize, zsize]).max() * 0.5
    mid_x = xsize * 0.5
    mid_y = ysize * 0.5
    mid_z = zsize * 0.5
    ax.set_xlim(mid_x - max_range, mid_x + max_range)
    ax.set_ylim(mid_y - max_range, mid_y + max_range)
    ax.set_zlim(mid_z - max_range, mid_z + max_range)

    # 目盛りを削除
    plt.setp(ax.get_xticklabels(), visible=False)
    plt.setp(ax.get_yticklabels(), visible=False)
    plt.setp(ax.get_zticklabels(), visible=False)

    ax.voxels(tensor, facecolors=colors, linewidth=0.3, edgecolor='k')
    plt.show()

なお、キューブの色はint2hueという自作関数で求めてます。

この関数int2hueと、もう1つの自作関数flattenはそれぞれ以下の記事で紹介しています。よかったらどうぞ。

www.mahirokazuko.com www.mahirokazuko.com

テストしてみる

適当なテンソルを作って描画してみます。

tensor = np.random.rand(3, 3, 3)
print(tensor)
draw3d(tensor)

f:id:twx:20190624231113p:plain
3x3x3のテンソル

tensor = np.random.rand(2, 3, 4)
print(tensor)
draw3d(tensor)

f:id:twx:20190624232431p:plain
2x3x4のテンソル

tensor = np.random.rand(10, 20, 30)
#print(tensor)
draw3d(tensor)

f:id:twx:20190624232645p:plain
10x20x30のテンソル

いい感じに描画できました。機械学習でテンソルを可視化したいときなどに使えそうです。

本日はmatplotlibで3次元配列を描画する方法をご紹介しました。良い記事だと思っていただいた方は、以下の「★+」ボタンのクリック、SNSでのシェア、「読者になる」ボタンのクリックをお願いします。 それではまたー!

Koma Hirokazu 's Hacklog ―― Copyright © 2018 Koma Hirokazu