Rework hooke.driver and hooke.driver.tutorial along the lines of hooke.plugin.
[hooke.git] / hooke / curve.py
1 """The curve module provides :class:`Curve` and :class:`Data` for storing
2 force curves.
3 """
4
5 import os.path
6 import numpy
7
8 from .driver import NotRecognized
9
10
11 class Data (numpy.ndarray):
12     """Stores a single, continuous data set.
13
14     Adds :attr:`info` :class:`dict` to the standard :class:`numpy.ndarray`.
15
16     See :mod:`numpy.doc.subclassing` for the peculiarities of
17     subclassing :class:`numpy.ndarray`.
18     """
19     def __new__(self, subtype, shape, dtype=numpy.float, buffer=None, offset=0,
20                 strides=None, order=None, info=None):
21         """Create the ndarray instance of our type, given the usual
22         input arguments.  This will call the standard ndarray
23         constructor, but return an object of our type.
24         """
25         obj = np.ndarray.__new__(subtype=subtype, shape=shape, dtype=dtype,
26                                  buffer=buffer, offset=offset, strides=strides,
27                                  order=order)
28         # add the new attribute to the created instance
29         if info == None:
30             info = {}
31         obj.info = info
32         # Finally, we must return the newly created object:
33         return obj
34
35     def __array_finalize__(self, obj):
36         """Set any extra attributes from the original object when
37         creating a new view object."""
38         # reset the attribute from passed original object
39         self.info = getattr(obj, 'info', {})
40         # We do not need to return anything
41
42
43 class Curve (object):
44     """A grouped set of :class:`Data` runs from the same file with metadata.
45
46     For an approach/retract force spectroscopy experiment, the group
47     would consist of the approach data and the retract data.  Metadata
48     would be the temperature, cantilever spring constant, etc.
49
50     Two important :attr:`info` settings are `filetype` and
51     `experiment`.  These are two strings that can be used by Hooke
52     commands/plugins to understand what they are looking at.
53
54     * `.info['filetype']` should contain the name of the exact
55       filetype defined by the driver (so that filetype-speciofic
56       commands can know if they're dealing with the correct filetype).
57     * `.info['experiment']` should contain an instance of a
58       :class:`hooke.experiment.Experiment` subclass to identify the
59       experiment type.  For example, various
60       :class:`hooke.driver.Driver`\s can read in force-clamp data, but
61       Hooke commands could like to know if they're looking at force
62       clamp data, regardless of their origin.
63     """
64     def __init__(self, path):
65         #the data dictionary contains: {name of data: list of data sets [{[x], [y]}]
66         self.path = path
67         self.driver = None
68         self.data = []
69         self.info = None
70         self.name = os.path.basename(path)
71         self.notes = ''
72
73     def identify(self, drivers):
74         """Identify the appropriate :class:`hooke.driver.Driver` for
75         the curve file (`.path`).
76         """
77         for driver in drivers:
78             if driver.is_me(self.path):
79                 self.driver = driver # remember the working driver
80                 return
81         raise NotRecognized(self.path)
82
83     def load(self):
84         """Use the driver to read the curve into memory.
85         """
86         pass