├── .gitignore ├── LICENSE.md ├── README.md ├── __init__.py ├── create.py ├── h5view.py └── setup.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | *.egg-info 3 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | H5View is licensed under the terms of the new or revised BSD license, as follows: 2 | 3 | Copyright (c) 2012, Cyrille Rossant 4 | 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without modification, 8 | are permitted provided that the following conditions are met: 9 | 10 | Redistributions of source code must retain the above copyright notice, this list of 11 | conditions and the following disclaimer. 12 | 13 | Redistributions in binary form must reproduce the above copyright notice, this list 14 | of conditions and the following disclaimer in the documentation and/or other 15 | materials provided with the distribution. 16 | 17 | Neither the name of the owner nor the names of its contributors 18 | may be used to endorse or promote products derived from this software without 19 | specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 22 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 23 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 | IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 25 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26 | NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 27 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 28 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 | POSSIBILITY OF SUCH DAMAGE. 31 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | H5View: a light, h5py/IPython-friendly HDF5 viewer in text mode 2 | =============================================================== 3 | 4 | This light Python module lets you explore interactively any HDF5 file in 5 | a Python console or in IPython. Pretty print the file structure and get the 6 | shape, data type, and size of any dataset. Tab completion works in IPython 7 | to let you access any subgroup or dataset. 8 | 9 | H5View is based on the h5py package. 10 | 11 | Usage 12 | ----- 13 | 14 | import h5view 15 | with h5view.open('test.h5') as f: 16 | # display the whole structure of the file 17 | print(f) 18 | # access a group and display its information 19 | print(f.MyGroup1.SubGroup) 20 | # access a dataset 21 | X = f.MyGroup2.MyDataset[0,:] 22 | # access an attribute 23 | val = f.MyGroup3.myAttr 24 | # access to the corresponding h5py object 25 | item = f.MyDataset.item() 26 | # get a descendant from its relative path 27 | print(f.MyGroup4.get('MySubgroup/MyDataset')) 28 | 29 | In IPython, tab completion shows all direct children (groups, datasets, 30 | attributes) of the file or any item (group/dataset), making it quite 31 | convenient to interactively explore a HDF5 file. 32 | 33 | Installation 34 | ------------ 35 | 36 | The code is only in `h5view.py`. The `create.py` file is used to create 37 | a test HDF5 file. 38 | 39 | Download the package and type in a shell (a test HDF5 file is created 40 | automatically in the same folder): 41 | 42 | $ python h5view.py 43 | Let's display the file. 44 | 45 | / 46 | * MyAttr: 23.0 47 | /MyGroup1 48 | * MyAttr2: my string 49 | /MyGroup1/MyGroup11 50 | /MyGroup1/MyGroup11/MyGroup111 51 | /MyGroup1/MyGroup11/MyGroup111/MyDataset2: shape (2, 3, 4, 5), dtype "float32", 480 B 52 | /MyGroup2 53 | /MyGroup2/MyDataset1: shape (100, 100), dtype "int32", 39.1 KB 54 | 55 | Now, let's access some attributes, groups, and datasets. 56 | 23.0 57 | /MyGroup2 58 | /MyGroup2/MyDataset1: shape (100, 100), dtype "int32", 39.1 KB 59 | [[42 42] 60 | [42 42]] 61 | [ 0. 0.] 62 | 63 | 64 | -------------------------------------------------------------------------------- /__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rossant/h5view/9a4153244af55d399c4769f847ea17f5637118f6/__init__.py -------------------------------------------------------------------------------- /create.py: -------------------------------------------------------------------------------- 1 | """Create a mock HDF5 file.""" 2 | import h5py 3 | 4 | with h5py.File('test.h5') as f: 5 | g1 = f.create_group('MyGroup1') 6 | g2 = f.create_group('MyGroup2') 7 | g11 = g1.create_group('MyGroup11') 8 | g111 = g11.create_group('MyGroup111') 9 | f.attrs['MyAttr'] = 23. 10 | dset = g2.create_dataset("MyDataset1", (100, 100), 'i') 11 | dset[...] = 42 12 | g111.create_dataset("MyDataset2", (2,3,4,5), 'f') 13 | g1.attrs['MyAttr2'] = 'my string' 14 | -------------------------------------------------------------------------------- /h5view.py: -------------------------------------------------------------------------------- 1 | """H5View: a light, h5py/IPython-friendly HDF5 viewer in text mode. 2 | 3 | Usage: 4 | 5 | import h5view 6 | with h5view.open('test.h5') as f: 7 | # display the whole structure of the file 8 | print(f) 9 | # access a group and display its information 10 | print(f.MyGroup1.SubGroup) 11 | # access a dataset 12 | X = f.MyGroup2.MyDataset[0,:] 13 | # access an attribute 14 | val = f.MyGroup3.myAttr 15 | # access the corresponding h5py object 16 | item = f.MyDataset.item() 17 | # get a descendant from its relative path 18 | print(f.MyGroup4.get('MySubgroup/MyDataset')) 19 | 20 | In IPython, tab completion shows all direct children (groups, datasets, 21 | attributes) of the file or any item (group/dataset), making it quite 22 | convenient to interactively explore a HDF5 file. 23 | 24 | """ 25 | import h5py 26 | from collections import namedtuple 27 | import operator 28 | import os 29 | 30 | 31 | ItemInfo = namedtuple('ItemInfo', ['path', 'itemtype', 'shape', 'dtype']) 32 | 33 | 34 | def format_size(num_bytes): 35 | """Pretty print a file size.""" 36 | num_bytes = float(num_bytes) 37 | KiB = 1024 38 | MiB = KiB * KiB 39 | GiB = KiB * MiB 40 | TiB = KiB * GiB 41 | PiB = KiB * TiB 42 | EiB = KiB * PiB 43 | ZiB = KiB * EiB 44 | YiB = KiB * ZiB 45 | if num_bytes > YiB: 46 | output = '%.3g YB' % (num_bytes / YiB) 47 | elif num_bytes > ZiB: 48 | output = '%.3g ZB' % (num_bytes / ZiB) 49 | elif num_bytes > EiB: 50 | output = '%.3g EB' % (num_bytes / EiB) 51 | elif num_bytes > PiB: 52 | output = '%.3g PB' % (num_bytes / PiB) 53 | elif num_bytes > TiB: 54 | output = '%.3g TB' % (num_bytes / TiB) 55 | elif num_bytes > GiB: 56 | output = '%.3g GB' % (num_bytes / GiB) 57 | elif num_bytes > MiB: 58 | output = '%.3g MB' % (num_bytes / MiB) 59 | elif num_bytes > KiB: 60 | output = '%.3g KB' % (num_bytes / KiB) 61 | else: 62 | output = '%.3g B' % num_bytes 63 | return output 64 | 65 | 66 | class Item(object): 67 | """Represents a group or a dataset in the file.""" 68 | def __init__(self, file, parent, name, itemtype, **kwargs): 69 | self.file = file 70 | self.parent = parent 71 | self.name = name 72 | self.itemtype = itemtype 73 | self._children = {} 74 | # set special keyword arguments as attributes 75 | self.kwargs = kwargs 76 | # for n, v in kwargs.iteritems(): 77 | # setattr(self, n, v) 78 | parentnm = parent.fullname 79 | if parentnm.endswith('/'): 80 | parentnm = parentnm[:-1] 81 | self.fullname = '/'.join([parentnm, name]) 82 | 83 | def _add_child(self, name, child): 84 | """Add a child.""" 85 | self._children[name] = child 86 | 87 | def children(self): 88 | """Return the list of children.""" 89 | return self._children.keys() 90 | 91 | 92 | # Hierarchy methods 93 | # ----------------- 94 | def get(self, name): 95 | """Return an attribute, a children, or any descendant from its full 96 | name.""" 97 | if name in self._attrs(): 98 | return self._attr(name) 99 | if '/' in name: 100 | parent, child = os.path.split(name) 101 | return self.get(parent).get(child) 102 | else: 103 | return self._children.get(name) 104 | 105 | def __getattr__(self, name): 106 | """Access a child.""" 107 | val = self.get(name) 108 | if val is None: 109 | val = self.kwargs.get(name) 110 | return val 111 | 112 | def __dir__(self): 113 | """Return the list of attributes and children.""" 114 | d = self._children.keys() 115 | d.extend(self._attrs()) 116 | d.extend(self.kwargs) 117 | return sorted(d) 118 | 119 | 120 | # Item methods 121 | # ------------ 122 | def item(self): 123 | """Return the associated h5py object (group or dataset).""" 124 | return self.file.f.get(self.fullname) 125 | 126 | def __getitem__(self, i): 127 | """For a dataset, access any part of the array.""" 128 | if self.itemtype == 'dataset': 129 | return self.item()[i] 130 | 131 | def _attr(self, name): 132 | """Return an attribute.""" 133 | item = self.item() 134 | return item.attrs[name] 135 | 136 | def _attrs(self): 137 | """Return the list of attributes.""" 138 | return sorted(self.item().attrs.keys()) 139 | 140 | 141 | # Display methods 142 | # --------------- 143 | def _get_repr(self): 144 | """Pretty print this item.""" 145 | if self.itemtype == 'group': 146 | # s = ''.format(self.fullname) 147 | s = self.fullname 148 | elif self.itemtype == 'dataset': 149 | item = self.file.f.get(self.fullname) 150 | shape, dtype = str(item.shape), str(item.dtype) 151 | try: 152 | nbytes = item.dtype.itemsize * item.size 153 | except: 154 | nbytes = item.dtype.itemsize * item.len() 155 | # s = ''.format( 156 | # self.fullname, shape, dtype) 157 | s = '{0:s}: shape {1:s}, dtype "{2:s}", {3:s}'.format( 158 | self.fullname, shape, dtype, format_size(nbytes)) 159 | for attr in self._attrs(): 160 | val = self.get(attr) 161 | s += '\n * {0}: {1}'.format(attr, val) 162 | return s 163 | 164 | def __repr__(self): 165 | """Pretty print this item and all its descendants recursively.""" 166 | repr = self._get_repr() 167 | for child in self._children: 168 | repr = repr + "\n" 169 | repr += self.get(child).__repr__() 170 | return repr 171 | 172 | 173 | class Dataset(Item): 174 | def __init__(self, file, parent, name): 175 | super(Dataset, self).__init__(file, parent, name, 'dataset') 176 | 177 | class Group(Item): 178 | def __init__(self, file, parent, name): 179 | super(Group, self).__init__(file, parent, name, 'group') 180 | 181 | 182 | class File(Item): 183 | """Represents a HDF5 file.""" 184 | def __init__(self, filename=None): 185 | self.fullname = '/' 186 | super(File, self).__init__(self, self, '', 'group') 187 | self.filename = filename 188 | self.f = None 189 | self.iteminfos = [] 190 | # open and visit the file 191 | self.open() 192 | 193 | 194 | # I/O methods 195 | # ----------- 196 | def open(self, filename=None): 197 | """Open the file in read-only mode.""" 198 | if filename is None: 199 | filename = self.filename 200 | else: 201 | self.filename = filename 202 | if self.f is None and filename is not None: 203 | self.f = h5py.File(filename, 'r') 204 | self._visit() 205 | 206 | def close(self): 207 | """Close the file.""" 208 | if self.f is not None: 209 | self.f.close() 210 | 211 | def __enter__(self): 212 | """Enter the file, to use with `with`.""" 213 | # self.open() 214 | return self 215 | 216 | def __exit__(self, type, value, tb): 217 | """Exit the file, to use with `with`.""" 218 | self.close() 219 | 220 | 221 | # Exploration methods 222 | # ------------------- 223 | def _visit_item(self, name): 224 | """Callback function for `visit`: register the item.""" 225 | item = self.f.get(name) 226 | # add item info 227 | if isinstance(item, h5py.Dataset): 228 | itemtype = 'dataset' 229 | shape, dtype = item.shape, item.dtype 230 | elif isinstance(item, h5py.Group): 231 | itemtype = 'group' 232 | shape, dtype = None, None 233 | self.iteminfos.append(ItemInfo(name, itemtype, shape, dtype)) 234 | # add child 235 | if '/' not in name: 236 | self._children[name] = Item(self, self, name, itemtype, shape=shape, dtype=dtype) 237 | else: 238 | parentnm, childnm = os.path.split(name) 239 | parent = self.get(parentnm) 240 | child = Item(self, parent, childnm, itemtype, shape=shape, dtype=dtype) 241 | parent._add_child(childnm, child) 242 | 243 | def _visit(self): 244 | """Visit the whole hierarchy of groups and datasets in the file.""" 245 | if self.f is not None: 246 | self.f.visit(self._visit_item) 247 | self.iteminfos = sorted(self.iteminfos, key=operator.itemgetter(0)) 248 | return self.iteminfos 249 | 250 | 251 | # Display methods 252 | # --------------- 253 | def __repr__(self): 254 | """Return a complete pretty print representation of the file and 255 | all its groups, datasets and attributes.""" 256 | filename = os.path.realpath(self.filename) 257 | s = '\n'.format( 258 | filename, format_size(os.path.getsize(filename))) 259 | s += super(File, self).__repr__() 260 | return s 261 | 262 | 263 | def open(filename): 264 | """Open a HDF5 file.""" 265 | return File(filename) 266 | 267 | 268 | if __name__ == '__main__': 269 | filename = 'test.h5' 270 | if not os.path.exists(filename): 271 | import create 272 | with open(filename) as f: 273 | print("Let's display the file.") 274 | print(f) 275 | print("") 276 | print("Now, let's access some attributes, groups, and datasets.") 277 | print(f.MyAttr) 278 | print(f.MyGroup2) 279 | print(f.MyGroup2.MyDataset1[2:4,3:5]) 280 | print(f.MyGroup1.MyGroup11.get('MyGroup111/MyDataset2')[0,0,0,1:3]) 281 | 282 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | import os 3 | 4 | here = os.path.abspath(os.path.dirname(__file__)) 5 | try: 6 | README = open(os.path.join(here, 'README.md')).read() 7 | except IOError: 8 | README = '' 9 | 10 | setup(name='h5view', 11 | long_description=README, 12 | license='LICENSE.md', 13 | py_modules=['h5view'], 14 | ) 15 | --------------------------------------------------------------------------------