大图:约2000万个样本,千兆字节的数据

时间:2011-05-02 07:25:40

标签: python performance matplotlib scientific-computing

我在这里遇到了问题(我的RAM):它无法保存我想要绘制的数据。我确实有足够的高清空间。是否有任何解决方案可以避免我的数据集“阴影”?

具体而言,我处理数字信号处理,我必须使用高采样率。我的框架(GNU Radio)以二进制形式保存值(以避免使用太多的磁盘空间)。我打开包装。之后我需要策划。我需要可缩放的图和交互式。这是一个问题。

是否有任何优化潜力,或其他软件/编程语言(如R等)可以处理更大的数据集?实际上我想在我的情节中获得更多数据。但我没有其他软件的经验。 GNUplot失败,采用与以下类似的方法。我不知道R(喷射)。

import matplotlib.pyplot as plt
import matplotlib.cbook as cbook
import struct

"""
plots a cfile

cfile - IEEE single-precision (4-byte) floats, IQ pairs, binary
txt - index,in-phase,quadrature in plaintext

note: directly plotting with numpy results into shadowed functions
"""

# unpacking the cfile dataset
def unpack_set(input_filename, output_filename):
    index = 0   # index of the samples
    output_filename = open(output_filename, 'wb')

    with open(input_filename, "rb") as f:

        byte = f.read(4)    # read 1. column of the vector

        while byte != "":
        # stored Bit Values
            floati = struct.unpack('f', byte)   # write value of 1. column to a variable
            byte = f.read(4)            # read 2. column of the vector
            floatq = struct.unpack('f', byte)   # write value of 2. column to a variable
            byte = f.read(4)            # next row of the vector and read 1. column
            # delimeter format for matplotlib 
            lines = ["%d," % index, format(floati), ",",  format(floatq), "\n"]
            output_filename.writelines(lines)
            index = index + 1
    output_filename.close
    return output_filename.name

# reformats output (precision configuration here)
def format(value):
    return "%.8f" % value            

# start
def main():

    # specify path
    unpacked_file = unpack_set("test01.cfile", "test01.txt")
    # pass file reference to matplotlib
    fname = str(unpacked_file)
    plt.plotfile(fname, cols=(0,1)) # index vs. in-phase

    # optional
    # plt.axes([0, 0.5, 0, 100000]) # for 100k samples
    plt.grid(True)
    plt.title("Signal-Diagram")
    plt.xlabel("Sample")
    plt.ylabel("In-Phase")

    plt.show();

if __name__ == "__main__":
    main()

像plt.swap_on_disk()这样的东西可以缓存我SSD上的东西;)

6 个答案:

答案 0 :(得分:65)

因此,您的数据并不是那么大,而且您在绘制数据时遇到问题的事实表明这些工具存在问题。 Matplotlib ....不是那么好。它有很多选项,输出很好,但它是一个巨大的记忆力,它从根本上假设你的数据很小。但是还有其他选择。

举个例子,我使用以下代码生成了一个20M的数据点文件'bigdata.bin':

#!/usr/bin/env python
import numpy
import scipy.io.numpyio

npts=20000000
filename='bigdata.bin'

def main():
    data = (numpy.random.uniform(0,1,(npts,3))).astype(numpy.float32)
    data[:,2] = 0.1*data[:,2]+numpy.exp(-((data[:,1]-0.5)**2.)/(0.25**2))
    fd = open(filename,'wb')
    scipy.io.numpyio.fwrite(fd,data.size,data)
    fd.close()

if __name__ == "__main__":
    main()

这会生成一个大小约为229MB的文件,并不是那么大;但是你已经表示你想要去更大的文件,所以你最终会达到内存限制。

首先让我们专注于非交互式情节。首先要意识到的是,每个点上都有字形的矢量图将成为一场灾难 - 对于20 M点中的每一点,其中大部分都会重叠,尝试渲染小十字或圆圈或者某些事情正在发生成为一个灾难,产生巨大的文件,并花费大量的时间。这个,我认为默认情况下matplotlib正在下沉。

Gnuplot处理这个问题没有问题:

gnuplot> set term png
gnuplot> set output 'foo.png'
gnuplot> plot 'bigdata.bin' binary format="%3float32" using 2:3 with dots

