回答此问题可获得 20 贡献值,回答如果被采纳可获得 50 分。
<p>使用传统的绘图类型可以相对直观地查看二维和三维数据。即使是四维数据,我们也经常能找到显示数据的方法。不过,4维以上的维度越来越难以显示。幸运的是,<a href="http://en.wikipedia.org/wiki/Parallel_coordinates" rel="noreferrer">parallel coordinates plots</a>提供了一种查看高维结果的机制。</p>
<p><img src="https://upload.wikimedia.org/wikipedia/en/4/4a/ParCorFisherIris.png" alt="Example Parallel Coordinates Plot from Wikipedia"/></p>
<p>有几个绘图包提供平行坐标绘图,例如<a href="http://www.mathworks.com/help/toolbox/stats/parallelcoords.html" rel="noreferrer">Matlab</a>、<a href="https://stackoverflow.com/questions/3942508/implementation-of-parallel-coordinates">R</a>、<a href="http://www.vtk.org/Wiki/VTK/Examples/Python/Infovis/ParallelCoordinatesView" rel="noreferrer">VTK type 1</a>和<a href="http://vtk.1045678.n5.nabble.com/Parallel-coordinates-Extraction-td4265045.html" rel="noreferrer">VTK type 2</a>,但我不知道如何使用Matplotlib创建一个。</p>
<ol>
<li>Matplotlib中是否有内置的平行坐标图?我当然看不到。</li>
<li>如果没有内置类型,是否可以使用Matplotlib的标准功能生成平行坐标图?</li>
</ol>
<hr/>
<p><strong>编辑</strong>:</p>
<p>基于下面的Zhenya提供的答案,我开发了以下支持任意轴数的泛化。按照我在上面原始问题中发布的示例的打印样式,每个轴都有自己的比例。我通过规范化每个轴点的数据并使轴的范围为0到1来实现这一点。然后我回去给每个记号贴上标签,在截距处给出正确的值。</p>
<p>该函数通过接受一组数据集来工作。每个数据集被视为一组点,其中每个点位于不同的轴上。<code>__main__</code>中的示例为两组30行中的每个轴获取随机数。这些行在导致行聚集的范围内是随机的;我想验证这一行为。</p>
<p>这个解决方案不如内置的解决方案,因为您有奇怪的鼠标行为,我通过标签伪造数据范围,但是在Matplotlib添加内置解决方案之前,这是可以接受的。</p>
<pre><code>#!/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.<a href="https://www.cnpython.com/list/append" class="inner-link">append</a>((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 <a href="https://www.cnpython.com/pypi/dataset" class="inner-link">dataset</a>s 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()
</code></pre>
<p><strong>编辑2:</strong></p>
<p>下面是一个在绘制<a href="http://en.wikipedia.org/wiki/Iris_flower_data_set" rel="noreferrer">Fisher's Iris data</a>时从上述代码中得到的结果的示例。它不像维基百科上的参考图片那么好,但是如果你只有Matplotlib并且你需要多维图的话,它是可以接受的。</p>
<p><img src="https://i.stack.imgur.com/N1mpi.png" alt="Example result of parallel coordinates plot from this answer"/></p>