Usage

Launch Binder to explore some interactive examples.

This is a quick example to give a feel for how it would work to acquire data using bluesky and access it using intake.

Acquire data. In this case we’ll serialize the stream of “documents” generated by bluesky to simple text files. See the Binder link above for an example with a live MongoDB.

In [1]: from bluesky import RunEngine

In [2]: RE = RunEngine()

In [3]: from bluesky.plans import scan

In [4]: from ophyd.sim import det, motor

In [5]: from suitcase.jsonl import Serializer

In [6]: serializer = Serializer('data')

In [7]: uid, = RE(scan([det], motor, -1, 1, 3), serializer)

In [8]: serializer.close()

We’ll access the data using intake locally. See the Binder link above for an example using a HTTP server, where the user may not have direct access to the file system where the data files are stored.

In [9]: from intake_bluesky.jsonl import BlueskyJSONLCatalog

In [10]: import glob

In [11]: catalog = BlueskyJSONLCatalog(glob.glob('data/*.jsonl'))

Read Data as Xarray

In [12]: catalog[uid]
Out[12]: name: 65d84525-ab45-49eb-ab42-c1ef7f06c70a
container: bluesky-run
plugin: ['catalog']
description: 
direct_access: forbid
user_parameters: []
metadata: 
  start: 
    uid: 65d84525-ab45-49eb-ab42-c1ef7f06c70a
    time: 1573521581.3453052
    scan_id: 1
    hints: 
      dimensions: [[['motor'], 'primary']]
    plan_pattern_args: 
      num: 3
      args: ["SynAxis(prefix='', name='motor', read_attrs=['readback', 'setpoint'], configuration_attrs=['velocity', 'acceleration'])", -1, 1]
    plan_pattern: inner_product
    plan_name: scan
    plan_type: generator
    num_intervals: 2
    plan_pattern_module: bluesky.plan_patterns
    detectors: ['det']
    motors: ['motor']
    plan_args: 
      detectors: ["SynGauss(name='det', value=1.0, timestamp=1573521581.3272657)"]
      num: 3
      args: ["SynAxis(prefix='', name='motor', read_attrs=['readback', 'setpoint'], configuration_attrs=['velocity', 'acceleration'])", -1, 1]
      per_step: None
    num_points: 3
  stop: 
    run_start: 65d84525-ab45-49eb-ab42-c1ef7f06c70a
    time: 1573521581.3531487
    uid: d7e6baf1-1b10-47da-8bd6-206e464edc67
    exit_status: success
    reason: 
    num_events: 
      primary: 3
args: 
  gen_func: <function gen at 0x7f9386e7bd90>
  gen_args: ('data/65d84525-ab45-49eb-ab42-c1ef7f06c70a.jsonl',)
  gen_kwargs: 
  filler: <Filler>

In [13]: catalog[uid]()
Out[13]: 
Run Catalog
  uid='65d84525-ab45-49eb-ab42-c1ef7f06c70a'
  exit_status='success'
  2019-11-12 01:19:41.345 -- 2019-11-12 01:19:41.353
  Streams:
    * primary

In [14]: catalog[uid]()['primary']
Out[14]: name: primary
container: xarray
plugin: ['bluesky-event-stream']
description: 
direct_access: forbid
user_parameters: []
metadata: 
  descriptors: [{'run_start': '65d84525-ab45-49eb-ab42-c1ef7f06c70a', 'time': 1573521581.3489022, 'data_keys': {'motor': {'source': 'SIM:motor', 'dtype': 'number', 'shape': [], 'precision': 3, 'object_name': 'motor'}, 'motor_setpoint': {'source': 'SIM:motor_setpoint', 'dtype': 'number', 'shape': [], 'precision': 3, 'object_name': 'motor'}, 'det': {'source': 'SIM:det', 'dtype': 'number', 'shape': [], 'precision': 3, 'object_name': 'det'}}, 'uid': '14c7c113-e869-4139-a45f-113764a5fe7f', 'configuration': {'motor': {'data': {'motor_velocity': 1, 'motor_acceleration': 1}, 'timestamps': {'motor_velocity': 1573521581.324532, 'motor_acceleration': 1573521581.3246017}, 'data_keys': {'motor_velocity': {'source': 'SIM:motor_velocity', 'dtype': 'integer', 'shape': []}, 'motor_acceleration': {'source': 'SIM:motor_acceleration', 'dtype': 'integer', 'shape': []}}}, 'det': {'data': {'det': 0.6065306597126334}, 'timestamps': {'det': 1573521581.3480463}, 'data_keys': {'det': {'source': 'SIM:det', 'dtype': 'number', 'shape': [], 'precision': 3}}}}, 'name': 'primary', 'hints': {'motor': {'fields': ['motor']}, 'det': {'fields': []}}, 'object_keys': {'motor': ['motor', 'motor_setpoint'], 'det': ['det']}}]
