Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions docs/docs/tutorials/analysis1d.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -81,15 +81,15 @@
")\n",
"\n",
"fit_result = my_analysis.fit()\n",
"my_analysis.plot_data_and_model()"
"my_analysis.plot_data_and_model(plot_residuals=True)"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python (Pixi)",
"display_name": "Python 3",
"language": "python",
"name": "pixi-kernel-python3"
"name": "python3"
},
"language_info": {
"codemirror_mode": {
Expand All @@ -101,7 +101,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.12"
"version": "3.14.5"
}
},
"nbformat": 4,
Expand Down
18 changes: 8 additions & 10 deletions docs/docs/tutorials/tutorial0_basics.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,8 @@
"experiment = edyn.Experiment(display_name='Tutorial')\n",
"\n",
"file_path = pooch.retrieve(\n",
" url='https://github.com/easyscience/dynamics-lib/raw/refs/heads/tutorial0/docs/docs/tutorials/data/fake_simple_data.hdf5',\n",
" known_hash='b49944c4447e69be4d30d1bed935173c4a1727c25a347285cbb156edc76ee261',\n",
" url='https://github.com/easyscience/dynamics-lib/raw/refs/heads/master/docs/docs/tutorials/data/fake_simple_data.hdf5',\n",
" known_hash='7aea2b5c315b0bd6f0a82ed925d07eaed93f5d61b13686935893c0b4e71999b6',\n",
")\n",
"\n",
"experiment.load_hdf5(filename=file_path)"
Expand Down Expand Up @@ -293,7 +293,7 @@
"</div>\n",
"</details>\n",
"\n",
"Since the fit looked good, we can now fit all $Q$. We also plot the result, again using the slicer."
"Since the fit looked good, we can now fit all $Q$. We also plot the result, again using the slicer. We can plot the residuals by setting `plot_residuals=True`."
]
},
{
Expand All @@ -304,15 +304,15 @@
"outputs": [],
"source": [
"fit_result_all_Q = analysis.fit()\n",
"analysis.plot_data_and_model()"
"analysis.plot_data_and_model(plot_residuals=True)"
]
},
{
"cell_type": "markdown",
"id": "64afbd3c",
"metadata": {},
"source": [
"Information about the fit is stored in the output. It is stored as a list of **EasyScience** `FitResult`s. Here we show a few of the relevant properties:"
"Information about the fit is stored in the output. It is stored as a list of **EasyScience** `FitResult`s. Here we show just the one for `Q_index=5`:"
]
},
{
Expand All @@ -322,9 +322,7 @@
"metadata": {},
"outputs": [],
"source": [
"print(f'The reduced chi-squared value for Q_index=5 is: {fit_result_all_Q[5].reduced_chi2}')\n",
"\n",
"print(f'The minimizer engine is: {fit_result_all_Q[5].minimizer_engine}')"
"print(fit_result_all_Q[5])"
]
},
{
Expand Down Expand Up @@ -478,7 +476,7 @@
],
"metadata": {
"kernelspec": {
"display_name": "in16b",
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
Expand All @@ -492,7 +490,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.14.4"
"version": "3.14.5"
}
},
"nbformat": 4,
Expand Down
10 changes: 5 additions & 5 deletions docs/docs/tutorials/tutorial0_more_advanced.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
"experiment = edyn.Experiment(display_name='Tutorial')\n",
"\n",
"file_path = pooch.retrieve(\n",
" url='https://github.com/easyscience/dynamics-lib/raw/refs/heads/tutorial0/docs/docs/tutorials/data/fake_advanced_data.hdf5',\n",
" url='https://github.com/easyscience/dynamics-lib/raw/refs/heads/master/docs/docs/tutorials/data/fake_advanced_data.hdf5',\n",
" known_hash='ee7310249df71a312ebc219f3e16b8da4e9aa37d29df919bbcaa541a38e1c39f',\n",
")\n",
"\n",
Expand Down Expand Up @@ -226,7 +226,7 @@
"id": "a81248a4",
"metadata": {},
"source": [
"As before, let us first fit a single $Q$ index and plot the data and model to see how it looks. We choose an arbitrary $Q$ and plot only that one"
"As before, let us first fit a single $Q$ index and plot the data and model to see how it looks. We choose an arbitrary $Q$ and plot only that one. We also plot the residuals underneath by setting plot_residuals to True:"
]
},
{
Expand All @@ -237,7 +237,7 @@
"outputs": [],
"source": [
"fit_result_independent_single_Q = analysis.fit(Q_index=5)\n",
"analysis.plot_data_and_model(Q_index=5)"
"analysis.plot_data_and_model(Q_index=5, plot_residuals=True)"
]
},
{
Expand Down Expand Up @@ -274,7 +274,7 @@
"outputs": [],
"source": [
"fit_result_all_Q = analysis.fit()\n",
"analysis.plot_data_and_model()"
"analysis.plot_data_and_model(plot_residuals=True, autoscale=False)"
]
},
{
Expand Down Expand Up @@ -366,7 +366,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.14.4"
"version": "3.14.5"
}
},
"nbformat": 4,
Expand Down
2 changes: 1 addition & 1 deletion docs/docs/tutorials/tutorial1_brownian.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -726,7 +726,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.14.4"
"version": "3.14.5"
}
},
"nbformat": 4,
Expand Down
2 changes: 1 addition & 1 deletion docs/docs/tutorials/tutorial2_nanoparticles.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -616,7 +616,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.14.4"
"version": "3.14.5"
}
},
"nbformat": 4,
Expand Down
58 changes: 52 additions & 6 deletions src/easydynamics/analysis/analysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from easydynamics.sample_model.instrument_model import InstrumentModel
from easydynamics.settings.convolution_settings import ConvolutionSettings
from easydynamics.settings.detailed_balance_settings import DetailedBalanceSettings
from easydynamics.utils.plotting import slicerplot_with_residuals
from easydynamics.utils.utils import _in_notebook


