nxs-analysis-tools 0.0.32__py3-none-any.whl → 0.0.34__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.
Potentially problematic release.
This version of nxs-analysis-tools might be problematic. Click here for more details.
- _meta/__init__.py +1 -1
- nxs_analysis_tools/__init__.py +2 -2
- nxs_analysis_tools/chess.py +413 -363
- nxs_analysis_tools/datareduction.py +989 -887
- nxs_analysis_tools/fitting.py +258 -262
- nxs_analysis_tools/pairdistribution.py +585 -515
- {nxs_analysis_tools-0.0.32.dist-info → nxs_analysis_tools-0.0.34.dist-info}/METADATA +1 -1
- nxs_analysis_tools-0.0.34.dist-info/RECORD +11 -0
- {nxs_analysis_tools-0.0.32.dist-info → nxs_analysis_tools-0.0.34.dist-info}/WHEEL +1 -1
- nxs_analysis_tools-0.0.32.dist-info/RECORD +0 -11
- {nxs_analysis_tools-0.0.32.dist-info → nxs_analysis_tools-0.0.34.dist-info}/LICENSE +0 -0
- {nxs_analysis_tools-0.0.32.dist-info → nxs_analysis_tools-0.0.34.dist-info}/top_level.txt +0 -0
nxs_analysis_tools/fitting.py
CHANGED
|
@@ -1,262 +1,258 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Module for fitting of linecuts using the lmfit package.
|
|
3
|
-
"""
|
|
4
|
-
|
|
5
|
-
import operator
|
|
6
|
-
from lmfit.model import Model
|
|
7
|
-
from lmfit.model import CompositeModel
|
|
8
|
-
import matplotlib.pyplot as plt
|
|
9
|
-
import numpy as np
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
class LinecutModel:
|
|
13
|
-
"""
|
|
14
|
-
A class representing a linecut model for data analysis and fitting.
|
|
15
|
-
|
|
16
|
-
Attributes
|
|
17
|
-
----------
|
|
18
|
-
y : array-like or None
|
|
19
|
-
The dependent variable data.
|
|
20
|
-
x : array-like or None
|
|
21
|
-
The independent variable data.
|
|
22
|
-
y_eval : array-like or None
|
|
23
|
-
The evaluated y-values of the fitted model.
|
|
24
|
-
x_eval : array-like or None
|
|
25
|
-
The x-values used for evaluation.
|
|
26
|
-
y_eval_components : dict or None
|
|
27
|
-
The evaluated y-values of the model components.
|
|
28
|
-
y_fit_components : dict or None
|
|
29
|
-
The fitted y-values of the model components.
|
|
30
|
-
y_fit : array-like or None
|
|
31
|
-
The fitted y-values of the model.
|
|
32
|
-
x_fit : array-like or None
|
|
33
|
-
The x-values used for fitting.
|
|
34
|
-
y_init_fit : array-like or None
|
|
35
|
-
The initial guess of the y-values.
|
|
36
|
-
params : Parameters or None
|
|
37
|
-
The parameters of the model.
|
|
38
|
-
model_components : Model or list of Models or None
|
|
39
|
-
The model component(s) used for fitting.
|
|
40
|
-
model : Model or None
|
|
41
|
-
The composite model used for fitting.
|
|
42
|
-
modelresult : ModelResult or None
|
|
43
|
-
The result of the model fitting.
|
|
44
|
-
data : NXdata or None
|
|
45
|
-
The 1D linecut data used for analysis.
|
|
46
|
-
|
|
47
|
-
Methods
|
|
48
|
-
-------
|
|
49
|
-
__init__(self, data=None)
|
|
50
|
-
Initialize the LinecutModel.
|
|
51
|
-
set_data(self, data)
|
|
52
|
-
Set the data for analysis.
|
|
53
|
-
set_model_components(self, model_components)
|
|
54
|
-
Set the model components.
|
|
55
|
-
set_param_hint(self, *args, **kwargs)
|
|
56
|
-
Set parameter hints for the model.
|
|
57
|
-
make_params(self)
|
|
58
|
-
Create and initialize the parameters for the model.
|
|
59
|
-
guess(self)
|
|
60
|
-
Perform initial guesses for each model component.
|
|
61
|
-
print_initial_params(self)
|
|
62
|
-
Print out initial guesses for each parameter of the model.
|
|
63
|
-
plot_initial_guess(self, numpoints=None)
|
|
64
|
-
Plot the initial guess.
|
|
65
|
-
fit(self)
|
|
66
|
-
Fit the model to the data.
|
|
67
|
-
plot_fit(self, numpoints=None, fit_report=True, **kwargs)
|
|
68
|
-
Plot the fitted model.
|
|
69
|
-
print_fit_report(self)
|
|
70
|
-
Print the fit report.
|
|
71
|
-
"""
|
|
72
|
-
def __init__(self, data=None):
|
|
73
|
-
"""
|
|
74
|
-
Initialize the LinecutModel.
|
|
75
|
-
"""
|
|
76
|
-
self.y = None
|
|
77
|
-
self.x = None
|
|
78
|
-
self.y_eval = None
|
|
79
|
-
self.x_eval = None
|
|
80
|
-
self.y_eval_components = None
|
|
81
|
-
self.y_fit_components = None
|
|
82
|
-
self.y_fit = None
|
|
83
|
-
self.x_fit = None
|
|
84
|
-
self.y_init_fit = None
|
|
85
|
-
self.params = None
|
|
86
|
-
self.model_components = None
|
|
87
|
-
self.model = None
|
|
88
|
-
self.modelresult = None
|
|
89
|
-
self.data = data if data is not None else None
|
|
90
|
-
if self.data is not None:
|
|
91
|
-
self.x = data[data.axes].nxdata
|
|
92
|
-
self.y = data[data.signal].nxdata
|
|
93
|
-
|
|
94
|
-
def set_data(self, data):
|
|
95
|
-
"""
|
|
96
|
-
Set the data for analysis.
|
|
97
|
-
|
|
98
|
-
Parameters
|
|
99
|
-
----------
|
|
100
|
-
data : NXdata
|
|
101
|
-
The 1D linecut data to be used for analysis.
|
|
102
|
-
"""
|
|
103
|
-
self.data = data
|
|
104
|
-
self.x = data[data.axes].nxdata
|
|
105
|
-
self.y = data[data.signal].nxdata
|
|
106
|
-
|
|
107
|
-
def set_model_components(self, model_components):
|
|
108
|
-
"""
|
|
109
|
-
Set the model components
|
|
110
|
-
|
|
111
|
-
Parameters
|
|
112
|
-
----------
|
|
113
|
-
model_components : Model or list of Models
|
|
114
|
-
The model component(s) to be used for fitting, which will be combined into a CompositeModel.
|
|
115
|
-
"""
|
|
116
|
-
|
|
117
|
-
# If the model only has one component, then use it as the model
|
|
118
|
-
if isinstance(model_components, Model):
|
|
119
|
-
self.model = model_components
|
|
120
|
-
# Else, combine the components into a composite model and use that as the
|
|
121
|
-
else:
|
|
122
|
-
self.model_components = model_components
|
|
123
|
-
self.model = model_components[0]
|
|
124
|
-
|
|
125
|
-
# Combine remaining components into the composite model
|
|
126
|
-
for component in model_components[1:]:
|
|
127
|
-
self.model = CompositeModel(self.model, component, operator.add)
|
|
128
|
-
|
|
129
|
-
def set_param_hint(self, *args, **kwargs):
|
|
130
|
-
"""
|
|
131
|
-
Set parameter hints for the model.
|
|
132
|
-
|
|
133
|
-
Parameters
|
|
134
|
-
----------
|
|
135
|
-
*args : positional arguments
|
|
136
|
-
Positional arguments passed to the `set_param_hint` method of the underlying model.
|
|
137
|
-
|
|
138
|
-
**kwargs : keyword arguments
|
|
139
|
-
Keyword arguments passed to the `set_param_hint` method of the underlying model.
|
|
140
|
-
"""
|
|
141
|
-
|
|
142
|
-
self.model.set_param_hint(*args, **kwargs)
|
|
143
|
-
|
|
144
|
-
def make_params(self):
|
|
145
|
-
"""
|
|
146
|
-
Create and initialize the parameters for the model.
|
|
147
|
-
|
|
148
|
-
Returns
|
|
149
|
-
-------
|
|
150
|
-
Parameters
|
|
151
|
-
The initialized parameters for the model.
|
|
152
|
-
"""
|
|
153
|
-
# Intialize empty parameters (in function)
|
|
154
|
-
params = self.model.make_params()
|
|
155
|
-
self.params = params
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
x =
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
"""
|
|
260
|
-
Show fit report.
|
|
261
|
-
"""
|
|
262
|
-
print(self.modelresult.fit_report())
|
|
1
|
+
"""
|
|
2
|
+
Module for fitting of linecuts using the lmfit package.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import operator
|
|
6
|
+
from lmfit.model import Model
|
|
7
|
+
from lmfit.model import CompositeModel
|
|
8
|
+
import matplotlib.pyplot as plt
|
|
9
|
+
import numpy as np
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class LinecutModel:
|
|
13
|
+
"""
|
|
14
|
+
A class representing a linecut model for data analysis and fitting.
|
|
15
|
+
|
|
16
|
+
Attributes
|
|
17
|
+
----------
|
|
18
|
+
y : array-like or None
|
|
19
|
+
The dependent variable data.
|
|
20
|
+
x : array-like or None
|
|
21
|
+
The independent variable data.
|
|
22
|
+
y_eval : array-like or None
|
|
23
|
+
The evaluated y-values of the fitted model.
|
|
24
|
+
x_eval : array-like or None
|
|
25
|
+
The x-values used for evaluation.
|
|
26
|
+
y_eval_components : dict or None
|
|
27
|
+
The evaluated y-values of the model components.
|
|
28
|
+
y_fit_components : dict or None
|
|
29
|
+
The fitted y-values of the model components.
|
|
30
|
+
y_fit : array-like or None
|
|
31
|
+
The fitted y-values of the model.
|
|
32
|
+
x_fit : array-like or None
|
|
33
|
+
The x-values used for fitting.
|
|
34
|
+
y_init_fit : array-like or None
|
|
35
|
+
The initial guess of the y-values.
|
|
36
|
+
params : Parameters or None
|
|
37
|
+
The parameters of the model.
|
|
38
|
+
model_components : Model or list of Models or None
|
|
39
|
+
The model component(s) used for fitting.
|
|
40
|
+
model : Model or None
|
|
41
|
+
The composite model used for fitting.
|
|
42
|
+
modelresult : ModelResult or None
|
|
43
|
+
The result of the model fitting.
|
|
44
|
+
data : NXdata or None
|
|
45
|
+
The 1D linecut data used for analysis.
|
|
46
|
+
|
|
47
|
+
Methods
|
|
48
|
+
-------
|
|
49
|
+
__init__(self, data=None)
|
|
50
|
+
Initialize the LinecutModel.
|
|
51
|
+
set_data(self, data)
|
|
52
|
+
Set the data for analysis.
|
|
53
|
+
set_model_components(self, model_components)
|
|
54
|
+
Set the model components.
|
|
55
|
+
set_param_hint(self, *args, **kwargs)
|
|
56
|
+
Set parameter hints for the model.
|
|
57
|
+
make_params(self)
|
|
58
|
+
Create and initialize the parameters for the model.
|
|
59
|
+
guess(self)
|
|
60
|
+
Perform initial guesses for each model component.
|
|
61
|
+
print_initial_params(self)
|
|
62
|
+
Print out initial guesses for each parameter of the model.
|
|
63
|
+
plot_initial_guess(self, numpoints=None)
|
|
64
|
+
Plot the initial guess.
|
|
65
|
+
fit(self)
|
|
66
|
+
Fit the model to the data.
|
|
67
|
+
plot_fit(self, numpoints=None, fit_report=True, **kwargs)
|
|
68
|
+
Plot the fitted model.
|
|
69
|
+
print_fit_report(self)
|
|
70
|
+
Print the fit report.
|
|
71
|
+
"""
|
|
72
|
+
def __init__(self, data=None):
|
|
73
|
+
"""
|
|
74
|
+
Initialize the LinecutModel.
|
|
75
|
+
"""
|
|
76
|
+
self.y = None
|
|
77
|
+
self.x = None
|
|
78
|
+
self.y_eval = None
|
|
79
|
+
self.x_eval = None
|
|
80
|
+
self.y_eval_components = None
|
|
81
|
+
self.y_fit_components = None
|
|
82
|
+
self.y_fit = None
|
|
83
|
+
self.x_fit = None
|
|
84
|
+
self.y_init_fit = None
|
|
85
|
+
self.params = None
|
|
86
|
+
self.model_components = None
|
|
87
|
+
self.model = None
|
|
88
|
+
self.modelresult = None
|
|
89
|
+
self.data = data if data is not None else None
|
|
90
|
+
if self.data is not None:
|
|
91
|
+
self.x = data[data.axes].nxdata
|
|
92
|
+
self.y = data[data.signal].nxdata
|
|
93
|
+
|
|
94
|
+
def set_data(self, data):
|
|
95
|
+
"""
|
|
96
|
+
Set the data for analysis.
|
|
97
|
+
|
|
98
|
+
Parameters
|
|
99
|
+
----------
|
|
100
|
+
data : NXdata
|
|
101
|
+
The 1D linecut data to be used for analysis.
|
|
102
|
+
"""
|
|
103
|
+
self.data = data
|
|
104
|
+
self.x = data[data.axes].nxdata
|
|
105
|
+
self.y = data[data.signal].nxdata
|
|
106
|
+
|
|
107
|
+
def set_model_components(self, model_components):
|
|
108
|
+
"""
|
|
109
|
+
Set the model components
|
|
110
|
+
|
|
111
|
+
Parameters
|
|
112
|
+
----------
|
|
113
|
+
model_components : Model or list of Models
|
|
114
|
+
The model component(s) to be used for fitting, which will be combined into a CompositeModel.
|
|
115
|
+
"""
|
|
116
|
+
|
|
117
|
+
# If the model only has one component, then use it as the model
|
|
118
|
+
if isinstance(model_components, Model):
|
|
119
|
+
self.model = model_components
|
|
120
|
+
# Else, combine the components into a composite model and use that as the
|
|
121
|
+
else:
|
|
122
|
+
self.model_components = model_components
|
|
123
|
+
self.model = model_components[0]
|
|
124
|
+
|
|
125
|
+
# Combine remaining components into the composite model
|
|
126
|
+
for component in model_components[1:]:
|
|
127
|
+
self.model = CompositeModel(self.model, component, operator.add)
|
|
128
|
+
|
|
129
|
+
def set_param_hint(self, *args, **kwargs):
|
|
130
|
+
"""
|
|
131
|
+
Set parameter hints for the model.
|
|
132
|
+
|
|
133
|
+
Parameters
|
|
134
|
+
----------
|
|
135
|
+
*args : positional arguments
|
|
136
|
+
Positional arguments passed to the `set_param_hint` method of the underlying model.
|
|
137
|
+
|
|
138
|
+
**kwargs : keyword arguments
|
|
139
|
+
Keyword arguments passed to the `set_param_hint` method of the underlying model.
|
|
140
|
+
"""
|
|
141
|
+
|
|
142
|
+
self.model.set_param_hint(*args, **kwargs)
|
|
143
|
+
|
|
144
|
+
def make_params(self):
|
|
145
|
+
"""
|
|
146
|
+
Create and initialize the parameters for the model.
|
|
147
|
+
|
|
148
|
+
Returns
|
|
149
|
+
-------
|
|
150
|
+
Parameters
|
|
151
|
+
The initialized parameters for the model.
|
|
152
|
+
"""
|
|
153
|
+
# Intialize empty parameters (in function)
|
|
154
|
+
params = self.model.make_params()
|
|
155
|
+
self.params = params
|
|
156
|
+
|
|
157
|
+
return params
|
|
158
|
+
|
|
159
|
+
def guess(self):
|
|
160
|
+
"""
|
|
161
|
+
Perform initial guesses for each model component.
|
|
162
|
+
"""
|
|
163
|
+
for model_component in list(self.model_components):
|
|
164
|
+
self.params.update(model_component.guess(self.y, x=self.x))
|
|
165
|
+
|
|
166
|
+
def print_initial_params(self):
|
|
167
|
+
"""
|
|
168
|
+
Print out initial guesses for each parameter of the model.
|
|
169
|
+
"""
|
|
170
|
+
model = self.model
|
|
171
|
+
for param, hint in model.param_hints.items():
|
|
172
|
+
print(f'{param}')
|
|
173
|
+
for key, value in hint.items():
|
|
174
|
+
print(f'\t{key}: {value}')
|
|
175
|
+
|
|
176
|
+
def plot_initial_guess(self, numpoints=None):
|
|
177
|
+
"""
|
|
178
|
+
Plot initial guess.
|
|
179
|
+
"""
|
|
180
|
+
model = self.model
|
|
181
|
+
params = self.params
|
|
182
|
+
x = self.x
|
|
183
|
+
y = self.y
|
|
184
|
+
y_init_fit = model.eval(params=params, x=x)
|
|
185
|
+
self.y_init_fit = y_init_fit
|
|
186
|
+
plt.plot(x, y, 'o', label='data')
|
|
187
|
+
plt.plot(x, y_init_fit, '--', label='guess')
|
|
188
|
+
|
|
189
|
+
# Plot the components of the model
|
|
190
|
+
if numpoints is None:
|
|
191
|
+
numpoints = len(self.x)
|
|
192
|
+
self.x_eval = np.linspace(self.x.min(), self.x.max(), numpoints)
|
|
193
|
+
y_init_fit_components = model.eval_components(params=params, x=self.x_eval)
|
|
194
|
+
ax = plt.gca()
|
|
195
|
+
for model_component, value in y_init_fit_components.items():
|
|
196
|
+
ax.fill_between(self.x_eval, value, alpha=0.3, label=model_component)
|
|
197
|
+
plt.legend()
|
|
198
|
+
plt.show()
|
|
199
|
+
|
|
200
|
+
def fit(self):
|
|
201
|
+
"""
|
|
202
|
+
Fit the model to the data.
|
|
203
|
+
|
|
204
|
+
This method fits the model to the data using the specified parameters and the x-values.
|
|
205
|
+
It updates the model result, fitted y-values, and the evaluated components.
|
|
206
|
+
|
|
207
|
+
"""
|
|
208
|
+
self.modelresult = self.model.fit(self.y, self.params, x=self.x)
|
|
209
|
+
self.y_fit = self.modelresult.eval(x=self.x)
|
|
210
|
+
self.y_fit_components = self.modelresult.eval_components(x=self.x)
|
|
211
|
+
|
|
212
|
+
def plot_fit(self, numpoints=None, fit_report=True, **kwargs):
|
|
213
|
+
"""
|
|
214
|
+
Plot the fitted model.
|
|
215
|
+
|
|
216
|
+
This method plots the fitted model along with the original data.
|
|
217
|
+
It evaluates the model and its components at the specified number of points (numpoints)
|
|
218
|
+
and plots the results.
|
|
219
|
+
|
|
220
|
+
Parameters
|
|
221
|
+
----------
|
|
222
|
+
numpoints : int, optional
|
|
223
|
+
Number of points to evaluate the model and its components. If not provided,
|
|
224
|
+
it defaults to the length of the x-values.
|
|
225
|
+
|
|
226
|
+
fit_report : bool, optional
|
|
227
|
+
Whether to print the fit report. Default is True.
|
|
228
|
+
|
|
229
|
+
**kwargs : dict, optional
|
|
230
|
+
Additional keyword arguments to be passed to the `plot` method.
|
|
231
|
+
|
|
232
|
+
Returns
|
|
233
|
+
-------
|
|
234
|
+
ax : matplotlib.axes.Axes
|
|
235
|
+
The Axes object containing the plot.
|
|
236
|
+
|
|
237
|
+
"""
|
|
238
|
+
if numpoints is None:
|
|
239
|
+
numpoints = len(self.x)
|
|
240
|
+
self.x_eval = np.linspace(self.x.min(), self.x.max(), numpoints)
|
|
241
|
+
self.y_eval = self.modelresult.eval(x=self.x_eval)
|
|
242
|
+
self.y_eval_components = self.modelresult.eval_components(x=self.x_eval)
|
|
243
|
+
self.modelresult.plot(numpoints=numpoints, **kwargs)
|
|
244
|
+
ax = plt.gca()
|
|
245
|
+
for model_component, value in self.y_eval_components.items():
|
|
246
|
+
ax.fill_between(self.x_eval, value, alpha=0.3, label=model_component)
|
|
247
|
+
# ax.plot(self.x_eval, value, label=model_component)
|
|
248
|
+
plt.legend()
|
|
249
|
+
plt.show()
|
|
250
|
+
if fit_report:
|
|
251
|
+
print(self.modelresult.fit_report())
|
|
252
|
+
return ax
|
|
253
|
+
|
|
254
|
+
def print_fit_report(self):
|
|
255
|
+
"""
|
|
256
|
+
Show fit report.
|
|
257
|
+
"""
|
|
258
|
+
print(self.modelresult.fit_report())
|