Python Matplotlib:用不同的颜色绘制大量不连续的线段
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/21352580/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Matplotlib: Plotting numerous disconnected line segments with different colors
提问by Rabih Kodeih
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-pointsof a line segment, the third value is the colorof that line segment. More specifically, (sn, tn)are the x-y coordinates of the first end-point, (un, vn)are the x-y coordinates of the second-endpoint. Also, coloris an rgb with alpha value.
在任何记录中,前两个值是线段的端点,第三个值是该线段的颜色。更具体地说,(sn, tn)是第一个端点(un, vn)的 xy 坐标,是第二个端点的 xy 坐标。此外,颜色是具有 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 matplotlibwith a single plotcall (or as few as possible) as there could be potentially thousands of records.
如何通过一次调用(或尽可能少)使用matplotlib绘制此数据plot,因为可能有数千条记录。
Attempts
尝试
Preparing the data in one big list and calling plotagainst it is way too slow. For example the following code couldn't finish in a reasonable amount of time:
在一个大列表中准备数据并调用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()
I was able to speed-up the plot rendering by using the Noneinsertion 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)。
采纳答案by Rabih Kodeih
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.
这是迄今为止最快的解决方案,它完全符合我的实时需求。但需要注意的是,线条是在没有抗锯齿的情况下绘制的。
回答by zhangxaochen
function plotallows 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>]


回答by HYRY
use 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:
这是输出:


回答by gatopeich
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 渲染引擎,同时为面向图像的深度学习和 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 笔记本电脑的效率顺序:
- PyGtk2: ~2500 FPS, (Python 2, GTK 2, not sure how to get AA)
- PyQt5: ~1200 FPS, ~350 with Antialias
- PyQt4: ~1100 FPS, ~380 with AA
- Cairo: ~750 FPS, ~250 with AA (only slightly faster with 'FAST' AA)
- PIL: ~600 FPS
- PyGtk2:~2500 FPS,(Python 2,GTK 2,不确定如何获得 AA)
- PyQt5:~1200 FPS,~350 使用抗锯齿
- PyQt4:~1100 FPS,~380 帧率
- 开罗:~750 FPS,使用 AA 时~250 FPS(使用“FAST” AA 时速度略快)
- PIL:~600 帧/秒
The baseline is a loop which takes ~0.1 ms (10,000 FPS) retrieving random numbers and calling the primitives.
基线是一个循环,它需要大约 0.1 毫秒(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')