gnuplot

甚至可以使Matplotlib表现得谨慎(选择光栅后端,并使用像素标记点):

#!/usr/bin/env python
import numpy
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt

datatype=[('index',numpy.float32), ('floati',numpy.float32), 
        ('floatq',numpy.float32)]
filename='bigdata.bin'

def main():
    data = numpy.memmap(filename, datatype, 'r') 
    plt.plot(data['floati'],data['floatq'],'r,')
    plt.grid(True)
    plt.title("Signal-Diagram")
    plt.xlabel("Sample")
    plt.ylabel("In-Phase")
    plt.savefig('foo2.png')

if __name__ == "__main__":
    main()  

matplotlib

现在,如果您想要交互式,那么您将不得不将数据分组以进行绘图,并即时放大。我不知道任何python工具可以帮助你做到这一点。

另一方面,绘制大数据是一项非常常见的任务,并且有一些工具可以胜任这项工作。 Paraview是我个人的最爱,VisIt是另一个。它们都主要用于3D数据,但Paraview尤其也是2d,并且非常具有交互性(甚至还有Python脚本界面)。唯一的技巧是将数据写入Paraview可以轻松读取的文件格式。

答案 1 :(得分:12)

您当然可以优化文件的读取:您可以直接将其读入NumPy数组,以便利用NumPy的原始速度。你有几个选择。如果RAM存在问题,可以使用memmap,它将大部分文件保存在磁盘上(而不是RAM中):

# Each data point is a sequence of three 32-bit floats:
data = np.memmap(filename, mode='r', dtype=[('index', 'float32'), ('floati','float32'), ('floatq', 'float32')])

如果RAM不是问题,您可以将整个数组放在RAM中fromfile

data = np.fromfile(filename, dtype=[('index', 'float32'), ('floati','float32'), ('floatq', 'float32')])

然后可以使用Matplotlib通常的plot(*data)函数完成绘图,可能通过另一种解决方案中提出的“放大”方法。

答案 2 :(得分:11)

较新的项目具有很大的潜力,可以使用Bokeh创建大型数据集exactly this in mind

实际上,只有与绘图比例相关的数据才会被发送到显示后端。这种方法比Matplotlib方法快得多。

答案 3 :(得分:7)

我会建议一些有点复杂的东西,但这应该有效:在不同的分辨率下,针对不同的范围构建你的图形。

例如,想想谷歌地球。如果你以最大水平解锁以覆盖整个行星,则分辨率最低。缩放时,图片会更改为更详细的图片,但只会更改您正在放大的区域。

所以基本上你的情节(是2D?3D?我会假设它是2D),我建议你建立一个覆盖整个[0,n]范围的低分辨率的大图,2个覆盖[ 0,n / 2]和[n / 2 + 1,n]分辨率是大分辨率的两倍,4个较小的图覆盖[0,n / 4] ... [3 * n / 4 + 1,n ]的分辨率是上述2的两倍,依此类推。

不确定我的解释是否清楚。此外,我不知道这种多分辨率图是否由任何现有的绘图程序处理。

答案 4 :(得分:4)

对在Ubuntu 18.10上具有1000万点散点图基准的开源交互式绘图软件的调查

https://stats.stackexchange.com/questions/376361/how-to-find-the-sample-points-that-have-statistically-meaningful-large-outlier-r中所述用例的启发,我已经用以下非常简单且幼稚的1000万点直线数据对一些实现进行了基准测试:

i=0; while [ "$i" -lt 10000000 ]; do echo "$i,$((2 * i)),$((4 * i))"; i=$((i + 1)); done > 10m.csv

此文件的前几行如下:

0,0,0
1,2,4
2,4,8
3,6,12
4,8,16

基本上,我想:

  • 绘制多维数据的XY散点图,希望将Z作为点颜色
  • 交互式选择一些有趣的观察点
  • 查看所选点的所有尺寸以尝试了解为什么它们在XY散点中是异常值

这些测试是在Ubuntu 18.10,配备Intel Core i7-7820HQ CPU(4核/ 8线程),2个Samsung M471A2K43BB1-CRC RAM(2个16GiB),NVIDIA Quadro M1200 4GB GDDR5 GPU的ThinkPad P51笔记本电脑上进行的。

