一个(次要)加速将会添加一个单独的行集合,而不是10000个单独的行集合。
只要所有线共享相同的颜色映射表,您可以将它们分组为单个线条集合,并且每个线条仍可以有独立的渐变。
Matplotlib对于这类事情仍然很慢。它针对质量输出进行了优化,而不是快速绘制时间。不过,你可以加速一些(〜3x)。 (?)
所以,我怎么想你可能是一个例子做它现在:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.collections import LineCollection
# Make random number generation consistent between runs
np.random.seed(5)
def main():
numlines, numpoints = 2, 3
lines = np.random.random((numlines, numpoints, 2))
fig, ax = plt.subplots()
for line in lines:
# Add "num" additional segments to the line
segments, color_scalar = interp(line, num=20)
coll = LineCollection(segments)
coll.set_array(color_scalar)
ax.add_collection(coll)
plt.show()
def interp(data, num=20):
"""Add "num" additional points to "data" at evenly spaced intervals and
separate into individual segments."""
x, y = data.T
dist = np.hypot(np.diff(x - x.min()), np.diff(y - y.min())).cumsum()
t = np.r_[0, dist]/dist.max()
ti = np.linspace(0, 1, num, endpoint=True)
xi = np.interp(ti, t, x)
yi = np.interp(ti, t, y)
# Insert the original vertices
indices = np.searchsorted(ti, t)
xi = np.insert(xi, indices, x)
yi = np.insert(yi, indices, y)
return reshuffle(xi, yi), ti
def reshuffle(x, y):
"""Reshape the line represented by "x" and "y" into an array of individual
segments."""
points = np.vstack([x, y]).T.reshape(-1,1,2)
points = np.concatenate([points[:-1], points[1:]], axis=1)
return points
if __name__ == '__main__':
main()
相反,我会建议做的东西沿着这些路线(唯一的区别是在main
功能):
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.collections import LineCollection
# Make random number generation consistent between runs
np.random.seed(5)
def main():
numlines, numpoints = 2, 3
points = np.random.random((numlines, numpoints, 2))
# Add "num" additional segments to each line
segments, color_scalar = zip(*[interp(item, num=20) for item in points])
segments = np.vstack(segments)
color_scalar = np.hstack(color_scalar)
fig, ax = plt.subplots()
coll = LineCollection(segments)
coll.set_array(color_scalar)
ax.add_collection(coll)
plt.show()
def interp(data, num=20):
"""Add "num" additional points to "data" at evenly spaced intervals and
separate into individual segments."""
x, y = data.T
dist = np.hypot(np.diff(x - x.min()), np.diff(y - y.min())).cumsum()
t = np.r_[0, dist]/dist.max()
ti = np.linspace(0, 1, num, endpoint=True)
xi = np.interp(ti, t, x)
yi = np.interp(ti, t, y)
# Insert the original vertices
indices = np.searchsorted(ti, t)
xi = np.insert(xi, indices, x)
yi = np.insert(yi, indices, y)
return reshuffle(xi, yi), ti
def reshuffle(x, y):
"""Reshape the line represented by "x" and "y" into an array of individual
segments."""
points = np.vstack([x, y]).T.reshape(-1,1,2)
points = np.concatenate([points[:-1], points[1:]], axis=1)
return points
if __name__ == '__main__':
main()
两个版本都产生相同的情节:
如果我们将行数增加到10000,我们将开始看到显着的性能差异。
使用万线,每3个点和额外的20个点的色梯度内插(23段中的每一行),并在看它需要一个数字保存到PNG时间:
Took 10.866694212 sec with a single collection
Took 28.594727993 sec with multiple collections
因此,在这种特殊情况下,使用单行集合会使速度略低于3倍。这不是一流的,但总比没有好。
下面是计时代码和输出图,无论它值什么(由于绘图顺序不同,输出数字并不完全相同。如果你需要的Z级控制,你就必须坚持独立的行集合):
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.collections import LineCollection
import time
# Make random number generation consistent between runs
np.random.seed(5)
def main():
numlines, numpoints = 10000, 3
lines = np.random.random((numlines, numpoints, 2))
# Overly simplistic timing, but timeit is overkill for this exmaple
tic = time.time()
single_collection(lines).savefig('/tmp/test_single.png')
toc = time.time()
print 'Took {} sec with a single collection'.format(toc-tic)
tic = time.time()
multiple_collections(lines).savefig('/tmp/test_multiple.png')
toc = time.time()
print 'Took {} sec with multiple collections'.format(toc-tic)
def single_collection(lines):
# Add "num" additional segments to each line
segments, color_scalar = zip(*[interp(item, num=20) for item in lines])
segments = np.vstack(segments)
color_scalar = np.hstack(color_scalar)
fig, ax = plt.subplots()
coll = LineCollection(segments)
coll.set_array(color_scalar)
ax.add_collection(coll)
return fig
def multiple_collections(lines):
fig, ax = plt.subplots()
for line in lines:
# Add "num" additional segments to the line
segments, color_scalar = interp(line, num=20)
coll = LineCollection(segments)
coll.set_array(color_scalar)
ax.add_collection(coll)
return fig
def interp(data, num=20):
"""Add "num" additional points to "data" at evenly spaced intervals and
separate into individual segments."""
x, y = data.T
dist = np.hypot(np.diff(x - x.min()), np.diff(y - y.min())).cumsum()
t = np.r_[0, dist]/dist.max()
ti = np.linspace(0, 1, num, endpoint=True)
xi = np.interp(ti, t, x)
yi = np.interp(ti, t, y)
# Insert the original vertices
indices = np.searchsorted(ti, t)
xi = np.insert(xi, indices, x)
yi = np.insert(yi, indices, y)
return reshuffle(xi, yi), ti
def reshuffle(x, y):
"""Reshape the line represented by "x" and "y" into an array of individual
segments."""
points = np.vstack([x, y]).T.reshape(-1,1,2)
points = np.concatenate([points[:-1], points[1:]], axis=1)
return points
if __name__ == '__main__':
main()
我怀疑你已经打matplotlib'的'的限制,但千万不要以为那是你的主要问题。如果你有10K行,即使你把它们绘制成1px宽,将它们排列起来也需要一个巨大的显示/打印出来,以便能够独立地看到它们。即使你能找到一种方法来制作这个情节,你也无法以合理的方式来看待它。有什么方法可以粗化数据吗? – tacaswell
您是否尝试添加单行收集而不是10000个单独的行集合?它仍然很慢,但速度更快。平移和缩放时它也更具响应性。 –
@JoeKington:好戏。 – Developer