<commit_before>Live Visualization and Processing
*********************************

.. ipython:: python
   :suppress:
   :okwarning:

   from bluesky import RunEngine
   RE = RunEngine({})

.. _callbacks:

Overview of Callbacks
---------------------

As the RunEngine executes a plan, it organizes metadata and data into
*Documents,* Python dictionaries organized in a
:doc:`specified but flexible <documents>` way. Each time a new Document is
created, the RunEngine passes it to a list of functions. These functions can do
anything: store the data to disk, print a line of text to the screen, add a
point to a plot, or even transfer the data to a cluster for immediate
processing. These functions are called "callbacks."

We "subscribe" callbacks to the live stream of Documents coming from the
RunEngine. You can think of a callback as a self-addressed stamped envelope: it
tells the RunEngine, "When you create a Document, send it to this function for
processing."

Callback functions are run in a blocking fashion: data acquisition cannot
continue until they return. For light tasks like simple plotting or critical
tasks like sending the data to a long-term storage medium, this behavior is
desirable. It is easy to debug and it guarantees that critical errors will be
noticed immediately. But heavy computational tasks --- anything that takes more
than about 0.2 seconds to finish --- should be executed in a separate process
or server so that they do not hold up data acquisition. Bluesky provides nice
tooling for this use case --- see :ref:`zmq_callback`.

Simplest Working Example
------------------------

This example passes every Document to the ``print`` function, printing
each Document as it is generated during data collection.

.. code-block:: python

    from bluesky.plans import count
    from ophyd.sim import det

    RE(count([det]), print)

The ``print`` function is a blunt instrument; it dumps too much information to
the screen.  See :ref:`LiveTable <livetable>` below for a more refined option.

Ways to Invoke Callbacks
------------------------

Interactively
+++++++++++++

As in the simple example above, pass a second argument to the RunEngine.
For some callback function ``cb``, the usage is:

.. code-block:: python

    RE(plan(), cb))

A working example:

.. code-block:: python

    from ophyd.sim import det, motor
    from bluesky.plans import scan
    from bluesky.callbacks import LiveTable
    dets = [det]
    RE(scan(dets, motor, 1, 5, 5), LiveTable(dets))

A *list* of callbacks --- ``[cb1, cb2]`` --- is also accepted; see
:ref:`filtering`, below, for additional options.

Persistently
++++++++++++

The RunEngine keeps a list of callbacks to apply to *every* plan it executes.
For example, the callback that saves the data to a database is typically
invoked this way. For some callback function ``cb``, the usage is:

.. code-block:: python

    RE.subscribe(cb)

This step is usually performed in a startup file (i.e., IPython profile).

.. automethod:: bluesky.run_engine.RunEngine.subscribe
    :noindex:

.. automethod:: bluesky.run_engine.RunEngine.unsubscribe
    :noindex:

.. _subs_decorator:

Through a plan
++++++++++++++

Use the ``subs_decorator`` :ref:`plan preprocessor <preprocessors>` to attach
callbacks to a plan so that they are subscribed every time it is run.

In this example, we define a new plan, ``plan2``, that adds some callback
``cb`` to some existing plan, ``plan1``.

.. code-block:: python

    from bluesky.preprocessors import subs_decorator

    @subs_decorator(cb)
    def plan2():
        yield from plan1()

or, equivalently,

.. code-block:: python

    plan2 = subs_decorator(cb)(plan1)

For example, to define a variant of ``scan`` that includes a table by default:

.. code-block:: python

    from bluesky.plans import scan
    from bluesky.preprocessors import subs_decorator

    def my_scan(detectors, motor, start, stop, num, *, per_step=None, md=None):
        "This plan takes the same arguments as `scan`."

        table = LiveTable([motor] + list(detectors))

        @subs_decorator(table)
        def inner():
            yield from scan(detectors, motor, start, stop, num,
                            per_step=per_step, md=md)

        yield from inner()

Callbacks for Visualization & Fitting
-------------------------------------

.. _livetable:

LiveTable
+++++++++

As each data point is collected (i.e., as each Event Document is generated) a
row is added to the table. Demo:

.. ipython:: python

    from bluesky.plans import scan
    from ophyd.sim import motor, det
    from bluesky.callbacks import LiveTable

    RE(scan([det], motor, 1, 5, 5), LiveTable([motor, det]))

Pass an empty list of columns to show simply 'time' and 'seq_num' (sequence
number).

.. code-block:: python

    LiveTable([])

In the demo above, we passed in a list of *device(s)*, like so:

.. code-block:: python

    LiveTable([motor])

Internally, ``LiveTable`` obtains the name(s) of the field(s) produced by
reading ``motor``. You can do this yourself too:

.. ipython:: python

    list(motor.describe().keys())

In the general case, a device can produce tens or even hundreds of separate
readings, and it can be useful to spell out specific fields rather than a whole
device.

.. code-block:: python

    # the field 'motor', in quotes, not the device, motor
    LiveTable(['motor'])

In fact, almost all other callbacks (including :ref:`LivePlot`) *require* a
specific field. They will not accept a device because it may have more than one
field.

.. autoclass:: bluesky.callbacks.LiveTable

.. _kickers:

Aside: Making plots update live
+++++++++++++++++++++++++++++++

.. note::

    If you are a user working with a pre-configured setup, you can probably<commit_msg>DOC: add warning about adjusting .PREC<commit_after>Live Visualization and Processing
*********************************

.. ipython:: python
   :suppress:
   :okwarning:

   from bluesky import RunEngine
   RE = RunEngine({})

.. _callbacks:

Overview of Callbacks
---------------------