结果摘要

这是我观察到的,考虑到我非常特定的测试用例,并且我是许多经过审查的软件的首次用户:

处理1000万点吗?

VisIt       Yes
Paraview    Barely
Mayavi      Yes
gnuplot     Barely on non-interactive mode.
matplotlib  No

它有很多功能吗?

VisIt       Yes, 2D and 3D, focus on interactive.
Paraview    Same as above, a bit less 2D features maybe.
Mayavi      3D only, good interactive and scripting support, but more limited features.
gnuplot     Lots of features, but limited in interactive mode.
matplotlib  Same as above.

GUI感觉良好吗?

VisIt       No
Paraview    Very
Mayavi      OK
gnuplot     OK
matplotlib  OK

VisIt 2.13.3

网站:https://wci.llnl.gov/simulation/computer-codes/visit

许可证:BSD

Lawrence Livermore National Laboratory实验室National Nuclear Security Administration开发,因此可以想象,如果我能使它工作,那么1000万点将毫无用处。

安装:没有Debian软件包,只需从网站下载Linux二进制文件即可。无需安装即可运行。另请参阅:https://askubuntu.com/questions/966901/installing-visit

基于VTK,这是许多高性能图形软件使用的后端库。用C编写。

3小时后,我确实开始使用它,并且确实解决了我的用例,详情如下:https://stats.stackexchange.com/questions/376361/how-to-find-the-sample-points-that-have-statistically-meaningful-large-outlier-r

这是这篇文章的测试数据上的样子:

enter image description here

并进行一些缩放:

enter image description here

这是选择窗口:

enter image description here

Vis在性能方面非常好:每个图形操作要么只花费很少的时间,要么立即完成,我认为它可以轻松处理更多数据。当我不得不等待时,它会显示一条“处理中”消息以及剩余的工作量,并且GUI没有冻结。

然而,最初的开始非常痛苦。一部分是由于目标用例,而另一部分是因为它已经存在了很长时间,并且使用了一些过时的GUI构想:

    除非您是核弹工程师,否则许多默认值都会令人感到残酷。例如。:
    • 默认点大小1像素(显示器上的灰尘会引起混淆)
    • 轴的范围从0.0到1.0
    • 多窗口设置,选择数据点时讨厌的多弹出窗口
  • 功能很多,所以很难找到想要的东西
  • 该手册非常有帮助,但是它是一个386页PDF庞然大物,日期不详,日期为“ October 2005 Version 1.5”。我想知道他们是否以此来开发Trinity
  • 没有Ubuntu软件包。但是预编译的二进制文件确实可以工作。

Paraview 5.4.1

网站:https://www.paraview.org/

许可证:BSD

安装:

sudo apt-get install paraview

Sandia National Laboratories开发,这是另一个NNSA实验室,因此我们再次希望它可以轻松处理数据。也是基于VTK并用C ++编写的,这进一步受到了推崇。

但是我很失望:由于某种原因,1000万点使GUI非常缓慢且无响应。

我对广告中的“我现在正在工作,稍等片刻”的控制良好没事,但是在这种情况下GUI冻结了吗?不可接受。

htop显示Paraview使用了4个线程,但是CPU和内存都没有达到极限。

在GUI方面,Paraview非常美观和现代,在不结结巴巴的情况下比VisIt更好。这里有一个较低的点数可供参考:

enter image description here

这是带有手动点选择的电子表格视图:

enter image description here

另一个缺点是与VisIt相比,Paraview感觉缺乏功能,例如:

Mayavi 4.6.2

网站:https://github.com/enthought/mayavi

开发者:Enthought

安装:

sudo apt-get install libvtk6-dev
python3 -m pip install -u mayavi PyQt5

VTK Python之一。

Mayavi似乎非常专注于3D,我找不到在其中进行2D绘制的方法,因此不幸的是,它并没有削减我的用例。

不过,只是为了检查性能,我将示例改编自:https://docs.enthought.com/mayavi/mayavi/auto/example_scatter_plot.html,获得了1000万分,并且运行得很好,没有滞后:

import numpy as np
from tvtk.api import tvtk
from mayavi.scripts import mayavi2