Expand Down Expand Up @@ -213,6 +214,7 @@ def plot_data_and_model(
Q_index: int | None = None,
plot_components: bool = True,
add_background: bool = True,
plot_residuals: bool = False,
energy: sc.Variable | None = None,
**kwargs: dict[str, Any],
) -> InteractiveFigure:
Expand All @@ -232,6 +234,8 @@ def plot_data_and_model(
add_background : bool, default=True
Whether to add background components to the sample model components when plotting.
Default is True.
plot_residuals : bool, default=False
Whether to plot the residuals (data - model). Default is False.
energy : sc.Variable | None, default=None
The energy values to use for calculating the model. If None, uses the energy from the
experiment.
Expand Down Expand Up @@ -259,6 +263,7 @@ def plot_data_and_model(
return self.analysis_list[Q_index].plot_data_and_model(
plot_components=plot_components,
add_background=add_background,
plot_residuals=plot_residuals,
energy=energy,
**kwargs,
)
Expand All @@ -280,6 +285,9 @@ def plot_data_and_model(
if not isinstance(add_background, bool):
raise TypeError('add_background must be True or False.')

if not isinstance(plot_residuals, bool):
raise TypeError('plot_residuals must be True or False.')

if energy is None:
energy = self.energy

Expand All @@ -289,6 +297,7 @@ def plot_data_and_model(
energy=energy,
add_background=add_background,
include_components=plot_components,
include_residuals=plot_residuals,
)

plot_kwargs_defaults = {
Expand All @@ -313,19 +322,34 @@ def plot_data_and_model(
plot_kwargs_defaults['color'][key] = 'red'
plot_kwargs_defaults['markerfacecolor'][key] = 'none'

elif key == 'Residuals':
plot_kwargs_defaults['linestyle'][key] = 'none'
plot_kwargs_defaults['marker'][key] = 'o'
plot_kwargs_defaults['color'][key] = 'blue'
plot_kwargs_defaults['markerfacecolor'][key] = 'none'

else:
plot_kwargs_defaults['linestyle'][key] = '--'
plot_kwargs_defaults['marker'][key] = None

# Overwrite defaults with any user-provided kwargs
plot_kwargs_defaults.update(kwargs)

fig = pp.slicer(
data_and_model,
**plot_kwargs_defaults,
)
for widget in fig.bottom_bar[0].controls.values():
widget.slider_toggler.value = '-o-'
if plot_residuals:
fig = slicerplot_with_residuals(
data_and_model,
residuals_key='Residuals',
operation='sum',
**plot_kwargs_defaults,
)

else:
fig = pp.slicer(
data_and_model,
**plot_kwargs_defaults,
)
for widget in fig.bottom_bar[0].controls.values():
widget.slider_toggler.value = '-o-'
fig.autoscale()
return fig

Expand All @@ -334,6 +358,7 @@ def data_and_model_to_datagroup(
energy: sc.Variable | None = None,
add_background: bool = True,
include_components: bool = True,
include_residuals: bool = False,
) -> sc.DataGroup:
"""
Create a scipp DataGroup containing the experimental data, model calculation and optionally
Expand All @@ -350,6 +375,8 @@ def data_and_model_to_datagroup(
include_components : bool, default=True
Whether to include the individual components of the model in the DataGroup. If False,
only the total model will be included.
include_residuals : bool, default=False
Whether to include the residuals (data - model) in the DataGroup.

Raises
------
Expand Down Expand Up @@ -380,6 +407,9 @@ def data_and_model_to_datagroup(
if not isinstance(include_components, bool):
raise TypeError('include_components must be True or False.')

if not isinstance(include_residuals, bool):
raise TypeError('include_residuals must be True or False.')

energy = self._verify_energy(energy)

if energy is None:
Expand All @@ -397,6 +427,9 @@ def data_and_model_to_datagroup(
for key in components:
data_and_model[key] = components[key]

if include_residuals:
data_and_model['Residuals'] = self._create_residuals_array()

return sc.DataGroup(data_and_model)

def parameters_to_dataset(self) -> sc.Dataset:
Expand Down Expand Up @@ -736,6 +769,19 @@ def _create_model_array(self, energy: sc.Variable | None = None) -> sc.DataArray
coords={'Q': self.Q, 'energy': energy},
)

def _create_residuals_array(self) -> sc.DataArray:
"""
Create a scipp array for the residuals (data - model).

Returns
-------
sc.DataArray
A DataArray containing the residuals, with dimensions "Q" and "energy".
"""
data = self.experiment.binned_data
model = self._create_model_array()
return data.copy(deep=True) - model

def _create_components_dataset(
self,
add_background: bool = True,
Expand Down
Loading
Loading