具有约2000万个采样点和千兆字节数据的交互式大型绘图

2024-10-01 22:36:46 发布

您现在位置:Python中文网/ 问答频道 /正文

我的内存有问题:它不能保存我想绘制的数据。我有足够的高清空间。有没有什么解决方案可以避免我的数据集被“遮蔽”?

具体来说,我处理数字信号处理,我必须使用高采样率。我的框架(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;)


Tags: ofthe数据formatreadoutputindexmatplotlib
3条回答

在Ubuntu上使用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

10m.csv的前几行如下:

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

基本上,我想:

  • 做多维数据的XY散点图,希望用Z作为点颜色
  • 交互选择一些有趣的观察点
  • 查看所选点的所有维度,以尝试理解它们为何在XY散点图中是异常值

为了获得更多乐趣,我还准备了一个更大的10亿点数据集,以防任何程序可以处理1000万点!CSV文件有点不稳定,我转到HDF5:

import h5py
import numpy

size = 1000000000

with h5py.File('1b.hdf5', 'w') as f:
    x = numpy.arange(size + 1)
    x[size] =  size / 2
    f.create_dataset('x', data=x, dtype='int64')
    y = numpy.arange(size + 1) * 2
    y[size] =  3 * size / 2
    f.create_dataset('y', data=y, dtype='int64')
    z = numpy.arange(size + 1) * 4
    z[size] = -1
    f.create_dataset('z', data=z, dtype='int64')

这将生成一个~23GiB文件,其中包含:

  • 10亿个点在一条直线上,很像10m.csv
  • 图中央顶部的一个异常点

这些测试是在Ubuntu18.10中进行的,除非a小节中另有说明,在一台ThinkPad P51笔记本电脑上,配备Intel Core i7-7820HQ CPU(4核/8线程)、2x Samsung M471A2K43BB1-CRC RAM(2x 16GiB)、NVIDIA Quadro M1200 4GB GDDR5 GPU。

结果摘要

这就是我观察到的,考虑到我非常具体的测试用例,并且我是许多被审查的软件的第一次用户:

它能处理1000万点吗:

Vaex        Yes, tested up to 1 Billion!
VisIt       Yes, but not 100m
Paraview    Barely
Mayavi      Yes
gnuplot     Barely on non-interactive mode.
matplotlib  No
Bokeh       No, up to 1m
PyViz       ?
seaborn     ?

它有很多特点吗:

Vaex        Yes.
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.
Bokeh       Yes, easy to script.
PyViz       ?
seaborn     ?

图形用户界面是否感觉良好(不考虑良好的性能):

Vaex        Yes, Jupyter widget
VisIt       No
Paraview    Very
Mayavi      OK
gnuplot     OK
matplotlib  OK
Bokeh       Very, Jupyter widget
PyViz       ?
seaborn     ?

Vaex 2.0.2

https://github.com/vaexio/vaex

安装并获得一个hello world,如下所示:How to do interactive 2D scatter plot zoom / point selection in Vaex?

我用高达10亿分测试了vaex,它成功了,太棒了!

它是“先编写Python脚本”的,这对于可重复性非常好,并且允许我轻松地与其他Python事物进行交互。

Jupyter的设置有几个移动部分,但是一旦我用virtualenv运行了它,它就非常棒了。

要在Jupyter中加载CSV运行:

import vaex
df = vaex.from_csv('10m.csv', names=['x', 'y', 'z'],)
df.plot_widget(df.x, df.y, backend='bqplot')

我们可以立即看到:

enter image description here

现在,我们可以用鼠标缩放、平移和选择点,更新速度非常快,都在10秒内完成。在这里,我放大看到了一些单独的点,并选择了其中的一些点(图像上较浅的矩形):

enter image description here

使用鼠标进行选择后,这与使用df.select()方法的效果完全相同。所以我们可以通过运行Jupyter来提取所选的点:

df.to_pandas_df(selection=True)

输出数据格式:

        x       y        z   index
