Custom plot class¶
Flint allows to define an own custom Qt chart.
The following example will show how to embed your own
plot inside Flint. But any other library using PyQt (like silx) could be used.
As this code will probably be designed at a beamline, be careful to only use it if nothing else really match. It’s probably better to improve the other existing charts, or to ask to merge that new code inside Flint at some point.
Create your Qt widget¶
This module have to be reachable by Flint but must not be imported by BLISS or any of your scripts.
I have created this file inside
bliss.git/bliss/my_plot_in_bliss.py, but you
should create it inside your beamline lib imported by BLISS.
import logging import time from silx.gui import qt from silx.gui.plot.matplotlib import FigureCanvasQTAgg from matplotlib.figure import Figure _logger = logging.getLogger(__name__) class MyPlotInFlint(qt.QWidget): """ This class describe the plot inside Flint. It's the only one which have to handle Qt and matplotlib. It must not be imported by BLISS or any of your scripts. """ def __init__(self, parent=None): super(MyPlotInFlint, self).__init__(parent=parent) fig = Figure() self._ax = fig.add_subplot(111) self.__plot = FigureCanvasQTAgg(fig) self.__plot.setParent(self) layout = qt.QVBoxLayout(self) layout.addWidget(self.__plot) # Your own attributes self._x = None self._y = None self._lastUpdate = None # # Your own API # def clear(self): self._lastUpdate = None self._ax.clear() def setData(self, x, y): self._lastUpdate = time.time() # Try-except to make sure no exception will be returned in BLISS # But instead logged inside Flint try: self._updatePlot(x, y) except Exception: _logger.critical("Error while updating the plot", exc_info=True) def getLastUpdate(self): return self._lastUpdate def _updatePlot(self, x, y): self._ax.plot(x, y) self._ax.grid(True) self._ax.set_xlabel("X") self._ax.set_ylabel("Y") self.__plot.draw()
Create custom BLISS proxy¶
This module has to be reachable by BLISS and it is better not to import it in Flint.
For this example, the file is created in
But it should be in beamline library imported by BLISS.
WIDGET attribute has to be updated according to the location of Qt module.
from bliss.flint.client.plots import BasePlot class MyPlotInBliss(BasePlot): """This class provides the API which is exposed by BLISS. It is basically a proxy to the real plot in Flint. """ WIDGET = "bliss.my_plot_in_flint.MyPlotInFlint" """Qualified name of the plot living in Flint""" def clear_data(self): """You can define methods """ # The submit is rused to call the real method of the plot in FLint self.submit("clear") def set_data(self, x, y): """ Methods can pass arguments. Everything will be pickled (standard Python serialization library), including numpy arrays. """ # Usually we use snake case in BLISS side, and camel case in Flint/Qt side # But it's up to you. self.submit("setData", x, y) def get_last_update(self): """ Methods can also return values. Which will also be pickled (standard Python serialization library). """ return self.submit("getLastUpdate")
Use the plot¶
This plot can be used after restart of BLISS and FLint.
# Create the plot f = flint() from bliss.my_plot_in_bliss import MyPlotInBliss p = f.get_plot(MyPlotInBliss, name="My plot", unique_name="MyPlot0001", selected=True) # Use the plot API p.clear_data() p.set_data([0,1,2,3,4,5],[0,1,0,1,0,1]) print(p.get_last_update())