2014-01-25 183 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') 
相關問題