0 4525460 9050920 18101840 4525460
1 4525461 9050922 18101844 4525461
2 4525462 9050924 18101848 4525462
3 4525463 9050926 18101852 4525463
4 4525464 9050928 18101856 4525464
5 4525465 9050930 18101860 4525465
6 4525466 9050932 18101864 4525466

既然10米的成绩不错,我决定试试1米的成绩!

import vaex
df = vaex.open('1b.hdf5')
df.plot_widget(df.x, df.y, backend='bqplot')

要观察原始图上看不到的异常值,我们可以遵循How change the point style in a vaex interactive Jupyter bqplot plot_widget to make individual points larger and visible?并使用:

df.plot_widget(df.x, df.y, f='log', shape=128, backend='bqplot')

产生:

enter image description here

选择点后:

enter image description here

我们得到离群值的完整数据:

   x          y           z
0  500000000  1500000000  -1

下面是创建者的演示,其中包含更有趣的数据集和更多功能:https://www.youtube.com/watch?v=2Tt0i823-ec&t=770

在Ubuntu19.04中测试。

访问2.13.3

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

许可证:BSD

Lawrence Livermore National Laboratory开发的,这是一个National Nuclear Security Administration实验室,所以你可以想象,如果我能让它工作的话,10米的积分对它来说是没有意义的。

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

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

在玩了3个小时的UI之后,我确实让它工作了,并且它确实解决了我的用例,详细内容如下:https://stats.stackexchange.com/questions/376361/how-to-find-the-sample-points-that-have-statistically-meaningful-large-outlier-r

以下是这篇文章的测试数据:

enter image description here

放大一些照片ks公司:

enter image description here

这里是picks窗口:

enter image description here

从性能上看,访问非常好:每一个图形操作要么只花了很少的时间,要么是立即的,我认为它可以轻松地处理更多的数据。当我不得不等待时,它会显示一条“正在处理”消息,显示剩余工作的百分比,并且GUI不会冻结。

由于10m点工作得很好,我也尝试了100m点(一个2.7G CSV文件),但它崩溃了/进入了一个奇怪的状态不幸的是,我在htop中看到它,因为4个访问线程占用了我所有的16GiB内存,很可能是由于malloc失败而死亡。

最初的开始有点痛苦:

  • 如果你不是核弹工程师,很多违约行为都会让你觉得很糟糕?例如。:
  • 有很多功能,所以很难找到你想要的
  • 该手册非常有用,但它是一个386页的PDF猛犸象不祥的日期“2005年10月版本1.5”。我想知道他们是不是用这个来开发Trinity它是在我最初回答这个问题之后创建的nice Sphinx HTML
  • 没有Ubuntu包。但预先构建的二进制文件确实起了作用。

我把这些问题归咎于:

  • 它已经存在了这么长时间,并且使用了一些过时的GUI思想
  • 你不能只点击绘图元素来改变它们(例如轴、标题等),而且有很多功能,所以很难找到你想要的

我也喜欢一点LLNL基础设施如何泄漏到repo中。请参阅该目录中的示例docs/OfficeHours.txt和其他文件!我很抱歉布拉德是“星期一早上的家伙”!哦,答录机的密码是“Kill Ed”,别忘了。

全景5.4.1

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

许可证:BSD

安装:

sudo apt-get install paraview

Sandia National Laboratories开发,这是另一个NNSA实验室,所以我们再次期待它能轻松处理数据。另外,VTK的基础上,用C++编写,这是进一步的承诺。

但是我很失望:由于某些原因,1000万点让GUI非常慢,而且没有反应。

我很好的控制广告“我现在工作,等一下”的时刻,但图形用户界面冻结而发生的事情?不可接受。

htop显示Paraview使用了4个线程,但是CPU和内存都没有耗尽。

从图形用户界面上看,Paraview非常漂亮和现代,在不结巴的情况下比访问要好得多。这里有一个较低的点数供参考:

enter image description here

下面是电子表格视图,其中包含手动选择点:

enter image description here

另一个缺点是,与访问相比,Paraview感觉缺少功能,例如:

梅亚维4.6.2

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

开发人:Enthought

安装:

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

VTKPython一号。

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

但是我不能放大到足以看到个人所有的点,近三维平面太远了。也许有办法?

Mayavi的一个很酷的地方是,开发人员花了很多精力让您能够很好地从Python脚本启动和设置GUI,就像Matplotlib和gnuplot一样。在Paraview中,这似乎也是可能的,但文档至少没有那么好。

一般来说,它不像VisIt/Paraview那样具有特色。例如,我无法直接从GUI加载CSV:How to load a CSV file from the Mayavi GUI?

Gnuplot 5.2.2

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

gnuplot在我需要快速和脏兮兮的时候非常方便,而且它总是我尝试的第一件事。

安装:

sudo apt-get install gnuplot

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

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

在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

但是标签功能有一个性能缺陷,包括非交互式渲染。但我报告了,伊桑一天就解决了:https://groups.google.com/forum/#!topic/comp.graphics.apps.gnuplot/qpL8aJIi9ZE

不过,我必须说,对于异常值选择有一个合理的解决方法:只需向所有点添加具有行ID的标签!如果附近有很多点,你将无法阅读标签。但是对于那些你关心的异类,你可能会!例如,如果在原始数据中添加一个异常值:

cp 10m.csv 10m1.csv
printf '2500000,10000000,40000000\n' >> 10m1.csv

并将plot命令修改为:

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

这显著减慢了绘图速度(在上述修复后40分钟),但产生了合理的输出:

enter image description here

所以通过一些数据过滤,我们最终会达到目的。

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)以便交互式版本出于某种原因工作,否则它会爆炸:

RuntimeError: In set_size: Could not set the fontsize

第1.3.1节

https://github.com/bokeh/bokeh

Ubuntu 19.04安装:

python3 -m pip install bokeh

然后启动Jupyter:

jupyter notebook

现在如果我画出1米的点,一切都很好,界面很棒,速度也很快,包括缩放和悬停信息:

from bokeh.io import output_notebook, show
from bokeh.models import HoverTool
from bokeh.transform import linear_cmap
from bokeh.plotting import figure
from bokeh.models import ColumnDataSource
import numpy as np

N = 1000000
source = ColumnDataSource(data=dict(
    x=np.random.random(size=N) * N,
    y=np.random.random(size=N) * N,
    z=np.random.random(size=N)
))
hover = HoverTool(tooltips=[("z", "@z")])
p = figure()
p.add_tools(hover)
p.circle(
    'x',
    'y',
    source=source,
    color=linear_cmap('z', 'Viridis256', 0, 1.0),
    size=5
)
show(p)

初始视图:

enter image description here

缩放后:

enter image description here

如果我到了10m,尽管它阻塞了,htop显示chromium有8个线程在不间断IO状态下占用了我的所有内存。

这询问关于引用点:How to reference selected bokeh data points

PyViz

https://pyviz.org/

待办事项评估。

集成Bokeh+datashader+其他工具。

视频演示1B数据点:https://www.youtube.com/watch?v=k27MJJLJNT4“PyViz:30行Python中的10亿数据点可视化仪表板”,由“Anaconda,Inc.”发布于2018-04-17。

西伯恩

https://seaborn.pydata.org/

待办事项评估。

how to use seaborn to visualize at least 50 million rows上已经有一个QA。

所以你的数据并没有那么大,而且你在绘制数据时遇到了麻烦,这说明工具有问题。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米的每一点来说,其中大部分都将重叠,试图渲染小的十字或圆或其他东西将是一个离散点,生成巨大的文件并花费数吨的时间。我认为这就是默认情况下下沉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可以轻松读取的文件格式。

您当然可以优化文件的读取:您可以直接将其读入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不是问题,可以使用fromfile将整个数组放入RAM中:

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

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

相关问题 更多 >

    热门问题