def __init__(self, parent=None): super(LevelsHistogram, self).__init__(parent=parent, title="", section="histogram") self.antialiased = False # a dict of dict : plot -> selected items -> HistogramItem self._tracked_items = {} self.curveparam = CurveParam(_("Curve"), icon="curve.png") self.curveparam.read_config(CONF, "histogram", "curve") self.histparam = HistogramParam(_("Histogram"), icon="histogram.png") self.histparam.logscale = False self.histparam.n_bins = 256 self.range = XRangeSelection(0, 1) self.range_mono_color = self.range.shapeparam.sel_line.color self.range_multi_color = CONF.get("histogram", "range/multi/color", "red") self.add_item(self.range, z=5) self.SIG_RANGE_CHANGED.connect(self.range_changed) self.set_active_item(self.range) self.setMinimumHeight(80) self.setAxisMaxMajor(self.Y_LEFT, 5) self.setAxisMaxMinor(self.Y_LEFT, 0) if parent is None: self.set_axis_title("bottom", "Levels")
def histogram( self, data, bins=None, logscale=None, title="", color=None, xaxis="bottom", yaxis="left", ): """ Make 1D Histogram `plot item` (:py:class:`guiqwt.histogram.HistogramItem` object) * data (1D NumPy array) * bins: number of bins (int) * logscale: Y-axis scale (bool) """ basename = _("Histogram") histparam = HistogramParam(title=basename, icon="histogram.png") curveparam = CurveParam(_("Curve"), icon="curve.png") curveparam.read_config(CONF, "histogram", "curve") if not title: global HISTOGRAM_COUNT HISTOGRAM_COUNT += 1 title = make_title(basename, HISTOGRAM_COUNT) curveparam.label = title if color is not None: curveparam.line.color = color if bins is not None: histparam.n_bins = bins if logscale is not None: histparam.logscale = logscale return self.phistogram(data, curveparam, histparam, xaxis, yaxis)
def histogram(self, data, bins=None, logscale=None, title="", color=None, xaxis="bottom", yaxis="left"): """ Make 1D Histogram `plot item` (:py:class:`guiqwt.histogram.HistogramItem` object) * data (1D NumPy array) * bins: number of bins (int) * logscale: Y-axis scale (bool) """ basename = _("Histogram") histparam = HistogramParam(title=basename, icon='histogram.png') curveparam = CurveParam(_("Curve"), icon='curve.png') curveparam.read_config(CONF, "histogram", "curve") if not title: global HISTOGRAM_COUNT HISTOGRAM_COUNT += 1 title = make_title(basename, HISTOGRAM_COUNT) curveparam.label = title if color is not None: curveparam.line.color = color if bins is not None: histparam.n_bins = bins if logscale is not None: histparam.logscale = logscale return self.phistogram(data, curveparam, histparam, xaxis, yaxis)
def __init__(self, parent=None): super(LevelsHistogram, self).__init__(parent=parent, title="", section="histogram") self.antialiased = False # a dict of dict : plot -> selected items -> HistogramItem self._tracked_items = {} self.curveparam = CurveParam(_("Curve"), icon="curve.png") self.curveparam.read_config(CONF, "histogram", "curve") self.histparam = HistogramParam(_("Histogram"), icon="histogram.png") self.histparam.logscale = False self.histparam.n_bins = 256 self.range = XRangeSelection(0, 1) self.range_mono_color = self.range.shapeparam.sel_line.color self.range_multi_color = CONF.get("histogram", "range/multi/color", "red") self.add_item(self.range, z=5) self.connect(self, SIG_RANGE_CHANGED, self.range_changed) self.set_active_item(self.range) self.setMinimumHeight(80) self.setAxisMaxMajor(self.Y_LEFT, 5) self.setAxisMaxMinor(self.Y_LEFT, 0) if parent is None: self.set_axis_title('bottom', 'Levels')
def __init__(self, curveparam=None, histparam=None): self.hist_count = None self.hist_bins = None self.bins = None self.old_bins = None self.source = None self.logscale = None self.old_logscale = None if curveparam is None: curveparam = CurveParam(_("Curve"), icon="curve.png") curveparam.curvestyle = "Steps" if histparam is None: self.histparam = HistogramParam(title=_("Histogram"), icon="histogram.png") else: self.histparam = histparam CurveItem.__init__(self, curveparam) self.setCurveAttribute(QwtPlotCurve.Inverted)
def __init__(self, curveparam=None, histparam=None): self.hist_count = None self.hist_bins = None self.bins = None self.old_bins = None self.source = None self.logscale = None self.old_logscale = None if curveparam is None: curveparam = CurveParam(_("Curve"), icon='curve.png') curveparam.curvestyle = "Steps" if histparam is None: self.histparam = HistogramParam(title=_("Histogram"), icon='histogram.png') else: self.histparam = histparam CurveItem.__init__(self, curveparam) self.setCurveAttribute(QwtPlotCurve.Inverted)
class LevelsHistogram(CurvePlot): """Image levels histogram widget""" #: Signal emitted by LevelsHistogram when LUT range was changed SIG_VOI_CHANGED = Signal() def __init__(self, parent=None): super(LevelsHistogram, self).__init__(parent=parent, title="", section="histogram") self.antialiased = False # a dict of dict : plot -> selected items -> HistogramItem self._tracked_items = {} self.curveparam = CurveParam(_("Curve"), icon="curve.png") self.curveparam.read_config(CONF, "histogram", "curve") self.histparam = HistogramParam(_("Histogram"), icon="histogram.png") self.histparam.logscale = False self.histparam.n_bins = 256 self.range = XRangeSelection(0, 1) self.range_mono_color = self.range.shapeparam.sel_line.color self.range_multi_color = CONF.get("histogram", "range/multi/color", "red") self.add_item(self.range, z=5) self.SIG_RANGE_CHANGED.connect(self.range_changed) self.set_active_item(self.range) self.setMinimumHeight(80) self.setAxisMaxMajor(self.Y_LEFT, 5) self.setAxisMaxMinor(self.Y_LEFT, 0) if parent is None: self.set_axis_title("bottom", "Levels") def connect_plot(self, plot): if not isinstance(plot, ImagePlot): # Connecting only to image plot widgets (allow mixing image and # curve widgets for the same plot manager -- e.g. in pyplot) return self.SIG_VOI_CHANGED.connect(plot.notify_colormap_changed) plot.SIG_ITEM_SELECTION_CHANGED.connect(self.selection_changed) plot.SIG_ITEM_REMOVED.connect(self.item_removed) plot.SIG_ACTIVE_ITEM_CHANGED.connect(self.active_item_changed) def tracked_items_gen(self): for plot, items in list(self._tracked_items.items()): for item in list(items.items()): yield item # tuple item,curve def __del_known_items(self, known_items, items): del_curves = [] for item in list(known_items.keys()): if item not in items: curve = known_items.pop(item) del_curves.append(curve) self.del_items(del_curves) def selection_changed(self, plot): items = plot.get_selected_items(item_type=IVoiImageItemType) known_items = self._tracked_items.setdefault(plot, {}) if items: self.__del_known_items(known_items, items) if len(items) == 1: # Removing any cached item for other plots for other_plot, _items in list(self._tracked_items.items()): if other_plot is not plot: if not other_plot.get_selected_items( item_type=IVoiImageItemType): other_known_items = self._tracked_items[other_plot] self.__del_known_items(other_known_items, []) else: # if all items are deselected we keep the last known # selection (for one plot only) for other_plot, _items in list(self._tracked_items.items()): if other_plot.get_selected_items(item_type=IVoiImageItemType): self.__del_known_items(known_items, []) break for item in items: if item not in known_items: curve = HistogramItem(self.curveparam, self.histparam) curve.set_hist_source(item) self.add_item(curve, z=0) known_items[item] = curve nb_selected = len(list(self.tracked_items_gen())) if not nb_selected: self.replot() return self.curveparam.shade = 1.0 / nb_selected for item, curve in self.tracked_items_gen(): self.curveparam.update_curve(curve) self.histparam.update_hist(curve) self.active_item_changed(plot) # Rescaling histogram plot axes for better visibility ymax = None for item in known_items: curve = known_items[item] _x, y = curve.get_data() ymax0 = y.mean() + 3 * y.std() if ymax is None or ymax0 > ymax: ymax = ymax0 ymin, _ymax = self.get_axis_limits("left") if ymax is not None: self.set_axis_limits("left", ymin, ymax) self.replot() def item_removed(self, item): for plot, items in list(self._tracked_items.items()): if item in items: curve = items.pop(item) self.del_items([curve]) self.replot() break def active_item_changed(self, plot): items = plot.get_selected_items(item_type=IVoiImageItemType) if not items: # XXX: workaround return active = plot.get_last_active_item(IVoiImageItemType) if active: active_range = active.get_lut_range() else: active_range = None multiple_ranges = False for item, curve in self.tracked_items_gen(): if active_range != item.get_lut_range(): multiple_ranges = True if active_range is not None: _m, _M = active_range self.set_range_style(multiple_ranges) self.range.set_range(_m, _M, dosignal=False) self.replot() def set_range_style(self, multiple_ranges): if multiple_ranges: self.range.shapeparam.sel_line.color = self.range_multi_color else: self.range.shapeparam.sel_line.color = self.range_mono_color self.range.shapeparam.update_range(self.range) def set_range(self, _min, _max): if _min < _max: self.set_range_style(False) self.range.set_range(_min, _max) self.replot() return True else: # Range was not changed return False def range_changed(self, _rangesel, _min, _max): for item, curve in self.tracked_items_gen(): item.set_lut_range([_min, _max]) self.SIG_VOI_CHANGED.emit() def set_full_range(self): """Set range bounds to image min/max levels""" _min = _max = None for item, curve in self.tracked_items_gen(): imin, imax = item.get_lut_range_full() if _min is None or _min > imin: _min = imin if _max is None or _max < imax: _max = imax if _min is not None: self.set_range(_min, _max) def apply_min_func(self, item, curve, min): _min, _max = item.get_lut_range() return min, _max def apply_max_func(self, item, curve, max): _min, _max = item.get_lut_range() return _min, max def reduce_range_func(self, item, curve, percent): return lut_range_threshold(item, curve.bins, percent) def apply_range_function(self, func, *args, **kwargs): item = None for item, curve in self.tracked_items_gen(): _min, _max = func(item, curve, *args, **kwargs) item.set_lut_range([_min, _max]) self.SIG_VOI_CHANGED.emit() if item is not None: self.active_item_changed(item.plot()) def eliminate_outliers(self, percent): """ Eliminate outliers: eliminate percent/2*N counts on each side of the histogram (where N is the total count number) """ self.apply_range_function(self.reduce_range_func, percent) def set_min(self, _min): self.apply_range_function(self.apply_min_func, _min) def set_max(self, _max): self.apply_range_function(self.apply_max_func, _max)
class HistogramItem(CurveItem): """A Qwt item representing histogram data""" __implements__ = (IBasePlotItem, ) def __init__(self, curveparam=None, histparam=None): self.hist_count = None self.hist_bins = None self.bins = None self.old_bins = None self.source = None self.logscale = None self.old_logscale = None if curveparam is None: curveparam = CurveParam(_("Curve"), icon="curve.png") curveparam.curvestyle = "Steps" if histparam is None: self.histparam = HistogramParam(title=_("Histogram"), icon="histogram.png") else: self.histparam = histparam CurveItem.__init__(self, curveparam) self.setCurveAttribute(QwtPlotCurve.Inverted) def set_hist_source(self, src): """ Set histogram source *source*: Object with method `get_histogram`, e.g. objects derived from :py:data:`guiqwt.image.ImageItem` """ self.source = weakref.ref(src) self.update_histogram() def get_hist_source(self): """ Return histogram source *source*: Object with method `get_histogram`, e.g. objects derived from :py:data:`guiqwt.image.ImageItem` """ if self.source is not None: return self.source() def set_hist_data(self, data): """Set histogram data""" self.set_hist_source(HistDataSource(data)) def set_logscale(self, state): """Sets whether we use a logarithm or linear scale for the histogram counts""" self.logscale = state self.update_histogram() def get_logscale(self): """Returns the status of the scale""" return self.logscale def set_bins(self, n_bins): self.bins = n_bins self.update_histogram() def get_bins(self): return self.bins def compute_histogram(self): return self.get_hist_source().get_histogram(self.bins) def update_histogram(self): if self.get_hist_source() is None: return hist, bin_edges = self.compute_histogram() hist = np.concatenate((hist, [0])) if self.logscale: hist = np.log(hist + 1) self.set_data(bin_edges, hist) # Autoscale only if logscale/bins have changed if self.bins != self.old_bins or self.logscale != self.old_logscale: if self.plot(): self.plot().do_autoscale() self.old_bins = self.bins self.old_logscale = self.logscale plot = self.plot() if plot is not None: plot.do_autoscale(replot=True) def update_params(self): self.histparam.update_hist(self) CurveItem.update_params(self) def get_item_parameters(self, itemparams): CurveItem.get_item_parameters(self, itemparams) itemparams.add("HistogramParam", self, self.histparam) def set_item_parameters(self, itemparams): update_dataset(self.histparam, itemparams.get("HistogramParam"), visible_only=True) self.histparam.update_hist(self) CurveItem.set_item_parameters(self, itemparams)
class LevelsHistogram(CurvePlot): """Image levels histogram widget""" def __init__(self, parent=None): super(LevelsHistogram, self).__init__(parent=parent, title="", section="histogram") self.antialiased = False # a dict of dict : plot -> selected items -> HistogramItem self._tracked_items = {} self.curveparam = CurveParam(_("Curve"), icon="curve.png") self.curveparam.read_config(CONF, "histogram", "curve") self.histparam = HistogramParam(_("Histogram"), icon="histogram.png") self.histparam.logscale = False self.histparam.n_bins = 256 self.range = XRangeSelection(0, 1) self.range_mono_color = self.range.shapeparam.sel_line.color self.range_multi_color = CONF.get("histogram", "range/multi/color", "red") self.add_item(self.range, z=5) self.connect(self, SIG_RANGE_CHANGED, self.range_changed) self.set_active_item(self.range) self.setMinimumHeight(80) self.setAxisMaxMajor(self.Y_LEFT, 5) self.setAxisMaxMinor(self.Y_LEFT, 0) if parent is None: self.set_axis_title('bottom', 'Levels') def connect_plot(self, plot): if not isinstance(plot, ImagePlot): # Connecting only to image plot widgets (allow mixing image and # curve widgets for the same plot manager -- e.g. in pyplot) return self.connect(self, SIG_VOI_CHANGED, plot.notify_colormap_changed) self.connect(plot, SIG_ITEM_SELECTION_CHANGED, self.selection_changed) self.connect(plot, SIG_ITEM_REMOVED, self.item_removed) self.connect(plot, SIG_ACTIVE_ITEM_CHANGED, self.active_item_changed) def tracked_items_gen(self): for plot, items in list(self._tracked_items.items()): for item in list(items.items()): yield item # tuple item,curve def __del_known_items(self, known_items, items): del_curves = [] for item in list(known_items.keys()): if item not in items: curve = known_items.pop(item) del_curves.append(curve) self.del_items(del_curves) def selection_changed(self, plot): items = plot.get_selected_items(item_type=IVoiImageItemType) known_items = self._tracked_items.setdefault(plot, {}) if items: self.__del_known_items(known_items, items) if len(items) == 1: # Removing any cached item for other plots for other_plot, _items in list(self._tracked_items.items()): if other_plot is not plot: if not other_plot.get_selected_items( item_type=IVoiImageItemType): other_known_items = self._tracked_items[other_plot] self.__del_known_items(other_known_items, []) else: # if all items are deselected we keep the last known # selection (for one plot only) for other_plot, _items in list(self._tracked_items.items()): if other_plot.get_selected_items(item_type=IVoiImageItemType): self.__del_known_items(known_items, []) break for item in items: if item not in known_items: curve = HistogramItem(self.curveparam, self.histparam) curve.set_hist_source(item) self.add_item(curve, z=0) known_items[item] = curve nb_selected = len(list(self.tracked_items_gen())) if not nb_selected: self.replot() return self.curveparam.shade = 1.0/nb_selected for item, curve in self.tracked_items_gen(): self.curveparam.update_curve(curve) self.histparam.update_hist(curve) self.active_item_changed(plot) # Rescaling histogram plot axes for better visibility ymax = None for item in known_items: curve = known_items[item] _x, y = curve.get_data() ymax0 = y.mean()+3*y.std() if ymax is None or ymax0 > ymax: ymax = ymax0 ymin, _ymax = self.get_axis_limits("left") if ymax is not None: self.set_axis_limits("left", ymin, ymax) self.replot() def item_removed(self, item): for plot, items in list(self._tracked_items.items()): if item in items: items.pop(item) break def active_item_changed(self, plot): items = plot.get_selected_items(item_type=IVoiImageItemType) if not items: #XXX: workaround return active = plot.get_last_active_item(IVoiImageItemType) if active: active_range = active.get_lut_range() else: active_range = None multiple_ranges = False for item, curve in self.tracked_items_gen(): if active_range != item.get_lut_range(): multiple_ranges = True if active_range is not None: _m, _M = active_range self.set_range_style(multiple_ranges) self.range.set_range(_m, _M, dosignal=False) self.replot() def set_range_style(self, multiple_ranges): if multiple_ranges: self.range.shapeparam.sel_line.color = self.range_multi_color else: self.range.shapeparam.sel_line.color = self.range_mono_color self.range.shapeparam.update_range(self.range) def set_range(self, _min, _max): if _min < _max: self.set_range_style(False) self.range.set_range(_min, _max) self.replot() return True else: # Range was not changed return False def range_changed(self, _rangesel, _min, _max): for item, curve in self.tracked_items_gen(): item.set_lut_range([_min, _max]) self.emit(SIG_VOI_CHANGED) def set_full_range(self): """Set range bounds to image min/max levels""" _min = _max = None for item, curve in self.tracked_items_gen(): imin, imax = item.get_lut_range_full() if _min is None or _min>imin: _min = imin if _max is None or _max<imax: _max = imax if _min is not None: self.set_range(_min, _max) def apply_min_func(self, item, curve, min): _min, _max = item.get_lut_range() return min, _max def apply_max_func(self, item, curve, max): _min, _max = item.get_lut_range() return _min, max def reduce_range_func(self, item, curve, percent): return lut_range_threshold(item, curve.bins, percent) def apply_range_function(self, func, *args, **kwargs): item = None for item, curve in self.tracked_items_gen(): _min, _max = func(item, curve, *args, **kwargs) item.set_lut_range([_min, _max]) self.emit(SIG_VOI_CHANGED) if item is not None: self.active_item_changed(item.plot()) def eliminate_outliers(self, percent): """ Eliminate outliers: eliminate percent/2*N counts on each side of the histogram (where N is the total count number) """ self.apply_range_function(self.reduce_range_func, percent) def set_min(self, _min): self.apply_range_function(self.apply_min_func, _min) def set_max(self, _max): self.apply_range_function(self.apply_max_func, _max)
class HistogramItem(CurveItem): """A Qwt item representing histogram data""" __implements__ = (IBasePlotItem,) def __init__(self, curveparam=None, histparam=None): self.hist_count = None self.hist_bins = None self.bins = None self.old_bins = None self.source = None self.logscale = None self.old_logscale = None if curveparam is None: curveparam = CurveParam(_("Curve"), icon='curve.png') curveparam.curvestyle = "Steps" if histparam is None: self.histparam = HistogramParam(title=_("Histogram"), icon='histogram.png') else: self.histparam = histparam CurveItem.__init__(self, curveparam) self.setCurveAttribute(QwtPlotCurve.Inverted) def set_hist_source(self, src): """Set histogram source (source: object with method 'get_histogram', e.g. objects derived from guiqwt.image.ImageItem)""" self.source = weakref.ref(src) self.update_histogram() def get_hist_source(self): """Return histogram source (source: object with method 'get_histogram', e.g. objects derived from guiqwt.image.ImageItem)""" if self.source is not None: return self.source() def set_hist_data(self, data): """Set histogram data""" self.set_hist_source(HistDataSource(data)) def set_logscale(self, state): """Sets whether we use a logarithm or linear scale for the histogram counts""" self.logscale = state self.update_histogram() def get_logscale(self): """Returns the status of the scale""" return self.logscale def set_bins(self, n_bins): self.bins = n_bins self.update_histogram() def get_bins(self): return self.bins def compute_histogram(self): return self.get_hist_source().get_histogram(self.bins) def update_histogram(self): if self.get_hist_source() is None: return hist, bin_edges = self.compute_histogram() hist = np.concatenate((hist, [0])) if self.logscale: hist = np.log(hist+1) self.set_data(bin_edges, hist) # Autoscale only if logscale/bins have changed if self.bins != self.old_bins or self.logscale != self.old_logscale: if self.plot(): self.plot().do_autoscale() self.old_bins = self.bins self.old_logscale = self.logscale plot = self.plot() if plot is not None: plot.do_autoscale(replot=True) def update_params(self): self.histparam.update_hist(self) CurveItem.update_params(self) def get_item_parameters(self, itemparams): CurveItem.get_item_parameters(self, itemparams) itemparams.add("HistogramParam", self, self.histparam) def set_item_parameters(self, itemparams): update_dataset(self.histparam, itemparams.get("HistogramParam"), visible_only=True) self.histparam.update_hist(self) CurveItem.set_item_parameters(self, itemparams)