Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
560d8a7
move polynomial model example to example/models
Sep 18, 2025
49dd290
rewrite sesans 2μ example to use bumps directly
Sep 18, 2025
b83ee18
update sesans Code Camp III example to use sasdata loader
Sep 18, 2025
20d6fac
update 2d fitting example to load data relative to model file
Sep 18, 2025
75a250b
update examples to use latex_smeared from sasdata example datasets
Sep 18, 2025
a5e2b7a
fix oriented usans example: Slit2D interface changed from qx_width,qy…
Sep 18, 2025
65c89ef
Rewrite plotters to a more compact layout, better suited to bumps; in…
Sep 18, 2025
8daeb6e
[pre-commit.ci lite] apply automatic fixes for ruff linting errors
pre-commit-ci-lite[bot] Sep 18, 2025
80b023f
nicer layout for sasmodels.compare plots
Sep 19, 2025
7dce76e
correct limits for 2d log plots
Sep 19, 2025
6e88cbb
don't return matplotlib figure; it confuses jupyter
Sep 19, 2025
767ef0c
make sure residuals plot uses same xscale as data; leave more room fo…
Sep 19, 2025
2099f29
use matplotlib backend in bumps fitter for now
Sep 20, 2025
cbb1e32
better 2D plots for matplotlib
Sep 26, 2025
f80b388
better 2D plots for matplotlib in bumps webview
Sep 26, 2025
621b2c5
Merge branch 'master' into fix-plotly-plotting
krzywon Dec 18, 2025
1892f03
[pre-commit.ci lite] apply automatic fixes for ruff linting errors
pre-commit-ci-lite[bot] Dec 18, 2025
88347c9
use plotly for bumps webview
Mar 2, 2026
bdbf066
fix 2D plots and enable plotly in webview
Mar 2, 2026
158c97e
bumps sliders do not support inf limits
Mar 3, 2026
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
16 changes: 13 additions & 3 deletions example/fit.py → example/fit2d.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#!/usr/bin/env python

import sys
from pathlib import Path

from bumps.names import FitProblem

Expand All @@ -9,11 +10,12 @@
from sasmodels.data import load_data, set_beam_stop, set_top

""" IMPORT THE DATA USED """
radial_data = load_data('DEC07267.DAT')
path = Path(__file__).resolve().parent
radial_data = load_data(str(path / 'DEC07267.DAT'))
set_beam_stop(radial_data, 0.00669, outer=0.025)
set_top(radial_data, -.0185)

tan_data = load_data('DEC07266.DAT')
tan_data = load_data(str(path / 'DEC07266.DAT'))
set_beam_stop(tan_data, 0.00669, outer=0.025)
set_top(tan_data, -.0185)
#sas.set_half(tan_data, 'right')
Expand Down Expand Up @@ -188,7 +190,15 @@
else:
problem = FitProblem(M)

M.problem = problem

if __name__ == "__main__":
import matplotlib.pyplot as plt
problem.plot()

problem.summarize()
# Plot using plotly
fig = M._plot(backend="plotly")
fig.show(renderer='browser')
# Plot using matplotlib
M._plot(backend="matplotlib")
plt.show()
File renamed without changes.
8 changes: 5 additions & 3 deletions example/multiscatfit.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@

from bumps.names import FitProblem

from sasdata import data_path

from sasmodels.bumps_model import Experiment, Model
from sasmodels.core import load_model
from sasmodels.data import load_data
Expand All @@ -36,7 +38,7 @@
## Load the data
#data = load_data('DEC07267.DAT')
#set_beam_stop(data, 0.003, outer=0.025)
data = load_data('latex_smeared.xml', index=0)
data = load_data(str(data_path / '1d_data' / 'latex_smeared.xml'), index=0)

## Define the model
kernel = load_model("ellipsoid")
Expand Down Expand Up @@ -78,5 +80,5 @@
if __name__ == "__main__":
#M.theory()
M.plot()
import pylab
pylab.show()
import matplotlib.pyplot as plt
plt.show()
4 changes: 3 additions & 1 deletion example/oriented_usans.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import numpy as np
from bumps.names import FitProblem

from sasdata import data_path

from sasmodels.bumps_model import Experiment, Model
from sasmodels.core import load_model
from sasmodels.data import load_data