args: 
  get_run_start: <function BlueskyRunFromGenerator.__init__.<locals>.get_run_start at 0x7f9380454c80>
  stream_name: primary
  get_run_stop: <function BlueskyRunFromGenerator.__init__.<locals>.get_run_stop at 0x7f93803df8c8>
  get_event_descriptors: <function BlueskyRunFromGenerator.__init__.<locals>.get_event_descriptors at 0x7f93803df950>
  get_event_pages: <function BlueskyRunFromGenerator.__init__.<locals>.get_event_pages at 0x7f93803df9d8>
  get_event_count: <function BlueskyRunFromGenerator.__init__.<locals>.get_event_count at 0x7f93803dfa60>
  get_resource: <function BlueskyRunFromGenerator.__init__.<locals>.get_resource at 0x7f93803dfae8>
  lookup_resource_for_datum: <function BlueskyRunFromGenerator.__init__.<locals>.lookup_resource_for_datum at 0x7f93803dfb70>
  get_datum_pages: <function BlueskyRunFromGenerator.__init__.<locals>.get_datum_pages at 0x7f93803dfbf8>
  filler: <Filler>
  metadata: 
    descriptors: [{'run_start': '65d84525-ab45-49eb-ab42-c1ef7f06c70a', 'time': 1573521581.3489022, 'data_keys': {'motor': {'source': 'SIM:motor', 'dtype': 'number', 'shape': [], 'precision': 3, 'object_name': 'motor'}, 'motor_setpoint': {'source': 'SIM:motor_setpoint', 'dtype': 'number', 'shape': [], 'precision': 3, 'object_name': 'motor'}, 'det': {'source': 'SIM:det', 'dtype': 'number', 'shape': [], 'precision': 3, 'object_name': 'det'}}, 'uid': '14c7c113-e869-4139-a45f-113764a5fe7f', 'configuration': {'motor': {'data': {'motor_velocity': 1, 'motor_acceleration': 1}, 'timestamps': {'motor_velocity': 1573521581.324532, 'motor_acceleration': 1573521581.3246017}, 'data_keys': {'motor_velocity': {'source': 'SIM:motor_velocity', 'dtype': 'integer', 'shape': []}, 'motor_acceleration': {'source': 'SIM:motor_acceleration', 'dtype': 'integer', 'shape': []}}}, 'det': {'data': {'det': 0.6065306597126334}, 'timestamps': {'det': 1573521581.3480463}, 'data_keys': {'det': {'source': 'SIM:det', 'dtype': 'number', 'shape': [], 'precision': 3}}}}, 'name': 'primary', 'hints': {'motor': {'fields': ['motor']}, 'det': {'fields': []}}, 'object_keys': {'motor': ['motor', 'motor_setpoint'], 'det': ['det']}}]

In [15]: catalog[uid]()['primary']()
Out[15]: <Intake catalog: Stream 'primary' from Run 65d84525...>

In [16]: catalog[uid]()['primary']().read()
Out[16]: 
<xarray.Dataset>
Dimensions:                   (time: 3)
Coordinates:
  * time                      (time) float64 1.574e+09 1.574e+09 1.574e+09