n = 10000000
pd = tvtk.PolyData()
pd.points = np.linspace((1,1,1),(n,n,n),n)
pd.verts = np.arange(n).reshape((-1, 1))
pd.point_data.scalars = np.arange(n)

@mayavi2.standalone
def main():
   from mayavi.sources.vtk_data_source import VTKDataSource
   from mayavi.modules.outline import Outline
   from mayavi.modules.surface import Surface
   mayavi.new_scene()
   d = VTKDataSource()
   d.data = pd
   mayavi.add_source(d)
   mayavi.add_module(Outline())
   s = Surface()
   mayavi.add_module(s)
   s.actor.property.trait_set(representation='p', point_size=1)
main()

输出:

enter image description here

但是我无法放大到足以看到单个点的地方,近3D平面太远了。也许有办法吗?

关于Mayavi的一件很酷的事情是,开发人员付出了很多努力,使您可以很好地从Python脚本启动和设置GUI,就像Matplotlib和gnuplot一样。看来在Paraview中也可以做到这一点,但是至少这些文档还不够好。

通常感觉不像VisIt / Paraview那样功能齐全。例如,我无法从GUI直接加载CSV:How to load a CSV file from the Mayavi GUI?

Gnuplot

网站:http://www.gnuplot.info/

当我需要快速又脏的时候,gnuplot真的很方便,这始终是我尝试的第一件事。

安装:

sudo apt-get install gnuplot

对于非交互使用,它可以很好地处理10m点:

#!/usr/bin/env gnuplot
set terminal png size 1024,1024
set output "gnuplot.png"
set key off
set datafile separator ","
plot "10m.csv" using 1:2:3 palette

在7秒内完成:

enter image description here

但是,如果我尝试与之互动

#!/usr/bin/env gnuplot
set terminal wxt size 1024,1024
set key off
set datafile separator ","
plot "10m.csv" using 1:2:3 palette

和:

gnuplot -persist main.gnuplot

然后,初始渲染和缩放感觉太迟钝了。我什至看不到矩形选择线!

还要注意,对于我的用例,我需要使用超文本标签,如下所示:

plot "10m.csv" using 1:2:3 with labels hypertext

,但标签功能存在性能错误,包括非交互式渲染。但是我报告了,伊森(Ethan)在一天之内解决了这个问题:https://groups.google.com/forum/#!topic/comp.graphics.apps.gnuplot/qpL8aJIi9ZE

Matplotlib 1.5.1,numpy 1.11.1,Python 3.6.7

网站:https://matplotlib.org/

当gnuplot脚本开始变得太疯狂时,我通常会尝试使用Matplotlib。

numpy.loadtxt仅花费了大约10秒钟,所以我知道这不会很好:

#!/usr/bin/env python3

import numpy
import matplotlib.pyplot as plt

x, y, z = numpy.loadtxt('10m.csv', delimiter=',', unpack=True)
plt.figure(figsize=(8, 8), dpi=128)
plt.scatter(x, y, c=z)
# Non-interactive.
#plt.savefig('matplotlib.png')
# Interactive.
plt.show()

首先,非交互尝试提供了很好的输出,但是耗时3分55秒...

然后,交互式交互花了很长时间进行初始渲染和缩放。无法使用:

enter image description here

关于此屏幕截图的通知,在等待缩放计算之前,应立即缩放并消失的缩放选择在屏幕上停留了很长时间!

由于某种原因,我不得不注释plt.figure(figsize=(8, 8), dpi=128)才能使交互式versoin正常工作,否则它会炸毁:

RuntimeError: In set_size: Could not set the fontsize

答案 5 :(得分:1)

我想知道通过加快查找你的积分是否有胜利? (我已经被R *(r star)树感兴趣了一段时间。)

我想知道在这种情况下使用类似r *树的东西是否可行。 (缩小时,树中较高的节点可能包含有关粗略,缩小渲染的信息,进一步朝向叶子的节点包含单个样本)

甚至内存可以将树(或者你最终使用的任何结构)映射到内存中,以保持性能提升和RAM使用率低。 (将内存管理任务卸载到内核中)

希望有道理..漫无边际。已经很晚了!