As the RunEngine executes a plan, it organizes metadata and data into
*Documents,* Python dictionaries organized in a
:doc:`specified but flexible <documents>` way. Each time a new Document is
created, the RunEngine passes it to a list of functions. These functions can do
anything: store the data to disk, print a line of text to the screen, add a
point to a plot, or even transfer the data to a cluster for immediate
processing. These functions are called "callbacks."

We "subscribe" callbacks to the live stream of Documents coming from the
RunEngine. You can think of a callback as a self-addressed stamped envelope: it
tells the RunEngine, "When you create a Document, send it to this function for
processing."

Callback functions are run in a blocking fashion: data acquisition cannot
continue until they return. For light tasks like simple plotting or critical
tasks like sending the data to a long-term storage medium, this behavior is
desirable. It is easy to debug and it guarantees that critical errors will be
noticed immediately. But heavy computational tasks --- anything that takes more
than about 0.2 seconds to finish --- should be executed in a separate process
or server so that they do not hold up data acquisition. Bluesky provides nice
tooling for this use case --- see :ref:`zmq_callback`.

Simplest Working Example
------------------------

This example passes every Document to the ``print`` function, printing
each Document as it is generated during data collection.

.. code-block:: python

    from bluesky.plans import count
    from ophyd.sim import det

    RE(count([det]), print)

The ``print`` function is a blunt instrument; it dumps too much information to
the screen.  See :ref:`LiveTable <livetable>` below for a more refined option.

Ways to Invoke Callbacks
------------------------

Interactively
+++++++++++++

As in the simple example above, pass a second argument to the RunEngine.
For some callback function ``cb``, the usage is:

.. code-block:: python

    RE(plan(), cb))

A working example:

.. code-block:: python

    from ophyd.sim import det, motor
    from bluesky.plans import scan
    from bluesky.callbacks import LiveTable
    dets = [det]
    RE(scan(dets, motor, 1, 5, 5), LiveTable(dets))

A *list* of callbacks --- ``[cb1, cb2]`` --- is also accepted; see
:ref:`filtering`, below, for additional options.

Persistently
++++++++++++

The RunEngine keeps a list of callbacks to apply to *every* plan it executes.
For example, the callback that saves the data to a database is typically
invoked this way. For some callback function ``cb``, the usage is:

.. code-block:: python

    RE.subscribe(cb)

This step is usually performed in a startup file (i.e., IPython profile).

.. automethod:: bluesky.run_engine.RunEngine.subscribe
    :noindex:

.. automethod:: bluesky.run_engine.RunEngine.unsubscribe
    :noindex:

.. _subs_decorator:

Through a plan
++++++++++++++

Use the ``subs_decorator`` :ref:`plan preprocessor <preprocessors>` to attach
callbacks to a plan so that they are subscribed every time it is run.

In this example, we define a new plan, ``plan2``, that adds some callback
``cb`` to some existing plan, ``plan1``.

.. code-block:: python

    from bluesky.preprocessors import subs_decorator

    @subs_decorator(cb)
    def plan2():
        yield from plan1()

or, equivalently,

.. code-block:: python

    plan2 = subs_decorator(cb)(plan1)

For example, to define a variant of ``scan`` that includes a table by default:

.. code-block:: python

    from bluesky.plans import scan
    from bluesky.preprocessors import subs_decorator

    def my_scan(detectors, motor, start, stop, num, *, per_step=None, md=None):
        "This plan takes the same arguments as `scan`."

        table = LiveTable([motor] + list(detectors))

        @subs_decorator(table)
        def inner():
            yield from scan(detectors, motor, start, stop, num,
                            per_step=per_step, md=md)

        yield from inner()

Callbacks for Visualization & Fitting
-------------------------------------

.. _livetable:

LiveTable
+++++++++

As each data point is collected (i.e., as each Event Document is generated) a
row is added to the table. Demo:

.. ipython:: python

    from bluesky.plans import scan
    from ophyd.sim import motor, det
    from bluesky.callbacks import LiveTable

    RE(scan([det], motor, 1, 5, 5), LiveTable([motor, det]))

Pass an empty list of columns to show simply 'time' and 'seq_num' (sequence
number).

.. code-block:: python

    LiveTable([])

In the demo above, we passed in a list of *device(s)*, like so:

.. code-block:: python

    LiveTable([motor])

Internally, ``LiveTable`` obtains the name(s) of the field(s) produced by
reading ``motor``. You can do this yourself too:

.. ipython:: python

    list(motor.describe().keys())

In the general case, a device can produce tens or even hundreds of separate
readings, and it can be useful to spell out specific fields rather than a whole
device.

.. code-block:: python

    # the field 'motor', in quotes, not the device, motor
    LiveTable(['motor'])

In fact, almost all other callbacks (including :ref:`LivePlot`) *require* a
specific field. They will not accept a device because it may have more than one
field.

.. autoclass:: bluesky.callbacks.LiveTable

.. warning

   The data in the table is formatted according to its type and the
   precision reported by the control system.  If you are seeing too
   many or too few decimal places, this should be adjusted at the
   controls system level.  In EPICS, this is typically the ``.PREC``
   field on the record.

.. _kickers:

Aside: Making plots update live
+++++++++++++++++++++++++++++++

.. note::

    If you are a user working with a pre-configured setup, you can probably
{'fraction_non_alphanumeric': 0.11702217350982211, 'fraction_numerical': 0.0026979175448950342, 'mean_word_length': 3.4327354260089686, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1039699', 'n_tokens_mistral': 3367, 'n_tokens_neox': 3212, 'n_words': 1525}