Python - 绘制大量线条

11

我试图读取一个包含线段XY端点和与该线段相关联的值的文件,然后绘制着色线段。 我遇到的问题是,可能会有数十万到数百万条线段,当我尝试读取这些较大的文件时,会遇到内存错误。 是否有更有效的内存使用方式?

import matplotlib.pyplot as plt
import matplotlib.colors as colors
import matplotlib.cm as cmx
import sys
import csv

if len(sys.argv) > 1:
    flofile = sys.argv[1]
else:
    flofile = "GU3\GU3.flo"

fig = plt.figure()
ax = fig.add_subplot(111)
jet = cm = plt.get_cmap('jet')
cNorm = colors.Normalize(vmin=0)
scalarMap = cmx.ScalarMappable(norm=cNorm,cmap=jet)
with open(flofile) as FLO:
    title = FLO.readline()
    limits = [float(tp) for tp in FLO.readline().split()]
    FLO.readline()#headers
    for line in FLO:
        if 'WELLS' in line: break        
        frac = ([float(tp) for tp in line.split()])
        ax.plot([frac[0],frac[2]],[frac[1],frac[3]],color=colorVal)


#ax.plot(*call_list)
scalarMap._A = []
plt.colorbar(scalarMap)
plt.xlim([0,limits[0]])
plt.ylim([0,limits[1]])

plt.show()

这段代码适用于小文件。谢谢。


你希望看到什么?是一个巨大的图像,让你可以区分数百万条线段,还是数百万条线段重叠在一个合理大小的图像上。你能否通过计算类似于密度的东西来减少问题的范围,将数百万条线段减少到几百或几千个数据点? - Daan
这是我希望生成的一个例子:链接,这个例子有超过100,000条线段。我真的无法将其减少到密度,因为线的方向以及它如何连接到其他线条可以像空间位置一样影响值。我有一个过时的Fortran/C++/OpenGL代码来完成这个任务,我只是希望更新并可能在程序上添加GUI。 - user2236411
2个回答

13

我会查看LineCollection(文档)

import matplotlib
import matplotlib.pyplot as plt    
import random


s = (600,400)
N = 100000

segs = []
colors = []
my_cmap = plt.get_cmap('jet')
for i in range(N):
    x1 = random.random() * s[0]
    y1 = random.random() * s[1]
    x2 = random.random() * s[0]
    y2 = random.random() * s[1]
    c  = random.random()
    colors.append(my_cmap(c))
    segs.append(((x1, y1), (x2, y2)))

ln_coll = matplotlib.collections.LineCollection(segs, colors=colors)

ax = plt.gca()
ax.add_collection(ln_coll)
ax.set_xlim(0, 600)    
ax.set_ylim(0, 400)
plt.draw()
 

它还可以接受一个numpy数组的列表作为第一个参数。


谢谢你,我之前看过LineCollection,但是没有在不创建多个LineCollection的情况下实现颜色变化,这最终导致了相同的内存错误。不过你的解决方案完美地解决了这个问题。 - user2236411
@user2236411 很高兴能帮到你。欢迎来到SO! - tacaswell

5
你可以考虑先在位图图像上绘制,这样不会出现内存问题,然后再使用Matplotlib调整绘图/图像。下面是一个例子:
from PIL import Image
from PIL import ImageDraw
import random
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.image as mpimg

s = (500,500)
N = 100000

im = Image.new('RGBA', s, (255,255,255,255))
draw = ImageDraw.Draw(im)

for i in range(N):
    x1 = random.random() * s[0]
    y1 = random.random() * s[1]
    x2 = random.random() * s[0]
    y2 = random.random() * s[1]
    c  = random.random() * 256
    draw.line(((x1,y1),(x2,y2)), fill=(0, 255 - int(c), int(c), 255), width=1)

plt.imshow(np.asarray(im), extent=(-1,1,-1,1), aspect='equal', origin='lower')
plt.show()

1
谢谢您提供的解决方案,最终我选择使用LineCollection,因为它更适合我的需求,但是这个解决方案也可以工作。然而,如果有人使用这个解决方案,我相信位图图像会将原点移动到左上角,而不是底部左侧的绘图;因此,您需要转换y值,否则您的图像将在x轴上镜像。 - user2236411
1
@user2236411 你说得对,这张图片在x轴上是镜像的,可以通过imshow函数的关键字参数'origin'来解决。我已经修复并编辑了脚本,还有一些其他问题(im.save和mpimg.imread不必要)。tcaswell的解决方案更好,因为它只使用一个坐标系和matplotlib。 - Jan Kuiken
2
这是一种非常适用于大数据的方法,比其他任何方法都快上数个数量级。 - Rabih Kodeih

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接