Fix Python wikilink in HDF5 post.
[blog.git] / posts / HDF5.mdwn
1 [[!meta  title="HDF5 and h5py"]]
2
3 [h5py][] is a [[Python]] interface to the [Hierarchical Data
4 Format][HDF] library, version 5.  It provides a mature, stable, open
5 way to store data.  The HDF5 [tutorial][] provides an excellent
6 introduction to the basic concepts of HDF5.
7
8 Useful utilities included with the HDF5 library:
9
10 * `h5dump` (command line HDF5 extraction)
11 * `h5stat` (command line HDF5 database statistics)
12
13 I'll walk through the HDF5 tutorial with `h5py` to give you a feel for
14 how things work.  It may help to keep in mind the following HDF5 to
15 filesystem concept map:
16
17 <table>
18   <tr><th>HDF5</th><th>filesystem</th></tr>
19   <tr><td>dataset</td><td>file</td></tr>
20   <tr><td>attribute</td><td>metadata/header</td></tr>
21   <tr><td>group</td><td>directory</td></tr>
22 </table>
23
24 [h5py]: http://code.google.com/p/h5py/
25 [HDF]: http://www.hdfgroup.org/HDF5/
26 [tutorial]: http://www.hdfgroup.org/HDF5/Tutor/
27
28
29 Creating an HDF5 file
30 ---------------------
31
32     >>> import h5py
33     >>> f = h5py.File('file.h5', 'w')
34     >>> f.close()
35
36 Which creates
37
38     $ h5dump file.h5
39     HDF5 "file.h5" {
40     GROUP "/" {
41     }
42     }
43
44 Creating a dataset
45 ------------------
46
47     >>> import h5py
48     >>> import numpy
49     >>> f = h5py.File('dset.h5', 'w')
50     >>> f['dset'] = numpy.zeros((6,4), dtype=numpy.int32)
51     >>> f.close()
52
53 Which creates
54
55     $ h5dump dset.h5
56     HDF5 "dset.h5" {
57     GROUP "/" {
58        DATASET "dset" {
59           DATATYPE  H5T_STD_I32LE
60           DATASPACE  SIMPLE { ( 6, 4 ) / ( 6, 4 ) }
61           DATA {
62           (0,0): 0, 0, 0, 0,
63           (1,0): 0, 0, 0, 0,
64           (2,0): 0, 0, 0, 0,
65           (3,0): 0, 0, 0, 0,
66           (4,0): 0, 0, 0, 0,
67           (5,0): 0, 0, 0, 0
68           }
69        }
70     }
71     }
72
73 Reading from and writing to a dataset
74 -------------------------------------
75
76     >>> import h5py
77     >>> import numpy
78     >>> f = h5py.File('dset.h5', 'w')
79     >>> f['dset'] = numpy.arange(24, dtype=numpy.int32).reshape((4, 6))
80     >>> dset = f['dset']
81     >>> dset
82     <HDF5 dataset "dset": shape (4, 6), type "<i4">
83     >>> dset.value
84     array([[ 0,  1,  2,  3,  4,  5],
85            [ 6,  7,  8,  9, 10, 11],
86            [12, 13, 14, 15, 16, 17],
87            [18, 19, 20, 21, 22, 23]])
88     >>> f.close()
89
90 Which creates
91
92     $ h5dump dset.h5
93     HDF5 "dset.h5" {
94     GROUP "/" {
95        DATASET "dset" {
96           DATATYPE  H5T_STD_I32LE
97           DATASPACE  SIMPLE { ( 4, 6 ) / ( 4, 6 ) }
98           DATA {
99           (0,0): 0, 1, 2, 3, 4, 5
100           (1,0): 6, 7, 8, 9, 10, 11
101           (3,0): 12, 13, 14, 15, 16, 17
102           (4,0): 18, 19, 20, 21, 22, 23
103           }
104        }
105     }
106     }
107
108 Creating an attribute
109 ---------------------
110
111 Using our file from the previous example:
112
113     >>> import h5py
114     >>> import numpy
115     >>> f = h5py.File('dset.h5', 'a')
116     >>> dset = f['dset']
117     >>> dset.attrs['Units'] = [100, 200]
118     >>> f.close()
119
120 Which creates
121
122     $ h5dump dset.h5
123     HDF5 "dset.h5" {
124     GROUP "/" {
125        DATASET "dset" {
126           DATATYPE  H5T_STD_I32LE
127           DATASPACE  SIMPLE { ( 6, 4 ) / ( 6, 4 ) }
128           DATA {
129           (0,0): 0, 1, 2, 3,
130           (1,0): 4, 5, 6, 7,
131           (2,0): 8, 9, 10, 11,
132           (3,0): 12, 13, 14, 15,
133           (4,0): 16, 17, 18, 19,
134           (5,0): 20, 21, 22, 23
135           }
136           ATTRIBUTE "Units" {
137              DATATYPE  H5T_STD_I32LE
138              DATASPACE  SIMPLE { ( 2 ) / ( 2 ) }
139              DATA {
140              (0): 100, 200
141              }
142           }
143        }
144     }
145     }
146
147 Creating a group
148 ----------------
149
150     >>> import h5py
151     >>> f = h5py.File('group.h5', 'w')
152     >>> g = f.create_group('/MyGroup')
153     >>> g
154     <HDF5 group "/MyGroup" (0 members)>
155     >>> f.close()
156
157 Which creates
158
159     $ h5dump group.h5
160     HDF5 "group.h5" {
161     GROUP "/" {
162        GROUP "MyGroup" {
163        }
164     }
165     }
166
167 Creating groups using absolute and relative names
168 -------------------------------------------------
169
170     >>> import h5py
171     >>> f = h5py.File('groups.h5', 'w')
172     >>> g1 = f.create_group('/MyGroup')
173     >>> g2 = f.create_group('/MyGroup/Group_A')
174     >>> g3 = g1.create_group('Group_B')
175     >>> f.keys()
176     ['MyGroup']
177     >>> f['MyGroup'].keys()
178     ['Group_A', 'Group_B']
179     >>> f.close()
180
181 Which creates
182
183     $ h5dump groups.h5
184     HDF5 "groups.h5" {
185     GROUP "/" {
186        GROUP "MyGroup" {
187           GROUP "Group_A" {
188           }
189           GROUP "Group_B" {
190           }
191        }
192     }
193     }
194
195 Creating datasets in groups
196 ---------------------------
197
198 Using our file from the previous example:
199
200     >>> import h5py
201     >>> f = h5py.File('groups.h5', 'a')
202     >>> f['/MyGroup/dset1'] = [3, 3]
203     >>> g = f['/MyGroup/Group_A']
204     >>> g['dset2'] = [2, 10]
205     >>> f.close()
206
207 Which creates
208
209     $ h5dump groups.h5
210     HDF5 "groups.h5" {
211     GROUP "/" {
212        GROUP "MyGroup" {
213           GROUP "Group_A" {
214              DATASET "dset2" {
215                 DATATYPE  H5T_STD_I32LE
216                 DATASPACE  SIMPLE { ( 2 ) / ( 2 ) }
217                 DATA {
218                 (0): 2, 10
219                 }
220              }
221           }
222           GROUP "Group_B" {
223           }
224           DATASET "dset1" {
225              DATATYPE  H5T_STD_I32LE
226              DATASPACE  SIMPLE { ( 2 ) / ( 2 ) }
227              DATA {
228              (0): 3, 3
229              }
230           }
231        }
232     }
233     }
234
235 Reading from or writing to a subset of a dataset
236 ------------------------------------------------
237
238 Just use the [Numpy slice indexing][slice] you're used to.
239
240     >>> import h5py
241     >>> import numpy
242     >>> f = h5py.File('hype.h5', 'w')
243     >>> f['IntArray'] = numpy.ones((8, 10))
244     >>> dset = f['IntArray']
245     >>> dset.value
246     array([[ 1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.],
247            [ 1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.],
248            [ 1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.],
249            [ 1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.],
250            [ 1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.],
251            [ 1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.],
252            [ 1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.],
253            [ 1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.]])
254     >>> f['IntArray'][:,5:] = 2
255     >>> dset.value
256     array([[ 1.,  1.,  1.,  1.,  1.,  2.,  2.,  2.,  2.,  2.],
257            [ 1.,  1.,  1.,  1.,  1.,  2.,  2.,  2.,  2.,  2.],
258            [ 1.,  1.,  1.,  1.,  1.,  2.,  2.,  2.,  2.,  2.],
259            [ 1.,  1.,  1.,  1.,  1.,  2.,  2.,  2.,  2.,  2.],
260            [ 1.,  1.,  1.,  1.,  1.,  2.,  2.,  2.,  2.,  2.],
261            [ 1.,  1.,  1.,  1.,  1.,  2.,  2.,  2.,  2.,  2.],
262            [ 1.,  1.,  1.,  1.,  1.,  2.,  2.,  2.,  2.,  2.],
263            [ 1.,  1.,  1.,  1.,  1.,  2.,  2.,  2.,  2.,  2.]])
264     >>> dset[1:4,2:6] = 5
265     >>> f['IntArray'].value
266     array([[ 1.,  1.,  1.,  1.,  1.,  2.,  2.,  2.,  2.,  2.],
267            [ 1.,  1.,  5.,  5.,  5.,  5.,  2.,  2.,  2.,  2.],
268            [ 1.,  1.,  5.,  5.,  5.,  5.,  2.,  2.,  2.,  2.],
269            [ 1.,  1.,  5.,  5.,  5.,  5.,  2.,  2.,  2.,  2.],
270            [ 1.,  1.,  1.,  1.,  1.,  2.,  2.,  2.,  2.,  2.],
271            [ 1.,  1.,  1.,  1.,  1.,  2.,  2.,  2.,  2.,  2.],
272            [ 1.,  1.,  1.,  1.,  1.,  2.,  2.,  2.,  2.,  2.],
273            [ 1.,  1.,  1.,  1.,  1.,  2.,  2.,  2.,  2.,  2.]])
274     >>> f.close()
275
276 [slice]: http://docs.scipy.org/doc/numpy/reference/arrays.indexing.html
277
278 Datatypes
279 ---------
280
281 Your array's `numpy.dtype` will be preserved.
282
283     >>> import h5py
284     >>> f = h5py.File('dtype.h5', 'w')
285     >>> f['complex'] = 2 + 3j
286     >>> f['complex'].dtype
287     dtype('complex128')
288     >>> type(f['complex'].value)
289     <type 'complex'>
290     >>> f['complex array'] = [1 + 2j, 3 + 4j]
291     >>> f['complex array'].dtype
292     dtype('complex128')
293     >>> type(f['complex array'].value)
294     <type 'numpy.ndarray'>
295     >>> f.close()
296
297 Which creates
298
299     $ h5dump dtype.h5
300     HDF5 "dtype.h5" {
301     GROUP "/" {
302        DATASET "complex" {
303           DATATYPE  H5T_COMPOUND {
304              H5T_IEEE_F64LE "r";
305              H5T_IEEE_F64LE "i";
306           }
307           DATASPACE  SCALAR
308           DATA {
309           (0): {
310                 2,
311                 3
312              }
313           }
314        }
315        DATASET "complex array" {
316           DATATYPE  H5T_COMPOUND {
317              H5T_IEEE_F64LE "r";
318              H5T_IEEE_F64LE "i";
319           }
320           DATASPACE  SIMPLE { ( 2 ) / ( 2 ) }
321           DATA {
322           (0): {
323                 1,
324                 2
325              },
326           (1): {
327                 3,
328                 4
329              }
330           }
331        }
332     }
333     }
334
335 Properties
336 ----------
337
338 No examples here...
339
340 Chunking and extendible datasets
341 --------------------------------
342
343 Extendible datasets must be chunked.
344
345     >>> import h5py
346     >>> import numpy
347     >>> f = h5py.File('ext.h5', 'w')
348     >>> f['simple'] = [1, 2, 3]  # not chunked
349     >>> s = f['simple']
350     >>> s.chunks == None
351     True
352     >>> s.resize((6,))
353     Traceback (most recent call last):
354       ...
355     TypeError: Only chunked datasets can be resized
356     >>> c = f.create_dataset('chunked', (3,), numpy.int32, chunks=(2,))
357     >>> c.chunks
358     (2,)
359     >>> c[:] = [9, 8, 7]
360     >>> c.resize((6,))
361     >>> c.value
362     array([1, 2, 3, 0, 0, 0])
363     >>> c.resize((6,2))
364     Traceback (most recent call last):
365       ...
366     TypeError: New shape length (2) must match dataset rank (1)
367     >>> f.close()
368
369 The "chunkiness" of data is not listed by `h5dump`,
370
371     $ h5dump dtype.h5
372     HDF5 "ext.h5" {
373     GROUP "/" {
374        DATASET "chunked" {
375           DATATYPE  H5T_STD_I32LE
376           DATASPACE  SIMPLE { ( 6 ) / ( 6 ) }
377           DATA {
378           (0): 1, 2, 3, 0, 0, 0
379           }
380        }
381        DATASET "simple" {
382           DATATYPE  H5T_STD_I32LE
383           DATASPACE  SIMPLE { ( 3 ) / ( 3 ) }
384           DATA {
385           (0): 1, 2, 3
386           }
387        }
388     }
389     }
390
391 but it is preserved.
392
393     >>> f = h5py.File('ext.h5', 'a')
394     >>> f['chunked'].chunks
395     (2,)
396     >>> f['simple'].chunks == None
397     True
398
399 [[!tag tags/python]]
400 [[!tag tags/programming]]
401 [[!tag tags/tools]]