2014-01-25 135 views
25

我有这样一组数据记录:Matplotlib:绘制众多断开线段具有不同颜色

(s1, t1), (u1, v1), color1 
(s2, t2), (u2, v2), color2 
. 
. 
. 
(sN, tN), (uN, vN), colorN 

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

一般来说,任意两条线段都是断开(意思是它们的终点不一定重合)。

如何使用一个单一的plot调用(或尽可能少)密谋用matplotlib这个数据可能存在潜在的几千条记录。

尝试

在一个大名单准备数据和呼叫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() 

我能够通过使用插入技巧来加速情节渲染如下:

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) 

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

+1

不使用'nan'代替'None'没有任何区别,它会产生相同的情节,但我可以使用'numpy.tile'和'numpy.repeat'来构建'x'和'y' inste附加到列表的广告。你是否也想过如果你可以用这个嵌入颜色(不像'LineColelction'方法)? – dashesy

回答

5

OK,我结束了在将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() 

这是迄今为止最快的解决方案它完全符合我的实时需求。但有一点需要注意的是,这些线条没有反锯齿。

+0

+1这个光栅化想法!喜欢它。 – zhangxaochen

8

功能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>] 

enter image description here

+0

对不起,没有工作 –

+0

@ user698585你尝试过吗?看到我粘贴的图片。我假设你的'(s1,t1),(u1,v1)'是以'(x1,x2),(y1,y2)'的形式,否则你应该压缩(x1,y1),(x2, y2)'到'(x1,x2),(y1,y2)'第一个 – zhangxaochen

+0

抱歉问题不够清楚,请检查更新。无论如何,我明白你的观点。您可能想要更新您的答案,以便与现在问题中明确提出的问题保持一致。 –

51

使用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) 

这里是输出:

enter image description here

+1

+1不知道这样的“sprite批处理”方法;) – zhangxaochen

+0

我试过了,它对于60000行还是不够快,对吧? – zhangxaochen

+0

@zhangxaochen:绝对!实际上我想为这个问题增加一个类似的更新,但是决定不要出于纯粹的懒惰。 –

1

我已经尝试了好几个2D渲染上的Python 3可用的引擎,同时寻找一个快速的解决方案输出阶段在面向图像的深度学习& GAN。

使用以下基准:将99行转换为256x256屏幕外图像(或任何更有效的图像)的时间,包含和不包含反别名。

结果,效率的顺序我老气X301笔记本:

  • PyGTK2的:〜2500 FPS(Python 2中,GTK 2,不知道如何获得AA)
  • PyQt5:〜1200 FPS,〜350与消除锯齿
  • PyQt4的:〜1100 FPS,〜380 AA
  • 开罗:〜750 FPS,〜250 AA
  • PIL(仅与 'FAST' AA稍快):〜600 FPS

基线是一个循环,需要约0.1毫秒(10,000 FPS)检索随机数并调用基元。

为PyGTK2的

Basic代码:

from gtk import gdk 
import random 

WIDTH = 256 
def r255(): return int(256.0*random.random()) 

cmap = gdk.Colormap(gdk.visual_get_best_with_depth(24), True) 
black = cmap.alloc_color('black') 
white = cmap.alloc_color('white') 
pixmap = gdk.Pixmap(None, WIDTH, WIDTH, 24) 
pixmap.set_colormap(cmap) 
gc = pixmap.new_gc(black, line_width=2) 
pixmap.draw_rectangle(gc, True, -1, -1, WIDTH+2, WIDTH+2); 
gc.set_foreground(white) 
for n in range(99): 
    pixmap.draw_line(gc, r255(), r255(), r255(), r255()) 

gdk.Pixbuf(gdk.COLORSPACE_RGB, False, 8, WIDTH, WIDTH 
    ).get_from_drawable(pixmap, cmap, 0,0, 0,0, WIDTH, WIDTH 
     ).save('Gdk2-lines.png','png') 

这里是PyQt5:

from PyQt5.QtCore import Qt 
from PyQt5.QtGui import * 
import random 

WIDTH = 256.0 
def r255(): return WIDTH*random.random() 

image = QImage(WIDTH, WIDTH, QImage.Format_RGB16) 
painter = QPainter() 
image.fill(Qt.black) 
painter.begin(image) 
painter.setPen(QPen(Qt.white, 2)) 
#painter.setRenderHint(QPainter.Antialiasing) 
for n in range(99): 
    painter.drawLine(WIDTH*r0to1(),WIDTH*r0to1(),WIDTH*r0to1(),WIDTH*r0to1())  
painter.end() 
image.save('Qt5-lines.png', 'png') 

这里是Python3开罗的完整性:

import cairo 
from random import random as r0to1 

WIDTH, HEIGHT = 256, 256 

surface = cairo.ImageSurface(cairo.FORMAT_A8, WIDTH, HEIGHT) 
ctx = cairo.Context(surface) 
ctx.scale(WIDTH, HEIGHT) # Normalizing the canvas 
ctx.set_line_width(0.01) 
ctx.set_source_rgb(1.0, 1.0, 1.0) 
ctx.set_antialias(cairo.ANTIALIAS_NONE) 
#ctx.set_antialias(cairo.ANTIALIAS_FAST) 

ctx.set_operator(cairo.OPERATOR_CLEAR) 
ctx.paint() 
ctx.set_operator(cairo.OPERATOR_SOURCE) 
for n in range(99): 
    ctx.move_to(r0to1(), r0to1()) 
    ctx.line_to(r0to1(), r0to1()) 
    ctx.stroke() 

surface.write_to_png('Cairo-lines.png') 
相关问题