ModelResult.plot(): cannot pass additional arguments to custom model function #1036
Replies: 2 comments
-
|
@chrkuhlmann You fully ignored the DO NOT IGNORE message when raising an issue. We can and will convert to a discussion. But that does kind of put you in a position of starting from a deficit. I'll say, completely separately, that I don't love having to support the So, what do you want? Right under the place where the issue instructions say "include A Minimal, Complete, and Verifiable example" you said "Can be provided if required". Well, it would be required if you wanted us to know what you were trying to do. |
Beta Was this translation helpful? Give feedback.
-
|
Hello Matt, TLDR: I found that I can use a class instance method to achieve the same functionality for my use case. I still think that the model Complete reply: The reason for using the additional kwargs in the model function is that I think other methods do not work well:
Because of this, I tried to pass the vector as an additional kwarg to the model function. This works for Since then I realized that I can pass a class instance method as model function and use local properties of the class to pass additional values (I didn't know that the model function reference seems to capture the instance and works with class methods too. I expected that the function signature would not match. Maybe a note in the docs that object method may be used instead of kwargs would help other users.) As a general comment, I think that having some standard plot functions to show e.g. residuals or histograms (maybe even depending on the chosen model) seems like a nice way to quickly see whether a fit yielded useful results or whether the model matches the data. Of course more advanced problems will require the user to write custom code to do that, but other packages like Origin do provide some preconfigured graphical fit result reports and they can be useful. For me this functionality helped to get colleagues to try lmfit instead of using Origin. import lmfit
import numpy as np
import numpy.typing as npt
import matplotlib.pyplot as plt
import warnings
def model_func(x:float|npt.NDArray, a0:float, a1:float, a2:float, a3:float, a_cal_vec:npt.NDArray=None ) -> float|npt.NDArray:
# x: independent variable
# a0 .. a3: model parameters
# a_val: calibration vector (fixed but not constant over experiments/setups/etc. and of variable length)
if a_cal_vec is None:
warnings.warn("a_cal_vec argument in model_func() was not provided by caller.")
a_cal_vec = np.array([0.5, 1, 2, 3])
y = a0*a_cal_vec[0] + a1*a_cal_vec[1]*(x**1) + a2*a_cal_vec[2]*(x**2) + a3*a_cal_vec[3]*(x**3)
return y
def make_data():
xd= np.linspace(-10, 10, 201)
ad0 = 0.5*np.pi
ad1 = 1*np.pi
ad2 = 2*np.pi
ad3 = 3*np.pi
yd = ad0 + ad1*(xd**1) + ad2*(xd**2) + ad3*(xd**3)
return (xd, yd)
def print_data(d:npt.NDArray, varname="d"):
l = d.size
w=3
print(f"{varname}=[ {(np.array2string(d[0:w], separator=', '))[1:-1]}, ..., {(np.array2string(d[round(l/2-w/2):round(l/2+w/2)], separator=', '))[1:-1]}, ..., {(np.array2string(d[-w:], separator=','))[1:-1]} ]")
(x_d, y_d) = make_data()
params_kws = {'a0':1.05, 'a1':1.1, 'a2':1.2, 'a3':1.3}
cal_vec = np.array([0.5*np.pi, 1*np.pi, 2*np.pi, 3*np.pi])
cal_kws = {'a_cal_vec':cal_vec}
a_model = lmfit.Model(model_func, independent_vars=["x"], param_names=["a0", "a1", "a2", "a3"])
a_params = a_model.make_params(verbose=True, **params_kws)
print(f"a_params={repr(a_params)}")
y_start = a_model.eval(x=x_d, a0=a_params['a0'].value, a1=a_params['a1'].value, a2=a_params['a2'].value, a3=a_params['a3'].value, a_cal_vec=cal_vec)
y_eval = a_model.eval(x=x_d, **params_kws, **cal_kws)
print_data(d=x_d, varname=" x_d")
print_data(d=y_eval, varname="y_eval")
a_fit_res = a_model.fit(x=x_d, data=y_d, params=a_params, **cal_kws)
print("Fit report:\n", a_fit_res.fit_report())
print(f"fitres.params={a_fit_res.params}")
y_f = model_func(x=x_d, a0=a_fit_res.params['a0'].value, a1=a_fit_res.params['a1'].value, a2=a_fit_res.params['a2'].value, a3=a_fit_res.params['a3'].value, **cal_kws)
if True:
plt.figure()
plt.title("Data (green) and fit result (red)")
d=plt.plot(x_d, y_d, color="green", linewidth=2.5, linestyle="-", marker="o")
#d=plt.plot(x_d, y_start, color="yellow", linewidth=2.5, linestyle=":", marker=".")
f=plt.plot(x_d, y_f, color="red", linewidth=1.5, linestyle="--", marker="x")
plt.show()
if True:
res_plt = a_fit_res.plot() # <-- Omitting cal_kws / cal_vec does not provide that parameter for model_func (see warning)
plt.show()
if True:
res_plt = a_fit_res.plot(**cal_kws) # <-- Cannot use cal_kws or cal_vec as argument here, please note resulting exception: "TypeError: ModelResult.plot() got an unexpected keyword argument 'a_cal_vec'"
plt.show() |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Description
It does not seem possible to pass additional kwargs to the
ModelResult.plot()function to send to a user defined model function.See line 2216 (lmfit version 1.3.4) of
def plot_fitWhile additional arguments (non-parameters and not independent variables) can be passed as kwargs when using
Model.eval()and get assigned to the kwargs of the user defined model function, there is no way to use theModelResult.plot()method on the fit result, since those parameters are missing.It would be great if the plot functions would also allow to pass additional arguments to a user defined model function (e.g. though an additional optional
model_func_kwsparameter).Independent parameters cannot be used for this since plotting with several independent parameters is not possible.
A Minimal, Complete, and Verifiable example
Can be provided if required.
Fit report:
N/A
Error message:
N/A
Version information:
Generate version information with this command in the Python shell and copy the output here:
Beta Was this translation helpful? Give feedback.
All reactions