From 0ee2cd5c32299c18bf95de2ec33cf102f05d7e83 Mon Sep 17 00:00:00 2001 From: Pierre Raybaut Date: Tue, 25 Jun 2024 11:35:03 +0200 Subject: [PATCH] Removed unnecessary `IStatsImageItemType` interface and `BaseImage.get_stats` method --- plotpy/interfaces/__init__.py | 1 - plotpy/interfaces/items.py | 25 ---------- plotpy/items/image/base.py | 84 --------------------------------- plotpy/tools/image.py | 88 +++++++++++++++++++++++++++++++++-- 4 files changed, 84 insertions(+), 114 deletions(-) diff --git a/plotpy/interfaces/__init__.py b/plotpy/interfaces/__init__.py index ee73e762..3111b702 100644 --- a/plotpy/interfaces/__init__.py +++ b/plotpy/interfaces/__init__.py @@ -16,7 +16,6 @@ IItemType, ISerializableType, IShapeItemType, - IStatsImageItemType, ITrackableItemType, IVoiImageItemType, ) diff --git a/plotpy/interfaces/items.py b/plotpy/interfaces/items.py index 56f00b6c..20f57d9f 100644 --- a/plotpy/interfaces/items.py +++ b/plotpy/interfaces/items.py @@ -148,31 +148,6 @@ def export_roi( pass -class IStatsImageItemType(IItemType): - """An image supporting stats computations""" - - def get_stats( - self, - x0: float, - y0: float, - x1: float, - y1: float, - show_surface: bool = False, - show_integral: bool = False, - ) -> str: - """Return formatted string with stats on image rectangular area - (output should be compatible with AnnotatedShape.get_infos) - - Args: - x0: X0 - y0: Y0 - x1: X1 - y1: Y1 - show_surface: Show surface (Default value = False) - show_integral: Show integral (Default value = False) - """ - - class ICSImageItemType(IItemType): """An image supporting X/Y cross sections""" diff --git a/plotpy/items/image/base.py b/plotpy/items/image/base.py index 732d4ff0..9a27a3d9 100644 --- a/plotpy/items/image/base.py +++ b/plotpy/items/image/base.py @@ -37,7 +37,6 @@ IHistDataSource, IImageItemType, ISerializableType, - IStatsImageItemType, ITrackableItemType, IVoiImageItemType, ) @@ -75,7 +74,6 @@ class BaseImageItem(QwtPlotItem): IHistDataSource, IVoiImageItemType, ICSImageItemType, - IStatsImageItemType, IExportROIImageItemType, ) _can_select = True @@ -720,8 +718,6 @@ def types(self) -> tuple[type[IItemType], ...]: ITrackableItemType, ICSImageItemType, IExportROIImageItemType, - IStatsImageItemType, - IStatsImageItemType, ) def set_readonly(self, state: bool) -> None: @@ -998,85 +994,6 @@ def __process_cross_section(self, ydata, apply_lut): else: return ydata - def get_stats( - self, - x0: float, - y0: float, - x1: float, - y1: float, - show_surface: bool = False, - show_integral: bool = False, - ) -> str: - """Return formatted string with stats on image rectangular area - (output should be compatible with AnnotatedShape.get_infos) - - Args: - x0: X0 - y0: Y0 - x1: X1 - y1: Y1 - show_surface: Show surface (Default value = False) - show_integral: Show integral (Default value = False) - """ - ix0, iy0, ix1, iy1 = self.get_closest_index_rect(x0, y0, x1, y1) - data = self.data[iy0:iy1, ix0:ix1] - xfmt = self.param.xformat - yfmt = self.param.yformat - zfmt = self.param.zformat - try: - xunit = xfmt.split()[1] - except IndexError: - xunit = "" - try: - yunit = yfmt.split()[1] - except IndexError: - yunit = "" - try: - zunit = zfmt.split()[1] - except IndexError: - zunit = "" - if show_integral: - integral = data.sum() - infos = "
".join( - [ - "%s" % self.param.label, - "%sx%s %s" - % (self.data.shape[1], self.data.shape[0], str(self.data.dtype)), - "", - "%s ≤ x ≤ %s" % (xfmt % x0, xfmt % x1), - "%s ≤ y ≤ %s" % (yfmt % y0, yfmt % y1), - "%s ≤ z ≤ %s" % (zfmt % data.min(), zfmt % data.max()), - "‹z› = " + zfmt % data.mean(), - "σ(z) = " + zfmt % data.std(), - ] - ) - if show_surface and xunit == yunit: - surfacefmt = xfmt.split()[0] + " " + xunit - if xunit != "": - surfacefmt = surfacefmt + "²" - surface = abs((x1 - x0) * (y1 - y0)) - infos = infos + "
" + _("surface = %s") % (surfacefmt % surface) - if show_integral: - integral = data.sum() - integral_fmt = r"%.3e " + zunit - infos = infos + "
" + _("sum = %s") % (integral_fmt % integral) - if ( - show_surface - and xunit == yunit - and xunit is not None - and show_integral - and zunit is not None - ): - if surface != 0: - density = integral / surface - densityfmt = r"%.3e " + zunit + "/" + xunit - if xunit != "": - densityfmt = densityfmt + "²" - infos = infos + "
" + _("density = %s") % (densityfmt % density) - else: - infos = infos + "
" + _("density not computed : surface is null !") - return infos - def get_xsection(self, y0: float | int, apply_lut: bool = False) -> np.ndarray: """Return cross section along x-axis at y=y0 @@ -1287,7 +1204,6 @@ def types(self) -> tuple[type[IItemType], ...]: ICSImageItemType, ISerializableType, IExportROIImageItemType, - IStatsImageItemType, ) def update_item_parameters(self) -> None: diff --git a/plotpy/tools/image.py b/plotpy/tools/image.py index 617e7bba..3f6fbc09 100644 --- a/plotpy/tools/image.py +++ b/plotpy/tools/image.py @@ -20,7 +20,7 @@ from plotpy.events import QtDragHandler, setup_standard_tool_filter from plotpy.interfaces import ( IColormapImageItemType, - IStatsImageItemType, + IImageItemType, IVoiImageItemType, ) from plotpy.items import ( @@ -63,6 +63,86 @@ from plotpy.styles.shape import AnnotationParam +def get_stats( + item: BaseImageItem, + x0: float, + y0: float, + x1: float, + y1: float, + show_surface: bool = False, + show_integral: bool = False, +) -> str: + """Return formatted string with stats on image rectangular area + (output should be compatible with AnnotatedShape.get_infos) + + Args: + x0: X0 + y0: Y0 + x1: X1 + y1: Y1 + show_surface: Show surface (Default value = False) + show_integral: Show integral (Default value = False) + """ + ix0, iy0, ix1, iy1 = item.get_closest_index_rect(x0, y0, x1, y1) + data = item.data[iy0:iy1, ix0:ix1] + param: BaseImageParam = item.param + xfmt = param.xformat + yfmt = param.yformat + zfmt = param.zformat + try: + xunit = xfmt.split()[1] + except IndexError: + xunit = "" + try: + yunit = yfmt.split()[1] + except IndexError: + yunit = "" + try: + zunit = zfmt.split()[1] + except IndexError: + zunit = "" + if show_integral: + integral = data.sum() + infos = "
".join( + [ + "%s" % param.label, + "%sx%s %s" % (item.data.shape[1], item.data.shape[0], str(item.data.dtype)), + "", + "%s ≤ x ≤ %s" % (xfmt % x0, xfmt % x1), + "%s ≤ y ≤ %s" % (yfmt % y0, yfmt % y1), + "%s ≤ z ≤ %s" % (zfmt % data.min(), zfmt % data.max()), + "‹z› = " + zfmt % data.mean(), + "σ(z) = " + zfmt % data.std(), + ] + ) + if show_surface and xunit == yunit: + surfacefmt = xfmt.split()[0] + " " + xunit + if xunit != "": + surfacefmt = surfacefmt + "²" + surface = abs((x1 - x0) * (y1 - y0)) + infos = infos + "
" + _("surface = %s") % (surfacefmt % surface) + if show_integral: + integral = data.sum() + integral_fmt = r"%.3e " + zunit + infos = infos + "
" + _("sum = %s") % (integral_fmt % integral) + if ( + show_surface + and xunit == yunit + and xunit is not None + and show_integral + and zunit is not None + ): + if surface != 0: + density = integral / surface + densityfmt = r"%.3e " + zunit + "/" + xunit + if xunit != "": + densityfmt = densityfmt + "²" + infos = infos + "
" + _("density = %s") % (densityfmt % density) + else: + infos = infos + "
" + _("density not computed : surface is null !") + return infos + + class ImageStatsRectangle(AnnotatedRectangle): """Rectangle used to display image statistics @@ -129,8 +209,8 @@ def get_infos(self) -> str | None: return _("No available data") else: return _("No available data") - return self.image_item.get_stats( - *self.get_rect(), self.show_surface, self.show_integral + return get_stats( + self.image_item, *self.get_rect(), self.show_surface, self.show_integral ) @@ -258,7 +338,7 @@ def get_associated_item(self, plot: BasePlot) -> BaseImageItem | None: Returns: Reference to the last image item associated with the tool """ - items = plot.get_selected_items(item_type=IStatsImageItemType) + items = plot.get_selected_items(item_type=IImageItemType) if len(items) == 1: self._last_item = weakref.ref(items[0]) return self.get_last_item()