# Spherical particle data, not ellipsoids
sans, usans = load_data('latex_smeared.xml', index='all')
sans, usans = load_data(str(data_path / '1d_data' / 'latex_smeared.xml'), index='all')
usans.qmin, usans.qmax = np.min(usans.x), np.max(usans.x)
usans.mask = (usans.x < 0.0)
usans.oriented = True
Expand Down
65 changes: 37 additions & 28 deletions example/sesans_sphere_2micron.py
Original file line number Diff line number Diff line change
@@ -1,45 +1,54 @@
"""
This is a data file used to load in sesans data and fit it using the bumps engine

Usage:

bumps sesans_sphere_2micron.py
"""
import sesansfit
from bumps.names import Parameter
from bumps.names import FitProblem, Parameter

# Enter the model name to use
model_name = "sphere"
from sasdata import data_path

# DO NOT MODIFY THIS LINE
model = sesansfit.get_bumps_model(model_name)
from sasmodels.bumps_model import Experiment, Model
from sasmodels.core import load_model
from sasmodels.data import load_data

# Enter any custom parameters
# name = Parameter(initial_value, name='name')
phi = Parameter(0.0855, name='phi')
# Add the parameters to this list that should be displayed in the fitting window
custom_params = {"phi" : phi}
# Enter the model name and the datafile path
model_name = "sphere"
data_file = data_path / "sesans_data" / "sphere2micron.ses"

# SESANS data file name
sesans_file = "spheres2micron.ses"
# Custom parameters for use in expressions
# name = Parameter(initial_value, name='name')
phi = Parameter(0.0855, name='phi') # scale = phi*(1-phi)

