[英]Matplotlib: Plotting numerous disconnected line segments with different colors
我有一組這樣的數據記錄:
(s1, t1), (u1, v1), color1
(s2, t2), (u2, v2), color2
.
.
.
(sN, tN), (uN, vN), colorN
在任何記錄中,前兩個值是線段的終點 ,第三個值是該線段的顏色 。 更具體地, (sn, tn)
是第一端點的xy坐標, (un, vn)
是第二端點的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()
我能夠使用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)
這在我的機器上執行一秒鍾。 我仍然需要弄清楚如何嵌入顏色值(帶alpha通道的RGB)。
使用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)
這是輸出:
函數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>]
好吧,我最終光柵化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()
這是迄今為止最快的解決方案,它完全符合我的實時需求。 但需要注意的是,繪制的線條沒有抗鋸齒。
我在Python 3上嘗試了很多2D渲染引擎,同時在面向圖像的Deep Learning和GAN中尋找輸出階段的快速解決方案。
使用以下基准:使用和不使用抗鋸齒將99行渲染為256x256離屏圖像(或任何更有效的圖像)的時間。
結果,按照我老式的x301筆記本電腦的效率順序:
基線是一個循環,需要~0.1 ms(10,000 FPS)檢索隨機數並調用基元。
PyGtk2的基本代碼:
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-Cairo的完整性:
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')
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.