Skip to content
Draft
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
88 changes: 88 additions & 0 deletions docs/learn/scans/argument-bundles.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
---
related:
- title: ScanArgument
url: learn/scans/scanargument.md
- title: GUI Config
url: learn/scans/gui-config.md
- title: Learn by Example
url: learn/scans/learn-by-example.md
---

# Argument Bundles

This page explains how scans can describe repeated positional input bundles when a normal fixed
Python signature is not enough.

## The Scan Signature

In the current scan implementation, a scan definition is described largely by its `__init__`
signature plus a few class attributes.

The scan server serializes that signature and publishes it to clients. The client then uses it to:

- expose the scan under `scans.<name>`
- attach a live Python signature in IPython
- validate kwargs and bundled positional inputs
- resolve device-name strings to device objects when the annotations require that

This means the signature is no longer only local Python documentation. It is part of the runtime API
contract between the scan server, the client, and GUIs.

## `arg_input` and `arg_bundle_size`

!!! tip
`arg_input` and `arg_bundle_size` are special cases for scans with an undefined number of
input arguments. Most scans developed in plugins do not need them.

If the number of input arguments is not fixed, the usual Python-style fixed signature is not enough.

For example, a line scan can work with any number of motors in parallel, so the scan cannot rely on
one fixed positional argument layout in the way an ordinary Python function usually would.

In those cases, scans with repeated positional bundles declare those bundles explicitly.

For a line scan, that can look like this:

```py
arg_input = {
"device": DeviceBase,
"start": float,
"stop": float,
}
arg_bundle_size = {"bundle": 3, "min": 1, "max": None}
```

`arg_bundle_size` then tells BEC how many positional values belong to one bundle and how many
bundles are allowed.

This is what lets BEC validate a call such as:

```py
scans.line_scan(dev.samx, -1, 1, dev.samy, -2, 2, steps=5, relative=False)
```

without treating those positional arguments as an unstructured `*args` blob.

Rich input metadata for individual parameters is covered separately on
[ScanArgument](scanargument.md).

## Reloading The Scan Server

If you add a new scan or change an existing scan class, the scan server must reload that Python code
before the changes become available.

In practice, that means you should restart or reload the scan server after editing scan
implementations. Otherwise the running server will continue using the old version of the scan.

## Next Step

After argument bundles, continue with [GUI Config](gui-config.md) to see how scans group inputs for
graphical clients.

## What To Remember

!!! info "What to remember"
- The serialized scan signature is part of the runtime API between the scan server, clients, and GUIs.
- `arg_input` and `arg_bundle_size` define repeated positional bundles such as move targets or line-scan ranges.
- `ScanArgument` covers rich metadata for individual inputs, while argument bundles describe repeated positional structure.
- After changing scan code, the scan server must be reloaded or restarted.
131 changes: 131 additions & 0 deletions docs/learn/scans/fast-axis-slow-axis.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
---
related:
- title: Position Generators
url: learn/scans/position-generators.md
- title: ScanArgument
url: learn/scans/scanargument.md
- title: Learn by Example
url: learn/scans/learn-by-example.md
---

# Fast Axis and Slow Axis

When a scan moves more than one axis, the order of those axes matters.

BEC follows one consistent convention:

- the outermost axis is the slow axis
- the innermost axis is the fast axis

That means the fast axis changes most often, while the slow axis changes only after the inner sweep
has finished.

## What That Means In Practice

A useful way to read the convention is:

For every point in `samx` from `-5` to `5`, move `samy` from `-10` to `10`.

In that example:

- `samx` is the slow axis
- `samy` is the fast axis

So the scan stays on one `samx` value while it sweeps through the full `samy` range, then advances
to the next `samx` value and repeats.

!!! example
A 2D grid scan like this:

```py
scans.grid_scan(dev.samx, -5, 5, 3, dev.samy, -10, 10, 5, snaked=False, relative=False)
```

would have `samx` as the slow axis and `samy` as the fast axis, so the scan would:

1. keep `samx` fixed at `-5` while it sweeps `samy` from `-10` to `10`
2. advance `samx` to the next value (in this case `0`) while it again sweeps `samy` from `-10` to `10`
3. advance `samx` to the next value (in this case `5`) while it again sweeps `samy` from `-10` to `10`
4. finish the scan after the last `samx` value has been reached and its inner sweep has completed

If the requirement is to have `samy` as the slow axis and `samx` as the fast axis, one would just swap the order of the motor arguments:

```py
scans.grid_scan(dev.samy, -10, 10, 5, dev.samx, -5, 5, 3, snaked=False, relative=False)
```

