Beispiel #1
0
    def __init__(self,
                 document_controller,
                 panel_id,
                 properties,
                 debounce=True,
                 sample=True):
        super().__init__(document_controller, panel_id, _("Histogram"))

        def calculate_region_data(display_data_and_metadata, region):
            if region is not None and display_data_and_metadata is not None:
                if display_data_and_metadata.is_data_1d and isinstance(
                        region, Graphics.IntervalGraphic):
                    interval = region.interval
                    if 0 <= interval[0] < 1 and 0 < interval[1] <= 1:
                        start, end = int(
                            interval[0] *
                            display_data_and_metadata.data_shape[0]), int(
                                interval[1] *
                                display_data_and_metadata.data_shape[0])
                        if end - start >= 1:
                            cropped_data_and_metadata = Core.function_crop_interval(
                                display_data_and_metadata, interval)
                            if cropped_data_and_metadata:
                                return cropped_data_and_metadata
                elif display_data_and_metadata.is_data_2d and isinstance(
                        region, Graphics.RectangleTypeGraphic):
                    cropped_data_and_metadata = Core.function_crop(
                        display_data_and_metadata, region.bounds)
                    if cropped_data_and_metadata:
                        return cropped_data_and_metadata
            return display_data_and_metadata

        def calculate_region_data_func(display_data_and_metadata, region):
            return functools.partial(calculate_region_data,
                                     display_data_and_metadata, region)

        def calculate_histogram_widget_data(display_data_and_metadata_func,
                                            display_range):
            bins = 320
            subsample = 0  # hard coded subsample size
            subsample_fraction = None  # fraction of total pixels
            subsample_min = 1024  # minimum subsample size
            display_data_and_metadata = display_data_and_metadata_func()
            display_data = display_data_and_metadata.data if display_data_and_metadata else None
            if display_data is not None:
                total_pixels = numpy.product(display_data.shape,
                                             dtype=numpy.uint64)
                if not subsample and subsample_fraction:
                    subsample = min(
                        max(total_pixels * subsample_fraction, subsample_min),
                        total_pixels)
                if subsample:
                    factor = total_pixels / subsample
                    data_sample = numpy.random.choice(
                        display_data.reshape(
                            numpy.product(display_data.shape,
                                          dtype=numpy.uint64)), subsample)
                else:
                    factor = 1.0
                    data_sample = numpy.copy(display_data)
                if display_range is None or data_sample is None:
                    return HistogramWidgetData()
                histogram_data = factor * numpy.histogram(
                    data_sample, range=display_range, bins=bins)[0]
                histogram_max = numpy.max(
                    histogram_data)  # assumes that histogram_data is int
                if histogram_max > 0:
                    histogram_data = histogram_data / float(histogram_max)
                return HistogramWidgetData(histogram_data, display_range)
            return HistogramWidgetData()

        def calculate_histogram_widget_data_func(
                display_data_and_metadata_model_func, display_range):
            return functools.partial(calculate_histogram_widget_data,
                                     display_data_and_metadata_model_func,
                                     display_range)

        display_item_stream = TargetDisplayItemStream(document_controller)
        display_data_channel_stream = StreamPropertyStream(
            display_item_stream, "display_data_channel")
        region_stream = TargetRegionStream(display_item_stream)

        def compare_data(a, b):
            return numpy.array_equal(a.data if a else None,
                                     b.data if b else None)

        display_data_and_metadata_stream = DisplayDataChannelTransientsStream(
            display_data_channel_stream,
            "display_data_and_metadata",
            cmp=compare_data)
        display_range_stream = DisplayDataChannelTransientsStream(
            display_data_channel_stream, "display_range")
        region_data_and_metadata_func_stream = Stream.CombineLatestStream(
            (display_data_and_metadata_stream, region_stream),
            calculate_region_data_func)
        histogram_widget_data_func_stream = Stream.CombineLatestStream(
            (region_data_and_metadata_func_stream, display_range_stream),
            calculate_histogram_widget_data_func)
        color_map_data_stream = StreamPropertyStream(
            display_data_channel_stream,
            "color_map_data",
            cmp=numpy.array_equal)
        if debounce:
            histogram_widget_data_func_stream = Stream.DebounceStream(
                histogram_widget_data_func_stream, 0.05,
                document_controller.event_loop)
        if sample:
            histogram_widget_data_func_stream = Stream.SampleStream(
                histogram_widget_data_func_stream, 0.5,
                document_controller.event_loop)

        def cursor_changed_fn(canvas_x: float, display_range) -> None:
            if not canvas_x:
                document_controller.cursor_changed(None)
            if display_item_stream and display_item_stream.value and canvas_x:
                if display_range is not None:  # can be None with empty data
                    displayed_intensity_calibration = display_item_stream.value.displayed_intensity_calibration
                    adjusted_x = display_range[0] + canvas_x * (
                        display_range[1] - display_range[0])
                    adjusted_x = displayed_intensity_calibration.convert_to_calibrated_value_str(
                        adjusted_x)
                    document_controller.cursor_changed(
                        [_('Intensity: ') + str(adjusted_x)])
                else:
                    document_controller.cursor_changed(None)

        self.__histogram_widget_data_model = Model.FuncStreamValueModel(
            histogram_widget_data_func_stream,
            document_controller.event_loop,
            value=HistogramWidgetData(),
            cmp=numpy.array_equal)
        self.__color_map_data_model = Model.StreamValueModel(
            color_map_data_stream, cmp=numpy.array_equal)

        self._histogram_widget = HistogramWidget(
            document_controller, display_item_stream,
            self.__histogram_widget_data_model, self.__color_map_data_model,
            cursor_changed_fn)

        def calculate_statistics(display_data_and_metadata_func,
                                 display_data_range, region,
                                 displayed_intensity_calibration):
            display_data_and_metadata = display_data_and_metadata_func()
            data = display_data_and_metadata.data if display_data_and_metadata else None
            data_range = display_data_range
            if data is not None and data.size > 0 and displayed_intensity_calibration:
                mean = numpy.mean(data)
                std = numpy.std(data)
                rms = numpy.sqrt(numpy.mean(numpy.square(
                    numpy.absolute(data))))
                sum_data = mean * functools.reduce(
                    operator.mul,
                    Image.dimensional_shape_from_shape_and_dtype(
                        data.shape, data.dtype))
                if region is None:
                    data_min, data_max = data_range if data_range is not None else (
                        None, None)
                else:
                    data_min, data_max = numpy.amin(data), numpy.amax(data)
                mean_str = displayed_intensity_calibration.convert_to_calibrated_value_str(
                    mean)
                std_str = displayed_intensity_calibration.convert_to_calibrated_value_str(
                    std)
                data_min_str = displayed_intensity_calibration.convert_to_calibrated_value_str(
                    data_min)
                data_max_str = displayed_intensity_calibration.convert_to_calibrated_value_str(
                    data_max)
                rms_str = displayed_intensity_calibration.convert_to_calibrated_value_str(
                    rms)
                sum_data_str = displayed_intensity_calibration.convert_to_calibrated_value_str(
                    sum_data)

                return {
                    "mean": mean_str,
                    "std": std_str,
                    "min": data_min_str,
                    "max": data_max_str,
                    "rms": rms_str,
                    "sum": sum_data_str
                }
            return dict()

        def calculate_statistics_func(display_data_and_metadata_model_func,
                                      display_data_range, region,
                                      displayed_intensity_calibration):
            return functools.partial(calculate_statistics,
                                     display_data_and_metadata_model_func,
                                     display_data_range, region,
                                     displayed_intensity_calibration)

        display_data_range_stream = DisplayDataChannelTransientsStream(
            display_data_channel_stream, "data_range")
        displayed_intensity_calibration_stream = StreamPropertyStream(
            display_item_stream, 'displayed_intensity_calibration')
        statistics_func_stream = Stream.CombineLatestStream(
            (region_data_and_metadata_func_stream, display_data_range_stream,
             region_stream, displayed_intensity_calibration_stream),
            calculate_statistics_func)
        if debounce:
            statistics_func_stream = Stream.DebounceStream(
                statistics_func_stream, 0.05, document_controller.event_loop)
        if sample:
            statistics_func_stream = Stream.SampleStream(
                statistics_func_stream, 0.5, document_controller.event_loop)

        self.__statistics_model = Model.FuncStreamValueModel(
            statistics_func_stream,
            document_controller.event_loop,
            value=dict(),
            cmp=numpy.array_equal)

        self._statistics_widget = StatisticsWidget(self.ui,
                                                   self.__statistics_model)

        # create the main column with the histogram and the statistics section
        column = self.ui.create_column_widget(
            properties={"height": 80 + 18 * 3 + 12})
        column.add(self._histogram_widget)
        column.add_spacing(6)
        column.add(self._statistics_widget)
        column.add_spacing(6)
        column.add_stretch()

        # this is necessary to make the panel happy
        self.widget = column
