device#
Talk to the connected NMR instrument.
Read and set the instrument's temperature, frequency, phase, and pulse
durations, and run pulse sequences on it with execute. Methods that
need hardware raise an error if no device is connected — guard with
is_connected when in doubt.
NMRRelaxometer
#
Base class for NMR Relaxometer devices with frequency and temperature control.
set_frequency
#
Set frequency in MHz (Protocol requirement).
get_frequency_range
#
Get frequency range in MHz (Protocol requirement).
set_frequency_device
#
Set frequency using device-specific units.
get_frequency_device
#
Get frequency with device-specific units.
set_temperature
#
Set temperature (Protocol requirement).
get_target_temperature
#
Get target temperature (Protocol requirement).
get_temperature_range
#
Get temperature range (Protocol requirement).
wait_for_temperature
#
Wait for temperature to stabilize (Protocol requirement).
set_temperature_device
#
Set temperature using device-specific units.
get_temperature_device
#
Get temperature with device-specific units.
Annotation
dataclass
#
Axis
dataclass
#
Settings for one axis: title, range, scale, gridlines, and ticks.
Common fields: title, range=[lo, hi] (or autorange=True),
type="log" for a logarithmic scale, and showgrid.
type
class-attribute
instance-attribute
#
Bar
dataclass
#
A bar series — vertical bars by default, horizontal with orientation="h".
Contour
dataclass
#
Contour lines over a 2D grid of values (a topographic-style map).
Like Heatmap, but draws lines joining equal values. ncontours
sets roughly how many levels to draw.
Figure
dataclass
#
A complete plot: one or more data series plus a Layout.
Add series with add, draw extra marks with add_shape /
add_annotation, and set titles and axes with update_layout.
All of these return the figure, so calls can be chained. Pass the finished
figure to viz.show_figure(...) or reporting.add_figure(...).
data
class-attribute
instance-attribute
#
add
#
add(*traces: _Trace | dict[str, Any]) -> Figure
Add one or more data series (Scatter, Bar, …) to the figure.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
*traces
|
_Trace | dict[str, Any]
|
The series to add. |
()
|
Returns:
| Type | Description |
|---|---|
Figure
|
The figure, so calls can be chained. |
add_shape
#
add_annotation
#
add_annotation(
annotation: Annotation | dict[str, Any],
) -> Figure
Add a text label (optionally with an arrow) at a point on the figure.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
annotation
|
Annotation | dict[str, Any]
|
The |
required |
Returns:
| Type | Description |
|---|---|
Figure
|
The figure, so calls can be chained. |
update_layout
#
update_layout(**kwargs: Any) -> Figure
Set figure-wide options like title and axes by keyword.
For example fig.update_layout(title="...", xaxis=charts.Axis(title="...")).
Use the flat form — the xaxis_title= shorthand is not supported; pass
xaxis=charts.Axis(title=...) instead.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
**kwargs
|
Any
|
Layout fields to set (e.g. |
{}
|
Returns:
| Type | Description |
|---|---|
Figure
|
The figure, so calls can be chained. |
to_spec
#
Export the figure as a plain dictionary.
You rarely need this directly — viz.show_figure and
reporting.add_figure call it for you. Useful if you want to inspect or
store the figure's definition. Unset options are dropped and numpy arrays
become lists.
Returns:
| Type | Description |
|---|---|
dict[str, Any]
|
A |
dict[str, Any]
|
figure. |
Font
dataclass
#
Font styling for titles, axis labels, and annotation text.
Heatmap
dataclass
#
A 2D grid of values shown as colours.
z is the grid (rows × columns); optional x and y label the column
and row positions. colorscale sets the colour mapping.
Layout
dataclass
#
The figure's overall look: title, axes, legend, margins, shapes, annotations.
Usually set through Figure.update_layout rather than constructed
directly. xaxis2/yaxis2 (and …3/…4) support extra axes for
multi-panel figures.
Line
dataclass
#
Line styling: color, width, and dash pattern.
dash
class-attribute
instance-attribute
#
Margin
dataclass
#
Plot margins in pixels: left, right, top, bottom.
Marker
dataclass
#
Marker styling for data points (color, size, symbol).
symbol
class-attribute
instance-attribute
#
symbol: (
Literal[
"circle",
"square",
"diamond",
"cross",
"x",
"triangle-up",
"triangle-down",
]
| None
) = None
Scatter
dataclass
#
A line and/or point series — the most common plot type.
Set mode to "lines", "markers", or "lines+markers" to choose
between a connected line, scattered points, or both. Style with line= and
marker=.
mode
class-attribute
instance-attribute
#
mode: (
Literal[
"lines",
"markers",
"lines+markers",
"text",
"lines+markers+text",
]
| None
) = None
fill
class-attribute
instance-attribute
#
textposition
class-attribute
instance-attribute
#
textposition: (
Literal[
"top left",
"top center",
"top right",
"middle left",
"middle center",
"middle right",
"bottom left",
"bottom center",
"bottom right",
]
| None
) = None
Shape
dataclass
#
A shape drawn over the plot to highlight a region or point.
Set type to "line", "rect", "circle", or "path" and give
its corners with x0/y0/x1/y1. A "triangle" type is also available as a
peak marker (positioned with tipX/tipY and sized with the dx/
dy/lengthPx/widthPx/label fields).
type
class-attribute
instance-attribute
#
DeviceState
#
GraphResult
#
GraphResult(
results: dict[str, object],
nodes: list[PostprocessingNode],
)
What a processing graph produced when run over one scan.
Read-only. signal and spectrum give the graph's final results; the
outputs mapping holds every final output keyed by the step that produced
it. ("Final" steps are the ones whose output nothing else in the graph feeds
into.)
Scan
#
One stored scan, with friendly access to its data.
Read its signal, spectrum, peaks, and metadata; the heavy data
is loaded from disk only when first accessed, then kept in memory. Assigning to
signal/spectrum/peaks changes the scan in memory only — call
save to write it back to its own file on disk.
This is what every scans method hands back; you work with it instead of the
raw stored record (still reachable via .raw if you ever need it).
signal
property
writable
#
Accumulated signal (FID) as a Signal1D/Signal2D.
spectrum
property
writable
#
spectrum: Spectrum1D | Spectrum2D | None
Accumulated spectrum as a Spectrum1D/Spectrum2D.
peaks
property
writable
#
Picked peaks for the scan.
Returns the manually picked peaks stored on the scan if present; otherwise
the peaks from the most recent explicit perform_analysis call (empty
if none). Peaks are not auto-detected on access — call
perform_analysis to run detection.
integration_regions
property
#
integration_regions: list[IntegrationRegion]
Integration regions defined on the scan.
raw
property
#
The underlying stored scan record, for advanced use.
Loads from disk on first access. Prefer the friendly accessors above
(signal, spectrum, peaks, metadata); reach for this only
when you need a field they don't expose.
perform_analysis
#
perform_analysis(
*,
settings: PeakDetectionSettings | None = None,
adaptive: bool | None = None,
min_distance_hz: float | None = None,
min_height_ratio: float | None = None,
prominence: float | None = None,
integration_width_hz: float | None = None,
normalize_to_peak: int | None = None,
multiplet_search_width_hz: float | None = None,
) -> list[PeakInfo]
Detect peaks and compute their integrals on this scan's 1D spectrum.
Runs the same analysis the app performs (adaptive detection + integration).
Any setting not provided falls back to the user's global peak-detection
settings (project display settings), then the app defaults. The result is
stored and returned (also reflected by .peaks when there are no manual
peaks). Returns an empty list for non-1D spectra.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
settings
|
PeakDetectionSettings | None
|
A full settings object to start from (overrides the global settings as the base); individual keyword args below still win. |
None
|
adaptive
|
bool | None
|
Noise-adaptive detection. |
None
|
min_distance_hz
|
float | None
|
Minimum spacing between peaks. |
None
|
min_height_ratio
|
float | None
|
Minimum height as a fraction of the max (manual mode). |
None
|
prominence
|
float | None
|
Minimum prominence (manual mode). |
None
|
integration_width_hz
|
float | None
|
Fixed integration width (0/None = auto). |
None
|
normalize_to_peak
|
int | None
|
Peak index to normalize areas to (<0 = none). |
None
|
multiplet_search_width_hz
|
float | None
|
Multiplet clustering window. |
None
|
save
#
Write modifications back to this scan's own file on disk.
Targets the scan by id/project, so persisting an analysis scan never touches the current/active scan.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
signed
|
bool
|
Use a CFR-21-Part-11 signed save (authorship signature). |
False
|
password
|
str | None
|
Profile password (required for admin signed saves only). |
None
|
comment
|
str
|
Optional signing comment. |
''
|
preprocess
#
preprocess(
*,
settings: PreprocessingSettings | None = None,
phase_correction: PhaseCorrectionSettings | None = None,
baseline_correction: BaselineCorrectionSettings
| None = None,
apodization: ApodizationSettings | None = None,
zero_fill: ZeroFillSettings | None = None,
fft: FftSettings | None = None,
reference_correction: ReferenceCorrectionSettings
| None = None,
group_delay: GroupDelaySettings | None = None,
solvent_suppression: SolventSuppressionSettings
| None = None,
) -> Scan
Apply preprocessing to this scan's 1D signal, in memory.
Runs the same pipeline as a normal scan load — solvent suppression,
apodization, zero-fill, FFT, group-delay removal, phase correction, reference
correction, baseline correction — producing a processed signal and spectrum.
Each stage not provided falls back to the user's global preprocessing settings
(project.preprocessing_settings). Updates .signal/.spectrum (and
invalidates cached peaks) without touching current_scan. No-op for non-1D
signals. Returns self.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
settings
|
PreprocessingSettings | None
|
A full settings object to start from (the global settings are the base otherwise); the per-stage args below still win. |
None
|
phase_correction
|
PhaseCorrectionSettings | None
|
Override the phase-correction stage. |
None
|
baseline_correction
|
BaselineCorrectionSettings | None
|
Override the baseline-correction stage. |
None
|
apodization
|
ApodizationSettings | None
|
Override the apodization (window) stage. |
None
|
zero_fill
|
ZeroFillSettings | None
|
Override the zero-fill stage. |
None
|
fft
|
FftSettings | None
|
Override the FFT stage. |
None
|
reference_correction
|
ReferenceCorrectionSettings | None
|
Override the reference-correction stage. |
None
|
group_delay
|
GroupDelaySettings | None
|
Override the group-delay stage. |
None
|
solvent_suppression
|
SolventSuppressionSettings | None
|
Override the solvent-suppression stage. |
None
|
Raises:
| Type | Description |
|---|---|
PreprocessingError
|
If a stage cannot be applied as configured. |
ProcessingParameterError
|
If a stage parameter is out of range. |
analyze
#
analyze(*, with_preprocessing: bool | None = None) -> Scan
Run the app's automatic processing on this scan (in memory).
Convenience bundle: optionally preprocess (phase correction, baseline,
etc.) then refresh peak analysis — matching what the app does on a normal
scan load, without touching current_scan. Returns self.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
with_preprocessing
|
bool | None
|
Whether to preprocess first. Defaults to the project's
|
None
|
process
#
process(graph: GraphSpec | None = None) -> GraphResult
Run a processing graph over this scan and return its outputs.
Processes this scan's signal/spectrum in the background, without changing
the active scan (scans.current) or the processor shown in the UI.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
graph
|
GraphSpec | None
|
Which graph to run — |
None
|
Returns:
| Type | Description |
|---|---|
GraphResult
|
A |
FunctionAnalysisResult
dataclass
#
SmartFittingResult
dataclass
#
Result from SmartFittingAPI.fit with comprehensive metadata.
BaseOp
#
Base class for all operations.
Operations are pure data models (Pydantic) that define their parameters. Devices are responsible for interpreting and executing operations.
Example
@operation # Decorator will register and assign ID class PulseOp(BaseOp): phase: rpc.NmrPulseDirection duration: rpc.Duration
model_config
class-attribute
instance-attribute
#
get_visualization
#
Get visualization data for this operation.
Returns a dict with visualization info or None if no visualization. Default implementation returns None - override in subclasses.
get_duration_ns
#
Get operation duration in nanoseconds.
Default returns 0 - override in operations with duration.
to_struct
#
Serialize this operation to a protobuf Struct.
Used for sending operations over gRPC.
PulseOp
#
RecordOp
#
SilenceOp
#
DEVICE_VENDOR
Requires device
#
Name of the connected instrument's vendor/provider (e.g. its make).
DWELL_TIME
Requires device
#
Dwell time in seconds — the spacing between acquired sample points.
This is the sampling interval of the digitiser; its inverse is the
spectral width. Available on relaxometer-type devices.
configure
Requires device
#
Push a settings bundle to the instrument in one call.
Args:
config: A device configuration object holding the settings to apply.
Returns:
``True`` if the instrument accepted the configuration.
execute
Requires device
#
execute(
sequence: Sequence[BaseOp],
return_type: Literal[
"signal", "spectrum", "both"
] = "spectrum",
num_accum: int = 1,
report: bool | Literal["auto"] = "auto",
record: bool = True,
plot: bool = True,
manage_run: bool = True,
) -> (
list[Signal1D]
| list[Spectrum1D]
| list[tuple[Signal1D, Spectrum1D]]
)
Run a pulse sequence on the instrument and collect the result.
Executes the given operations, accumulates the requested number of scans,
and (by default) plots the result and saves it into the current state.
Args:
sequence: The list of operations to run (build them with the ``ops``
namespace).
return_type: What to hand back — ``"signal"`` (the time-domain FID),
``"spectrum"`` (the transformed spectrum), or ``"both"``.
num_accum: Number of scans to average together for signal-to-noise.
report: Whether to generate a report for the run. ``"auto"`` reports
unless this call is inside a progress-tracked loop.
record: Whether to record/persist the acquisition.
plot: Whether to display the result in the UI.
manage_run: Leave ``True`` to start and finalise the acquisition
automatically. Set ``False`` only when you are managing the run
yourself across several calls (e.g. inside a tuning loop).
Returns:
A list of results matching ``return_type``: ``Signal1D`` items,
``Spectrum1D`` items, or ``(Signal1D, Spectrum1D)`` tuples. For 2D
acquisitions the data is plotted/saved and an empty list is returned.
get_frequency
Requires NMRRelaxometer
#
Read the instrument's current spectrometer (carrier) frequency.
Args:
return_unit: Unit to report in — e.g. ``"Hz"``, ``"kHz"``, ``"MHz"``,
``"GHz"``.
Returns:
The current frequency in ``return_unit``.
get_info
Requires device
#
get_info() -> DeviceState
Get a snapshot of the connected instrument.
Returns:
A device-state object with ``connected`` (bool), ``vendor`` (str), and
``metadata`` (model/capability details).
get_pulse_duration
Requires NMRRelaxometer
#
get_pulse_duration(
pulse_type: Literal[
"90deg", "180deg", "270deg", "360deg"
]
| Literal["ringing", "echo"]
| NmrPulseDirection,
return_unit: Literal[
"ns", "us", "ms", "s", "m", "h", "d"
] = "us",
) -> float
Read the configured duration of a named pulse.
Args:
pulse_type: Which pulse to read — a calibrated spec such as ``"90deg"``
or ``"180deg"``, or a pulse direction.
return_unit: Time unit to report in (e.g. ``"us"``, ``"ms"``).
Returns:
The pulse duration in ``return_unit``.
get_settings
#
Read all current instrument settings as a plain dictionary.
Returns:
| Type | Description |
|---|---|
dict
|
The device settings as name→value pairs (empty if the device exposes |
dict
|
none). |
get_temperature
Requires NMRRelaxometer
#
Read the instrument's current and target sample temperature.
Args:
return_unit: Unit to report in — ``"C"``, ``"K"``, or ``"F"``.
Returns:
A ``(current, target)`` tuple in ``return_unit``.
is_connected
#
Check whether an instrument is connected and ready.
Returns:
| Type | Description |
|---|---|
bool
|
|
set_frequency
Requires NMRRelaxometer
#
Set the instrument's spectrometer (carrier) frequency.
Args:
frequency: Target frequency value.
unit: Unit of ``frequency`` — e.g. ``"Hz"``, ``"kHz"``, ``"MHz"``,
``"GHz"``.
Returns:
``True`` once the frequency has been sent.
set_phase
Requires NMRRelaxometer
#
Set the instrument's receiver/transmitter phase.
Args:
phase_deg: Phase in degrees.
Returns:
``True`` once the phase has been sent.
set_pulse_duration
Requires NMRRelaxometer
#
set_pulse_duration(
pulse_type: Literal[
"90deg", "180deg", "270deg", "360deg"
]
| Literal["ringing", "echo"]
| NmrPulseDirection,
duration: float,
unit: Literal[
"ns", "us", "ms", "s", "m", "h", "d"
] = "us",
) -> None
Set the duration of a named pulse on the instrument.
Args:
pulse_type: Which pulse to set — a calibrated spec such as ``"90deg"``
or ``"180deg"``, or a pulse direction.
duration: New pulse length.
unit: Unit of ``duration`` (e.g. ``"us"``, ``"ms"``).
set_temperature
Requires NMRRelaxometer
#
Set the instrument's target sample temperature.
Args:
temperature: Target temperature value.
unit: Unit of ``temperature`` — ``"C"``, ``"K"``, or ``"F"``.
Returns:
``True`` once the setpoint has been sent.