gpt4 book ai didi

python - Matplotlib:如何有效地将大量线段着色为独立梯度

转载 作者:太空狗 更新时间:2023-10-29 21:40:30 26 4
gpt4 key购买 nike

Python.matplotlib:如何高效地将大量线段着色为独立渐变?
已经阅读 thisthis和其他东西;没有一个是我们的答案!

我们有许多单独的线希望以渐变颜色绘制每条线。

上面第一个链接中提到的解决方案,如果你有多于一个字符串,则不起作用。换句话说,改变颜色循环会影响绘图中的所有内容,而不是唯一感兴趣的行。 这根本不符合我们的兴趣。

指向 matplotlib 站点的第二个链接使用将每一行分割成许多行。这不是一个好方法,因为对于大量的行,比如 10000 行甚至更多;即使每行只选择 10 个段,结果也太大了!即使这样,生成的线条也根本不会平滑着色!如果将分割数作为线段的函数以获得更好的梯度,结果将非常巨大!难以显示,难以正确保存为文件。

最佳答案

一个(小的)加速是添加一个行集合而不是 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()

两个版本生成相同的图:

enter image description here


但是,如果我们将行数增加到 10000,我们将开始看到性能上的显着差异。

使用 10000 条线,每条线有 3 个点,另外还有 20 个点在整个颜色渐变中插值(每条线有 23 个线段),并查看将图形保存为 png 文件所花费的时间:

Took 10.866694212 sec with a single collection
Took 28.594727993 sec with multiple collections

因此,在这种特殊情况下,使用单行集合将提供不到 3 倍的加速。它不是很出色,但聊胜于无。

这是时序代码和输出图,不管它值多少钱(由于绘图的顺序不同,输出图并不完全相同。如果您需要控制 z 级别,则必须坚持分开行集合):

enter image description here

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()

关于python - Matplotlib:如何有效地将大量线段着色为独立梯度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13622909/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com