def _computeAutoscaleRange(self, data): """Compute the data range which will be used in autoscale mode. :param numpy.ndarray data: The data for which to compute the range :return: (vmin, vmax) range (vmin and /or vmax might be `None`) """ if data is None: return None, None if data.size == 0: return None, None if self.getNormalization() == Colormap.LOGARITHM: if self._autoscaleMode == Colormap.MINMAX: result = min_max(data, min_positive=True, finite=True) vMin = result.min_positive # >0 or None vMax = result.maximum # can be <= 0 elif self._autoscaleMode == Colormap.STDDEV3: with numpy.errstate(divide='ignore', invalid='ignore'): normdata = numpy.log10(data) mean = numpy.nanmean(normdata) std = numpy.nanstd(normdata) vMin = float(10**(mean - 3 * std)) vMax = float(10**(mean + 3 * std)) else: assert False else: if self._autoscaleMode == Colormap.MINMAX: vMin, vMax = min_max(data, min_positive=False, finite=True) elif self._autoscaleMode == Colormap.STDDEV3: mean = numpy.nanmean(data) std = numpy.nanstd(data) vMin, vMax = float(mean - 3 * std), float(mean + 3 * std) else: assert False return vMin, vMax
def test_nodata(self): """Test min_max with None and empty array""" for dtype in self.DTYPES: with self.subTest(dtype=dtype): with self.assertRaises(TypeError): min_max(None) data = numpy.array((), dtype=dtype) with self.assertRaises(ValueError): min_max(data)
def getColormapRange(self, data=None): """Return (vmin, vmax) :return: the tuple vmin, vmax fitting vmin, vmax, normalization and data if any given :rtype: tuple """ vmin = self._vmin vmax = self._vmax assert vmin is None or vmax is None or vmin <= vmax # TODO handle this in setters if self.getNormalization() == self.LOGARITHM: # Handle negative bounds as autoscale if vmin is not None and (vmin is not None and vmin <= 0.): mess = 'negative vmin, moving to autoscale for lower bound' _logger.warning(mess) vmin = None if vmax is not None and (vmax is not None and vmax <= 0.): mess = 'negative vmax, moving to autoscale for upper bound' _logger.warning(mess) vmax = None if vmin is None or vmax is None: # Handle autoscale # Get min/max from data if data is not None: data = numpy.array(data, copy=False) if data.size == 0: # Fallback an array but no data min_, max_ = self._getDefaultMin(), self._getDefaultMax() else: if self.getNormalization() == self.LOGARITHM: result = min_max(data, min_positive=True, finite=True) min_ = result.min_positive # >0 or None max_ = result.maximum # can be <= 0 else: min_, max_ = min_max(data, min_positive=False, finite=True) # Handle fallback if min_ is None or not numpy.isfinite(min_): min_ = self._getDefaultMin() if max_ is None or not numpy.isfinite(max_): max_ = self._getDefaultMax() else: # Fallback if no data is provided min_, max_ = self._getDefaultMin(), self._getDefaultMax() if vmin is None: # Set vmin respecting provided vmax vmin = min_ if vmax is None else min(min_, vmax) if vmax is None: vmax = max(max_, vmin) # Handle max_ <= 0 for log scale return vmin, vmax
def computeHistogram(data): """Compute the data histogram as used by :meth:`setHistogram`. :param data: The data to process :rtype: Tuple(List(float),List(float) """ _data = data if _data.ndim == 3: # RGB(A) images _logger.info('Converting current image from RGB(A) to grayscale\ in order to compute the intensity distribution') _data = (_data[:, :, 0] * 0.299 + _data[:, :, 1] * 0.587 + _data[:, :, 2] * 0.114) if len(_data) == 0: return None, None xmin, xmax = min_max(_data, min_positive=False, finite=True) nbins = min(256, int(numpy.sqrt(_data.size))) data_range = xmin, xmax # bad hack: get 256 bins in the case we have a B&W if numpy.issubdtype(_data.dtype, numpy.integer): if nbins > xmax - xmin: nbins = xmax - xmin nbins = max(2, nbins) _data = _data.ravel().astype(numpy.float32) histogram = Histogramnd(_data, n_bins=nbins, histo_range=data_range) return histogram.histo, histogram.edges[0]
def computeDataRange(data): """Compute the data range as used by :meth:`setDataRange`. :param data: The data to process :rtype: Tuple(float, float, float) """ if data is None or len(data) == 0: return None, None, None dataRange = min_max(data, min_positive=True, finite=True) if dataRange.minimum is None: # Only non-finite data dataRange = None if dataRange is not None: min_positive = dataRange.min_positive if min_positive is None: min_positive = float('nan') dataRange = dataRange.minimum, min_positive, dataRange.maximum if dataRange is None or len(dataRange) != 3: qt.QMessageBox.warning( None, "No Data", "Image data does not contain any real value") dataRange = 1., 1., 10. return dataRange
def createContext(self, item, plot, onlimits): self.origin = item.getOrigin() self.scale = item.getScale() self.data = item.getData() if onlimits: minX, maxX = plot.getXAxis().getLimits() minY, maxY = plot.getYAxis().getLimits() XMinBound = int((minX - self.origin[0]) / self.scale[0]) YMinBound = int((minY - self.origin[1]) / self.scale[1]) XMaxBound = int((maxX - self.origin[0]) / self.scale[0]) YMaxBound = int((maxY - self.origin[1]) / self.scale[1]) XMinBound = max(XMinBound, 0) YMinBound = max(YMinBound, 0) if XMaxBound <= XMinBound or YMaxBound <= YMinBound: return self.noDataSelected() data = item.getData() self.data = data[YMinBound:YMaxBound + 1, XMinBound:XMaxBound + 1] else: self.data = item.getData() if self.data.size > 0: self.min, self.max = min_max(self.data) else: self.min, self.max = None, None self.values = self.data
def test_benchmark_min_max(self): """Benchmark min_max without min positive. Compares with: - numpy.nanmin, numpy.nanmax and - numpy.argmin, numpy.argmax It runs bench for different types, different data size and 3 data sets: increasing , decreasing and random data. """ durations = {'min/max': [], 'argmin/max': [], 'combo': []} _logger.info('Benchmark against argmin/argmax and nanmin/nanmax') for dtype in self.DTYPES: for arange in self.ARANGE: for exponent in self.EXPONENT: size = 10**exponent with self.subTest(dtype=dtype, size=size, arange=arange): if arange == 'ascent': data = numpy.arange(0, size, 1, dtype=dtype) elif arange == 'descent': data = numpy.arange(size, 0, -1, dtype=dtype) else: if dtype in ('float32', 'float64'): data = numpy.random.random(size) else: data = numpy.random.randint(10**6, size=size) data = numpy.array(data, dtype=dtype) start = time.time() ref_min = numpy.nanmin(data) ref_max = numpy.nanmax(data) durations['min/max'].append(time.time() - start) start = time.time() ref_argmin = numpy.argmin(data) ref_argmax = numpy.argmax(data) durations['argmin/max'].append(time.time() - start) start = time.time() result = combo.min_max(data, min_positive=False) durations['combo'].append(time.time() - start) _logger.info( '%s-%s-10**%d\tx%.2f argmin/max x%.2f min/max', dtype, arange, exponent, durations['argmin/max'][-1] / durations['combo'][-1], durations['min/max'][-1] / durations['combo'][-1]) self.assertEqual(result.minimum, ref_min) self.assertEqual(result.maximum, ref_max) self.assertEqual(result.argmin, ref_argmin) self.assertEqual(result.argmax, ref_argmax) self.show_results('min/max', durations, 'combo')
def from_points(points): """ :param numpy.array tuple points: list of points. Should be 2D: [(y1, x1), (y2, x2), (y3, x3), ...] :return: bounding box from two points :rtype: _BoundingBox """ if not isinstance(points, numpy.ndarray): points_ = numpy.ndarray(points) else: points_ = points x = points_[:, 1] y = points_[:, 0] x_min, x_max = min_max(x) y_min, y_max = min_max(y) return _BoundingBox(bottom_left=(y_min, x_min), top_right=(y_max, x_max))
def setData(self, data, copy=True): """Set the 3D scalar data set to use for building the iso-surface. Dataset order is zyx (i.e., first dimension is z). :param data: scalar field from which to extract the iso-surface :type data: 3D numpy.ndarray of float32 with shape at least (2, 2, 2) :param bool copy: True (default) to make a copy, False to avoid copy (DO NOT MODIFY data afterwards) """ if data is None: self._data = None self._dataRange = None self.setSelectedRegion(zrange=None, yrange=None, xrange_=None) self._group.shape = None self.centerScene() else: data = numpy.array(data, copy=copy, dtype=numpy.float32, order='C') assert data.ndim == 3 assert min(data.shape) >= 2 wasData = self._data is not None previousSelectedRegion = self.getSelectedRegion() self._data = data # Store data range info dataRange = min_max(self._data, min_positive=True, finite=True) if dataRange.minimum is None: # Only non-finite data dataRange = None if dataRange is not None: min_positive = dataRange.min_positive if min_positive is None: min_positive = float('nan') dataRange = dataRange.minimum, min_positive, dataRange.maximum self._dataRange = dataRange if previousSelectedRegion is not None: # Update selected region to ensure it is clipped to array range self.setSelectedRegion(*previousSelectedRegion.getArrayRange()) self._group.shape = self._data.shape if not wasData: self.centerScene() # Reset viewpoint the first time only # Update iso-surfaces for isosurface in self.getIsosurfaces(): isosurface._setData(self._data, copy=False) self.sigDataChanged.emit()
def autoscaleMinMax(self, data): """Autoscale using min/max :param numpy.ndarray data: :returns: (vmin, vmax) :rtype: Tuple[float,float] """ data = data[self.isValid(data)] if data.size == 0: return None, None result = min_max(data, min_positive=False, finite=True) return result.minimum, result.maximum
def computeIntensityDistribution(self): """Get the active image and compute the image intensity distribution """ item = self._getSelectedItem() if item is None: self._cleanUp() return if isinstance(item, items.ImageBase): array = item.getData(copy=False) if array.ndim == 3: # RGB(A) images _logger.info('Converting current image from RGB(A) to grayscale\ in order to compute the intensity distribution') array = (array[:, :, 0] * 0.299 + array[:, :, 1] * 0.587 + array[:, :, 2] * 0.114) elif isinstance(item, items.Scatter): array = item.getValueData(copy=False) else: assert(False) if array.size == 0: self._cleanUp() return xmin, xmax = min_max(array, min_positive=False, finite=True) nbins = min(1024, int(numpy.sqrt(array.size))) data_range = xmin, xmax # bad hack: get 256 bins in the case we have a B&W if numpy.issubdtype(array.dtype, numpy.integer): if nbins > xmax - xmin: nbins = xmax - xmin nbins = max(2, nbins) data = array.ravel().astype(numpy.float32) histogram = Histogramnd(data, n_bins=nbins, histo_range=data_range) assert len(histogram.edges) == 1 self._histo = histogram.histo edges = histogram.edges[0] plot = self.getHistogramPlotWidget() plot.addHistogram(histogram=self._histo, edges=edges, legend='pixel intensity', fill=True, color='#66aad7') plot.resetZoom()
def _computeView(self, dataMin, dataMax): """Compute the location of the view according to the bound of the data :rtype: Tuple(float, float) """ marginRatio = 1.0 / 6.0 scale = self._plot.getXAxis().getScale() if self._dataRange is not None: if scale == Axis.LOGARITHMIC: minRange = self._dataRange[1] else: minRange = self._dataRange[0] maxRange = self._dataRange[2] if minRange is not None: dataMin = min(dataMin, minRange) dataMax = max(dataMax, maxRange) if self._histogramData is not None: info = min_max(self._histogramData[1]) if scale == Axis.LOGARITHMIC: minHisto = info.min_positive else: minHisto = info.minimum maxHisto = info.maximum if minHisto is not None: dataMin = min(dataMin, minHisto) dataMax = max(dataMax, maxHisto) if scale == Axis.LOGARITHMIC: epsilon = numpy.finfo(numpy.float32).eps if dataMin == 0: dataMin = epsilon if dataMax < dataMin: dataMax = dataMin + epsilon marge = marginRatio * abs( numpy.log10(dataMax) - numpy.log10(dataMin)) viewMin = 10**(numpy.log10(dataMin) - marge) viewMax = 10**(numpy.log10(dataMax) + marge) else: # scale == Axis.LINEAR: marge = marginRatio * abs(dataMax - dataMin) if marge < 0.0001: # Smaller that the QLineEdit precision marge = 0.0001 viewMin = dataMin - marge viewMax = dataMax + marge return viewMin, viewMax
def createContext(self, item, plot, onlimits): xData, edges = item.getData(copy=True)[0:2] yData = item._revertComputeEdges(x=edges, histogramType=item.getAlignment()) if onlimits: minX, maxX = plot.getXAxis().getLimits() yData = yData[(minX <= xData) & (xData <= maxX)] xData = xData[(minX <= xData) & (xData <= maxX)] self.xData = xData self.yData = yData if len(yData) > 0: self.min, self.max = min_max(yData) else: self.min, self.max = None, None self.data = (xData, yData) self.values = yData
def createContext(self, item, plot, onlimits): xData, yData = item.getData(copy=True)[0:2] if onlimits: minX, maxX = plot.getXAxis().getLimits() yData = yData[(minX <= xData) & (xData <= maxX)] xData = xData[(minX <= xData) & (xData <= maxX)] self.xData = xData self.yData = yData if len(yData) > 0: self.min, self.max = min_max(yData) else: self.min, self.max = None, None self.data = (xData, yData) self.values = yData
def _computeView(self, dataMin, dataMax): """Compute the location of the view according to the bound of the data :rtype: Tuple(float, float) """ marginRatio = 1.0 / 6.0 scale = self._plot.getXAxis().getScale() if self._dataRange is not None: if scale == Axis.LOGARITHMIC: minRange = self._dataRange[1] else: minRange = self._dataRange[0] maxRange = self._dataRange[2] if minRange is not None: dataMin = min(dataMin, minRange) dataMax = max(dataMax, maxRange) if self._histogramData is not None: info = min_max(self._histogramData[1]) if scale == Axis.LOGARITHMIC: minHisto = info.min_positive else: minHisto = info.minimum maxHisto = info.maximum if minHisto is not None: dataMin = min(dataMin, minHisto) dataMax = max(dataMax, maxHisto) if scale == Axis.LOGARITHMIC: epsilon = numpy.finfo(numpy.float32).eps if dataMin == 0: dataMin = epsilon if dataMax < dataMin: dataMax = dataMin + epsilon marge = marginRatio * abs(numpy.log10(dataMax) - numpy.log10(dataMin)) viewMin = 10**(numpy.log10(dataMin) - marge) viewMax = 10**(numpy.log10(dataMax) + marge) else: # scale == Axis.LINEAR: marge = marginRatio * abs(dataMax - dataMin) if marge < 0.0001: # Smaller that the QLineEdit precision marge = 0.0001 viewMin = dataMin - marge viewMax = dataMax + marge return viewMin, viewMax
def _updateFromItem(self): """Update histogram and stats from the item""" item = self.getItem() if item is None: self.reset() return if not isinstance(item, self._SUPPORTED_ITEM_CLASS): _logger.error("Unsupported item", item) self.reset() return # Compute histogram and stats array = item.getValueData(copy=False) if array.size == 0: self.reset() return xmin, xmax = min_max(array, min_positive=False, finite=True) nbins = min(1024, int(numpy.sqrt(array.size))) data_range = xmin, xmax # bad hack: get 256 bins in the case we have a B&W if numpy.issubdtype(array.dtype, numpy.integer): if nbins > xmax - xmin: nbins = xmax - xmin nbins = max(2, nbins) data = array.ravel().astype(numpy.float32) histogram = Histogramnd(data, n_bins=nbins, histo_range=data_range) if len(histogram.edges) != 1: _logger.error("Error while computing the histogram") self.reset() return self.setHistogram(histogram.histo, histogram.edges[0]) self.resetZoom() self.setStatistics( min_=xmin, max_=xmax, mean=numpy.nanmean(array), std=numpy.nanstd(array), sum_=numpy.nansum(array))
def _computeRangeFromData(data): """Compute range info (min, min positive, max) from data :param Union[numpy.ndarray,None] data: :return: Union[List[float],None] """ if data is None: return None dataRange = min_max(data, min_positive=True, finite=True) if dataRange.minimum is None: # Only non-finite data return None if dataRange is not None: min_positive = dataRange.min_positive if min_positive is None: min_positive = float('nan') return dataRange.minimum, min_positive, dataRange.maximum
def _test_min_max(self, data, min_positive, finite=False): """Compare min_max with numpy for the given dataset :param numpy.ndarray data: Data set to use for test :param bool min_positive: True to test with positive min :param bool finite: True to only test finite values """ minimum, min_pos, maximum, argmin, argmin_pos, argmax = \ self._numpy_min_max(data, min_positive, finite) result = min_max(data, min_positive, finite) self.assertSimilar(minimum, result.minimum) self.assertSimilar(min_pos, result.min_positive) self.assertSimilar(maximum, result.maximum) self.assertSimilar(argmin, result.argmin) self.assertSimilar(argmin_pos, result.argmin_positive) self.assertSimilar(argmax, result.argmax)
def setData(self, data, copy=True): """Set the 3D scalar data represented by this item. Dataset order is zyx (i.e., first dimension is z). :param data: 3D array :type data: 3D numpy.ndarray of float32 with shape at least (2, 2, 2) :param bool copy: True (default) to make a copy, False to avoid copy (DO NOT MODIFY data afterwards) """ if data is None: self._data = None self._dataRange = None self._boundedGroup.shape = None else: data = numpy.array(data, copy=copy, dtype=numpy.float32, order='C') assert data.ndim == 3 assert min(data.shape) >= 2 self._data = data # Store data range info dataRange = min_max(self._data, min_positive=True, finite=True) if dataRange.minimum is None: # Only non-finite data dataRange = None if dataRange is not None: min_positive = dataRange.min_positive if min_positive is None: min_positive = float('nan') dataRange = dataRange.minimum, min_positive, dataRange.maximum self._dataRange = dataRange self._boundedGroup.shape = self._data.shape # Update iso-surfaces for isosurface in self.getIsosurfaces(): isosurface._setData(self._data, copy=False) self._updated(ItemChangedType.DATA)
def createContext(self, item, plot, onlimits): xData, yData, valueData, xerror, yerror = item.getData(copy=True) assert plot if onlimits: minX, maxX = plot.getXAxis().getLimits() minY, maxY = plot.getYAxis().getLimits() # filter on X axis valueData = valueData[(minX <= xData) & (xData <= maxX)] yData = yData[(minX <= xData) & (xData <= maxX)] xData = xData[(minX <= xData) & (xData <= maxX)] # filter on Y axis valueData = valueData[(minY <= yData) & (yData <= maxY)] xData = xData[(minY <= yData) & (yData <= maxY)] yData = yData[(minY <= yData) & (yData <= maxY)] if len(valueData) > 0: self.min, self.max = min_max(valueData) else: self.min, self.max = None, None self.data = (xData, yData, valueData) self.values = valueData
def _test_min_max(self, data, min_positive): """Compare min_max with numpy for the given dataset :param numpy.ndarray data: Data set to use for test :param bool min_positive: True to test with positive min """ result = min_max(data, min_positive) minimum = numpy.nanmin(data) if numpy.isnan(minimum): # All NaNs self.assertTrue(numpy.isnan(result.minimum)) self.assertEqual(result.argmin, 0) else: self.assertEqual(result.minimum, minimum) argmin = numpy.where(data == minimum)[0][0] self.assertEqual(result.argmin, argmin) maximum = numpy.nanmax(data) if numpy.isnan(maximum): # All NaNs self.assertTrue(numpy.isnan(result.maximum)) self.assertEqual(result.argmax, 0) else: self.assertEqual(result.maximum, maximum) argmax = numpy.where(data == maximum)[0][0] self.assertEqual(result.argmax, argmax) if min_positive: pos_data = data[data > 0] if len(pos_data) > 0: min_pos = numpy.min(pos_data) argmin_pos = numpy.where(data == min_pos)[0][0] else: min_pos = None argmin_pos = None self.assertEqual(result.min_positive, min_pos) self.assertEqual(result.argmin_positive, argmin_pos)
def _setRangeFromData(self, data=None): """Compute the data range the colormap should use from provided data. :param data: Data set from which to compute the range or None """ if data is None or len(data) == 0: dataRange = None else: dataRange = min_max(data, min_positive=True, finite=True) if dataRange.minimum is None: # Only non-finite data dataRange = None if dataRange is not None: min_positive = dataRange.min_positive if min_positive is None: min_positive = float('nan') dataRange = dataRange.minimum, min_positive, dataRange.maximum self._dataRange = dataRange if self.getColormap().isAutoscale(): self._syncSceneColormap()
def _setRangeFromData(self, data=None): """Compute the data range the colormap should use from provided data. :param data: Data set from which to compute the range or None """ if data is None or data.size == 0: dataRange = None else: dataRange = min_max(data, min_positive=True, finite=True) if dataRange.minimum is None: # Only non-finite data dataRange = None if dataRange is not None: min_positive = dataRange.min_positive if min_positive is None: min_positive = float('nan') dataRange = dataRange.minimum, min_positive, dataRange.maximum self._dataRange = dataRange colormap = self.getColormap() if None in (colormap.getVMin(), colormap.getVMax()): self._colormapChanged()
def computeIntensityDistribution(self): """Get the active image and compute the image intensity distribution """ activeImage = self.plot.getActiveImage() if activeImage is not None: image = activeImage.getData(copy=False) if image.ndim == 3: # RGB(A) images _logger.info( 'Converting current image from RGB(A) to grayscale\ in order to compute the intensity distribution') image = (image[:, :, 0] * 0.299 + image[:, :, 1] * 0.587 + image[:, :, 2] * 0.114) xmin, xmax = min_max(image, min_positive=False, finite=True) nbins = min(1024, int(numpy.sqrt(image.size))) data_range = xmin, xmax # bad hack: get 256 bins in the case we have a B&W if numpy.issubdtype(image.dtype, numpy.integer): if nbins > xmax - xmin: nbins = xmax - xmin nbins = max(2, nbins) data = image.ravel().astype(numpy.float32) histogram = Histogramnd(data, n_bins=nbins, histo_range=data_range) assert len(histogram.edges) == 1 self._histo = histogram.histo edges = histogram.edges[0] plot = self.getHistogramPlotWidget() plot.addHistogram(histogram=self._histo, edges=edges, legend='pixel intensity', fill=True, color='#66aad7') plot.resetZoom()
def computeIntensityDistribution(self): """Get the active image and compute the image intensity distribution """ activeImage = self.plot.getActiveImage() if activeImage is not None: image = activeImage.getData(copy=False) if image.ndim == 3: # RGB(A) images _logger.info('Converting current image from RGB(A) to grayscale\ in order to compute the intensity distribution') image = (image[:, :, 0] * 0.299 + image[:, :, 1] * 0.587 + image[:, :, 2] * 0.114) xmin, xmax = min_max(image, min_positive=False, finite=True) nbins = min(1024, int(numpy.sqrt(image.size))) data_range = xmin, xmax # bad hack: get 256 bins in the case we have a B&W if numpy.issubdtype(image.dtype, numpy.integer): if nbins > xmax - xmin: nbins = xmax - xmin nbins = max(2, nbins) data = image.ravel().astype(numpy.float32) histogram = Histogramnd(data, n_bins=nbins, histo_range=data_range) assert len(histogram.edges) == 1 self._histo = histogram.histo edges = histogram.edges[0] plot = self.getHistogramPlotWidget() plot.addHistogram(histogram=self._histo, edges=edges, legend='pixel intensity', fill=True, color='#66aad7') plot.resetZoom()
def __init__(self, xData, yData, colorData=None, xError=None, yError=None, lineStyle=SOLID, lineColor=(0., 0., 0., 1.), lineWidth=1, lineDashPeriod=20, marker=SQUARE, markerColor=(0., 0., 0., 1.), markerSize=7, fillColor=None, isYLog=False): self.colorData = colorData # Compute x bounds if xError is None: self.xMin, self.xMax = min_max(xData, min_positive=False) else: # Takes the error into account if hasattr(xError, 'shape') and len(xError.shape) == 2: xErrorMinus, xErrorPlus = xError[0], xError[1] else: xErrorMinus, xErrorPlus = xError, xError self.xMin = numpy.nanmin(xData - xErrorMinus) self.xMax = numpy.nanmax(xData + xErrorPlus) # Compute y bounds if yError is None: self.yMin, self.yMax = min_max(yData, min_positive=False) else: # Takes the error into account if hasattr(yError, 'shape') and len(yError.shape) == 2: yErrorMinus, yErrorPlus = yError[0], yError[1] else: yErrorMinus, yErrorPlus = yError, yError self.yMin = numpy.nanmin(yData - yErrorMinus) self.yMax = numpy.nanmax(yData + yErrorPlus) # Handle data offset if xData.itemsize > 4 or yData.itemsize > 4: # Use normalization # offset data, do not offset error as it is relative self.offset = self.xMin, self.yMin self.xData = (xData - self.offset[0]).astype(numpy.float32) self.yData = (yData - self.offset[1]).astype(numpy.float32) else: # float32 self.offset = 0., 0. self.xData = xData self.yData = yData if fillColor is not None: # Use different baseline depending of Y log scale self.fill = _Fill2D(self.xData, self.yData, baseline=-38 if isYLog else 0, color=fillColor, offset=self.offset) else: self.fill = None self._errorBars = _ErrorBars(self.xData, self.yData, xError, yError, self.xMin, self.yMin, offset=self.offset) self.lines = GLLines2D() self.lines.style = lineStyle self.lines.color = lineColor self.lines.width = lineWidth self.lines.dashPeriod = lineDashPeriod self.lines.offset = self.offset self.points = _Points2D() self.points.marker = marker self.points.color = markerColor self.points.size = markerSize self.points.offset = self.offset
def __init__(self, xData, yData, colorData=None, xError=None, yError=None, lineStyle=SOLID, lineColor=(0., 0., 0., 1.), lineWidth=1, lineDashPeriod=20, marker=SQUARE, markerColor=(0., 0., 0., 1.), markerSize=7, fillColor=None, baseline=None, isYLog=False): self.colorData = colorData # Compute x bounds if xError is None: self.xMin, self.xMax = min_max(xData, min_positive=False) else: # Takes the error into account if hasattr(xError, 'shape') and len(xError.shape) == 2: xErrorMinus, xErrorPlus = xError[0], xError[1] else: xErrorMinus, xErrorPlus = xError, xError self.xMin = numpy.nanmin(xData - xErrorMinus) self.xMax = numpy.nanmax(xData + xErrorPlus) # Compute y bounds if yError is None: self.yMin, self.yMax = min_max(yData, min_positive=False) else: # Takes the error into account if hasattr(yError, 'shape') and len(yError.shape) == 2: yErrorMinus, yErrorPlus = yError[0], yError[1] else: yErrorMinus, yErrorPlus = yError, yError self.yMin = numpy.nanmin(yData - yErrorMinus) self.yMax = numpy.nanmax(yData + yErrorPlus) # Handle data offset if xData.itemsize > 4 or yData.itemsize > 4: # Use normalization # offset data, do not offset error as it is relative self.offset = self.xMin, self.yMin self.xData = (xData - self.offset[0]).astype(numpy.float32) self.yData = (yData - self.offset[1]).astype(numpy.float32) else: # float32 self.offset = 0., 0. self.xData = xData self.yData = yData if fillColor is not None: def deduce_baseline(baseline): if baseline is None: _baseline = 0 else: _baseline = baseline if not isinstance(_baseline, numpy.ndarray): _baseline = numpy.repeat(_baseline, len(self.xData)) if isYLog is True: with numpy.errstate(divide='ignore', invalid='ignore'): log_val = numpy.log10(_baseline) _baseline = numpy.where(_baseline > 0.0, log_val, -38) return _baseline _baseline = deduce_baseline(baseline) # Use different baseline depending of Y log scale self.fill = _Fill2D(self.xData, self.yData, baseline=_baseline, color=fillColor, offset=self.offset) else: self.fill = None self._errorBars = _ErrorBars(self.xData, self.yData, xError, yError, self.xMin, self.yMin, offset=self.offset) self.lines = GLLines2D() self.lines.style = lineStyle self.lines.color = lineColor self.lines.width = lineWidth self.lines.dashPeriod = lineDashPeriod self.lines.offset = self.offset self.points = _Points2D() self.points.marker = marker self.points.color = markerColor self.points.size = markerSize self.points.offset = self.offset
def _updateFromItem(self): """Update histogram and stats from the item""" item = self.getItem() if item is None: self.reset() return if not isinstance(item, self._SUPPORTED_ITEM_CLASS): _logger.error("Unsupported item", item) self.reset() return # Compute histogram and stats array = item.getValueData(copy=False) if array.size == 0: self.reset() return xmin, xmax = min_max(array, min_positive=False, finite=True) if xmin is None or xmax is None: # All not finite data self.reset() return guessed_nbins = min(1024, int(numpy.sqrt(array.size))) # bad hack: get 256 bins in the case we have a B&W if numpy.issubdtype(array.dtype, numpy.integer): if guessed_nbins > xmax - xmin: guessed_nbins = xmax - xmin guessed_nbins = max(2, guessed_nbins) # Set default nbins self.__nbinsLineEdit.setDefaultValue(guessed_nbins, extend_range=True) # Set slider range: do not keep the range value, but the relative pos. previousPositions = self.__rangeSlider.getPositions() if xmin == xmax: # Enlarge range is none if xmin == 0: range_ = -0.01, 0.01 else: range_ = sorted((xmin * .99, xmin * 1.01)) else: range_ = xmin, xmax self.__rangeSlider.setRange(*range_) self.__rangeSlider.setPositions(*previousPositions) histogram = Histogramnd( array.ravel().astype(numpy.float32), n_bins=max(2, self.__nbinsLineEdit.getValue()), histo_range=self.__rangeSlider.getValues(), ) if len(histogram.edges) != 1: _logger.error("Error while computing the histogram") self.reset() return self.setHistogram(histogram.histo, histogram.edges[0]) self.resetZoom() self.setStatistics(min_=xmin, max_=xmax, mean=numpy.nanmean(array), std=numpy.nanstd(array), sum_=numpy.nansum(array))
def autoscaleMinMax(self, data): result = min_max(data, min_positive=True, finite=True) return result.min_positive, result.maximum
def __init__(self, xData, yData, colorData=None, xError=None, yError=None, lineStyle=None, lineColor=None, lineWidth=None, lineDashPeriod=None, marker=None, markerColor=None, markerSize=None, fillColor=None): self._isXLog = False self._isYLog = False self.xData, self.yData, self.colorData = xData, yData, colorData if fillColor is not None: self.fill = _Fill2D(color=fillColor) else: self.fill = None # Compute x bounds if xError is None: result = min_max(xData, min_positive=True) self.xMin = result.minimum self.xMinPos = result.min_positive self.xMax = result.maximum else: # Takes the error into account if hasattr(xError, 'shape') and len(xError.shape) == 2: xErrorPlus, xErrorMinus = xError[0], xError[1] else: xErrorPlus, xErrorMinus = xError, xError result = min_max(xData - xErrorMinus, min_positive=True) self.xMin = result.minimum self.xMinPos = result.min_positive self.xMax = (xData + xErrorPlus).max() # Compute y bounds if yError is None: result = min_max(yData, min_positive=True) self.yMin = result.minimum self.yMinPos = result.min_positive self.yMax = result.maximum else: # Takes the error into account if hasattr(yError, 'shape') and len(yError.shape) == 2: yErrorPlus, yErrorMinus = yError[0], yError[1] else: yErrorPlus, yErrorMinus = yError, yError result = min_max(yData - yErrorMinus, min_positive=True) self.yMin = result.minimum self.yMinPos = result.min_positive self.yMax = (yData + yErrorPlus).max() self._errorBars = _ErrorBars(xData, yData, xError, yError, self.xMin, self.yMin) kwargs = {'style': lineStyle} if lineColor is not None: kwargs['color'] = lineColor if lineWidth is not None: kwargs['width'] = lineWidth if lineDashPeriod is not None: kwargs['dashPeriod'] = lineDashPeriod self.lines = _Lines2D(**kwargs) kwargs = {'marker': marker} if markerColor is not None: kwargs['color'] = markerColor if markerSize is not None: kwargs['size'] = markerSize self.points = _Points2D(**kwargs)