HDF5Exporter handling of ragged curves with tests (#1072)

* HDF5Exporter handles ragged curves by saving them into different datasets based on their names.

* Add HDF5Exporter tests

* Document HDF5Exporter

* Fix tmp file path
This commit is contained in:
Kenneth Lyons 2019-11-12 09:01:49 -08:00 committed by Ogi Moore
parent faef56c3e7
commit ec445e7601
4 changed files with 98 additions and 15 deletions

View File

@ -116,9 +116,9 @@ jobs:
conda install -c conda-forge $(qt.bindings) --yes conda install -c conda-forge $(qt.bindings) --yes
fi fi
echo "Installing remainder of dependencies" echo "Installing remainder of dependencies"
conda install -c conda-forge numpy scipy six pyopengl --yes conda install -c conda-forge numpy scipy six pyopengl h5py --yes
else else
pip install $(qt.bindings) numpy scipy pyopengl six pip install $(qt.bindings) numpy scipy pyopengl six h5py
fi fi
echo "" echo ""
pip install pytest pytest-xdist pytest-cov coverage pip install pytest pytest-xdist pytest-cov coverage

View File

@ -30,8 +30,13 @@ Export Formats
for export. for export.
* Printer - Exports to the operating system's printing service. This exporter is provided for completeness, * Printer - Exports to the operating system's printing service. This exporter is provided for completeness,
but is not well supported due to problems with Qt's printing system. but is not well supported due to problems with Qt's printing system.
* HDF5 - Exports data from a :class:`~pyqtgraph.PlotItem` to a HDF5 file if
h5py_ is installed. This exporter supports :class:`~pyqtgraph.PlotItem`
objects containing multiple curves, stacking the data into a single HDF5
dataset based on the ``columnMode`` parameter. If data items aren't the same
size, each one is given its own dataset.
.. _h5py: https://www.h5py.org/
Exporting from the API Exporting from the API
---------------------- ----------------------

View File

@ -44,20 +44,27 @@ class HDF5Exporter(Exporter):
data = [] data = []
appendAllX = self.params['columnMode'] == '(x,y) per plot' appendAllX = self.params['columnMode'] == '(x,y) per plot'
#print dir(self.item.curves[0]) # Check if the arrays are ragged
tlen = 0 len_first = len(self.item.curves[0].getData()[0]) if self.item.curves[0] else None
ragged = any(len(i.getData()[0]) != len_first for i in self.item.curves)
if ragged:
dgroup = fd.create_group(dsname)
for i, c in enumerate(self.item.curves):
d = c.getData()
fdata = numpy.array([d[0], d[1]]).astype('double')
cname = c.name() if c.name() is not None else str(i)
dset = dgroup.create_dataset(cname, data=fdata)
else:
for i, c in enumerate(self.item.curves): for i, c in enumerate(self.item.curves):
d = c.getData() d = c.getData()
if i > 0 and len(d[0]) != tlen:
raise ValueError ("HDF5 Export requires all curves in plot to have same length")
if appendAllX or i == 0: if appendAllX or i == 0:
data.append(d[0]) data.append(d[0])
tlen = len(d[0])
data.append(d[1]) data.append(d[1])
fdata = numpy.array(data).astype('double') fdata = numpy.array(data).astype('double')
dset = fd.create_dataset(dsname, data=fdata) dset = fd.create_dataset(dsname, data=fdata)
fd.close() fd.close()
if HAVE_HDF5: if HAVE_HDF5:

View File

@ -0,0 +1,71 @@
# -*- coding: utf-8 -*-
import pytest
import pyqtgraph as pg
from pyqtgraph.exporters import HDF5Exporter
import numpy as np
from numpy.testing import assert_equal
import h5py
import os
@pytest.fixture
def tmp_h5(tmp_path):
yield tmp_path / "data.h5"
@pytest.mark.parametrize("combine", [False, True])
def test_HDF5Exporter(tmp_h5, combine):
# Basic test of functionality: multiple curves with shared x array. Tests
# both options for stacking the data (columnMode).
x = np.linspace(0, 1, 100)
y1 = np.sin(x)
y2 = np.cos(x)
plt = pg.plot()
plt.plot(x=x, y=y1)
plt.plot(x=x, y=y2)
ex = HDF5Exporter(plt.plotItem)
if combine:
ex.parameters()['columnMode'] = '(x,y,y,y) for all plots'
ex.export(fileName=tmp_h5)
with h5py.File(tmp_h5, 'r') as f:
# should be a single dataset with the name of the exporter
dset = f[ex.parameters()['Name']]
assert isinstance(dset, h5py.Dataset)
if combine:
assert_equal(np.array([x, y1, y2]), dset)
else:
assert_equal(np.array([x, y1, x, y2]), dset)
def test_HDF5Exporter_unequal_lengths(tmp_h5):
# Test export with multiple curves of different size. The exporter should
# detect this and create multiple hdf5 datasets under a group.
x1 = np.linspace(0, 1, 10)
y1 = np.sin(x1)
x2 = np.linspace(0, 1, 100)
y2 = np.cos(x2)
plt = pg.plot()
plt.plot(x=x1, y=y1, name='plot0')
plt.plot(x=x2, y=y2)
ex = HDF5Exporter(plt.plotItem)
ex.export(fileName=tmp_h5)
with h5py.File(tmp_h5, 'r') as f:
# should be a group with the name of the exporter
group = f[ex.parameters()['Name']]
assert isinstance(group, h5py.Group)
# should be a dataset under the group with the name of the PlotItem
assert_equal(np.array([x1, y1]), group['plot0'])
# should be a dataset under the group with a default name that's the
# index of the curve in the PlotItem
assert_equal(np.array([x2, y2]), group['1'])