Beispiel #2
0
 def __init__(self, stream, property_name, cmp=None):
     super().__init__(
         stream,
         lambda x: Stream.PropertyChangedEventStream(x, property_name, cmp))
Beispiel #3
0
 def test_refcounts(self) -> None:
     with event_loop_context() as event_loop:
         # map stream, value stream
         stream = Stream.MapStream(Stream.ValueStream(0), lambda x: x)
         stream_ref = weakref.ref(stream)
         del stream
         self.assertIsNone(stream_ref())
         # combine stream
         stream2 = Stream.CombineLatestStream[typing.Any, typing.Any](
             [Stream.ValueStream(0),
              Stream.ValueStream(0)])
         stream_ref2 = weakref.ref(stream2)
         del stream2
         self.assertIsNone(stream_ref2())
         # debounce
         stream3 = Stream.DebounceStream(Stream.ValueStream(0), 0.0,
                                         event_loop)
         stream_ref3 = weakref.ref(stream3)
         del stream3
         self.assertIsNone(stream_ref3())
         # sample
         stream4 = Stream.SampleStream(Stream.ValueStream(0), 0.0,
                                       event_loop)
         stream_ref4 = weakref.ref(stream4)
         del stream4
         self.assertIsNone(stream_ref4())
         # property changed event stream
         stream5 = Stream.PropertyChangedEventStream[typing.Any](
             Model.PropertyModel(0), "value")
         stream_ref5 = weakref.ref(stream5)
         del stream5
         self.assertIsNone(stream_ref5())
         # optional stream
         stream6 = Stream.OptionalStream(Stream.ValueStream(0),
                                         lambda x: True)
         stream_ref6 = weakref.ref(stream6)
         del stream6
         self.assertIsNone(stream_ref6())
         # value stream action
         action = Stream.ValueStreamAction(Stream.ValueStream(0),
                                           lambda x: None)
         action_ref = weakref.ref(action)
         del action
         self.assertIsNone(action_ref())
         # value change stream
         stream7 = Stream.ValueChangeStream(Stream.ValueStream(0))
         stream_ref7 = weakref.ref(stream7)
         del stream7
         self.assertIsNone(stream_ref7())