source: sasview/sansmodels/src/sans/models/pyre/pyre_plottable.py @ 8a25523

ESS_GUIESS_GUI_DocsESS_GUI_batch_fittingESS_GUI_bumps_abstractionESS_GUI_iss1116ESS_GUI_iss879ESS_GUI_iss959ESS_GUI_openclESS_GUI_orderingESS_GUI_sync_sascalccostrafo411magnetic_scattrelease-4.1.1release-4.1.2release-4.2.2release_4.0.1ticket-1009ticket-1094-headlessticket-1242-2d-resolutionticket-1243ticket-1249ticket885unittest-saveload
Last change on this file since 8a25523 was ae3ce4e, checked in by Mathieu Doucet <doucetm@…>, 17 years ago

Moving sansmodels to trunk

  • Property mode set to 100644
File size: 5.7 KB
Line 
1"""
2plottables.pyre is a module for registering pyre objects as plottables.
3
4Uses plottables from the reflectivity repository
5Plottables require Python 2.5
6
7"""
8from plottables import Plottable
9
10def label(model, collection):
11    """Build a label mostly unique within a collection"""
12    # Find all items in the collection of the same type
13    conflicts = []
14       
15    model_object = model.component
16   
17    for item in collection:
18        if item.component.name == model_object.name:
19            conflicts.append(item.component)
20       
21    # If no conflict, return name
22    if len(conflicts) == 0:
23        return model_object.name
24       
25    # Fill out the usual detail from the inventory
26    detail = {}
27    #for item in model_object.properties():
28    #    if not item.name.startswith("help"):
29    #        detail[item.name] = item.name
30           
31    # Check which fields differ (only to the first level!)
32    for c in conflicts:
33       
34        # Loop through the local properties and find differences
35        for item in model_object.properties():
36            if not item.name.startswith("help"):
37               
38                # Check common parameters for now
39                if hasattr(c, item.name) and hasattr(model_object, item.name):
40                    c_val = getattr(c, item.name)
41                    o_val = getattr(model_object, item.name)
42                   
43                    if not c_val == o_val:
44                        detail[item.name] = o_val
45                           
46    # Build a label out of the distinctions
47    # TODO: how do we force natural order traversal on detail keys?
48    label = model_object.name
49    for item in detail:
50        label += " %s=%s" % (item, str(detail[item]))
51
52    return label
53
54class Model(Plottable):
55    """
56    Prototype pyre model plottable. 
57   
58    Being 'model' rather than 'data' means that it will have certain style
59    attributes (e.g., lines rather than symbols) and respond in certain ways
60    to the callbacks (e.g., by recomputing the model when the limits change).
61   
62    We have the following attributes:
63   
64    - inventory: manage user visible state
65    - changed(): return true if a replot is required.
66    - x,y = data(): return the plottable data.
67   
68    """
69    def __init__(self, component):
70        Plottable.__init__(self)
71        self.component = component
72        self._xaxis, symbol, self._xunit = component.xaxis()
73        self._yaxis, symbol, self._yunit = component.yaxis()
74       
75        self.min = 0.1
76        self.max = 1.0
77        self.n = 20
78       
79        self.has_changed = False
80        self.dirty = True
81       
82        # Fill inventory backup
83        # Pyre Trait have no way to notify us that
84        # it has changed. Hack it for now.
85        self.value_dict = {}
86        for item in self.component.properties():
87            if not item.name.startswith("help"):
88                descr = self.component.inventory.getTraitDescriptor(item.name)               
89                self.value_dict[item.name] = descr.value
90
91    def __setattr__(self, key, value):
92        if key in ["min", "max", "n"]:
93            self.has_changed = True
94           
95        self.__dict__[key] = value
96   
97    def changed(self):
98        """
99        Return true if a replot is required.
100       
101        Queries our inventory and the inventory of our attached
102        model to see if any aspects of the model have changed, forcing a
103        replot.  Specialized plottables will be able to query the inventory
104        intelligently. 
105       
106        changed() could also be used to provide 'holographic update', where
107        the first pass does very coarse sampling, and this gets refined at
108        the next idle.  That way we can remain responsive to the mouse while
109        expensive calculations go on.
110        """
111        self.dirty = self.dirty or self.has_changed or self.component.changed()
112        return self.dirty
113   
114    def data(self):
115        """
116        Return the plottable data.  This will automatically respond to
117        changes in inventory by recalculating.
118       
119        The plottables graph does not use this function directly, but
120        rather calls it through render.  Later the default render for 1D
121        theory style may want to call back to data.
122        """
123        if self.dirty:
124            import numpy as nx
125            self.x = nx.linspace(self.min, self.max, self.n)
126            self.y = []
127            import math
128            for x in self.x:
129                self.y.append(math.log(self.component(x)))
130            self.dirty = False   
131        return self.x, self.y
132
133    def update_xlim(self, lo, hi):
134        """
135        Record the change in the graph limits.  This updates the xrange
136        stored in the model plottable inventory. Later, when the application
137        is idle, obj.changed() will note the change in inventory and ask
138        the data to recalculate.
139        """
140        self.inventory.min = lo
141        self.inventory.max = hi
142       
143    def render(self, plot, **kw):
144        """
145        Add the appropriate lines to the plot for the component.
146       
147        The plot interface implements generic styles for particular types
148        of data and formalizes the callback mechanism.  See the methods
149        available in mplplot for details.
150        """
151        Plottable.render(self, plot)
152        x, y = self.data()
153        plot.xaxis(self._xaxis, self._xunit)
154        plot.yaxis(self._yaxis, self._yunit)
155        plot.curve(x, y, **kw)
156        #plot.connect('xlim',self.update_xlim)
157
158    @classmethod
159    def labels(cls, collection):
160        """Build a label mostly unique within a collection"""
161        map = {}
162        for item in collection:
163            map[item] = label(item, collection)
164        return map
Note: See TracBrowser for help on using the repository browser.