# Initial parameter values (if other than defaults)
# "model_parameter_name" : value
initial_vals = {
# Initial parameter values and expressions (if other than defaults)
# "model_parameter_name" : value or expression
pars = {
"scale": phi*(1-phi),
"sld" : 1.41,
"radius" : 10000,
"sld_solvent" : 2.70,
}

# Ranges for parameters if other than default
# "model_parameter_name" : [min, max]
param_range = {
"phi" : [0.001, 0.5],
"radius" : [100, 100000]
}
# DO NOT MODIFY THIS LINE
model = Model(load_model(model_name), **pars)

# Constraints
# Bounds constraints
# model.param_name = f(other params)
# EXAMPLE: model.scale = model.radius*model.radius*(1 - phi) - where radius
# and scale are model functions and phi is a custom parameter
model.scale = phi*(1-phi)
model.radius.range(100, 100000)
phi.range(0.001, 0.5)


# Send to the fitting engine
# DO NOT MODIFY THIS LINE
problem = sesansfit.sesans_fit(sesans_file, model, initial_vals, custom_params, param_range)
# DO NOT MODIFY THESE LINES
data = load_data(str(data_file))
M = Experiment(data=data, model=model)
problem = FitProblem([M])

if __name__ == "__main__":
import matplotlib.pyplot as plt

print(f"==== {model_name} model for {data_file.name} has χ² = {problem.chisq_str()} ====")
print(problem.summarize())
problem.plot()
plt.show()
49 changes: 15 additions & 34 deletions example/sesansfit_CodeCampIII.py
Original file line number Diff line number Diff line change
@@ -1,48 +1,23 @@
import numpy as np
from pathlib import Path

from bumps.names import FitProblem, Parameter

from sasmodels import bumps_model, core
from sasmodels.data import load_data

if True: # fix when data loader exists
# from sas.dataloader.readers\
from sas.dataloader.loader import Loader
loader = Loader()
filename = 'sphere.ses'
data = loader.load(filename)
if data is None:
raise OSError("Could not load file %r"%(filename,))
data.x /= 10
# print data
# data = load_sesans('mydatfile.pz')
# sans_data = load_sans('mysansfile.xml')

else:
SElength = np.linspace(0, 2400, 61) # [A]
data = np.ones_like(SElength)
err_data = np.ones_like(SElength)*0.03

class Sample:
zacceptance = 0.1 # [A^-1]
thickness = 0.2 # [cm]

class SESANSData1D:
#q_zmax = 0.23 # [A^-1]
lam = 0.2 # [nm]
x = SElength
y = data
dy = err_data
sample = Sample()
data = SESANSData1D()
path = Path(__file__).resolve().parent
data = load_data(str(path / 'sphere.ses'))

radius = 1000
data.Rmax = 3*radius # [A]

## Sphere parameters

kernel = core.load_model("sphere", dtype='single')
kernel = core.load_model("sphere")
phi = Parameter(0.1, name="phi")
model = bumps_model.Model(kernel,
scale=phi*(1-phi), sld=7.0, solvent_sld=1.0, radius=radius,
model = bumps_model.Model(
kernel,
scale=phi*(1-phi), sld=7.0, sld_solvent=1.0, radius=radius,
)
phi.range(0.001,0.5)
#model.radius.pmp(40)
Expand Down Expand Up @@ -74,3 +49,9 @@ class SESANSData1D:
else:
M_sesans = bumps_model.Experiment(data=data, model=model)
problem = FitProblem(M_sesans)


if __name__ == "__main__":
import matplotlib.pyplot as plt
problem.plot()
plt.show()
16 changes: 11 additions & 5 deletions example/simul_fit.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import numpy as np
from bumps.names import FitProblem, FreeVariables

from sasdata import data_path

from sasmodels.bumps_model import Experiment, Model
from sasmodels.core import load_model
from sasmodels.data import load_data

# latex data, same sample usans and sans
# particles radius ~2300, uniform dispersity
datasets = load_data('latex_smeared.xml', index='all')
datasets = load_data(str(data_path / '1d_data' / 'latex_smeared.xml'), index='all')
#[print(data) for data in datasets]

# A single sphere model to share between the datasets. We will use
Expand All @@ -20,14 +21,14 @@
model = Model(kernel, **pars)

# radius and polydispersity (if any) are shared
model.radius.range(0, np.inf)
model.radius.range(0, 3000.)
#model.radius_pd.range(0, 1)

# Contrast and dilution are the same for both measurements, but are not
# separable with a single measurement (i.e., I(q) ~ F(q) contrast^2 Vf),
# so fit one of scale, sld or solvent sld. With absolute scaling from
# data reduction, can use the same parameter for both datasets.
model.scale.range(0, np.inf)
model.scale.range(0, 1.0)
#model.sld.range(-inf, inf)
#model.sld_solvent.range(-inf, inf)

Expand All @@ -37,7 +38,7 @@
names=[data.run[0] for data in datasets],
background=model.background,
)
free.background.range(-np.inf, np.inf)
free.background.range(-1, 1)

# Note: can access the parameters for the individual models using
# free.background[0] and free.background[1], setting constraints or
Expand All @@ -61,3 +62,8 @@
M = [Experiment(data=data, model=model, name=data.run[0]) for data in datasets]

problem = FitProblem(M, freevars=free)

if __name__ == "__main__":
import matplotlib.pyplot as plt
problem.plot()
plt.show()
20 changes: 16 additions & 4 deletions sasmodels/bumps_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,7 @@ def parameters(self):
"""
Return a dictionary of parameters
"""
# TODO: tie the background and scale to the data rather than the model
pars = self.model.parameters()
if self.extra_pars is not None:
pars.update(self.extra_pars)
Expand All @@ -241,7 +242,9 @@ def residuals(self):
"""
Return theory minus data normalized by uncertainty.
"""
#if np.any(self.err ==0): print("zeros in err")
# if np.any(self.err ==0): print("zeros in err")
# from bumps.fitproblem import fitness_show_parameters
# if any(np.isnan(self.theory())): (print("nan in theory for:"),fitness_show_parameters(self))
return (self.theory() - self.Iq) / self.dIq

def nllf(self):
Expand All @@ -258,15 +261,24 @@ def nllf(self):
#def __call__(self):
# return 2 * self.nllf() / self.dof

def plot(self, view=None):
def _plot(self, view=None, backend='matplotlib'):
# type: (str) -> None
"""
Plot the data and residuals.
"""
data, theory, resid = self._data, self.theory(), self.residuals()
# TODO: hack to display oriented usans 2-D pattern
Iq_calc = self.Iq_calc if isinstance(self.Iq_calc, tuple) else None
plot_theory(data, theory, resid, view, Iq_calc=Iq_calc)
#Iq_calc = self.Iq_calc if isinstance(self.Iq_calc, tuple) else None
label = f"I(q) {self.model.sasmodel.info.name}"
Iq_calc = self.Iq_calc
fig = plot_theory(data, theory, resid, view, Iq_calc=Iq_calc, label=label, backend=backend)
return fig

def plot(self, view=None):
return self._plot(view=view, backend='matplotlib')
Comment thread
krzywon marked this conversation as resolved.

def plotly(self, view=None):
return self._plot(view=view, backend='plotly')

def simulate_data(self, noise=None):
# type: (float) -> None
Expand Down
Loading