From 072d8b76e7adefd37ec73e836dc2b5adf541eb99 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Tue, 20 Dec 2016 16:07:38 -0500 Subject: [PATCH 1/3] ENH: add radial integration example --- source/_cookbook/README.txt | 8 ++ source/_cookbook/live_integration.py | 149 +++++++++++++++++++++++++++ 2 files changed, 157 insertions(+) create mode 100644 source/_cookbook/live_integration.py diff --git a/source/_cookbook/README.txt b/source/_cookbook/README.txt index 340a86f..a38f697 100644 --- a/source/_cookbook/README.txt +++ b/source/_cookbook/README.txt @@ -6,3 +6,11 @@ Cookbook (Examples) Each recipe is a complete, runnable example. See the individual project documentation, linked in the menu at left, for detailed prose documentation and API specification. + +.. warning:: + + Because these are complete runnable examples they will create new + :class:`~bluesky.run_engine.RunEngine`, + :class:`~databroker.Broker`, and temporary databases which will be + populated with synthetic data. Running these examples as-is on a + production machine at a beamline is greatly discouraged. diff --git a/source/_cookbook/live_integration.py b/source/_cookbook/live_integration.py new file mode 100644 index 0000000..eb1f564 --- /dev/null +++ b/source/_cookbook/live_integration.py @@ -0,0 +1,149 @@ +# -*- coding: utf-8 -*- +""" +Automatically show integrate S(q) during data collection +******************************************************** + +Problem +======= + +As 2D diffraction images are collected, extract and plot the intgrated +:math:`S(q)`. + +Approach +======== + +Write a callback which on each event: + + - uses filestore to retrieve the full image + - uses :class:`~skbeam.core.accumulators.binned_statistic.RadialBinnedStatistic` to + compute + +Example Solution +================ + +The :func:`bluesky.plans.adaptive_scan` aims to maintain a certain delta in y +between successive steps through x. After each step, it accounts for the local +derivative and adjusts it step size accordingly. If it misses by a large +margin, it takes a step backward (if allowed). + +""" + + +import matplotlib.pyplot as plt +from bluesky import RunEngine +from bluesky.examples import Mover, ReaderWithFileStore, ReaderWithFSHandler +import bluesky.plans as bp +from bluesky.callbacks import CallbackBase +import portable_fs.sqlite.fs as psf +import os +import numpy as np +import skbeam.core.accumulators.binned_statistic as scabs +import portable_mds.sqlite.mds as psm +import databroker + +############################################################################### +# Setup synthetic Broker, motor, and detector +# ------------------------------------------- +# +# The image is +# +# .. math:: +# +# T*\left|\sin\left(R/5)\right)\right|*\exp\left({\frac{-R^2}{10}}\right) +# +# where :math:`T` is the temperature and :math:`R` is distance from the origin + +mds = psm.MDS({'directory': '/tmp/pmds'}) +fs = psf.FileStore({'dbpath': '/tmp/fs1'}) +fs.register_handler('RWFS_NPY', ReaderWithFSHandler, overwrite=True) +db = databroker.Broker(mds, fs) +os.makedirs('/tmp/fake_data', exist_ok=True) + +temp = Mover('T', {'T': lambda x: x}, {'x': 0}) + +X, Y = np.ogrid[-53:54, -50:51] +R = np.hypot(X, Y) / 5 +base = np.exp(- R*R / 70) * np.abs(np.sin(R)) + + +def synthetic_data(): + return temp.read()['T']['value'] * base + + +det = ReaderWithFileStore('det', {'image': synthetic_data}, + fs=fs, save_path='/tmp/fake_data') + + +# Do this if running the example interactively; +# skip it when building the documentation. +if 'BUILDING_DOCS' not in os.environ: + from bluesky.utils import install_qt_kicker # for notebooks, qt -> nb + det.exposure_time = 1 + temp._fake_sleep = 1 + install_qt_kicker() + plt.ion() + + +############################################################################### +# The callback object +# ------------------- +# + +class LiveIntegrate(CallbackBase): + SMALL = 1e-6 + + def __init__(self, name, ax=None, bins=100): + if ax is None: + ax = plt.gca() + ax.set_xlabel('$q$') + ax.set_ylabel('$s(q)$') + self.ax = ax + self._name = name + self._bins = bins + self.binner = None + self.wl = 1 + self.center = None + + def start(self, doc): + # pull wave length data from the start document + self.wl = doc.get('wavelength', self.wl) + # extract the center from the start document + self.center = doc.get('center', None) + # extract the uid and sample from the start document + self.ax.set_title('[{uid:.6}]: {sample}'.format( + **doc)) + + def descriptor(self, doc): + # pull the image size data from the descriptor + dk = doc['data_keys'][self._name] + # set up the binning + self.binner = scabs.RadialBinnedStatistic(dk['shape'], bins=100, + origin=self.center) + + def event(self, doc): + # go to filestore to get the raw image back + image = db.fs.retrieve(doc['data'][self._name]) + # bin the image + ret = self.binner(image) + # scale the pixel position by wavelength + centers = self.binner.bin_centers / self.wl + # plot the integrated data, label with temperature + self.ax.plot(centers, ret, + label='{} K'.format(doc['data']['T'])) + # update the legend + self.ax.legend() + # ask the graph to redraw the next time it is convenient + self.ax.figure.canvas.draw_idle() + + +############################################################################### +# Set up the :class:`~bluesky.run_engine.RunEngine` and some configuration data +# ----------------------------------------------------------------------------- + +RE = RunEngine({}) +RE.md['wavelength'] = 15 +RE.md['center'] = [107/2, 101/2] +RE.subscribe('all', mds.insert) + +RE(bp.scan([det], temp, 200, 270, 5), LiveIntegrate('image', None), + sample='FooBar') From 7b2e9fd2cf146e6468d40910000098a6efce6fad Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Tue, 20 Dec 2016 20:57:54 -0500 Subject: [PATCH 2/3] MNT: remove napoleon + add more intersphinx --- source/conf.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/source/conf.py b/source/conf.py index 338e8ac..511b82a 100644 --- a/source/conf.py +++ b/source/conf.py @@ -47,7 +47,6 @@ 'sphinx.ext.viewcode', 'sphinx.ext.autosummary', 'sphinx.ext.extlinks', - 'sphinxcontrib.napoleon', 'sphinxext.jsonschema_diff', 'numpydoc', 'sphinxext.xfig', @@ -305,10 +304,12 @@ # Example configuration for intersphinx: refer to the Python standard library. intersphinx_mapping = {'python': ('https://docs.python.org/3.5', None), - 'bluesky': ('http://nsls-ii.github.io/bluesky', None), - 'databroker': ('http://nsls-ii.github.io/databroker', + 'bluesky': ('https://nsls-ii.github.io/bluesky', None), + 'databroker': ('https://nsls-ii.github.io/databroker', None), - 'ophyd': ('http://nsls-ii.github.io/ophyd', None)} + 'ophyd': ('https://nsls-ii.github.io/ophyd', None), + 'skbeam': ('https://scikit-beam.github.io/scikit-beam/', + None)} # Enable showing todos From 52a73e17e16dd9bc24156ee90a918bc480928fa1 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Tue, 20 Dec 2016 20:58:09 -0500 Subject: [PATCH 3/3] MNT: tweak rst --- source/_cookbook/count_with_table.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/source/_cookbook/count_with_table.py b/source/_cookbook/count_with_table.py index 48d3d63..b6f7855 100644 --- a/source/_cookbook/count_with_table.py +++ b/source/_cookbook/count_with_table.py @@ -1,21 +1,22 @@ """ -Simply 'count' a detector -************************* +=========================== + Simply 'count' a detector +=========================== Problem -------- +======= Take five sequential readings of a detector. Approach --------- +======== Execute :func:`bluesky.plans.count` with a simulated detector (which could be substituted by a real detector from ophyd) and display the reading using :func:`bluesky.callbacks.LiveTable`. Example Solution ----------------- +================ """ import bluesky.plans as bp import bluesky.callbacks as bc