Add a progress bar to a fly scan¶
Problem¶
At the end of a run involving a “flyer” (a fly-scanning device), all the data from the flyer has to be retrieved from the device and processed. This can be take a significant amount of time, giving no indication of whether the process has crashed or is merely working slowly.
Approach¶
For progress bars in general, we recommend a Python pacakge named tqdm (read “taqadum” or تقدّم, which means “progress” in Arabic). It is remarkably simple and flexible, and adds minimal overhead. Follow the link to tqdm for nice demo of tqdm in action.
A “flyer” is implemented as a Python class with a method named collect
that yields all of the data produced by the flyer. By wrapping the output
of collect in tqdm
, we create a progress bar that is updated each time
collect
yields a new data point.
Example Solution¶
Configuration¶
If tqdm is not already installed, install it with pip.
pip install tqdm
Suppose the flyer in question is called flyer
, an instance of the class
Flyer
. Find where flyer
is defined in your IPython profile. Something
like:
flyer = Flyer(some_arguments)
We can subclass Flyer
, customizing its collect
method to incorporate a
progress bar.
class FlyerWithProgressBar(Flyer):
def collect(self):
yield from tqdm(super().collect())
flyer = FlyerWithProgressBar(some_arguments)
If you have some way of knowing in advance how many data points will be
yielded by collect
, you can provide that information to tqdm
to make
it more informative. (It can predict the time remaining, for example.)
Suppose we have a flyer that always produces 100 data points. The class
should be defined like:
class FlyerWithProgressBar(Flyer):
def collect(self):
yield from tqdm(super().collect(), total=100)
Or, add an attribute that can be updated interactively:
class FlyerWithProgressBar(Flyer):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs) # pass arguments to Flyer
self.total = 100
def collect(self):
yield from tqdm(super().collect(), total=self.total)
Here is a demo of FlyerWithProgressBar
.
In [1]: from bluesky.plans import fly
In [2]: flyer = FlyerWithProgressBar()
In [3]: plan = fly([flyer])
In [4]: RE(plan)
100%|█████████████████████████████████████████████████| 100/100 [00:01<00:00, 92.35it/s]
Out[4]: ['3acf0eb7-96bf-4c09-b813-e715dabc7060']