diffpy.srfit 3.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. diffpy/__init__.py +15 -0
  2. diffpy/srfit/__init__.py +41 -0
  3. diffpy/srfit/equation/__init__.py +31 -0
  4. diffpy/srfit/equation/builder.py +702 -0
  5. diffpy/srfit/equation/equationmod.py +213 -0
  6. diffpy/srfit/equation/literals/__init__.py +71 -0
  7. diffpy/srfit/equation/literals/abcs.py +81 -0
  8. diffpy/srfit/equation/literals/argument.py +76 -0
  9. diffpy/srfit/equation/literals/literal.py +69 -0
  10. diffpy/srfit/equation/literals/operators.py +380 -0
  11. diffpy/srfit/equation/visitors/__init__.py +94 -0
  12. diffpy/srfit/equation/visitors/argfinder.py +62 -0
  13. diffpy/srfit/equation/visitors/printer.py +120 -0
  14. diffpy/srfit/equation/visitors/swapper.py +142 -0
  15. diffpy/srfit/equation/visitors/validator.py +113 -0
  16. diffpy/srfit/equation/visitors/visitor.py +62 -0
  17. diffpy/srfit/exceptions.py +29 -0
  18. diffpy/srfit/fitbase/__init__.py +53 -0
  19. diffpy/srfit/fitbase/calculator.py +110 -0
  20. diffpy/srfit/fitbase/configurable.py +57 -0
  21. diffpy/srfit/fitbase/constraint.py +117 -0
  22. diffpy/srfit/fitbase/fitcontribution.py +351 -0
  23. diffpy/srfit/fitbase/fithook.py +227 -0
  24. diffpy/srfit/fitbase/fitrecipe.py +826 -0
  25. diffpy/srfit/fitbase/fitresults.py +674 -0
  26. diffpy/srfit/fitbase/parameter.py +314 -0
  27. diffpy/srfit/fitbase/parameterset.py +110 -0
  28. diffpy/srfit/fitbase/profile.py +405 -0
  29. diffpy/srfit/fitbase/profilegenerator.py +168 -0
  30. diffpy/srfit/fitbase/profileparser.py +179 -0
  31. diffpy/srfit/fitbase/recipeorganizer.py +1074 -0
  32. diffpy/srfit/fitbase/restraint.py +117 -0
  33. diffpy/srfit/fitbase/simplerecipe.py +230 -0
  34. diffpy/srfit/fitbase/validatable.py +59 -0
  35. diffpy/srfit/interface/__init__.py +33 -0
  36. diffpy/srfit/interface/interface.py +180 -0
  37. diffpy/srfit/pdf/__init__.py +24 -0
  38. diffpy/srfit/pdf/basepdfgenerator.py +296 -0
  39. diffpy/srfit/pdf/characteristicfunctions.py +432 -0
  40. diffpy/srfit/pdf/debyepdfgenerator.py +115 -0
  41. diffpy/srfit/pdf/pdfcontribution.py +311 -0
  42. diffpy/srfit/pdf/pdfgenerator.py +77 -0
  43. diffpy/srfit/pdf/pdfparser.py +226 -0
  44. diffpy/srfit/sas/__init__.py +30 -0
  45. diffpy/srfit/sas/prcalculator.py +139 -0
  46. diffpy/srfit/sas/sasgenerator.py +70 -0
  47. diffpy/srfit/sas/sasimport.py +66 -0
  48. diffpy/srfit/sas/sasparameter.py +70 -0
  49. diffpy/srfit/sas/sasparser.py +133 -0
  50. diffpy/srfit/sas/sasprofile.py +94 -0
  51. diffpy/srfit/structure/__init__.py +60 -0
  52. diffpy/srfit/structure/basestructureparset.py +62 -0
  53. diffpy/srfit/structure/bvsrestraint.py +101 -0
  54. diffpy/srfit/structure/cctbxparset.py +292 -0
  55. diffpy/srfit/structure/diffpyparset.py +303 -0
  56. diffpy/srfit/structure/objcrystparset.py +1552 -0
  57. diffpy/srfit/structure/sgconstraints.py +761 -0
  58. diffpy/srfit/structure/srrealparset.py +92 -0
  59. diffpy/srfit/util/__init__.py +50 -0
  60. diffpy/srfit/util/argbinders.py +29 -0
  61. diffpy/srfit/util/inpututils.py +50 -0
  62. diffpy/srfit/util/nameutils.py +45 -0
  63. diffpy/srfit/util/observable.py +93 -0
  64. diffpy/srfit/util/tagmanager.py +150 -0
  65. diffpy/srfit/util/weakrefcallable.py +170 -0
  66. diffpy/srfit/version.py +26 -0
  67. diffpy_srfit-3.1.0.dist-info/METADATA +216 -0
  68. diffpy_srfit-3.1.0.dist-info/RECORD +73 -0
  69. diffpy_srfit-3.1.0.dist-info/WHEEL +5 -0
  70. diffpy_srfit-3.1.0.dist-info/licenses/AUTHORS.rst +10 -0
  71. diffpy_srfit-3.1.0.dist-info/licenses/LICENSE.rst +138 -0
  72. diffpy_srfit-3.1.0.dist-info/licenses/LICENSE_DANSE.rst +34 -0
  73. diffpy_srfit-3.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,351 @@
