2次元および3次元のデータは、従来のプロットタイプを使用して比較的簡単に表示できます。4次元データでも、データを表示する方法を見つけることがよくあります。ただし、4を超える寸法は、表示がますます困難になります。幸いなことに、平行座標プロットは、より高い次元で結果を表示するためのメカニズムを提供します。
Matlab、R、VTKタイプ1、VTKタイプ2など、いくつかのプロットパッケージは平行座標プロットを提供しますが、Matplotlibを使用して作成する方法がわかりません。
- Matplotlibに組み込みの平行座標プロットはありますか?確かにギャラリーには見当たりません。
- 組み込み型がない場合、Matplotlibの標準機能を使用して平行座標プロットを作成することは可能ですか?
編集:
以下のZhenyaの回答に基づいて、任意の数の軸をサポートする次の一般化を開発しました。上記の元の質問で投稿した例のプロットスタイルに従って、各軸は独自のスケールを取得します。これは、各軸ポイントでデータを正規化し、軸の範囲を0〜1にすることで実現しました。次に、戻って、その切片で正しい値を示すラベルを各目盛りに適用します。
この関数は、反復可能なデータセットを受け入れることによって機能します。各データセットは、各ポイントが異なる軸上にあるポイントのセットと見なされます。の例で__main__
は、30行の2セットで各軸のランダムな数値を取得します。線は、線のクラスタリングを引き起こす範囲内でランダムです。確認したい動作。
このソリューションは、マウスの動作がおかしく、ラベルを介してデータ範囲を偽造しているため、組み込みソリューションほど良くありませんが、Matplotlibが組み込みソリューションを追加するまでは、許容範囲内です。
#!/usr/bin/python
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
def parallel_coordinates(data_sets, style=None):
dims = len(data_sets[0])
x = range(dims)
fig, axes = plt.subplots(1, dims-1, sharey=False)
if style is None:
style = ['r-']*len(data_sets)
# Calculate the limits on the data
min_max_range = list()
for m in zip(*data_sets):
mn = min(m)
mx = max(m)
if mn == mx:
mn -= 0.5
mx = mn + 1.
r = float(mx - mn)
min_max_range.append((mn, mx, r))
# Normalize the data sets
norm_data_sets = list()
for ds in data_sets:
nds = [(value - min_max_range[dimension][0]) /
min_max_range[dimension][2]
for dimension,value in enumerate(ds)]
norm_data_sets.append(nds)
data_sets = norm_data_sets
# Plot the datasets on all the subplots
for i, ax in enumerate(axes):
for dsi, d in enumerate(data_sets):
ax.plot(x, d, style[dsi])
ax.set_xlim([x[i], x[i+1]])
# Set the x axis ticks
for dimension, (axx,xx) in enumerate(zip(axes, x[:-1])):
axx.xaxis.set_major_locator(ticker.FixedLocator([xx]))
ticks = len(axx.get_yticklabels())
labels = list()
step = min_max_range[dimension][2] / (ticks - 1)
mn = min_max_range[dimension][0]
for i in xrange(ticks):
v = mn + i*step
labels.append('%4.2f' % v)
axx.set_yticklabels(labels)
# Move the final axis' ticks to the right-hand side
axx = plt.twinx(axes[-1])
dimension += 1
axx.xaxis.set_major_locator(ticker.FixedLocator([x[-2], x[-1]]))
ticks = len(axx.get_yticklabels())
step = min_max_range[dimension][2] / (ticks - 1)
mn = min_max_range[dimension][0]
labels = ['%4.2f' % (mn + i*step) for i in xrange(ticks)]
axx.set_yticklabels(labels)
# Stack the subplots
plt.subplots_adjust(wspace=0)
return plt
if __name__ == '__main__':
import random
base = [0, 0, 5, 5, 0]
scale = [1.5, 2., 1.0, 2., 2.]
data = [[base[x] + random.uniform(0., 1.)*scale[x]
for x in xrange(5)] for y in xrange(30)]
colors = ['r'] * 30
base = [3, 6, 0, 1, 3]
scale = [1.5, 2., 2.5, 2., 2.]
data.extend([[base[x] + random.uniform(0., 1.)*scale[x]
for x in xrange(5)] for y in xrange(30)])
colors.extend(['b'] * 30)
parallel_coordinates(data, style=colors).show()
編集2:
これは、フィッシャーのアイリスデータをプロットするときに上記のコードから得られるものの例です。ウィキペディアの参照画像ほど良くはありませんが、Matplotlibだけがあり、多次元プロットが必要な場合は問題ありません。