Data variables:
    motor                     (time) float64 -1.0 0.0 1.0
    motor_setpoint            (time) float64 -1.0 0.0 1.0
    det                       (time) float64 0.6065 1.0 0.6065
    motor:motor_velocity      (time) int64 1 1 1
    motor:motor_acceleration  (time) int64 1 1 1
    det:det                   (time) float64 0.6065 0.6065 0.6065
    seq_num                   (time) int64 1 2 3
    uid                       (time) <U36 '7b3b7215-6eeb-4906-8bce-16cabe97bbaa' ... '921cba89-7f2f-4aa9-81e1-de3708e8050b'

The calls accept optional arguments. For example, we can filter by field name to avoid reading data that we do not need.

In [17]: catalog[uid]().primary(include=['det']).read()
Out[17]: 
<xarray.Dataset>
Dimensions:  (time: 3)
Coordinates:
  * time     (time) float64 1.574e+09 1.574e+09 1.574e+09
Data variables:
    det      (time) float64 0.6065 1.0 0.6065
    seq_num  (time) int64 1 2 3
    uid      (time) <U36 '7b3b7215-6eeb-4906-8bce-16cabe97bbaa' ... '921cba89-7f2f-4aa9-81e1-de3708e8050b'

If the defaults suffice, intake allows the user to elide the calls, supporting this more succinct expression:

In [18]: catalog[uid].primary.read()
Out[18]: 
<xarray.Dataset>
Dimensions:                   (time: 3)
Coordinates:
  * time                      (time) float64 1.574e+09 1.574e+09 1.574e+09
Data variables:
    motor                     (time) float64 -1.0 0.0 1.0
    motor_setpoint            (time) float64 -1.0 0.0 1.0
    det                       (time) float64 0.6065 1.0 0.6065
    motor:motor_velocity      (time) int64 1 1 1
    motor:motor_acceleration  (time) int64 1 1 1
    det:det                   (time) float64 0.6065 0.6065 0.6065
    seq_num                   (time) int64 1 2 3
    uid                       (time) <U36 '7b3b7215-6eeb-4906-8bce-16cabe97bbaa' ... '921cba89-7f2f-4aa9-81e1-de3708e8050b'

Our simple scan produced one logical table (“event stream”) named ‘primary’. In general experiments can produce multiple tables with different time-bases. They can be merged into one xarray Dataset like so:

In [19]: run = catalog[uid]()

In [20]: run
Out[20]: 
Run Catalog
  uid='65d84525-ab45-49eb-ab42-c1ef7f06c70a'
  exit_status='success'
  2019-11-12 01:19:41.345 -- 2019-11-12 01:19:41.353
  Streams:
    * primary

In [21]: import xarray

In [22]: xarray.merge(run[key].read() for key in run)
Out[22]: 
<xarray.Dataset>
Dimensions:                   (time: 3)
Coordinates:
  * time                      (time) float64 1.574e+09 1.574e+09 1.574e+09
Data variables:
    motor                     (time) float64 -1.0 0.0 1.0
    motor_setpoint            (time) float64 -1.0 0.0 1.0
    det                       (time) float64 0.6065 1.0 0.6065
    motor:motor_velocity      (time) int64 1 1 1
    motor:motor_acceleration  (time) int64 1 1 1
    det:det                   (time) float64 0.6065 0.6065 0.6065
    seq_num                   (time) int64 1 2 3
    uid                       (time) <U36 '7b3b7215-6eeb-4906-8bce-16cabe97bbaa' ... '921cba89-7f2f-4aa9-81e1-de3708e8050b'

Read Data as Bluesky “Documents”

In [23]: catalog[uid].canonical()
Out[23]: <generator object BlueskyRun.canonical at 0x7f9380370258>

This generator yields (name, doc) pairs and can be fed into streaming visualization, processing, and serialization tools that consume this representation, such as those provided by bluesky. This is the same representation that was emitted when the data was first acquired, so the user can apply the same streaming pipelines to data while it is being acquired and after it is saved.