Loading a hdf5 file and displaying the data with pyqtgraph

230 views
Skip to first unread message

Anna Nkldun

unread,
Aug 18, 2021, 6:40:35 PM8/18/21
to pyqtgraph

I would like to show the data of a hdf5 file in the ImageView() class from pyqtgraph. The bare code of displaying the plot for ImageView() is:

    
    from pyqtgraph.Qt import QtCore, QtGui
    import pyqtgraph as pg
    
    # Interpret image data as row-major instead of col-major
    pg.setConfigOptions(leftButtonPan = False, imageAxisOrder='row-major')
    
    app = QtGui.QApplication([])
    
    ## Create window with ImageView widget
    win = QtGui.QMainWindow()
    win.resize(800,800)
    imv = pg.ImageView()
    win.setCentralWidget(imv)
    win.show()
    win.setWindowTitle('pyqtgraph example: ImageView')
    
    if __name__ == '__main__':
        import sys
        if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
            QtGui.QApplication.instance().exec_()

There is however also a hdf5 example in the pyqtgraph example set. I'm unfortunately not able to get it to work. I made some alterations to the example to make it work for my needs but I'm getting an error. Here is first the code:



    import numpy as np
    import h5py
    import pyqtgraph as pg
    from pyqtgraph.Qt import QtCore, QtGui

    pg.mkQApp()

    plt = pg.plot()
    plt.setWindowTitle('pyqtgraph example: HDF5 big data')
    plt.enableAutoRange(False, False)
    plt.setXRange(0, 500)


    class HDF5Plot(pg.ImageItem):
        def __init__(self, *args, **kwds):
            self.hdf5 = None
            self.limit = 10000  # maximum number of samples to be plotted
            pg.ImageItem.__init__(self, *args, **kwds)

        def setHDF5(self, data):
            self.hdf5 = data
            self.updateHDF5Plot()

        def viewRangeChanged(self):
            self.updateHDF5Plot()

        def updateHDF5Plot(self):
            if self.hdf5 is None:
                self.setData([])
                return

            vb = self.getViewBox()
            if vb is None:
                return  # no ViewBox yet

            # Determine what data range must be read from HDF5
            xrange = vb.viewRange()[0]
            start = max(0, int(xrange[0]) - 1)
            stop = min(len(self.hdf5), int(xrange[1] + 2))

            # Decide by how much we should downsample
            ds = int((stop - start) / self.limit) + 1

            if ds == 1:
                # Small enough to display with no intervention.
                visible = self.hdf5[start:stop]
                scale = 1
            else:
                # Here convert data into a down-sampled array suitable for visualizing.
                # Must do this piecewise to limit memory usage.
                samples = 1 + ((stop - start) // ds)
                visible = np.zeros(samples * 2, dtype=self.hdf5.dtype)
                sourcePtr = start
                targetPtr = 0

                # read data in chunks of ~1M samples
                chunkSize = (1000000 // ds) * ds
                while sourcePtr < stop - 1:
                    chunk = self.hdf5[sourcePtr:min(stop, sourcePtr + chunkSize)]
                    sourcePtr += len(chunk)

                    # reshape chunk to be integral multiple of ds
                    chunk = chunk[:(len(chunk) // ds) * ds].reshape(len(chunk) // ds, ds)

                    # compute max and min
                    chunkMax = chunk.max(axis=1)
                    chunkMin = chunk.min(axis=1)

                    # interleave min and max into plot data to preserve envelope shape
                    visible[targetPtr:targetPtr + chunk.shape[0] * 2:2] = chunkMin
                    visible[1 + targetPtr:1 + targetPtr + chunk.shape[0] * 2:2] = chunkMax
                    targetPtr += chunk.shape[0] * 2

                visible = visible[:targetPtr]
                scale = ds * 0.5

            self.setData(visible)  # update the plot
            self.setPos(start, 0)  # shift to match starting index
            self.resetTransform()
            self.scale(scale, 1)  # scale to match downsampling


    f = h5py.File('test.hdf5', 'r')
    curve = HDF5Plot()
    curve.setHDF5(f['data'])
    plt.addItem(curve)

    ## Start Qt event loop unless running in interactive mode or using pyside.
    if __name__ == '__main__':

        import sys

        if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
            QtGui.QApplication.instance().exec_()

And here is the error:

    Traceback (most recent call last):
      File "pyqtg.py", line 206, in <module>
        curve.setHDF5(f['data'])
      File "h5py/_objects.pyx", line 54, in h5py._objects.with_phil.wrapper
      File "h5py/_objects.pyx", line 55, in h5py._objects.with_phil.wrapper
      File "/home/anaconda3/envs/img/lib/python3.8/site-packages/h5py-3.3.0-py3.8-linux-x86_64.egg/h5py/_hl/group.py", line 305, in __getitem__
        oid = h5o.open(self.id, self._e(name), lapl=self._lapl)
      File "h5py/_objects.pyx", line 54, in h5py._objects.with_phil.wrapper
      File "h5py/_objects.pyx", line 55, in h5py._objects.with_phil.wrapper
      File "h5py/h5o.pyx", line 190, in h5py.h5o.open
    KeyError: "Unable to open object (object 'data' doesn't exist)"


The problem is that I don't know what/how the hdf5 file looks so I am unsure how to replace 'data' with the correct term or if it is completely different in and of itself. Any help is greatly appreciated.

Martin Chase

unread,
Aug 19, 2021, 2:55:57 PM8/19/21
to pyqt...@googlegroups.com
Hey,

You should be able to inspect your `h5py.File` object in an interactive shell to learn more about it. Just open up `python` ( or `ipython` ) and start playing around. Here's an example of how I inspected an hdf5 file's structure:

```python
    import hdf5
    f = hdf5.File("test.hdf5", "r")
    dir(f)
    vars(f)
    list(f.keys())
    help(f.visit)
    f.visit(print)
```

Best,
 - Martin
Reply all
Reply to author
Forward
0 new messages