Matplotlib:用不同的颜色绘制许多断开的线段

Rab*_*eih 44 python plot matplotlib line

我有一组这样的数据记录:

(s1, t1), (u1, v1), color1
(s2, t2), (u2, v2), color2
.
.
.
(sN, tN), (uN, vN), colorN
Run Code Online (Sandbox Code Playgroud)

在任何记录中,前两个值是线段的终点,第三个值是该线段的颜色.更具体地说,(sn, tn)第一个端点(un, vn)的xy坐标是第二个端点的xy坐标.此外,颜色是具有alpha值的rgb.

通常,任何两个线段都是断开的(意味着它们的端点不一定重合).

如何使用matplotlib使用单个plot调用(或尽可能少)来绘制此数据,因为可能存在数千条记录.

尝试

在一个大列表中准备数据并对其进行调用plot太慢了.例如,以下代码无法在合理的时间内完成:

import numpy as np
import matplotlib.pyplot as plt

data = []
for _ in xrange(60000):
    data.append((np.random.rand(), np.random.rand()))
    data.append((np.random.rand(), np.random.rand()))
    data.append('r')

print 'now plotting...' # from now on, takes too long
plt.plot(*data)
print 'done'
#plt.show()
Run Code Online (Sandbox Code Playgroud)

我能够使用None插入技巧加速绘图渲染,如下所示:

import numpy as np
import matplotlib.pyplot as plt
from timeit import timeit

N = 60000
_s = np.random.rand(N)
_t = np.random.rand(N)
_u = np.random.rand(N)
_v = np.random.rand(N)
x = []
y = []
for s, t, u, v in zip(_s, _t, _u, _v):
    x.append(s)
    x.append(u)
    x.append(None)
    y.append(t)
    y.append(v)
    y.append(None)
print timeit(lambda:plt.plot(x, y), number=1)
Run Code Online (Sandbox Code Playgroud)

这在我的机器上执行一秒钟.我仍然需要弄清楚如何嵌入颜色值(带alpha通道的RGB).

HYR*_*YRY 80

用途LineCollection:

import numpy as np
import pylab as pl
from matplotlib import collections  as mc

lines = [[(0, 1), (1, 1)], [(2, 3), (3, 3)], [(1, 2), (1, 3)]]
c = np.array([(1, 0, 0, 1), (0, 1, 0, 1), (0, 0, 1, 1)])

lc = mc.LineCollection(lines, colors=c, linewidths=2)
fig, ax = pl.subplots()
ax.add_collection(lc)
ax.autoscale()
ax.margins(0.1)
Run Code Online (Sandbox Code Playgroud)

这是输出:

在此输入图像描述

  • 我试过了,60000行还是不够快,对吧? (2认同)
  • 很好的答案,这是我使用matplotlib找到的唯一可以有效处理大量行的解决方案。对于〜2000行,它是60毫秒,而不是其他技术的1.6秒。 (2认同)

zha*_*hen 9

函数plot允许在一次调用中绘制多行,如果您的数据只在列表中,只需将其传递给plot:

In [315]: data=[(1, 1), (2, 3), 'r', #assuming points are (1,2) (1,3) actually and,
                                     #here they are in form of (x1, x2), (y1, y2)
     ...: (2, 2), (4, 5), 'g',
     ...: (5, 5), (6, 7), 'b',]

In [316]: plot(*data)
Out[316]: 
[<matplotlib.lines.Line2D at 0x8752870>,
 <matplotlib.lines.Line2D at 0x8752a30>,
 <matplotlib.lines.Line2D at 0x8752db0>]
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

  • @user698585 这就是你所要求的(使用单个 **plot** 调用)...没有人说在单个图形上绘制 60,000 条线是有效的,无论是使用单个调用还是在 for 循环中调用。 (2认同)

Rab*_*eih 6

好吧,我最终光栅化PIL图像上的线条,然后将其转换为numpy数组:

from PIL import Image
from PIL import ImageDraw
import random as rnd
import numpy as np
import matplotlib.pyplot as plt

N = 60000
s = (500, 500)

im = Image.new('RGBA', s, (255,255,255,255))
draw = ImageDraw.Draw(im)

for i in range(N):
    x1 = rnd.random() * s[0]
    y1 = rnd.random() * s[1]
    x2 = rnd.random() * s[0]
    y2 = rnd.random() * s[1]
    alpha = rnd.random()
    color  = (int(rnd.random() * 256), int(rnd.random() * 256), int(rnd.random() * 256), int(alpha * 256)) 
    draw.line(((x1,y1),(x2,y2)), fill=color, width=1)

plt.imshow(np.asarray(im),
           origin='lower')
plt.show()
Run Code Online (Sandbox Code Playgroud)

这是迄今为止最快的解决方案,它完全符合我的实时需求.但需要注意的是,绘制的线条没有抗锯齿.