diff --git a/src/calng/DetectorAssembler.py b/src/calng/DetectorAssembler.py index 56178d94382d27569c7cfa73615e6a6e84c94891..dbfd22228cf1d61e4944033fd11a1e1becab78d6 100644 --- a/src/calng/DetectorAssembler.py +++ b/src/calng/DetectorAssembler.py @@ -5,6 +5,7 @@ import re import numpy as np from karabo.bound import ( DOUBLE_ELEMENT, + FLOAT_ELEMENT, IMAGEDATA_ELEMENT, NDARRAY_ELEMENT, NODE_ELEMENT, @@ -131,6 +132,20 @@ class DetectorAssembler(TrainMatcher.TrainMatcher): .reconfigurable() .commit(), + FLOAT_ELEMENT(expected) + .key("preview.replaceNanWith") + .description( + "Displaying images in KaraboGUI seems to not go well when there are " + "NaN values in data. And there will be with bad pixel masking or just " + "geometry space between modules. NaN values get replaced with this " + "value to get around this; choose a value which clearly stands out " + "from the image data you want to see." + ) + .assignmentOptional() + .defaultValue(-1000) + .reconfigurable() + .commit(), + DOUBLE_ELEMENT(expected) .key("preview.maxRate") .displayedName("Max rate") @@ -241,7 +256,9 @@ class DetectorAssembler(TrainMatcher.TrainMatcher): return self._geometry = geom_utils.deserialize_geometry(serialized_geometry) # TODO: allow multiple memory cells (extra geom notion of extra dimensions) - self._stack_input_buffer = np.zeros(self._geometry.expected_data_shape) + self._stack_input_buffer = np.zeros( + self._geometry.expected_data_shape, dtype=np.float32 + ) def on_matched_data(self, train_id, sources): if self._geometry is None: @@ -265,9 +282,9 @@ class DetectorAssembler(TrainMatcher.TrainMatcher): # prepare for assembly # TODO: handle failure to "parse" source, get data out module_index = self._source_to_index(source) - self._stack_input_buffer[module_index] = np.squeeze( - data.get(self._path_to_stack) - ) + self._stack_input_buffer[module_index] = data.get( + self._path_to_stack + ).astype(np.float32, copy=False) # TODO: set dtype based on input? module_indices_unfilled.discard(module_index) earliest_source_timestamp = min( earliest_source_timestamp, source_timestamp.toTimestamp() @@ -308,11 +325,12 @@ class DetectorAssembler(TrainMatcher.TrainMatcher): np, self.unsafe_get("preview.downsamplingFunction") ), ) + assembled[np.isnan(assembled)] = self.unsafe_get("preview.replaceNanWith") output_hash = Hash( "image.data", ImageData( # TODO: get around this being mirrored... - assembled.astype(np.int32)[::-1, ::-1], + assembled[::-1, ::-1], Dims(*assembled.shape), Encoding.GRAY, bitsPerPixel=32, diff --git a/src/calng/scenes.py b/src/calng/scenes.py index ed9dd89e045cfbbce24f509a64ea2803edb4b82a..68bfa38a00627abc6bbc4bb44ed5344f61b44830 100644 --- a/src/calng/scenes.py +++ b/src/calng/scenes.py @@ -17,6 +17,7 @@ from karabo.common.scenemodel.api import ( IntLineEditModel, LabelModel, LineEditModel, + LineModel, RectangleModel, SceneModel, SceneTargetWindow, @@ -138,6 +139,23 @@ class Space: return [] +class Hline: + def __init__(self, width): + self.width = width + self.height = 0 + + def render(self, x, y): + return [ + LineModel( + stroke="#000000", + x1=x, + x2=x+self.width, + y1=y, + y2=y, + ) + ] + + def dummy_wrap(model_class): class Wrapper: def __init__(self, *args, **kwargs): @@ -557,6 +575,16 @@ class AssemblerDeviceStatus(VerticalLayout): width=7 * BASE_INC, height=BASE_INC, ) + rate = DisplayRoundedFloat( + keys=[f"{device_id}.outProcessing"], + width=7 * BASE_INC, + height=BASE_INC, + ) + tof = DisplayRoundedFloat( + keys=[f"{device_id}.timeOfFlight"], + width=7 * BASE_INC, + height=BASE_INC, + ) self.children.extend( [ name, @@ -565,37 +593,9 @@ class AssemblerDeviceStatus(VerticalLayout): train_id, padding=0, ), - LabelModel( - text="Image downsampling", - width=14 * BASE_INC, - height=BASE_INC, - ), - HorizontalLayout( - LabelModel( - text="Factor", - width=7 * BASE_INC, - height=BASE_INC, - ), - ComboBoxModel( - keys=[f"{device_id}.preview.downsamplingFactor"], - width=7 * BASE_INC, - height=BASE_INC, - klass="EditableComboBox", - ), - padding=0, - ), HorizontalLayout( - LabelModel( - text="Function", - width=7 * BASE_INC, - height=BASE_INC, - ), - ComboBoxModel( - keys=[f"{device_id}.preview.downsamplingFunction"], - width=7 * BASE_INC, - height=BASE_INC, - klass="EditableComboBox", - ), + rate, + tof, padding=0, ), DeviceSceneLinkModel( @@ -606,6 +606,16 @@ class AssemblerDeviceStatus(VerticalLayout): width=14 * BASE_INC, height=BASE_INC, ), + LabelModel( + text="My geometry device:", + width=14 * BASE_INC, + height=BASE_INC, + ), + DisplayLabelModel( + keys=[f"{device_id}.geometryDevice"], + width=14 * BASE_INC, + height=BASE_INC, + ), # TODO: some day, get dynamic link to this friend ] ) @@ -1131,12 +1141,67 @@ def detector_assembler_overview(device_id): return VerticalLayout( HorizontalLayout( AssemblerDeviceStatus(device_id), - titled("My geometry device")(boxed(VerticalLayout))( - DisplayLabelModel( - keys=[f"{device_id}.geometryDevice"], - width=6 * BASE_INC, + titled("Preview settings")(boxed(VerticalLayout))( + HorizontalLayout( + LabelModel( + text="Display NaN values as:", + width=7 * BASE_INC, + height=BASE_INC, + ), + DoubleLineEditModel( + keys=[f"{device_id}.preview.replaceNanWith"], + width=7 * BASE_INC, + height=BASE_INC, + ), + padding=0, + ), + HorizontalLayout( + LabelModel( + text="Max preview rate", + width=7 * BASE_INC, + height=BASE_INC, + ), + DoubleLineEditModel( + keys=[f"{device_id}.preview.maxRate"], + width=7 * BASE_INC, + height=BASE_INC, + ), + padding=0, + ), + Hline(width=14 * BASE_INC), + LabelModel( + text="Image downsampling", + width=14 * BASE_INC, height=BASE_INC, - ) + ), + HorizontalLayout( + LabelModel( + text="Factor", + width=7 * BASE_INC, + height=BASE_INC, + ), + ComboBoxModel( + keys=[f"{device_id}.preview.downsamplingFactor"], + width=7 * BASE_INC, + height=BASE_INC, + klass="EditableComboBox", + ), + padding=0, + ), + HorizontalLayout( + LabelModel( + text="Function", + width=7 * BASE_INC, + height=BASE_INC, + ), + ComboBoxModel( + keys=[f"{device_id}.preview.downsamplingFunction"], + width=7 * BASE_INC, + height=BASE_INC, + klass="EditableComboBox", + ), + padding=0, + ), ), ), titled("Preview image")(boxed(dummy_wrap(DetectorGraphModel)))(