Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ISIS standard callback collection #93

Open
8 tasks
Tom-Willemsen opened this issue Dec 2, 2024 · 0 comments
Open
8 tasks

ISIS standard callback collection #93

Tom-Willemsen opened this issue Dec 2, 2024 · 0 comments
Labels

Comments

@Tom-Willemsen
Copy link
Contributor

Tom-Willemsen commented Dec 2, 2024

In a lot of our plans we have callbacks that look very similar to:

def some_plan():
    ...
    x = some_device()
    y = some_device()

    ...

    _, ax = yield from call_qt_aware(plt.subplots)

    lf = LiveFit(
        Linear.fit(), y=y.name, x=x.name, yerr=y.stddev.name
    )

    @subs_decorator(
        [
            HumanReadableFileCallback(
                Path("C:\\") / "instrument" / "var" / "logs" / "bluesky" / "output_files",
                [
                    x.name,
                    y.name,
                    y.stddev.name,
                    y.foo.name,
                    y.bar.name,
                ],
            ),
            LiveFitPlot(livefit=lf, ax=ax),
            LivePlot(
                y=y.name,
                x=x.name,
                marker="x",
                linestyle="none",
                ax=ax,
                yerr=y.stddev.name,
            ),
            LiveTable(
                [
                    x.name,
                    y.name,
                    y.stddev.name,
                    y.foo.name,
                    y.bar.name,
                ]
            ),
        ]
    )
    def _inner() -> Generator[Msg, None, None]:
        yield from the_thing_i_want_to_do()

While this is very explicit and also very flexible, as a developer & user I'd like this to be more concise - since most of these callbacks will be wanted most of the time, I think we should have a standard "callback collection" that allows us to write something more like:

def some_plan():
    ...
    x = some_device()
    y = some_device()

    ...

    @isis_standard_callbacks(x=x, y=y, yerr=y.stddev, fit=Linear.fit(), extras=[y.foo, y.bar])
    def _inner() -> Generator[Msg, None, None]:
        yield from the_thing_i_want_to_do()

This is in the general spirit of the "best effort callback" from bluesky, I don't think we can use that directly - we still need to be able to specify e.g. fit types and extras.

The isis_standard_callbacks decorator is about a set of "typical" callbacks which will work for many plans. It's ok if it doesn't work for all cases - here we should use "opionated" defaults (can always fall back to explicit approach if people need fine-grained control).

Acceptance criteria:

  • isis_standard_callbacks exists and works functionally similarly to subs_decorator but adds all of our "usual" callbacks and configures mpl plotting in the "usual" way for the user.
  • It is still possible to use full explicit callbacks if desired (i.e. first option above should still be possible)
  • If yerr is omitted, error bars do not appear on plot, fit is unweighted, yerr not present in file/table
  • If yerr is present, error bars appear on plot and fit is weighted, yerr present in file/table
  • It must still be possible to access the result of the LiveFit in some way (e.g. make return value of the decorated function (original_return value, live_fit_result))
  • Must be possible to add "extra" signals to put in files and on the livetable (e.g. y.foo and y.bar above), as well as x, y, yerr
  • If fit is not specified, don't add LiveFit and LiveFitPlot
  • Have a set of keyword toggles, defaulting to True, which include / exclude the underlying callbacks:
    • e.g. isis_standard_callbacks(..., table=False) would be good for LOQ's laser scan, we get so many points that the table is quite noisy.

Planning

10/01/25 - 00:36:00

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
Status: No status
Status: Backlog
Development

No branches or pull requests

2 participants