可以使用传统的绘图类型相对直观地查看二维和三维数据 . 即使使用四维数据,我们也经常可以找到显示数据的方法 . 但是,高于4的尺寸变得越来越难以显示 . 幸运的是,parallel coordinates plots提供了一种查看更高维度结果的机制 .
几个绘图包提供了平行坐标图,例如Matlab,R,VTK type 1和VTK type 2,但我没有看到如何使用Matplotlib创建一个 .
-
Matplotlib中是否有内置的平行坐标图?我当然看不到一个in the gallery .
-
如果没有内置类型,是否可以使用Matplotlib的标准功能构建平行坐标图?
Edit :
根据以下振亚提供的答案,我开发了以下支持任意数量轴的概括 . 按照我在上面原始问题中发布的示例的绘图样式,每个轴都有自己的比例 . 我通过对每个轴点的数据进行归一化并使轴的范围为0到1来实现这一点 . 然后返回并为每个刻度线应用标签,在该截距处给出正确的值 .
该函数通过接受可迭代的数据集来工作 . 每个数据集被认为是一组点,其中每个点位于不同的轴上 . __main__
中的示例为两组30行中的每个轴抓取随机数 . 线条在引起线条聚类的范围内是随机的;我想验证的行为 .
这个解决方案不如内置解决方案好,因为你有奇怪的鼠标行为,而且我通过标签伪造数据范围,但在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()
Edit 2:
以下是绘制Fisher's Iris data时上述代码的示例 . 它不如维基百科的参考图像那么好,但如果你拥有的只是Matplotlib并且你需要多维图,它是可以通过的 .
4 回答
我确信有更好的方法可以做到这一点,但这是一个快速而肮脏的方法(一个非常脏的方式):
这基本上是基于Joe Kingon的一个(更好的)Python/Matplotlib - Is there a way to make a discontinuous axis? . 您可能还想查看同一问题的其他答案 .
在这个例子中,我甚至没有尝试缩放垂直标度,因为它取决于你想要实现的目标 .
编辑:这是结果
pandas有一个平行坐标包装器:
源代码,他们是如何做到的:plotting.py#L494
使用pandas时(如theta所示),无法独立缩放轴 .
https://github.com/pydata/pandas/issues/7083#issuecomment-74253671
到目前为止,我见过的最好的例子就是这个
https://python.g-node.org/python-summerschool-2013/_media/wiki/datavis/olympics_vis.py
请参阅normalised_coordinates函数 . 不是超级快,但从我尝试过的工作 .