1
+ #!/usr/bin/env python
2
+ ##############################################################################
3
+ #
4
+ # diffpy.srfit by DANSE Diffraction group
5
+ # Simon J. L. Billinge
6
+ # (c) 2008 The Trustees of Columbia University
7
+ # in the City of New York. All rights reserved.
8
+ #
9
+ # File coded by: Chris Farrow
10
+ #
11
+ # See AUTHORS.txt for a list of people who contributed.
12
+ # See LICENSE_DANSE.txt for license information.
13
+ #
14
+ ##############################################################################
15
+ """FitContribution class.
16
+
17
+ FitContributions generate a residual function for a FitRecipe. A
18
+ FitContribution associates an Equation for generating a signal,
19
+ optionally one or more ProfileGenerators or Calculators that help in
20
+ this, and a Profile that holds the observed and calculated signals.
21
+
22
+ See the examples in the documentation for how to use a FitContribution.
23
+ """
24
+
25
+ __all__ = ["FitContribution"]
26
+
27
+ from diffpy.srfit.exceptions import SrFitError
28
+ from diffpy.srfit.fitbase.parameter import ParameterProxy
29
+ from diffpy.srfit.fitbase.parameterset import ParameterSet
30
+ from diffpy.srfit.fitbase.profile import Profile
31
+ from diffpy.srfit.fitbase.recipeorganizer import equationFromString
32
+
33
+
34
+ class FitContribution(ParameterSet):
35
+ """FitContribution class.
36
+
37
+ FitContributions organize an Equation that calculates the signal, and a
38
+ Profile that holds the signal. ProfileGenerators and Calculators can be
39
+ used as well. Constraints and Restraints can be created as part of a
40
+ FitContribution.
41
+
42
+ Attributes
43
+ name -- A name for this FitContribution.
44
+ profile -- A Profile that holds the measured (and calculated)
45
+ signal.
46
+ _calculators -- A managed dictionary of Calculators, indexed by name.
47
+ _constraints -- A set of constrained Parameters. Constraints can be
48
+ added using the 'constrain' methods.
49
+ _generators -- A managed dictionary of ProfileGenerators.
50
+ _parameters -- A managed OrderedDict of parameters.
51
+ _restraints -- A set of Restraints. Restraints can be added using the
52
+ 'restrain' method.
53
+ _parsets -- A managed dictionary of ParameterSets.
54
+ _eqfactory -- A diffpy.srfit.equation.builder.EquationFactory
55
+ instance that is used to create constraints and
56
+ restraints from string
57
+ _eq -- The FitContribution equation that will be optimized.
58
+ _reseq -- The residual equation.
59
+ _xname -- Name of the x-variable
60
+ _yname -- Name of the y-variable
61
+ _dyname -- Name of the dy-variable
62
+
63
+ Properties
64
+ names -- Variable names (read only). See getNames.
65
+ values -- Variable values (read only). See getValues.
66
+ """
67
+
68
+ def __init__(self, name):
69
+ """Initialization."""
70
+ ParameterSet.__init__(self, name)
71
+ self._eq = None
72
+ self._reseq = None
73
+ self.profile = None
74
+ self._xname = None
75
+ self._yname = None
76
+ self._dyname = None
77
+
78
+ self._generators = {}
79
+ self._manage(self._generators)
80
+ return
81
+
82
+ def setProfile(self, profile, xname=None, yname=None, dyname=None):
83
+ """Assign the Profile for this FitContribution.
84
+
85
+ profile -- A Profile that specifies the calculation points and that
86
+ will store the calculated signal.
87
+ xname -- The name of the independent variable from the Profile. If
88
+ this is None (default), then the name specified by the
89
+ Profile for this parameter will be used. This variable is
90
+ usable within string equations with the specified name.
91
+ yname -- The name of the observed Profile. If this is None
92
+ (default), then the name specified by the Profile for this
93
+ parameter will be used. This variable is usable within
94
+ string equations with the specified name.
95
+ dyname -- The name of the uncertainty in the observed Profile. If
96
+ this is None (default), then the name specified by the
97
+ Profile for this parameter will be used. This variable is
98
+ usable within string equations with the specified name.
99
+ """
100
+ # Enforce type of the profile argument
101
+ if not isinstance(profile, Profile):
102
+ emsg = "Argument must be an instance of the Profile class."
103
+ raise TypeError(emsg)
104
+
105
+ # Set the Profile and add its parameters to this organizer.
106
+ self.profile = profile
107
+
108
+ if xname is None:
109
+ xname = self.profile.xpar.name
110
+ if yname is None:
111
+ yname = self.profile.ypar.name
112
+ if dyname is None:
113
+ dyname = self.profile.dypar.name
114
+
115
+ self._xname = xname
116
+ self._yname = yname
117
+ self._dyname = dyname
118
+
119
+ xpar = ParameterProxy(xname, self.profile.xpar)
120
+ ypar = ParameterProxy(yname, self.profile.ypar)
121
+ dypar = ParameterProxy(dyname, self.profile.dypar)
122
+ self.addParameter(xpar, check=False)
123
+ self.addParameter(ypar, check=False)
124
+ self.addParameter(dypar, check=False)
125
+
126
+ # If we have ProfileGenerators, set their Profiles.
127
+ for gen in self._generators.values():
128
+ gen.setProfile(profile)
129
+
130
+ # If we have _eq, but not _reseq, set the residual
131
+ if self._eq is not None and self._reseq is None:
132
+ self.setResidualEquation("chiv")
133
+
134
+ return
135
+
136
+ def addProfileGenerator(self, gen, name=None):
137
+ """Add a ProfileGenerator to be used by this FitContribution.
138
+
139
+ The ProfileGenerator is given a name so that it can be used as part of
140
+ the profile equation (see setEquation). This can be different from the
141
+ name of the ProfileGenerator used for attribute access.
142
+ FitContributions should not share ProfileGenerator instances. Different
143
+ ProfileGenerators can share Parameters and ParameterSets, however.
144
+
145
+ Calling addProfileGenerator sets the profile equation to call the
146
+ calculator and if there is not a profile equation already.
147
+
148
+ gen -- A ProfileGenerator instance
149
+ name -- A name for the calculator. If name is None (default), then
150
+ the ProfileGenerator's name attribute will be used.
151
+
152
+ Raises ValueError if the ProfileGenerator has no name.
153
+ Raises ValueError if the ProfileGenerator has the same name as some
154
+ other managed object.
155
+ """
156
+ if name is None:
157
+ name = gen.name
158
+
159
+ # Register the generator with the equation factory and add it as a
160
+ # managed object.
161
+ self._eqfactory.registerOperator(name, gen)
162
+ self._addObject(gen, self._generators, True)
163
+
164
+ # If we have a profile, set the profile of the generator.
165
+ if self.profile is not None:
166
+ gen.setProfile(self.profile)
167
+
168
+ # Make this our equation if we don't have one. This will set the
169
+ # residual equation if necessary.
170
+ if self._eq is None:
171
+ self.setEquation(name)
172
+
173
+ return
174
+
175
+ def setEquation(self, eqstr, ns={}):
176
+ """Set the profile equation for the FitContribution.
177
+
178
+ This sets the equation that will be used when generating the residual
179
+ for this FitContribution. The equation will be usable within
180
+ setResidualEquation as "eq", and it takes no arguments.
181
+
182
+ eqstr -- A string representation of the equation. Any Parameter
183
+ registered by addParameter or setProfile, or function
184
+ registered by setCalculator, registerFunction or
185
+ registerStringFunction can be can be used in the equation
186
+ by name. Other names will be turned into Parameters of this
187
+ FitContribution.
188
+ ns -- A dictionary of Parameters, indexed by name, that are used
189
+ in the eqstr, but not registered (default {}).
190
+
191
+ Raises ValueError if ns uses a name that is already used for a
192
+ variable.
193
+ """
194
+ # Build the equation instance.
195
+ eq = equationFromString(eqstr, self._eqfactory, buildargs=True, ns=ns)
196
+ eq.name = "eq"
197
+
198
+ # Register any new Parameters.
199
+ for par in self._eqfactory.newargs:
200
+ self._addParameter(par)
201
+
202
+ # Register eq as an operator
203
+ self._eqfactory.registerOperator("eq", eq)
204
+ self._eqfactory.wipeout(self._eq)
205
+ self._eq = eq
206
+
207
+ # Set the residual if we need to
208
+ if self.profile is not None and self._reseq is None:
209
+ self.setResidualEquation("chiv")
210
+
211
+ return
212
+
213
+ def getEquation(self):
214
+ """Get math expression string for the active profile equation.
215
+
216
+ Return normalized math expression or an empty string if profile
217
+ equation has not been set yet.
218
+ """
219
+ from diffpy.srfit.equation.visitors import getExpression
220
+
221
+ rv = ""
222
+ if self._eq is not None:
223
+ rv = getExpression(self._eq)
224
+ return rv
225
+
226
+ def setResidualEquation(self, eqstr):
227
+ """Set the residual equation for the FitContribution.
228
+
229
+ eqstr -- A string representation of the residual. If eqstr is None
230
+ (default), then the previous residual equation will be
231
+ used, or the chi2 residual will be used if that does not
232
+ exist.
233
+
234
+ Two residuals are preset for convenience, "chiv" and "resv".
235
+ chiv is defined such that dot(chiv, chiv) = chi^2.
236
+ resv is defined such that dot(resv, resv) = Rw^2.
237
+ You can call on these in your residual equation. Note that the quantity
238
+ that will be optimized is the summed square of the residual equation.
239
+ Keep that in mind when defining a new residual or using the built-in
240
+ ones.
241
+
242
+ Raises SrFitError if the Profile is not yet defined.
243
+ Raises ValueError if eqstr depends on a Parameter that is not part of
244
+ the FitContribution.
245
+ """
246
+ if self.profile is None:
247
+ raise SrFitError("Assign the Profile first")
248
+ if self._eq is None:
249
+ raise SrFitError("Assign the Equation first")
250
+
251
+ chivstr = "(eq - %s)/%s" % (self._yname, self._dyname)
252
+ resvstr = "(eq - %s)/sum(%s**2)**0.5" % (self._yname, self._yname)
253
+
254
+ # Get the equation string if it is not defined
255
+ if eqstr == "chiv":
256
+ eqstr = chivstr
257
+ elif eqstr == "resv":
258
+ eqstr = resvstr
259
+
260
+ reseq = equationFromString(eqstr, self._eqfactory)
261
+ self._eqfactory.wipeout(self._reseq)
262
+ self._reseq = reseq
263
+
264
+ return
265
+
266
+ def getResidualEquation(self):
267
+ """Get math expression string for the active residual equation.
268
+
269
+ Return normalized math formula or an empty string if residual
270
+ equation has not been configured yet.
271
+ """
272
+ from diffpy.srfit.equation.visitors import getExpression
273
+
274
+ rv = ""
275
+ if self._reseq is not None:
276
+ rv = getExpression(self._reseq, eqskip="eq$")
277
+ return rv
278
+
279
+ def residual(self):
280
+ """Calculate the residual for this fitcontribution.
281
+
282
+ When this method is called, it is assumed that all parameters have been
283
+ assigned their most current values by the FitRecipe. This will be the
284
+ case when being called as part of a FitRecipe refinement.
285
+
286
+ The residual is by default an array chiv:
287
+ chiv = (eq() - self.profile.y) / self.profile.dy
288
+ The value that is optimized is dot(chiv, chiv).
289
+
290
+ The residual equation can be changed with the setResidualEquation
291
+ method.
292
+ """
293
+ # Assign the calculated profile
294
+ self.profile.ycalc = self._eq()
295
+ # Note that equations only recompute when their inputs are modified, so
296
+ # the following will not recompute the equation.
297
+ return self._reseq()
298
+
299
+ def evaluate(self):
300
+ """Evaluate the contribution equation and update profile.ycalc."""
301
+ yc = self._eq()
302
+ if self.profile is not None:
303
+ self.profile.ycalc = yc
304
+ return yc
305
+
306
+ def _validate(self):
307
+ """Validate my state.
308
+
309
+ This performs profile validations. This performs
310
+ ProfileGenerator validations. This validates _eq. This validates
311
+ _reseq and residual.
312
+
313
+ Raises SrFitError if validation fails.
314
+ """
315
+ self.profile._validate()
316
+ ParameterSet._validate(self)
317
+
318
+ # Try to get the value of eq.
319
+ from diffpy.srfit.equation.visitors import validate
320
+
321
+ try:
322
+ validate(self._eq)
323
+ except ValueError as e:
324
+ raise SrFitError(e)
325
+ if self._eq is None:
326
+ raise SrFitError("_eq is None")
327
+
328
+ val = None
329
+ try:
330
+ val = self._eq()
331
+ except TypeError as e:
332
+ raise SrFitError("_eq cannot be evaluated: %s" % e)
333
+
334
+ if val is None:
335
+ raise SrFitError("_eq evaluates to None")
336
+
337
+ # Try to get the value for residual
338
+ try:
339
+ validate(self._reseq)
340
+ except ValueError as e:
341
+ raise SrFitError(e)
342
+ try:
343
+ val = self.residual()
344
+ except TypeError:
345
+ raise SrFitError("residual cannot be evaluated")
346
+ if val is None:
347
+ raise SrFitError("residual evaluates to None")
348
+ return
349
+
350
+
351
+ # End of file
@@ -0,0 +1,227 @@
1
+ #!/usr/bin/env python
2
+ ##############################################################################
3
+ #
4
+ # diffpy.srfit by DANSE Diffraction group
5
+ # Simon J. L. Billinge
6
+ # (c) 2008 The Trustees of Columbia University
7
+ # in the City of New York. All rights reserved.
8
+ #
9
+ # File coded by: Chris Farrow
10
+ #
11
+ # See AUTHORS.txt for a list of people who contributed.
12
+ # See LICENSE_DANSE.txt for license information.
13
+ #
14
+ ##############################################################################
15
+ """The FitHook class for inspecting the progress of a FitRecipe refinement.
16
+
17
+ FitHooks are called by a FitRecipe during various times of the residual
18
+ is evaluation. The default FitHook simply counts the number of times the
19
+ residual is called, and reports that number every time the residual is
20
+ calculated. Depending on the verbosity, it will also report the residual
21
+ and the current variable values.
22
+
23
+ Custom FitHooks can be added to a FitRecipe with the
24
+ FitRecipe.setFitHook method.
25
+ """
26
+
27
+ from __future__ import print_function
28
+
29
+ __all__ = ["FitHook"]
30
+
31
+ import numpy
32
+
33
+ from diffpy.srfit.util import sortKeyForNumericString
34
+
35
+
36
+ class FitHook(object):
37
+ """Base class for inspecting the progress of a FitRecipe refinement.
38
+
39
+ Can serve as a fithook for the FitRecipe class (see
40
+ FitRecipe.pushFitHook method.) The methods in this class are called
41
+ during the preparation of the FitRecipe for refinement, and during
42
+ the residual call. See the class methods for a description of their
43
+ purpose.
44
+ """
45
+
46
+ def reset(self, recipe):
47
+ """Reset the hook data.
48
+
49
+ This is called whenever FitRecipe._prepare is called, which is
50
+ whenever a configurational change to the fit hierarchy takes
51
+ place, such as adding a new ParameterSet, constraint or
52
+ restraint.
53
+ """
54
+ return
55
+
56
+ def precall(self, recipe):
57
+ """This is called within FitRecipe.residual, before the calculation.
58
+
59
+ recipe -- The FitRecipe instance
60
+ """
61
+ return
62
+
63
+ def postcall(self, recipe, chiv):
64
+ """This is called within FitRecipe.residual, after the calculation.
65
+
66
+ recipe -- The FitRecipe instance
67
+ chiv -- The residual vector
68
+ """
69
+ return
70
+
71
+
72
+ # End class FitHook
73
+
74
+
75
+ class PrintFitHook(FitHook):
76
+ """Base class for inspecting the progress of a FitRecipe refinement.
77
+
78
+ This FitHook prints out a running count of the number of times the residual
79
+ has been called, or other information, based on the verbosity.
80
+
81
+ Attributes
82
+
83
+ count -- The number of times the residual has been called (default 0).
84
+ verbose -- An integer telling how verbose to be (default 1).
85
+ 0 -- print nothing
86
+ 1 -- print the count during the precall
87
+ 2 -- print the residual during the postcall
88
+ >=3 -- print the variables during the postcall
89
+ """
90
+
91
+ def __init__(self):
92
+ """Initialize the attributes."""
93
+ self.count = 0
94
+ self.verbose = 1
95
+ return
96
+
97
+ def reset(self, recipe):
98
+ """Reset the hook data.
99
+
100
+ This is called whenever FitRecipe._prepare is called, which is
101
+ whenever a configurational change to the fit hierarchy takes
102
+ place, such as adding a new ParameterSet, constraint or
103
+ restraint.
104
+ """
105
+ self.count = 0
106
+ return
107
+
108
+ def precall(self, recipe):
109
+ """This is called within FitRecipe.residual, before the calculation.
110
+
111
+ recipe -- The FitRecipe instance
112
+ """
113
+ self.count += 1
114
+ if self.verbose > 0:
115
+ print(self.count)
116
+ return
117
+
118
+ def postcall(self, recipe, chiv):
119
+ """This is called within FitRecipe.residual, after the calculation.
120
+
121
+ recipe -- The FitRecipe instance
122
+ chiv -- The residual vector
123
+ """
124
+ if self.verbose < 2:
125
+ return
126
+
127
+ # Get the number of restraints
128
+ numres = len(recipe._restraintlist)
129
+ chi2tot = numpy.dot(chiv, chiv)
130
+ chi2 = 0
131
+ res = 0
132
+ if numres > 0:
133
+ chi = chiv[:-numres]
134
+ resv = chiv[-numres:]
135
+ chi2 = numpy.dot(chi, chi)
136
+ res = numpy.dot(resv, resv)
137
+
138
+ print("Residual:", chi2tot)
139
+ if numres:
140
+ print("FitContributions:", chi2)
141
+ print("Restraints:", res)
142
+
143
+ if self.verbose >= 3:
144
+ print("Variables")
145
+ vnames = recipe.getNames()
146
+ vals = recipe.getValues()
147
+ # byname = _byname()
148
+ items = sorted(zip(vnames, vals), key=_byname)
149
+ for name, val in items:
150
+ print(" %s = %f" % (name, val))
151
+ return
152
+
153
+
154
+ def _byname(nv):
155
+ return sortKeyForNumericString(nv[0])
156
+
157
+
158
+ # End class PrintFitHook
159
+
160
+
161
+ # TODO - Display the chi^2 on the plot during refinement.
162
+ class PlotFitHook(FitHook):
163
+ """This FitHook has live plotting of whatever is being refined."""
164
+
165
+ def reset(self, recipe):
166
+ """Set up the plot."""
167
+ FitHook.reset(self, recipe)
168
+
169
+ self._plots = []
170
+
171
+ import pylab
172
+
173
+ pylab.clf()
174
+ pylab.ion()
175
+
176
+ nc = len(recipe._contributions)
177
+ if nc > 1:
178
+ ncols = 2
179
+ nrows = (nc + 1) / 2
180
+
181
+ for idx, c in enumerate(recipe._contributions.values()):
182
+
183
+ name = c.name
184
+ xname = c._xname
185
+ yname = c._yname
186
+ p = c.profile
187
+
188
+ # Create a subplot
189
+ if nc > 1:
190
+ pylab.subplot(nrows, ncols, idx + 1)
191
+ pdata = pylab.plot(p.x, p.y, "bo")[0]
192
+ pfit = pylab.plot(p.x, p.y, "r-")[0]
193
+ self._plots.append((pdata, pfit))
194
+ pylab.xlabel(xname)
195
+ pylab.ylabel(yname)
196
+ pylab.title(name)
197
+
198
+ # Set up some event handling, so things behave nicely.
199
+ # def redraw(event):
200
+ # canvas = event.canvas
201
+ # canvas.draw()
202
+ # return
203
+ # pylab.connect('resize_event', redraw)
204
+
205
+ return
206
+
207
+ def postcall(self, recipe, chiv):
208
+ """This is called within FitRecipe.residual, after the calculation.
209
+
210
+ Find data and plot it.
211
+
212
+ recipe -- The FitRecipe instance
213
+ chiv -- The residual vector
214
+ """
215
+ FitHook.postcall(self, recipe, chiv)
216
+ import pylab
217
+
218
+ for c, plottup in zip(recipe._contributions.values(), self._plots):
219
+
220
+ p = c.profile
221
+ pdata = plottup[0]
222
+ pfit = plottup[1]
223
+ pdata.set_data(p.x, p.y)
224
+ pfit.set_data(p.x, p.ycalc)
225
+
226
+ pylab.draw()
227
+ return