Example Data
Getting started with a fitting package usually means finding a data file first.
sans_fitter.examples removes that step in two ways: a curated set of bundled
datasets, and a simulator that generates data.
from sans_fitter import examples
examples.describe() # what's available
data = examples.load('silica_spheres') # fit-ready Data1D
fitter = examples.load_fitter('silica_spheres') # data + model + parameters
result = fitter.fit()
Bundled datasets
These are the same example datasets SasView ships. They are not vendored
into this repository — they live inside the installed sasdata package, which
is already a hard dependency. That keeps the wheel small and the collection in
sync with sasdata.
examples.describe() prints the whole collection:
| Name | Model | What it is good for |
|---|---|---|
cylinder |
cylinder | Noise-free calculated cylinder, R=20 Å, L=400 Å. A verification reference, not a fitting exercise (see the note below). |
sphere |
sphere | 100 nm spheres, dI but no dQ. |
sphere_smeared |
sphere | The same spheres with dQ — pair the two to see what resolution smearing does. |
polydisperse_spheres |
sphere | Fit with polydispersity off, then on, and watch the residuals collapse. |
silica_spheres |
sphere | Measured Ludox colloidal silica, with both dI and dQ. |
sds_micelles |
ellipsoid | Measured charged SDS micelles — needs the hayter_msa structure factor. |
sds_micelles_salt |
ellipsoid | The same micelles with 0.2 M NaCl; the salt screens the charge, so hardsphere suffices. |
core_shell |
core_shell_sphere | Partly degenerate core radius and shell thickness — a lesson in correlated parameters. |
polymer_micelles |
ellipsoid | Measured 10% Pluronic P123, with a clear structure-factor peak. |
protein |
sphere | Measured apoferritin: ~400 points, flat incoherent background, noisy high-Q tail. |
canSAS_xml |
sphere | Measured SANS2D data as canSAS-1D XML. |
nxcanSAS_h5 |
sphere | The identical measurement as NXcanSAS HDF5. |
Filter by tag to find one of a given kind:
examples.list_examples(tag='measured') # real instrument data
examples.list_examples(tag='structure-factor') # concentrated samples
examples.list_examples(tag='resolution') # datasets carrying dQ
examples.describe('name') prints the full detail for one entry, including live
facts read from the file — point count, Q range, and whether dI and dQ are
present:
silica_spheres
==============
Measured Ludox colloidal silica. Carries both dI and dQ, so it exercises
weighted fitting and resolution smearing on real data.
file Ludox_silica.xml
model sphere
polydispersity radius
tags measured, colloid, resolution
points 92
Q range 0.0071429 to 0.25169 1/A
dI column yes
dQ column yes
Presets
load_fitter() returns a SANSFitter with the data, model, structure factor,
polydispersity and starting parameters already set:
The starting values are coarse — chosen to put the optimiser in the right basin,
not published results. Check examples.get_example(name).truth to see whether
ground truth is known at all; for measured data it is None, because there is
none.
cylinder is a verification dataset, not a fitting exercise
cyl_400_20.txt is a noise-free calculation: evaluating the model at its
truth reproduces all 20 points exactly, which makes it the right thing to
check the model pipeline against. It cannot be fitted, though — it has no
dI column, so the bumps engine refuses it, and its intensity spans five
decades unweighted, which the scipy engine cannot descend. For a cylinder
you can actually fit, use simulate('cylinder', radius=20, length=400).
Simulated data
examples.simulate() computes a dataset from any sasmodels model and attaches
the generating parameters as data.truth:
This is often the better teaching tool: you can state the answer up front and have the reader check that the fit recovers it. It works for any of the ~100 sasmodels models, needs no files, and lets you dial noise, Q range and resolution independently.
# wider Q range, more points, 5% noise
examples.simulate('cylinder', radius=20, length=400,
qmin=0.001, qmax=0.7, npoints=200, noise=0.05)
# with instrument resolution — the intensity is smeared, not just labelled
examples.simulate('sphere', radius=50, dq=0.05)
# polydisperse; the _pd_n/_pd_type companions are filled in for you
examples.simulate('sphere', radius=50, radius_pd=0.15)
# onto the Q grid of a real dataset
real = examples.load('silica_spheres')
examples.simulate('sphere', radius=100, q=real.x)
How the noise is generated
Uncertainties follow counting statistics, scaled so a point at the median intensity gets exactly the requested relative error:
The scatter is drawn from that same width, so the error bars honestly describe the noise and reduced χ² lands near 1 for a correct model.
A purely relative dI = noise * I would be simpler but is wrong here: it drives
the uncertainty to zero inside the form-factor minima, where the intensity
itself goes to zero. Those points then carry runaway weight and pull the fit
away from the truth — measurably so, a simulated 50 Å sphere recovers as 88 Å.
Counting statistics keep the absolute uncertainty from collapsing while
letting the relative uncertainty grow in the dim minima and the high-Q tail,
which is what real SANS data does.
Sample and background pairs
simulate_pair() returns a matched sample and background on an identical Q
grid, which is what data_ops requires:
from sans_fitter import SANSFitter, data_ops, examples
sample, background = examples.simulate_pair('sphere', radius=50,
background_level=0.5)
subtracted = data_ops.subtract(sample, background)
fitter = SANSFitter()
fitter.set_data(subtracted)
fitter.set_model('sphere')
fitter.set_param('radius', value=30, min=5, max=300)
result = fitter.fit() # recovers radius ≈ 50
If the bundled files are missing
load() raises FileNotFoundError naming the expected location if your
sasdata build excludes its example data or has moved it. simulate() needs no
files at all and is unaffected.
API
sans_fitter.examples
Example datasets and simulated data (issue #53).
Two complementary ways to get data without hunting for a file:
Bundled example datasets — the same collection SasView ships, curated here with the model that fits each one and sensible starting parameters::
>>> from sans_fitter import examples
>>> examples.describe() # what is available
>>> data = examples.load('silica_spheres') # fit-ready Data1D
>>> fitter = examples.load_fitter('silica_spheres') # data + model + parameters
>>> result = fitter.fit()
The files themselves are not vendored into this package. They live inside
the installed sasdata distribution (sasdata/example_data/1d_data), which
is already a hard dependency, so the set stays in sync with sasdata and costs
nothing to ship. :func:load resolves them through :mod:importlib.resources
and raises an actionable error if the layout ever changes.
Simulated data — computed on demand from any sasmodels model, with known ground truth::
>>> data = examples.simulate('sphere', radius=50, noise=0.03, seed=0)
>>> data.truth
{'radius': 50.0, 'sld': 1.0, ...}
Simulated data is the better teaching tool when you want a self-checking exercise ("fit this, you should recover radius = 50"), works for any of the ~100 sasmodels models, and needs no files on disk. Real bundled data is the better tool for everything a simulation will not show you: instrument resolution, sloping backgrounds, noisy high-Q tails and negative intensities after subtraction.
Both routes return a fit-ready Data1D — qmin/qmax/mask set —
that can be handed straight to :meth:SANSFitter.set_data or to
:mod:sans_fitter.data.ops.
Example
dataclass
A curated bundled dataset and how to fit it.
Attributes:
| Name | Type | Description |
|---|---|---|
name |
str
|
Short key used by :func: |
filename |
str
|
File name within the sasdata 1D example directory. |
model |
str
|
sasmodels model name that describes this sample. |
description |
str
|
What the sample is and what it is useful for teaching. |
params |
dict[str, dict[str, Any]]
|
Suggested starting configuration, as
|
structure_factor |
str | None
|
Structure factor to apply, if the sample is concentrated enough to need one. |
polydispersity |
dict[str, dict[str, Any]]
|
|
truth |
dict[str, float] | None
|
Generating parameters, for simulated files only. |
notes |
str
|
Caveats worth knowing before fitting — engine restrictions, known difficulties. Empty when there are none. |
tags |
tuple[str, ...]
|
Free-form labels for filtering with :func: |
source |
str
|
Provenance note. |
Source code in src/sans_fitter/examples.py
list_examples(tag=None)
Return the names of the bundled examples, optionally filtered by tag.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tag
|
str | None
|
Only return examples carrying this tag (e.g. |
None
|
Returns:
| Type | Description |
|---|---|
list[str]
|
Sorted example names. |
Source code in src/sans_fitter/examples.py
describe(name=None)
Print a human-readable summary of the bundled examples.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str | None
|
Print the full detail for a single example. When omitted, print a one-line-per-example overview of the whole collection. |
None
|
Source code in src/sans_fitter/examples.py
get_example(name)
Return the :class:Example record for name.
Raises:
| Type | Description |
|---|---|
KeyError
|
If name is not a known example. |
Source code in src/sans_fitter/examples.py
example_path(name)
Return the filesystem path of a bundled example file.
Useful when you want to pass the file to :func:sans_fitter.data.ops.load
or to any other reader yourself.
Raises:
| Type | Description |
|---|---|
KeyError
|
If name is not a known example. |
FileNotFoundError
|
If the file is missing from the sasdata install. |
Source code in src/sans_fitter/examples.py
load(name)
Load a bundled example dataset and return a fit-ready Data1D.
Goes through the same loader as :meth:SANSFitter.load_data, so the result
behaves identically to any dataset you load yourself.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Example name — see :func: |
required |
Returns:
| Type | Description |
|---|---|
Data1D
|
A |
Raises:
| Type | Description |
|---|---|
KeyError
|
If name is not a known example. |
FileNotFoundError
|
If the file is missing from the sasdata install. |
ValueError
|
If the file cannot be parsed. |
Source code in src/sans_fitter/examples.py
load_fitter(name, quiet=True)
Return a :class:SANSFitter preloaded with an example and ready to fit.
Sets the data, the model, any structure factor and polydispersity, and the
suggested starting parameters — so a tutorial reaches fitter.fit() in
one line::
>>> fitter = examples.load_fitter('silica_spheres')
>>> result = fitter.fit()
The starting parameters are coarse values chosen to put the model in the
right basin, not published results. Check get_example(name).truth to see
whether ground truth is known.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Example name — see :func: |
required |
quiet
|
bool
|
Suppress the progress messages that |
True
|
Returns:
| Type | Description |
|---|---|
SANSFitter
|
A configured |
Source code in src/sans_fitter/examples.py
simulate(model='sphere', qmin=0.005, qmax=0.5, npoints=100, noise=0.02, seed=0, dq=None, q=None, **params)
Simulate a SANS dataset from any sasmodels model, with known truth.
The generating parameters are attached to the result as data.truth, so
a tutorial can state the answer up front and the reader can check whether
the fit recovers it.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
model
|
str
|
sasmodels model name, e.g. |
'sphere'
|
qmin
|
float
|
Lowest Q, in 1/A. Ignored when q is given. |
0.005
|
qmax
|
float
|
Highest Q, in 1/A. Ignored when q is given. |
0.5
|
npoints
|
int
|
Number of log-spaced Q points. Ignored when q is given. |
100
|
noise
|
float
|
Relative noise level. |
0.02
|
seed
|
int | None
|
Seed for the noise, so results are reproducible. Pass |
0
|
dq
|
float | None
|
Relative resolution width. When given, |
None
|
q
|
ndarray | None
|
Explicit Q array, overriding qmin/qmax/npoints. Use this to simulate onto the grid of a real dataset. |
None
|
**params
|
Any
|
Model parameters, e.g. |
{}
|
Returns:
| Type | Description |
|---|---|
Data1D
|
A fit-ready |
Data1D
|
full parameter set used to generate it. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the model name is unknown, a parameter is not valid for the model, or the Q range is not positive and increasing. |
Example
data = simulate('sphere', radius=50, noise=0.03, seed=1) data.truth['radius'] 50.0
Source code in src/sans_fitter/examples.py
626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 | |
simulate_pair(model='sphere', background_level=0.5, noise=0.02, seed=0, **kwargs)
Simulate a matched sample and background pair for dataset arithmetic.
Both datasets land on an identical Q grid, which is what
:mod:sans_fitter.data.ops requires — the sample is model + flat
background, and the background dataset is that flat level alone::
>>> sample, background = simulate_pair('sphere', radius=50)
>>> subtracted = data_ops.subtract(sample, background)
>>> fitter = SANSFitter()
>>> fitter.set_data(subtracted)
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
model
|
str
|
sasmodels model name for the sample. |
'sphere'
|
background_level
|
float
|
Flat intensity added to the sample and carried by the
background dataset. An explicit |
0.5
|
noise
|
float
|
Relative Gaussian noise, applied independently to each dataset. |
0.02
|
seed
|
int | None
|
Seed for reproducibility. The background uses |
0
|
**kwargs
|
Any
|
Forwarded to :func: |
{}
|
Returns:
| Type | Description |
|---|---|
tuple[Data1D, Data1D]
|
|