[英]Matplotlib: Plotting numerous disconnected line segments with different colors
I have a set of data records like this: 我有一组这样的数据记录:
(s1, t1), (u1, v1), color1
(s2, t2), (u2, v2), color2
.
.
.
(sN, tN), (uN, vN), colorN
In any record, the first two values are the end-points of a line segment, the third value is the color of that line segment. 在任何记录中,前两个值是线段的终点 ,第三个值是该线段的颜色 。 More specifically,
(sn, tn)
are the xy coordinates of the first end-point, (un, vn)
are the xy coordinates of the second-endpoint. 更具体地,
(sn, tn)
是第一端点的xy坐标, (un, vn)
是第二端点的xy坐标。 Also, color is an rgb with alpha value. 此外, 颜色是具有alpha值的rgb。
In general, any two line segments are disconnected (meaning that their end-points do not necessarily coincide). 通常,任何两个线段都是断开的 (意味着它们的端点不一定重合)。
How to plot this data using matplotlib with a single plot
call (or as few as possible) as there could be potentially thousands of records. 如何使用matplotlib使用单个
plot
调用(或尽可能少)绘制此数据,因为可能存在数千条记录。
Preparing the data in one big list and calling plot
against it is way too slow. 准备一个大清单中的数据并调用对它的
plot
太慢了。 For example the following code couldn't finish in a reasonable amount of time: 例如,以下代码无法在合理的时间内完成:
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()
I was able to speed-up the plot rendering by using the None insertion trick as follows: 我能够使用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)
This executes in under a second on my machine. 这在我的机器上执行一秒钟。 I still have to figure out how to embed the color values (RGB with alpha channel).
我仍然需要弄清楚如何嵌入颜色值(带alpha通道的RGB)。
use LineCollection
: 使用
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)
here is the output: 这是输出:
function plot
allows to draw multiple lines in one call, if your data is just in a list, just unpack it when passing it to plot
: 函数
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>]
OK, I ended up rasterising the lines on a PIL image before converting it to a numpy array: 好吧,我最终光栅化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()
This is by far the fastest solution and it fits my real-time needs perfectly. 这是迄今为止最快的解决方案,它完全符合我的实时需求。 One caveat though is the lines are drawn without anti-aliasing.
但需要注意的是,绘制的线条没有抗锯齿。
I have tried a good few 2D rendering engines available on Python 3, while looking for a fast solution for an output stage in image-oriented Deep Learning & GAN. 我在Python 3上尝试了很多2D渲染引擎,同时在面向图像的Deep Learning和GAN中寻找输出阶段的快速解决方案。
Using the following benchmark: Time to render 99 lines into a 256x256 off-screen image (or whatever is more effective) with and without anti-alias. 使用以下基准:使用和不使用抗锯齿将99行渲染为256x256离屏图像(或任何更有效的图像)的时间。
The results, in order of efficiency on my oldish x301 laptop: 结果,按照我老式的x301笔记本电脑的效率顺序:
The baseline is a loop which takes ~0.1 ms (10,000 FPS) retrieving random numbers and calling the primitives. 基线是一个循环,需要~0.1 ms(10,000 FPS)检索随机数并调用基元。
Basic code for PyGtk2: 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')
And here is for PyQt5: 这是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')
And here is Python3-Cairo for completeness: 这里是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.