class _TestRoiStatsBase(TestCaseQt): """Base class for several unittest relative to ROIStatsWidget""" def setUp(self): TestCaseQt.setUp(self) # define plot self.plot = PlotWindow() self.plot.addImage(numpy.arange(10000).reshape(100, 100), legend='img1') self.img_item = self.plot.getImage('img1') self.plot.addCurve(x=numpy.linspace(0, 10, 56), y=numpy.arange(56), legend='curve1') self.curve_item = self.plot.getCurve('curve1') self.plot.addHistogram(edges=numpy.linspace(0, 10, 56), histogram=numpy.arange(56), legend='histo1') self.histogram_item = self.plot.getHistogram(legend='histo1') self.plot.addScatter(x=numpy.linspace(0, 10, 56), y=numpy.linspace(0, 10, 56), value=numpy.arange(56), legend='scatter1') self.scatter_item = self.plot.getScatter(legend='scatter1') # stats widget self.statsWidget = ROIStatsWidget(plot=self.plot) # define stats stats = [ ('sum', numpy.sum), ('mean', numpy.mean), ] self.statsWidget.setStats(stats=stats) # define rois self.roi1D = ROI(name='range1', fromdata=0, todata=4, type_='energy') self.rectangle_roi = RectangleROI() self.rectangle_roi.setGeometry(origin=(0, 0), size=(20, 20)) self.rectangle_roi.setName('Initial ROI') self.polygon_roi = PolygonROI() points = numpy.array([[0, 5], [5, 0], [10, 5], [5, 10]]) self.polygon_roi.setPoints(points) def statsTable(self): return self.statsWidget._statsROITable def tearDown(self): Stats._getContext.cache_clear() self.statsWidget.setAttribute(qt.Qt.WA_DeleteOnClose, True) self.statsWidget.close() self.statsWidget = None self.plot.setAttribute(qt.Qt.WA_DeleteOnClose, True) self.plot.close() self.plot = None TestCaseQt.tearDown(self)
def get_2D_rois(): """return some RectangleROI instance""" rectangle_roi = RectangleROI() rectangle_roi.setGeometry(origin=(0, 100), size=(20, 20)) rectangle_roi.setName('Initial ROI') polygon_roi = PolygonROI() polygon_points = numpy.array([(0, 10), (10, 20), (45, 30), (35, 0)]) polygon_roi.setPoints(polygon_points) polygon_roi.setName('polygon ROI') arc_roi = ArcROI() arc_roi.setName('arc ROI') arc_roi.setFirstShapePoints(numpy.array([[50, 10], [80, 120]])) arc_roi.setGeometry(*arc_roi.getGeometry()) return rectangle_roi, polygon_roi, arc_roi
def test(self): """Test stats result on an image context with different scale and origins""" roi_origins = [(0, 0), (2, 10), (14, 20)] img_origins = [(0, 0), (14, 20), (2, 10)] img_scales = [1.0, 0.5, 2.0] _stats = { 'sum': stats.Stat(name='sum', fct=numpy.sum), } for roi_origin in roi_origins: for img_origin in img_origins: for img_scale in img_scales: with self.subTest(roi_origin=roi_origin, img_origin=img_origin, img_scale=img_scale): self.plot.addImage(self.data, legend='img', origin=img_origin, scale=img_scale) roi = RectangleROI() roi.setGeometry(origin=roi_origin, size=(20, 20)) context = stats._ImageContext( item=self.plot.getImage('img'), plot=self.plot, onlimits=False, roi=roi) x_start = int( (roi_origin[0] - img_origin[0]) / img_scale) x_end = int(x_start + (20 / img_scale)) + 1 y_start = int( (roi_origin[1] - img_origin[1]) / img_scale) y_end = int(y_start + (20 / img_scale)) + 1 x_start = max(x_start, 0) x_end = min(max(x_end, 0), self.data_dims[1]) y_start = max(y_start, 0) y_end = min(max(y_end, 0), self.data_dims[0]) th_sum = numpy.sum(self.data[y_start:y_end, x_start:x_end]) self.assertAlmostEqual( _stats['sum'].calculate(context), th_sum)
if roi.getName() == '': roi.setName('ROI %d' % len(roiManager.getRois())) if isinstance(roi, LineMixIn): roi.setLineWidth(1) roi.setLineStyle('--') if isinstance(roi, SymbolMixIn): roi.setSymbolSize(5) roi.setSelectable(True) roi.setEditable(True) roiManager.sigRoiAdded.connect(updateAddedRegionOfInterest) # Add a rectangular region of interest roi = RectangleROI() roi.setGeometry(origin=(50, 50), size=(200, 200)) roi.setName('Initial ROI') roiManager.addRoi(roi) # Create the table widget displaying roiTable = RegionOfInterestTableWidget() roiTable.setRegionOfInterestManager(roiManager) # Create a toolbar containing buttons for all ROI 'drawing' modes roiToolbar = qt.QToolBar() # The layout to store the buttons roiToolbar.setIconSize(qt.QSize(16, 16)) for roiClass in roiManager.getSupportedRoiClasses(): # Create a tool button and associate it with the QAction of each mode action = roiManager.getInteractionModeAction(roiClass) roiToolbar.addAction(action)
"""Called for each added region of interest: set the name""" if roi.getLabel() == '': roi.setLabel('ROI %d' % len(roiManager.getRois())) if isinstance(roi, LineMixIn): roi.setLineWidth(2) roi.setLineStyle('--') if isinstance(roi, SymbolMixIn): roi.setSymbol('o') roi.setSymbolSize(5) roiManager.sigRoiAdded.connect(updateAddedRegionOfInterest) # Add a rectangular region of interest roi = RectangleROI() roi.setGeometry(origin=(50, 50), size=(200, 200)) roi.setLabel('Initial ROI') roiManager.addRoi(roi) # Create the table widget displaying roiTable = RegionOfInterestTableWidget() roiTable.setRegionOfInterestManager(roiManager) # Create a toolbar containing buttons for all ROI 'drawing' modes roiToolbar = qt.QToolBar() # The layout to store the buttons roiToolbar.setIconSize(qt.QSize(16, 16)) for roiClass in roiManager.getSupportedRoiClasses(): # Create a tool button and associate it with the QAction of each mode action = roiManager.getInteractionModeAction(roiClass) roiToolbar.addAction(action)
class TestStatsROI(TestStatsBase, TestCaseQt): """ Test stats based on ROI """ def setUp(self): TestCaseQt.setUp(self) self.createRois() TestStatsBase.setUp(self) self.createHistogramContext() self.roiManager = RegionOfInterestManager(self.plot2d) self.roiManager.addRoi(self._2Droi_rect) self.roiManager.addRoi(self._2Droi_poly) def tearDown(self): self.roiManager.clear() self.roiManager = None self._1Droi = None self._2Droi_rect = None self._2Droi_poly = None self.plotHisto.setAttribute(qt.Qt.WA_DeleteOnClose) self.plotHisto.close() self.plotHisto = None TestStatsBase.tearDown(self) TestCaseQt.tearDown(self) def createRois(self): self._1Droi = ROI(name='my1DRoi', fromdata=2.0, todata=5.0) self._2Droi_rect = RectangleROI() self._2Droi_rect.setGeometry(size=(10, 10), origin=(10, 0)) self._2Droi_poly = PolygonROI() points = numpy.array(((0, 20), (0, 0), (10, 0))) self._2Droi_poly.setPoints(points=points) def createCurveContext(self): TestStatsBase.createCurveContext(self) self.curveContext = stats._CurveContext( item=self.plot1d.getCurve('curve0'), plot=self.plot1d, onlimits=False, roi=self._1Droi) def createHistogramContext(self): self.plotHisto = Plot1D() x = range(20) y = range(20) self.plotHisto.addHistogram(x, y, legend='histo0') self.histoContext = stats._HistogramContext( item=self.plotHisto.getHistogram('histo0'), plot=self.plotHisto, onlimits=False, roi=self._1Droi) def createScatterContext(self): TestStatsBase.createScatterContext(self) self.scatterContext = stats._ScatterContext( item=self.scatterPlot.getScatter('scatter plot'), plot=self.scatterPlot, onlimits=False, roi=self._1Droi) def createImageContext(self): TestStatsBase.createImageContext(self) self.imageContext = stats._ImageContext(item=self.plot2d.getImage( self._imgLgd), plot=self.plot2d, onlimits=False, roi=self._2Droi_rect) self.imageContext_2 = stats._ImageContext(item=self.plot2d.getImage( self._imgLgd), plot=self.plot2d, onlimits=False, roi=self._2Droi_poly) def testErrors(self): # test if onlimits is True and give also a roi with self.assertRaises(ValueError): stats._CurveContext(item=self.plot1d.getCurve('curve0'), plot=self.plot1d, onlimits=True, roi=self._1Droi) # test if is a curve context and give an invalid 2D roi with self.assertRaises(TypeError): stats._CurveContext(item=self.plot1d.getCurve('curve0'), plot=self.plot1d, onlimits=False, roi=self._2Droi_rect) def testBasicStatsCurve(self): """Test result for simple stats on a curve""" _stats = self.getBasicStats() xData = yData = numpy.array(range(0, 10)) self.assertEqual(_stats['min'].calculate(self.curveContext), 2) self.assertEqual(_stats['max'].calculate(self.curveContext), 5) self.assertEqual(_stats['minCoords'].calculate(self.curveContext), (2, )) self.assertEqual(_stats['maxCoords'].calculate(self.curveContext), (5, )) self.assertEqual(_stats['std'].calculate(self.curveContext), numpy.std(yData[2:6])) self.assertEqual(_stats['mean'].calculate(self.curveContext), numpy.mean(yData[2:6])) com = numpy.sum(xData[2:6] * yData[2:6]) / numpy.sum(yData[2:6]) self.assertEqual(_stats['com'].calculate(self.curveContext), com) def testBasicStatsImageRectRoi(self): """Test result for simple stats on an image""" self.assertEqual(self.imageContext.values.compressed().size, 121) _stats = self.getBasicStats() self.assertEqual(_stats['min'].calculate(self.imageContext), 10) self.assertEqual(_stats['max'].calculate(self.imageContext), 1300) self.assertEqual(_stats['minCoords'].calculate(self.imageContext), (10, 0)) self.assertEqual(_stats['maxCoords'].calculate(self.imageContext), (20.0, 10.0)) self.assertAlmostEqual(_stats['std'].calculate(self.imageContext), numpy.std(self.imageData[0:11, 10:21])) self.assertAlmostEqual(_stats['mean'].calculate(self.imageContext), numpy.mean(self.imageData[0:11, 10:21])) compressed_values = self.imageContext.values.compressed() compressed_values = compressed_values.reshape(11, 11) yData = numpy.sum(compressed_values.astype(numpy.float64), axis=1) xData = numpy.sum(compressed_values.astype(numpy.float64), axis=0) dataYRange = range(11) dataXRange = range(10, 21) ycom = numpy.sum(yData * dataYRange) / numpy.sum(yData) xcom = numpy.sum(xData * dataXRange) / numpy.sum(xData) self.assertEqual(_stats['com'].calculate(self.imageContext), (xcom, ycom)) def testBasicStatsImagePolyRoi(self): """Test a simple rectangle ROI""" _stats = self.getBasicStats() self.assertEqual(_stats['min'].calculate(self.imageContext_2), 0) self.assertEqual(_stats['max'].calculate(self.imageContext_2), 2432) self.assertEqual(_stats['minCoords'].calculate(self.imageContext_2), (0.0, 0.0)) # not 0.0, 19.0 because not fully in. Should all pixel have a weight, # on to manage them in stats. For now 0 if the center is not in, else 1 self.assertEqual(_stats['maxCoords'].calculate(self.imageContext_2), (0.0, 19.0)) def testBasicStatsScatter(self): self.assertEqual(self.scatterContext.values.compressed().size, 2) _stats = self.getBasicStats() self.assertEqual(_stats['min'].calculate(self.scatterContext), 6) self.assertEqual(_stats['max'].calculate(self.scatterContext), 7) self.assertEqual(_stats['minCoords'].calculate(self.scatterContext), (2, 3)) self.assertEqual(_stats['maxCoords'].calculate(self.scatterContext), (3, 4)) self.assertEqual(_stats['std'].calculate(self.scatterContext), numpy.std([6, 7])) self.assertEqual(_stats['mean'].calculate(self.scatterContext), numpy.mean([6, 7])) def testBasicHistogram(self): _stats = self.getBasicStats() xData = yData = numpy.array(range(2, 6)) self.assertEqual(_stats['min'].calculate(self.histoContext), 2) self.assertEqual(_stats['max'].calculate(self.histoContext), 5) self.assertEqual(_stats['minCoords'].calculate(self.histoContext), (2, )) self.assertEqual(_stats['maxCoords'].calculate(self.histoContext), (5, )) self.assertEqual(_stats['std'].calculate(self.histoContext), numpy.std(yData)) self.assertEqual(_stats['mean'].calculate(self.histoContext), numpy.mean(yData)) com = numpy.sum(xData * yData) / numpy.sum(yData) self.assertEqual(_stats['com'].calculate(self.histoContext), com)