## Why This Matters

This convention affects how you read and define multi-axis scans:

- the order of axes in a grid or nested scan is meaningful
- the generated point order follows that nesting
- snaking typically changes the traversal direction of the fast axis while keeping the same slow-axis structure

Keeping that convention stable makes scan definitions easier to reason about and makes generated
point lists more predictable.

## A Simple Example

At the user level, a grid scan might look like this:

```py
scans.grid_scan(dev.samx, -5, 5, 3, dev.samy, -10, 10, 5, snaked=False)
```

The same ordering appears in the generated positions:

```py
positions = position_generators.nd_grid_positions(

Check warning on line 79 in docs/learn/scans/fast-axis-slow-axis.md

View workflow job for this annotation

GitHub Actions / linting_and_formatting / Spellcheck

"nd" should be "and".
[(-5.0, 5.0, 3), (-10.0, 10.0, 5)],
snaked=False,
)

for point in positions:
samx_position = point[0]
samy_position = point[1]
```

Here the first axis is the outer loop and the second axis is the inner loop:

- axis 1: slow axis
- axis 2: fast axis

So the point order follows this pattern:

1. keep the first axis fixed
2. sweep the second axis through all of its values
3. advance the first axis
4. repeat

## How To Read Existing Scan Code

When you see code such as:

```py
positions = position_generators.nd_grid_positions(

Check warning on line 106 in docs/learn/scans/fast-axis-slow-axis.md

View workflow job for this annotation

GitHub Actions / linting_and_formatting / Spellcheck

"nd" should be "and".
[(start_motor1, stop_motor1, steps_motor1), (start_motor2, stop_motor2, steps_motor2)],
snaked=True,
)
```

read it as:

- the first tuple defines the slow axis
- the second tuple defines the fast axis

That same idea also applies more generally to nested point generation: outer definitions correspond
to slower-changing axes, and inner definitions correspond to faster-changing axes.

## Next Step

After axis-order conventions, continue with [ScanArgument](scanargument.md).

That page covers the rich input metadata used in scan signatures.

## What To Remember

!!! info "What to remember"
- In BEC, the outermost axis is the slow axis and the innermost axis is the fast axis.
- The fast axis changes most often within the generated point list.
- This convention makes multi-axis scan definitions and point ordering easier to read.
78 changes: 78 additions & 0 deletions docs/learn/scans/gui-config.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
---
related:
- title: ScanArgument
url: learn/scans/scanargument.md
- title: Argument Bundles
url: learn/scans/argument-bundles.md
- title: Learn by Example
url: learn/scans/learn-by-example.md
---

# GUI Config

This page explains how scans can group their inputs for graphical clients through `gui_config`.

## What `gui_config` Does

`gui_config` describes how scan inputs should be grouped in graphical interfaces.

For example, a scan can group inputs under headings such as:

- `Device`
- `Movement Parameters`
- `Acquisition Parameters`

This does not change how the scan runs. It helps GUIs present scan inputs in a clear structure
instead of showing one flat list of parameters.

## A Typical Example

```py
gui_config = {
"Device 1": ["motor1", "start_motor1", "stop_motor1"],
"Device 2": ["motor2", "start_motor2", "stop_motor2"],
"Movement Parameters": ["step", "relative"],
"Acquisition Parameters": [
"exp_time",
"frames_per_trigger",
"settling_time",
"readout_time",
],
}
```

In this example, the scan definition is still the same Python class and the same Python signature.
`gui_config` only changes how that information is grouped and presented in graphical clients.

## How It Fits With Scan Signatures

`gui_config` does not replace the scan signature or `ScanArgument` metadata.

Instead, these pieces work together:

- the signature defines which inputs exist
- `ScanArgument` enriches individual inputs with labels, units, bounds, and descriptions
- `gui_config` groups those inputs into a clearer layout for GUIs

This is why `gui_config` is best thought of as presentation metadata rather than execution logic.

## Reloading The Scan Server

If you add a new scan or change an existing scan class, the scan server must reload that Python code
before the changes become available.

In practice, that means you should restart or reload the scan server after editing scan
implementations. Otherwise the running server will continue using the old version of the scan.

## Next Step

If you want to see `gui_config` and related scan-definition details in a richer real scan, read the
[worked example: hexagonal scan](hexagonal-scan-example.md).

## What To Remember

!!! info "What to remember"
- `gui_config` groups scan inputs for graphical clients.
- It changes presentation, not scan execution.
- `gui_config` works alongside the scan signature and `ScanArgument` metadata.
- After changing scan code, the scan server must be reloaded or restarted.
Loading
Loading