Commit e91b65b2 authored by Matias Guijarro's avatar Matias Guijarro
Browse files

Merge branch 'fix-2770' into 'master'

Flint: Make sure new scanned ROIs are displayed

Closes #2770

See merge request !3725
parents 04939dc4 28416b43
Pipeline #47130 failed with stages
in 38 minutes and 42 seconds
......@@ -702,30 +702,60 @@ def copyItemsFromChannelNames(
copyItemConfig(sourceItem, item)
def copyItemsFromRoiNames(
sourcePlot: plot_model.Plot, destinationPlot: plot_model.Plot
):
"""Copy from the source plot the item which was setup into the destination plot.
ROIs already contained in the destination plot will be setup the same way it is
done for the source plot.
"""
availableItems = {}
for item in sourcePlot.items():
if isinstance(item, plot_item_model.RoiItem):
name = item.roiName()
if name is None:
continue
availableItems[name] = item
with destinationPlot.transaction():
for item in destinationPlot.items():
if isinstance(item, plot_item_model.RoiItem):
name = item.roiName()
if name is None:
continue
sourceItem = availableItems.pop(name, None)
if sourceItem is not None:
copyItemConfig(sourceItem, item)
def copyItemConfig(sourceItem: plot_model.Item, destinationItem: plot_model.Item):
"""Copy the configuration and the item tree from a source item to a
destination item"""
if not isinstance(sourceItem, plot_item_model.CurveItem):
raise TypeError("Only available for curve item. Found %s" % type(sourceItem))
if not isinstance(destinationItem, type(sourceItem)):
raise TypeError(
"Both items must have the same type. Found %s" % type(destinationItem)
)
destinationItem.setYAxis(sourceItem.yAxis())
sourceToDest = {}
sourceToDest[sourceItem] = destinationItem
destinationPlot = destinationItem.plot()
for item in sourceItem.plot().items():
if item.isChildOf(sourceItem):
newItem = item.copy(destinationPlot)
newItem.setParent(destinationPlot)
destinationSource = sourceToDest[item.source()]
newItem.setSource(destinationSource)
destinationPlot.addItem(newItem)
sourceToDest[item] = newItem
if isinstance(sourceItem, plot_item_model.CurveItem):
destinationItem.setVisible(sourceItem.isVisible())
destinationItem.setYAxis(sourceItem.yAxis())
sourceToDest = {}
sourceToDest[sourceItem] = destinationItem
destinationPlot = destinationItem.plot()
for item in sourceItem.plot().items():
if item.isChildOf(sourceItem):
newItem = item.copy(destinationPlot)
newItem.setParent(destinationPlot)
destinationSource = sourceToDest[item.source()]
newItem.setSource(destinationSource)
destinationPlot.addItem(newItem)
sourceToDest[item] = newItem
elif isinstance(sourceItem, plot_item_model.RoiItem):
destinationItem.setVisible(sourceItem.isVisible())
else:
raise TypeError("Only available for curve item. Found %s" % type(sourceItem))
def updateXAxis(
......
......@@ -535,6 +535,7 @@ class ManageMainBehaviours(qt.QObject):
self.__updateFocus(defaultWidget, usedWidgets)
def updateWidgetWithPlot(self, widget, scan, plotModel, useDefaultPlot):
# FIXME: useDefaultPlot is probably not much useful
def reusePreviousPlotItems(previousWidgetPlot, plotModel, scan):
with previousWidgetPlot.transaction():
# Clean up temporary items
......@@ -552,10 +553,10 @@ class ManageMainBehaviours(qt.QObject):
previousWidgetPlot, plotModel, scan
)
# FIXME: This if-else branches should be the same, but for now
# make it safe for BLISS 1.8
# FIXME: This looks to became business model
# This have to be refactored in order to answer to each cases the way
# people expect to retrieve the selection
if isinstance(plotModel, plot_item_model.CurvePlot):
# For BLISS 1.8
previousPlotModel = widget.plotModel()
if previousPlotModel is None:
......@@ -584,6 +585,13 @@ class ManageMainBehaviours(qt.QObject):
if plotModel.styleStrategy() is None:
plotModel.setStyleStrategy(DefaultStyleStrategy(self.__flintModel))
widget.setPlotModel(plotModel)
elif isinstance(plotModel, plot_item_model.ImagePlot):
previousPlotModel = widget.plotModel()
if previousPlotModel is not None:
model_helper.copyItemsFromRoiNames(previousPlotModel, plotModel)
if plotModel.styleStrategy() is None:
plotModel.setStyleStrategy(DefaultStyleStrategy(self.__flintModel))
widget.setPlotModel(plotModel)
else:
previousWidgetPlot = widget.plotModel()
if previousWidgetPlot is not None:
......
"""Testing manager module."""
import copy
from bliss.flint.manager.manager import ManageMainBehaviours
from bliss.flint.model import flint_model
from bliss.flint.model import plot_item_model
from bliss.flint.widgets.curve_plot import CurvePlotWidget
from bliss.flint.helper import scan_info_helper
from bliss.flint.helper import model_helper
SCAN_INFO_LIMA_ROIS = {
"acquisition_chain": {
"timer": {"devices": ["timer", "beamviewer", "beamviewer:roi_counters"]}
},
"devices": {
"timer": {
"channels": ["timer:elapsed_time", "timer:epoch"],
"triggered_devices": ["beamviewer"],
},
"beamviewer": {
"type": "lima",
"triggered_devices": ["beamviewer:roi_counters"],
"channels": ["beamviewer:image"],
},
"beamviewer:roi_counters": {
"channels": [
"beamviewer:roi_counters:roi1_sum",
"beamviewer:roi_counters:roi2_sum",
],
"roi1": {"kind": "rect", "x": 190, "y": 110, "width": 600, "height": 230},
"roi2": {
"kind": "arc",
"cx": 487.0,
"cy": 513.0,
"r1": 137.0,
"r2": 198.0,
"a1": -172.0,
"a2": -300.0,
},
},
},
"channels": {
"timer:elapsed_time": {"dim": 0},
"timer:epoch": {"dim": 0},
"beamviewer:roi_counters:roi1_sum": {"dim": 0},
"beamviewer:roi_counters:roi2_sum": {"dim": 0},
"beamviewer:image": {"dim": 2},
},
}
def _create_loopscan_scan_info(extra_name=None):
result = {
"type": "ascan",
"acquisition_chain": {"main": {"devices": ["master", "slave"]}},
"devices": {
"master": {
"channels": ["timer:elapsed_time", "timer:epoch"],
"triggered_devices": ["slave"],
},
"slave": {
"channels": [
"timer:elapsed_time",
"timer:epoch",
"simulation_diode_sampling_controller:diode1",
"simulation_diode_sampling_controller:diode2",
]
},
},
"channels": {
"timer:elapsed_time": {"dim": 0},
"timer:epoch": {"dim": 0},
"simulation_diode_sampling_controller:diode1": {"dim": 0},
"simulation_diode_sampling_controller:diode2": {"dim": 0},
},
}
if extra_name is not None:
result["devices"]["slave"]["channels"].append(extra_name)
result["channels"][extra_name] = {"dim": 0}
return result
def _create_ascan_scan_info(master_name, extra_name=None):
......@@ -35,6 +110,16 @@ def _create_ascan_scan_info(master_name, extra_name=None):
return result
def _create_lima_scan_info(include_roi2):
"""
Simulate a scan containing a lima detector with ROIs.
"""
result = copy.deepcopy(SCAN_INFO_LIMA_ROIS)
if not include_roi2:
del result["devices"]["beamviewer:roi_counters"]["roi2"]
return result
def test_consecutive_scans__loopscan_ascan(local_flint):
"""
Test plot state with consecutive scans
......@@ -51,22 +136,7 @@ def test_consecutive_scans__loopscan_ascan(local_flint):
manager = ManageMainBehaviours()
manager.setFlintModel(flint)
loopscan_info = {
"type": "loopscan",
"acquisition_chain": {"main": {"devices": ["master", "slave"]}},
"devices": {
"master": {
"channels": ["timer:elapsed_time", "timer:epoch"],
"triggered_devices": ["slave"],
},
"slave": {"channels": ["simulation_diode_sampling_controller:diode1"]},
},
"channels": {
"timer:elapsed_time": {"dim": 0},
"timer:epoch": {"dim": 0},
"simulation_diode_sampling_controller:diode1": {"dim": 0},
},
}
loopscan_info = _create_loopscan_scan_info()
scan = scan_info_helper.create_scan_model(loopscan_info)
plots = scan_info_helper.create_plot_model(loopscan_info, scan)
manager.updateScanAndPlots(scan, plots)
......@@ -81,6 +151,50 @@ def test_consecutive_scans__loopscan_ascan(local_flint):
assert item.xChannel().name() == "axis:sx"
def test_consecutive_scans__user_selection(local_flint):
"""
Test plot state with consecutive scans and a user selection in between
We expect the user selection to be restored
"""
flint = flint_model.FlintState()
workspace = flint_model.Workspace()
flint.setWorkspace(workspace)
widget = CurvePlotWidget()
workspace.addWidget(widget)
manager = ManageMainBehaviours()
manager.setFlintModel(flint)
loopscan_info = _create_loopscan_scan_info()
scan = scan_info_helper.create_scan_model(loopscan_info)
plots = scan_info_helper.create_plot_model(loopscan_info, scan)
plot = [p for p in plots if isinstance(p, plot_item_model.CurvePlot)][0]
manager.updateWidgetWithPlot(widget, scan, plot, useDefaultPlot=True)
model = widget.plotModel()
assert len(model.items()) == 1
# user selection
model_helper.updateDisplayedChannelNames(
plot,
scan,
[
"simulation_diode_sampling_controller:diode1",
"simulation_diode_sampling_controller:diode2",
],
)
plot.tagUserEditTime()
ascan_info = _create_ascan_scan_info("axis:sx")
scan = scan_info_helper.create_scan_model(ascan_info)
plots = scan_info_helper.create_plot_model(ascan_info, scan)
plot = [p for p in plots if isinstance(p, plot_item_model.CurvePlot)][0]
manager.updateWidgetWithPlot(widget, scan, plot, useDefaultPlot=True)
model = widget.plotModel()
assert len(model.items()) == 2
def test_consecutive_scans__ascan_ascan(local_flint):
"""
Test plot state with consecutive scans
......@@ -114,3 +228,47 @@ def test_consecutive_scans__ascan_ascan(local_flint):
model = widget.plotModel()
item = model.items()[0]
assert item.xChannel().name() == "axis:sy"
def test_plot_with_new_roi(local_flint):
"""Test the resulted image plot when a new ROI is part of the scan.
We expect:
- The previous ROI to still use the same config
- The new ROI to be displayed.
"""
flint = flint_model.FlintState()
workspace = flint_model.Workspace()
flint.setWorkspace(workspace)
widget = CurvePlotWidget()
workspace.addWidget(widget)
manager = ManageMainBehaviours()
manager.setFlintModel(flint)
scan_info1 = _create_lima_scan_info(include_roi2=False)
scan = scan_info_helper.create_scan_model(scan_info1)
plots = scan_info_helper.create_plot_model(scan_info1, scan)
plot = [p for p in plots if isinstance(p, plot_item_model.ImagePlot)][0]
manager.updateWidgetWithPlot(widget, scan, plot, useDefaultPlot=True)
plotModel = widget.plotModel()
assert len(plotModel.items()) == 2 # image + ROI
roiItem = [i for i in plotModel.items() if isinstance(i, plot_item_model.RoiItem)][
0
]
roiItem.setVisible(False)
scan_info2 = _create_lima_scan_info(include_roi2=True)
scan = scan_info_helper.create_scan_model(scan_info2)
plots = scan_info_helper.create_plot_model(scan_info2, scan)
plot = [p for p in plots if isinstance(p, plot_item_model.ImagePlot)][0]
manager.updateWidgetWithPlot(widget, scan, plot, useDefaultPlot=True)
plotModel = widget.plotModel()
assert len(plotModel.items()) == 3 # image + ROI * 2
roiItems = [i for i in plotModel.items() if isinstance(i, plot_item_model.RoiItem)]
rois = {r.name(): r.isVisible() for r in roiItems}
assert rois == {"roi1": False, "roi2": True}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment