def testColomap(self): dialog = self.createDialog() colormap = dialog.colormap() self.assertEqual(colormap.getNormalization(), "linear") colormap = Colormap(normalization=Colormap.LOGARITHM) dialog.setColormap(colormap) self.assertEqual(colormap.getNormalization(), "log")
def restoreSettings(self): """Restore the settings of all the application""" settings = self.__settings if settings is None: return parent = self.__parent() parent.restoreSettings(settings) settings.beginGroup("colormap") byteArray = settings.value("default", None) if byteArray is not None: try: colormap = Colormap() colormap.restoreState(byteArray) self.__defaultColormap = colormap except Exception: _logger.debug("Backtrace", exc_info=True) settings.endGroup() self.__recentFiles = [] settings.beginGroup("recent-files") for index in range(1, 10 + 1): if not settings.contains("path%d" % index): break filePath = settings.value("path%d" % index) self.__recentFiles.append(filePath) settings.endGroup()
def __getPixmap(self): if self.__pixmap is not None: return self.__pixmap calibrant = self.__getConfiguredCalibrant() if calibrant is None: return None tths = numpy.array(calibrant.get_2th()) tth_min, tth_max = 0, numpy.pi size = 360 agregation = numpy.zeros((1, size)) for tth in tths: pos = int((tth - tth_min) / (tth_max - tth_min) * size) if pos < 0: continue if pos >= size: continue agregation[0, pos] += 1 agregation = -agregation colormap = Colormap() rgbImage = colormap.applyToData(agregation)[:, :, :3] qimage = imageutils.convertArrayToQImage(rgbImage) qpixmap = qt.QPixmap.fromImage(qimage) self.__pixmap = qpixmap return self.__pixmap
def testSet(self): colormap = Colormap() other = Colormap(name="viridis", vmin=1, vmax=2, normalization=Colormap.LOGARITHM) self.assertNotEqual(colormap, other) colormap.setFromColormap(other) self.assertIsNot(colormap, other) self.assertEqual(colormap, other)
def testNumericalColors(self): """Make sure the old API using colors=int was supported""" clm_dict = { 'name': 'temperature', 'vmin': 1.0, 'vmax': 2.0, 'colors': 256, 'autoscale': False } Colormap._fromDict(clm_dict)
def getFreeColorRange(colormap): name = colormap['name'] colormap = Colormap(name) # extract all hues from colormap colors = colormap.getNColors() hues = [] for c in colors: c = qt.QColor.fromRgb(c[0], c[1], c[2]) hues.append(c.hueF()) # search the bigger empty hue range current = (0, 0.0, 0.2) hues = filter(lambda x: x >= 0, set(hues)) hues = list(sorted(hues)) if len(hues) > 1: for i in range(len(hues)): h1 = hues[i] h2 = hues[(i + 1) % len(hues)] if h2 < h1: h2 = h2 + 1.0 diff = h2 - h1 if diff > 0.5: diff = 1.0 - diff if diff > current[0]: current = diff, h1, h2 elif len(hues) == 1: h = (hues[0] + 0.5) % 1.0 current = (0, h - 0.1, h + 0.1) else: pass h1, h2 = current[1:] delta = (h2 - h1) / 6.0 # move the range from the colormap h1, h2 = h1 + delta, h2 - delta hmin = (h1 + h2) / 2.0 # generate colors with 3 hsv control points # (h1, 1, 1), (hmid, 1, 0.5), (h2, 1, 1) colors = [] for i in range(5): h = h1 + (hmin - h1) * (i / 5.0) v = 0.5 + 0.1 * (5 - i) c = qt.QColor.fromHsvF(h % 1.0, 1.0, v) colors.append(c) for i in range(5): h = hmin + (h2 - hmin) * (i / 5.0) v = 0.5 + 0.1 * (i) c = qt.QColor.fromHsvF(h % 1.0, 1.0, v) colors.append(c) return colors
def testGetNColors(self): """Test getNColors method""" # specific LUT colormap = Colormap(name=None, colors=((0., 0., 0.), (1., 1., 1.)), vmin=1000, vmax=2000) colors = colormap.getNColors() self.assertTrue(numpy.all(numpy.equal( colors, ((0, 0, 0, 255), (255, 255, 255, 255)))))
def testMissingKeysFromDict(self): """Make sure we can create a Colormap object from a dictionnary even if there is missing keys excepts if those keys are 'colors' or 'name' """ colormap = Colormap._fromDict({'name': 'toto'}) self.assertTrue(colormap.getVMin() is None) colormap = Colormap._fromDict({'colors': numpy.zeros(10)}) self.assertTrue(colormap.getName() is None) with self.assertRaises(ValueError): Colormap._fromDict({})
def testUnknowNorm(self): """Make sure an error is raised if the given normalization is not knowed """ clm_dict = { 'name': 'temperature', 'vmin': 1.0, 'vmax': 2.0, 'normalization': 'toto', 'colors': None, 'autoscale': False } with self.assertRaises(ValueError): Colormap._fromDict(clm_dict)
def testGetDict(self): """Test the getDict function API""" clmObject = Colormap(name='viridis', normalization=Colormap.LINEAR, vmin=self.vmin, vmax=self.vmax) clmDict = clmObject._toDict() self.assertTrue(clmDict['name'] == 'viridis') self.assertTrue(clmDict['autoscale'] is False) self.assertTrue(clmDict['vmin'] == self.vmin) self.assertTrue(clmDict['vmax'] == self.vmax) self.assertTrue(clmDict['normalization'] == Colormap.LINEAR) clmObject.setVRange(None, None) self.assertTrue(clmObject._toDict()['autoscale'] is True)
def testSetValidDict(self): """Test that if a colormap is created from a dict then it is correctly created and the values are copied (so if some values from the dict is changing, this won't affect the Colormap object""" clm_dict = { 'name': 'temperature', 'vmin': 1.0, 'vmax': 2.0, 'normalization': 'linear', 'colors': None, 'autoscale': False } # Test that the colormap is correctly created colormapObject = Colormap._fromDict(clm_dict) self.assertTrue(colormapObject.getName() == clm_dict['name']) self.assertTrue(colormapObject.getColormapLUT() == clm_dict['colors']) self.assertTrue(colormapObject.getVMin() == clm_dict['vmin']) self.assertTrue(colormapObject.getVMax() == clm_dict['vmax']) self.assertTrue(colormapObject.isAutoscale() == clm_dict['autoscale']) # Check that the colormap has copied the values clm_dict['vmin'] = None clm_dict['vmax'] = None clm_dict['colors'] = [1.0, 2.0] clm_dict['autoscale'] = True clm_dict['normalization'] = Colormap.LOGARITHM clm_dict['name'] = 'viridis' self.assertFalse(colormapObject.getName() == clm_dict['name']) self.assertFalse(colormapObject.getColormapLUT() == clm_dict['colors']) self.assertFalse(colormapObject.getVMin() == clm_dict['vmin']) self.assertFalse(colormapObject.getVMax() == clm_dict['vmax']) self.assertFalse(colormapObject.isAutoscale() == clm_dict['autoscale'])
def getFirstNotPreferredColormap(): cms = Colormap.getSupportedColormaps() preferred = preferredColormaps() for cm in cms: if cm not in preferred: return cm return None
def testApplyColormapToData(self): """Simple test of applyColormapToData function""" colormap = Colormap(name='gray', normalization='linear', vmin=0, vmax=255) size = 10 expected = numpy.empty((size, 4), dtype='uint8') expected[:, 0] = numpy.arange(size, dtype='uint8') expected[:, 1] = expected[:, 0] expected[:, 2] = expected[:, 0] expected[:, 3] = 255 for dtype in ('uint8', 'int32', 'float32', 'float64'): with self.subTest(dtype=dtype): array = numpy.arange(size, dtype=dtype) result = colormap.applyToData(data=array) self.assertTrue(numpy.all(numpy.equal(result, expected)))
def setUp(self): TestCaseQt.setUp(self) ParametricTestCase.setUp(self) self.colormap = Colormap(name='gray', vmin=10.0, vmax=20.0, normalization='linear') self.colormapDiag = ColormapDialog.ColormapDialog() self.colormapDiag.setAttribute(qt.Qt.WA_DeleteOnClose)
def testColormapEditableMode(self): """Test that the colormapDialog is correctly updated when changing the colormap editable status""" colormap = Colormap(normalization='linear', vmin=1.0, vmax=10.0) self.colormapDiag.show() self.colormapDiag.setColormap(colormap) for editable in (True, False): with self.subTest(editable=editable): colormap.setEditable(editable) self.assertTrue( self.colormapDiag._comboBoxColormap.isEnabled() is editable) self.assertTrue( self.colormapDiag._minValue.isEnabled() is editable) self.assertTrue( self.colormapDiag._maxValue.isEnabled() is editable) self.assertTrue( self.colormapDiag._normButtonLinear.isEnabled() is editable) self.assertTrue( self.colormapDiag._normButtonLog.isEnabled() is editable) # Make sure the reset button is also set to enable when edition mode is # False self.colormapDiag.setModal(False) colormap.setEditable(True) self.colormapDiag._normButtonLog.click() resetButton = self.colormapDiag._buttonsNonModal.button(qt.QDialogButtonBox.Reset) self.assertTrue(resetButton.isEnabled()) colormap.setEditable(False) self.assertFalse(resetButton.isEnabled())
def testUpdateColorMap(self): colormap = Colormap(name='gray', normalization='linear', vmin=0, vmax=1) # check inital state self.plot.addImage(data=self.data, colormap=colormap, legend='toto') self.plot.setActiveImage('toto') self.assertTrue(self.colorBar.getColorScaleBar().minVal == 0) self.assertTrue(self.colorBar.getColorScaleBar().maxVal == 1) self.assertTrue( self.colorBar.getColorScaleBar().getTickBar()._vmin == 0) self.assertTrue( self.colorBar.getColorScaleBar().getTickBar()._vmax == 1) self.assertTrue( self.colorBar.getColorScaleBar().getTickBar()._norm == "linear") # update colormap colormap.setVMin(0.5) self.assertTrue(self.colorBar.getColorScaleBar().minVal == 0.5) self.assertTrue( self.colorBar.getColorScaleBar().getTickBar()._vmin == 0.5) colormap.setVMax(0.8) self.assertTrue(self.colorBar.getColorScaleBar().maxVal == 0.8) self.assertTrue( self.colorBar.getColorScaleBar().getTickBar()._vmax == 0.8) colormap.setNormalization('log') self.assertTrue( self.colorBar.getColorScaleBar().getTickBar()._norm == 'log')
def testApplyToData(self): """Test applyToData on different datasets""" datasets = [ numpy.zeros((0, 0)), # Empty array numpy.array((numpy.nan, numpy.inf)), # All non-finite numpy.array((-numpy.inf, numpy.inf, 1.0, 2.0)), # Some infinite ] for normalization in ('linear', 'log'): colormap = Colormap(name='gray', normalization=normalization, vmin=None, vmax=None) for data in datasets: with self.subTest(data=data): image = colormap.applyToData(data) self.assertEqual(image.dtype, numpy.uint8) self.assertEqual(image.shape[-1], 4) self.assertEqual(image.shape[:-1], data.shape)
def testGetItem(self): """test the item getter API ([xxx])""" colormap = Colormap(name='viridis', normalization=Colormap.LINEAR, vmin=self.vmin, vmax=self.vmax) self.assertTrue(colormap['name'] == 'viridis') self.assertTrue(colormap['normalization'] == Colormap.LINEAR) self.assertTrue(colormap['vmin'] == self.vmin) self.assertTrue(colormap['vmax'] == self.vmax) with self.assertRaises(KeyError): colormap['toto']
def __init__(self, settings=None): super(CalibrationContext, self).__init__(settings=settings) assert (CalibrationContext.__instance is None) self.__defaultColormapDialog = None CalibrationContext.__instance = self self.__calibrationModel = None self.__rawColormap = Colormap("inferno", normalization=Colormap.LOGARITHM) self.__settings = settings self.__angleUnit = DataModel() self.__angleUnit.setValue(units.Unit.RADIAN) self.__lengthUnit = DataModel() self.__lengthUnit.setValue(units.Unit.METER) self.__wavelengthUnit = DataModel() self.__wavelengthUnit.setValue(units.Unit.ANGSTROM) self.__scatteringVectorUnit = DataModel() self.__scatteringVectorUnit.setValue(units.Unit.INV_ANGSTROM) self.__markerColors = {} self.__cacheStyles = {} self.sigStyleChanged = self.__rawColormap.sigChanged
def __init__(self): qt.QMainWindow.__init__(self) self.setWindowTitle("Plot with synchronized axes") widget = qt.QWidget(self) self.setCentralWidget(widget) layout = qt.QGridLayout() widget.setLayout(layout) backend = "gl" plots = [] data = numpy.arange(100 * 100) data = (data % 100) / 5.0 data = numpy.sin(data) data.shape = 100, 100 colormaps = ["gray", "red", "green", "blue"] for i in range(2 * 2): plot = Plot2D(parent=widget, backend=backend) plot.setInteractiveMode('pan') plot.setDefaultColormap(Colormap(colormaps[i])) noisyData = silx.test.utils.add_gaussian_noise(data, mean=i / 10.0) plot.addImage(noisyData) plots.append(plot) xAxis = [p.getXAxis() for p in plots] yAxis = [p.getYAxis() for p in plots] self.constraint1 = SyncAxes(xAxis, syncLimits=False, syncScale=True, syncDirection=True, syncCenter=True, syncZoom=True) self.constraint2 = SyncAxes(yAxis, syncLimits=False, syncScale=True, syncDirection=True, syncCenter=True, syncZoom=True) for i, plot in enumerate(plots): if i % 2 == 0: plot.setFixedWidth(400) else: plot.setFixedWidth(500) if i // 2 == 0: plot.setFixedHeight(400) else: plot.setFixedHeight(500) layout.addWidget(plot, i // 2, i % 2)
def testSetColormapScenario(self): """Test of a simple scenario of a colormap dialog editing several colormap""" colormap1 = Colormap(name='gray', vmin=10.0, vmax=20.0, normalization='linear') colormap2 = Colormap(name='red', vmin=10.0, vmax=20.0, normalization='log') colormap3 = Colormap(name='blue', vmin=None, vmax=None, normalization='linear') self.colormapDiag.setColormap(self.colormap) self.colormapDiag.setColormap(colormap1) del colormap1 self.colormapDiag.setColormap(colormap2) del colormap2 self.colormapDiag.setColormap(colormap3) del colormap3
def __updateKeyPoints(self): """Update the displayed keypoints using cached keypoints. """ if self.__keypointsVisible: data = self.__matching_keypoints else: data = [], [], [] self.__plot.addScatter(x=data[0], y=data[1], z=1, value=data[2], legend="keypoints", colormap=Colormap("spring"))
def testStorageV2(self): state = b'\x00\x00\x00\x10\x00C\x00o\x00l\x00o\x00r\x00m\x00a\x00p\x00'\ b'\x00\x00\x02\x00\x00\x00\x0e\x00v\x00i\x00r\x00i\x00d\x00i\x00'\ b's\x00\x00\x00\x00\x06\x00?\xf0\x00\x00\x00\x00\x00\x00\x00\x00'\ b'\x00\x00\x06\x00@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06'\ b'\x00l\x00o\x00g\x00\x00\x00\x0c\x00m\x00i\x00n\x00m\x00a\x00x' state = qt.QByteArray(state) colormap = Colormap() colormap.restoreState(state) expected = Colormap(name="viridis", vmin=1, vmax=2, normalization=Colormap.LOGARITHM) expected.setGammaNormalizationParameter(1.5) self.assertEqual(colormap, expected)
def testSaveRestoreState(self): dialog = self.createDialog() dialog.setDirectory(_tmpDirectory) colormap = Colormap(normalization=Colormap.LOGARITHM) dialog.setColormap(colormap) self.qWaitForPendingActions(dialog) state = dialog.saveState() dialog = None dialog2 = self.createDialog() result = dialog2.restoreState(state) self.qWaitForPendingActions(dialog2) self.assertTrue(result) self.assertTrue(dialog2.colormap().getNormalization(), "log")
def setUp(self): TestCaseQt.setUp(self) self.plot = PlotWindow() self.plot.setAttribute(qt.Qt.WA_DeleteOnClose) self.colormap1 = Colormap(name='blue', vmin=0.0, vmax=1.0, normalization='linear') self.colormap2 = Colormap(name='red', vmin=10.0, vmax=100.0, normalization='log') self.defaultColormap = self.plot.getDefaultColormap() self.plot.getColormapAction()._actionTriggered(checked=True) self.colormapDialog = self.plot.getColormapAction()._dialog self.colormapDialog.setAttribute(qt.Qt.WA_DeleteOnClose)
def testImageItem(self): """Check that an ImageData plot item can be used""" dialog = self.colormapDiag colormap = Colormap(name='gray', vmin=None, vmax=None) data = numpy.arange(3**2).reshape(3, 3) item = ImageData() item.setData(data, copy=False) dialog.setColormap(colormap) dialog.show() self.qapp.processEvents() dialog.setItem(item) vrange = dialog._getFiniteColormapRange() self.assertEqual(vrange, (0, 8))
def __init__(self, parent=None): super(ColormapDialogExample, self).__init__(parent) self.setWindowTitle("Colormap dialog example") self.colormap1 = Colormap("viridis") self.colormap2 = Colormap("gray") self.colorBar = ColorBarWidget(self) self.colorDialogs = [] options = qt.QWidget(self) options.setLayout(qt.QVBoxLayout()) self.createOptions(options.layout()) mainWidget = qt.QWidget(self) mainWidget.setLayout(qt.QHBoxLayout()) mainWidget.layout().addWidget(options) mainWidget.layout().addWidget(self.colorBar) self.mainWidget = mainWidget self.setCentralWidget(mainWidget) self.createColorDialog()
def __init__(self, parent=None, backend="gl"): super(SilxScatterWindow, self).__init__(parent) self.mainLayout = qt.QVBoxLayout(self) self._defaultSymbol = "s" self._defaultColormap = Colormap("temperature") self.plot = Plot2D(self, backend=backend) self.plot.setColormap(self._defaultColormap) self.plot.getPlotWidget().setDataMargins(0.05, 0.05, 0.05, 0.05) self.mainLayout.addWidget(self.plot) self._plotEnabled = True self.dataObjectsList = [] self.dataObjectsDict = {} self._xLabel = "X" self._yLabel = "Y"
def testDataDel(self): """Check that the data are not hard linked to the dialog""" dialog = self.colormapDiag colormap = Colormap(name='gray', vmin=None, vmax=None) data = numpy.arange(5) dialog.setColormap(colormap) dialog.show() self.qapp.processEvents() dialog.setData(data) previousRange = dialog._getFiniteColormapRange() del data vrange = dialog._getFiniteColormapRange() self.assertNotEqual(vrange, previousRange)
def _onLoad3DMesh(self, checked): legend, data = getMesh() if legend is None or data.ndim != 2: return xSize, ySize = data.shape x, y = numpy.meshgrid(numpy.arange(xSize), numpy.arange(ySize)) x = x.reshape(-1) y = y.reshape(-1) item3d = self._sceneGlWindow.getSceneWidget().add2DScatter(x=x, y=y, value=data) item3d.setVisualization("solid") # this is expensive for large images item3d.setHeightMap(True) item3d.setColormap(Colormap(name="temperature"))
def __init__(self, settings=None): assert(self.__class__._instance is None) self.__parent = None self.__defaultColormapDialog = None self.__class__._instance = self self.__calibrationModel = None self.__rawColormap = Colormap("inferno", normalization=Colormap.LOGARITHM) self.__settings = settings self.__angleUnit = DataModel() self.__angleUnit.setValue(units.Unit.RADIAN) self.__lengthUnit = DataModel() self.__lengthUnit.setValue(units.Unit.METER) self.__wavelengthUnit = DataModel() self.__wavelengthUnit.setValue(units.Unit.ANGSTROM) self.__dialogState = None self.__markerColors = {}
def testRelativePositionLog(self): self.colorMapLog1 = Colormap(name='temperature', normalization=Colormap.LOGARITHM, vmin=1.0, vmax=100.0) self.colorScaleWidget.setColormap(self.colorMapLog1) val = self.colorScaleWidget.getValueFromRelativePosition(1.0) self.assertAlmostEqual(val, 100.0) val = self.colorScaleWidget.getValueFromRelativePosition(0.5) self.assertAlmostEqual(val, 10.0) val = self.colorScaleWidget.getValueFromRelativePosition(0.0) self.assertTrue(val == 1.0)
def testItemDel(self): """Check that the plot items are not hard linked to the dialog""" dialog = self.colormapDiag colormap = Colormap(name='gray', vmin=None, vmax=None) data = numpy.arange(3**2).reshape(3, 3) item = ImageData() item.setData(data, copy=False) dialog.setColormap(colormap) dialog.show() self.qapp.processEvents() dialog.setItem(item) previousRange = dialog._getFiniteColormapRange() del item vrange = dialog._getFiniteColormapRange() self.assertNotEqual(vrange, previousRange)
def testCopy(self): """Make sure the copy function is correctly processing """ colormapObject = Colormap(name='toto', colors=numpy.array([12, 13, 14]), vmin=None, vmax=None, normalization=Colormap.LOGARITHM) colormapObject2 = colormapObject.copy() self.assertTrue(colormapObject == colormapObject2) colormapObject.setColormapLUT(numpy.array([0, 1])) self.assertFalse(colormapObject == colormapObject2) colormapObject2 = colormapObject.copy() self.assertTrue(colormapObject == colormapObject2) colormapObject.setNormalization(Colormap.LINEAR) self.assertFalse(colormapObject == colormapObject2)
def testAutoscaleRange(self): nan = numpy.nan data_std_inside = numpy.array( [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2]) data_std_inside_nan = numpy.array([ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, numpy.nan ]) data = [ # Positive values (Colormap.LINEAR, Colormap.MINMAX, numpy.array([10, 20, 50]), (10, 50)), (Colormap.LOGARITHM, Colormap.MINMAX, numpy.array([10, 50, 100]), (10, 100)), (Colormap.LINEAR, Colormap.STDDEV3, data_std_inside, (0.026671473215424735, 1.9733285267845753)), (Colormap.LOGARITHM, Colormap.STDDEV3, data_std_inside, (1, 1.6733506885453602)), (Colormap.LINEAR, Colormap.STDDEV3, numpy.array([10, 100]), (10, 100)), (Colormap.LOGARITHM, Colormap.STDDEV3, numpy.array([10, 100]), (10, 100)), # With nan (Colormap.LINEAR, Colormap.MINMAX, numpy.array([10, 20, 50, nan]), (10, 50)), (Colormap.LOGARITHM, Colormap.MINMAX, numpy.array([10, 50, 100, nan]), (10, 100)), (Colormap.LINEAR, Colormap.STDDEV3, data_std_inside_nan, (0.026671473215424735, 1.9733285267845753)), (Colormap.LOGARITHM, Colormap.STDDEV3, data_std_inside_nan, (1, 1.6733506885453602)), # With negative (Colormap.LOGARITHM, Colormap.MINMAX, numpy.array([10, 50, 100, -50]), (10, 100)), (Colormap.LOGARITHM, Colormap.STDDEV3, numpy.array([10, 100, -10]), (10, 100)), ] for norm, mode, array, expectedRange in data: with self.subTest(norm=norm, mode=mode, array=array): colormap = Colormap() colormap.setNormalization(norm) colormap.setAutoscaleMode(mode) vRange = colormap._computeAutoscaleRange(array) if vRange is None: self.assertIsNone(expectedRange) else: self.assertAlmostEqual(vRange[0], expectedRange[0]) self.assertAlmostEqual(vRange[1], expectedRange[1])
def __init__(self, parent=None, plot=None, mask=None): """ :param parent: Parent QWidget :param plot: Plot widget on which to operate :param mask: Instance of subclass of :class:`BaseMask` (e.g. :class:`ImageMask`) """ super(BaseMaskToolsWidget, self).__init__(parent) # register if the user as force a color for the corresponding mask level self._defaultColors = numpy.ones((self._maxLevelNumber + 1), dtype=numpy.bool) # overlays colors set by the user self._overlayColors = numpy.zeros((self._maxLevelNumber + 1, 3), dtype=numpy.float32) # as parent have to be the first argument of the widget to fit # QtDesigner need but here plot can't be None by default. assert plot is not None self._plotRef = weakref.ref(plot) self._maskName = '__MASK_TOOLS_%d' % id(self) # Legend of the mask self._colormap = Colormap(name="", normalization='linear', vmin=0, vmax=self._maxLevelNumber, colors=None) self._defaultOverlayColor = rgba('gray') # Color of the mask self._setMaskColors(1, 0.5) if not isinstance(mask, BaseMask): raise TypeError("mask is not an instance of BaseMask") self._mask = mask self._mask.sigChanged.connect(self._updatePlotMask) self._mask.sigChanged.connect(self._emitSigMaskChanged) self._drawingMode = None # Store current drawing mode self._lastPencilPos = None self._multipleMasks = 'exclusive' self._maskFileDir = qt.QDir.home().absolutePath() self.plot.sigInteractiveModeChanged.connect( self._interactiveModeChanged) self._initWidgets()
def test_imshow(self): """Test imshow function""" from silx import sx # Lazy loading to avoid it to create QApplication img = numpy.arange(100.).reshape(10, 10) + 1 # Nothing plt = sx.imshow() self._expose_and_close(plt) # image plt = sx.imshow(img) self._expose_and_close(plt) # image, named cmap plt = sx.imshow(img, cmap='jet', title='jet cmap') self._expose_and_close(plt) # image, custom colormap plt = sx.imshow(img, cmap=Colormap(), title='custom colormap') self._expose_and_close(plt) # image, log cmap plt = sx.imshow(img, norm='log', title='log cmap') self._expose_and_close(plt) # image, fixed range plt = sx.imshow(img, vmin=10, vmax=20, title='[10,20] cmap') self._expose_and_close(plt) # image, keep ratio plt = sx.imshow(img, aspect=True, title='keep ratio') self._expose_and_close(plt) # image, change origin and scale plt = sx.imshow(img, origin=(10, 10), scale=(2, 2), title='origin=(10, 10), scale=(2, 2)') self._expose_and_close(plt) # image, origin='lower' plt = sx.imshow(img, origin='upper', title='origin="lower"') self._expose_and_close(plt)
def testCopy(self): """Make sure the copy function is correctly processing """ colormapObject = Colormap(name=None, colors=numpy.array([[1., 0., 0.], [0., 1., 0.], [0., 0., 1.]]), vmin=None, vmax=None, normalization=Colormap.LOGARITHM) colormapObject2 = colormapObject.copy() self.assertTrue(colormapObject == colormapObject2) colormapObject.setColormapLUT([[0, 0, 0], [255, 255, 255]]) self.assertFalse(colormapObject == colormapObject2) colormapObject2 = colormapObject.copy() self.assertTrue(colormapObject == colormapObject2) colormapObject.setNormalization(Colormap.LINEAR) self.assertFalse(colormapObject == colormapObject2)
def testNaNColor(self): """Test Colormap.applyToData with NaN values""" colormap = Colormap(name='gray', normalization='linear') colormap.setNaNColor('red') self.assertEqual(colormap.getNaNColor(), qt.QColor(255, 0, 0)) data = numpy.array([50., numpy.nan]) image = items.ImageData() image.setData(numpy.array([[0, 100]])) value = colormap.applyToData(data, reference=image) self.assertEqual(len(value), 2) self.assertTrue(numpy.array_equal(value[0], (128, 128, 128, 255))) self.assertTrue(numpy.array_equal(value[1], (255, 0, 0, 255)))
def __init__(self, parent=None, backend="mpl"): qt.QMainWindow.__init__(self, parent) self._scatterView = ScatterView(parent=self, backend=backend) self._scatterView.setColormap(Colormap("temperature")) self._scatterView.getScatterItem().setSymbol("s") self._axesSelector = AxesPositionersSelector(parent=self._scatterView) self._axesSelector.sigSelectionChanged.connect(self._setAxesData) self.setCentralWidget(self._scatterView) _axesSelectorDock = BoxLayoutDockWidget() _axesSelectorDock.setWindowTitle('Axes selection') _axesSelectorDock.setWidget(self._axesSelector) self.addDockWidget(qt.Qt.BottomDockWidgetArea, _axesSelectorDock) self._positioners = {} self._xdata = None self._ydata = None self._stackImage = None
def __init__(self, parent=None): """ :param parent: Parent QWidget """ super(ArrayImagePlot, self).__init__(parent) self.__signals = None self.__signals_names = None self.__x_axis = None self.__x_axis_name = None self.__y_axis = None self.__y_axis_name = None self._plot = Plot2D(self) self._plot.setDefaultColormap( Colormap(name="viridis", vmin=None, vmax=None, normalization=Colormap.LINEAR)) self._plot.getIntensityHistogramAction().setVisible(True) self.selectorDock = qt.QDockWidget("Data selector", self._plot) # not closable self.selectorDock.setFeatures(qt.QDockWidget.DockWidgetMovable | qt.QDockWidget.DockWidgetFloatable) self._selector = NumpyAxesSelector(self.selectorDock) self._selector.setNamedAxesSelectorVisibility(False) self._selector.selectionChanged.connect(self._updateImage) self._auxSigSlider = HorizontalSliderWithBrowser(parent=self) self._auxSigSlider.setMinimum(0) self._auxSigSlider.setValue(0) self._auxSigSlider.valueChanged[int].connect(self._sliderIdxChanged) self._auxSigSlider.setToolTip("Select auxiliary signals") layout = qt.QVBoxLayout() layout.addWidget(self._plot) layout.addWidget(self._auxSigSlider) self.selectorDock.setWidget(self._selector) self._plot.addTabbedDockWidget(self.selectorDock) self.setLayout(layout)
def test_imshow(sx, qapp_utils): """Test imshow function""" img = numpy.arange(100.).reshape(10, 10) + 1 # Nothing plt = sx.imshow() qapp_utils.exposeAndClose(plt) # image plt = sx.imshow(img) qapp_utils.exposeAndClose(plt) # image, named cmap plt = sx.imshow(img, cmap='jet', title='jet cmap') qapp_utils.exposeAndClose(plt) # image, custom colormap plt = sx.imshow(img, cmap=Colormap(), title='custom colormap') qapp_utils.exposeAndClose(plt) # image, log cmap plt = sx.imshow(img, norm='log', title='log cmap') qapp_utils.exposeAndClose(plt) # image, fixed range plt = sx.imshow(img, vmin=10, vmax=20, title='[10,20] cmap') qapp_utils.exposeAndClose(plt) # image, keep ratio plt = sx.imshow(img, aspect=True, title='keep ratio') qapp_utils.exposeAndClose(plt) # image, change origin and scale plt = sx.imshow(img, origin=(10, 10), scale=(2, 2), title='origin=(10, 10), scale=(2, 2)') qapp_utils.exposeAndClose(plt) # image, origin='lower' plt = sx.imshow(img, origin='upper', title='origin="lower"') qapp_utils.exposeAndClose(plt)
def __init__(self, parent): super().__init__(parent=parent) self.scatter_view = ScatterView(self) colormap = Colormap('viridis', normalization='log') self.scatter_view.setGraphTitle("Stack of unfolded data") self.scatter_view.setColormap(colormap) self.plot = self.scatter_view.getPlotWidget() self.plot.setGraphXLabel("two-theta (°)") self.plot.setGraphYLabel("psi (°)") self.plot.setKeepDataAspectRatio(False) self.plot.setYAxisInverted(True) self.scatter_selector = NumpyAxesSelector(self) # Prevent user from changing dimensions for the plot self.scatter_selector.setNamedAxesSelectorVisibility(False) self.scatter_selector.setVisible(True) self.scatter_selector.setAxisNames("12") self.layout = QVBoxLayout(self) self.layout.addWidget(self.scatter_view) self.layout.addWidget(self.scatter_selector) self.stack = [] self.initial_data_flag = True self.toolbar = QToolBar("Custom toolbar 1") self.scatter_view.addToolBar(self.toolbar) self.action_unfold = Unfold(self.plot, parent=self) self.action_unfold_with_flatfield = UnfoldWithFlatfield(self.plot, parent=self) self.action_save = SaveAction(self.plot, parent=self) self.toolbar.addAction(self.action_unfold) self.toolbar.addAction(self.action_unfold_with_flatfield) self.toolbar.addAction(self.action_save) self.scatter_selector.selectionChanged.connect( self.change_displayed_data)
def generateGravityField(self): shape = 512 nb = numpy.random.randint(2, 10) objects = [] for _ in range(nb): x = numpy.random.random() * 2 - 1 y = numpy.random.random() * 2 - 1 m = numpy.random.random() * 10 + 1.0 objects.append((x, y, m)) image = create_gravity_field(shape, objects) self.__colormap = Colormap("inferno") self.setData(image=image, mask=None) delta = (image.max() - image.min()) / 30.0 values = numpy.arange(image.min(), image.max(), delta) def styleCallback(value, ivalue, ipolygon): return {"linestyle": "-", "linewidth": 0.1, "color": "white"} self.__drawContours(values, styleCallback) self.__defineDefaultValues()
def __init__(self, parent=None): """ :param parent: Parent QWidget """ super(XYVScatterPlot, self).__init__(parent) self.__y_axis = None """1D array""" self.__y_axis_name = None self.__values = None """List of 1D arrays (for multiple scatters with identical x, y coordinates)""" self.__x_axis = None self.__x_axis_name = None self.__x_axis_errors = None self.__y_axis = None self.__y_axis_name = None self.__y_axis_errors = None self._plot = ScatterView(self) self._plot.setColormap( Colormap(name="viridis", vmin=None, vmax=None, normalization=Colormap.LINEAR)) self._slider = HorizontalSliderWithBrowser(parent=self) self._slider.setMinimum(0) self._slider.setValue(0) self._slider.valueChanged[int].connect(self._sliderIdxChanged) self._slider.setToolTip("Select auxiliary signals") layout = qt.QGridLayout() layout.setContentsMargins(0, 0, 0, 0) layout.addWidget(self._plot, 0, 0) layout.addWidget(self._slider, 1, 0) self.setLayout(layout)
def generateIsland(self): shape = (512, 512) image = create_island(shape, summit=4808.72, under_water=1500) self.__colormap = Colormap("terrain") self.setData(image=image, mask=None) values = range(-800, 5000, 200) def styleCallback(value, ivalue, ipolygon): if value == 0: style = {"linestyle": "-", "linewidth": 1.0, "color": "black"} elif value % 1000 == 0: style = {"linestyle": "--", "linewidth": 0.5, "color": "black"} else: style = {"linestyle": "--", "linewidth": 0.1, "color": "black"} return style self.__drawContours(values, styleCallback) self.__value.setValue(0) self.__value.setRange(0, 5000) self.__updateCustomContours(0)
def testLinearNormNoAutoscale(self): colormapLog = Colormap(name='gray', normalization=Colormap.LINEAR, vmin=-4, vmax=5) data = numpy.linspace(1, 9, 9).reshape(3, 3) self.plot.addImage(data=data, colormap=colormapLog, legend='toto') self.plot.setActiveImage('toto') # test Ticks self.tickBar.setTicksNumber(10) self.tickBar.computeTicks() numpy.array_equal(self.tickBar.ticks, numpy.linspace(-4, 5, 10)) # test ColorScale val = self.colorScale.getValueFromRelativePosition(1.0) self.assertTrue(val == 5.0) val = self.colorScale.getValueFromRelativePosition(0.0) self.assertTrue(val == -4.0)
def testCopy(self): """Make sure the copy function is correctly processing """ colormapObject = Colormap(name='red', colors=numpy.array([[1., 0., 0.], [0., 1., 0.], [0., 0., 1.]]), vmin=None, vmax=None, normalization=Colormap.LOGARITHM) colormapObject2 = colormapObject.copy() self.assertTrue(colormapObject == colormapObject2) colormapObject.setColormapLUT([[0, 0, 0], [255, 255, 255]]) self.assertFalse(colormapObject == colormapObject2) colormapObject2 = colormapObject.copy() self.assertTrue(colormapObject == colormapObject2) colormapObject.setNormalization(Colormap.LINEAR) self.assertFalse(colormapObject == colormapObject2)
def testLogNormNoAutoscale(self): colormapLog = Colormap(name='gray', normalization=Colormap.LOGARITHM, vmin=1.0, vmax=100.0) data = numpy.linspace(10, 1e10, 9).reshape(3, 3) self.plot.addImage(data=data, colormap=colormapLog, legend='toto') self.plot.setActiveImage('toto') # test Ticks self.tickBar.setTicksNumber(10) self.tickBar.computeTicks() ticksTh = numpy.linspace(1.0, 100.0, 10) ticksTh = 10**ticksTh numpy.array_equal(self.tickBar.ticks, ticksTh) # test ColorScale val = self.colorScale.getValueFromRelativePosition(1.0) self.assertAlmostEqual(val, 100.0) val = self.colorScale.getValueFromRelativePosition(0.0) self.assertTrue(val == 1.0)
class TestColormapAction(TestCaseQt): def setUp(self): TestCaseQt.setUp(self) self.plot = PlotWindow() self.plot.setAttribute(qt.Qt.WA_DeleteOnClose) self.colormap1 = Colormap(name='blue', vmin=0.0, vmax=1.0, normalization='linear') self.colormap2 = Colormap(name='red', vmin=10.0, vmax=100.0, normalization='log') self.defaultColormap = self.plot.getDefaultColormap() self.plot.getColormapAction()._actionTriggered(checked=True) self.colormapDialog = self.plot.getColormapAction()._dialog self.colormapDialog.setAttribute(qt.Qt.WA_DeleteOnClose) def tearDown(self): self.colormapDialog.close() self.plot.close() del self.colormapDialog del self.plot TestCaseQt.tearDown(self) def testActiveColormap(self): self.assertTrue(self.colormapDialog.getColormap() is self.defaultColormap) self.plot.addImage(data=numpy.random.rand(10, 10), legend='img1', origin=(0, 0), colormap=self.colormap1) self.plot.setActiveImage('img1') self.assertTrue(self.colormapDialog.getColormap() is self.colormap1) self.plot.addImage(data=numpy.random.rand(10, 10), legend='img2', origin=(0, 0), colormap=self.colormap2) self.plot.addImage(data=numpy.random.rand(10, 10), legend='img3', origin=(0, 0)) self.plot.setActiveImage('img3') self.assertTrue(self.colormapDialog.getColormap() is self.defaultColormap) self.plot.getActiveImage().setColormap(self.colormap2) self.assertTrue(self.colormapDialog.getColormap() is self.colormap2) self.plot.remove('img2') self.plot.remove('img3') self.plot.remove('img1') self.assertTrue(self.colormapDialog.getColormap() is self.defaultColormap) def testShowHideColormapDialog(self): self.plot.getColormapAction()._actionTriggered(checked=False) self.assertFalse(self.plot.getColormapAction().isChecked()) self.plot.getColormapAction()._actionTriggered(checked=True) self.assertTrue(self.plot.getColormapAction().isChecked()) self.plot.addImage(data=numpy.random.rand(10, 10), legend='img1', origin=(0, 0), colormap=self.colormap1) self.colormap1.setName('red') self.plot.getColormapAction()._actionTriggered() self.colormap1.setName('blue') self.colormapDialog.close() self.assertFalse(self.plot.getColormapAction().isChecked())
def testEditableMode(self): """Make sure the colormap will raise NotEditableError when try to change a colormap not editable""" colormap = Colormap() colormap.setEditable(False) with self.assertRaises(NotEditableError): colormap.setVRange(0., 1.) with self.assertRaises(NotEditableError): colormap.setVMin(1.) with self.assertRaises(NotEditableError): colormap.setVMax(1.) with self.assertRaises(NotEditableError): colormap.setNormalization(Colormap.LOGARITHM) with self.assertRaises(NotEditableError): colormap.setName('magma') with self.assertRaises(NotEditableError): colormap.setColormapLUT(numpy.array([0, 1])) with self.assertRaises(NotEditableError): colormap._setFromDict(colormap._toDict()) state = colormap.saveState() with self.assertRaises(NotEditableError): colormap.restoreState(state)
def testGetColorMapRange(self): """Make sure the getColormapRange function of colormap is correctly applying """ # test linear scale data = numpy.array([-1, 1, 2, 3, float('nan')]) cl1 = Colormap(name='gray', normalization=Colormap.LINEAR, vmin=0, vmax=2) cl2 = Colormap(name='gray', normalization=Colormap.LINEAR, vmin=None, vmax=2) cl3 = Colormap(name='gray', normalization=Colormap.LINEAR, vmin=0, vmax=None) cl4 = Colormap(name='gray', normalization=Colormap.LINEAR, vmin=None, vmax=None) self.assertTrue(cl1.getColormapRange(data) == (0, 2)) self.assertTrue(cl2.getColormapRange(data) == (-1, 2)) self.assertTrue(cl3.getColormapRange(data) == (0, 3)) self.assertTrue(cl4.getColormapRange(data) == (-1, 3)) # test linear with annoying cases self.assertEqual(cl3.getColormapRange((-1, -2)), (0, 0)) self.assertEqual(cl4.getColormapRange(()), (0., 1.)) self.assertEqual(cl4.getColormapRange( (float('nan'), float('inf'), 1., -float('inf'), 2)), (1., 2.)) self.assertEqual(cl4.getColormapRange( (float('nan'), float('inf'))), (0., 1.)) # test log scale data = numpy.array([float('nan'), -1, 1, 10, 100, 1000]) cl1 = Colormap(name='gray', normalization=Colormap.LOGARITHM, vmin=1, vmax=100) cl2 = Colormap(name='gray', normalization=Colormap.LOGARITHM, vmin=None, vmax=100) cl3 = Colormap(name='gray', normalization=Colormap.LOGARITHM, vmin=1, vmax=None) cl4 = Colormap(name='gray', normalization=Colormap.LOGARITHM, vmin=None, vmax=None) self.assertTrue(cl1.getColormapRange(data) == (1, 100)) self.assertTrue(cl2.getColormapRange(data) == (1, 100)) self.assertTrue(cl3.getColormapRange(data) == (1, 1000)) self.assertTrue(cl4.getColormapRange(data) == (1, 1000)) # test log with annoying cases self.assertEqual(cl3.getColormapRange((0.1, 0.2)), (1, 1)) self.assertEqual(cl4.getColormapRange((-2., -1.)), (1., 1.)) self.assertEqual(cl4.getColormapRange(()), (1., 10.)) self.assertEqual(cl4.getColormapRange( (float('nan'), float('inf'), 1., -float('inf'), 2)), (1., 2.)) self.assertEqual(cl4.getColormapRange( (float('nan'), float('inf'))), (1., 10.))
class BaseMaskToolsWidget(qt.QWidget): """Base class for :class:`MaskToolsWidget` (image mask) and :class:`scatterMaskToolsWidget`""" sigMaskChanged = qt.Signal() _maxLevelNumber = 255 def __init__(self, parent=None, plot=None, mask=None): """ :param parent: Parent QWidget :param plot: Plot widget on which to operate :param mask: Instance of subclass of :class:`BaseMask` (e.g. :class:`ImageMask`) """ super(BaseMaskToolsWidget, self).__init__(parent) # register if the user as force a color for the corresponding mask level self._defaultColors = numpy.ones((self._maxLevelNumber + 1), dtype=numpy.bool) # overlays colors set by the user self._overlayColors = numpy.zeros((self._maxLevelNumber + 1, 3), dtype=numpy.float32) # as parent have to be the first argument of the widget to fit # QtDesigner need but here plot can't be None by default. assert plot is not None self._plotRef = weakref.ref(plot) self._maskName = '__MASK_TOOLS_%d' % id(self) # Legend of the mask self._colormap = Colormap(normalization='linear', vmin=0, vmax=self._maxLevelNumber) self._defaultOverlayColor = rgba('gray') # Color of the mask self._setMaskColors(1, 0.5) # Set the colormap LUT if not isinstance(mask, BaseMask): raise TypeError("mask is not an instance of BaseMask") self._mask = mask self._mask.sigChanged.connect(self._updatePlotMask) self._mask.sigChanged.connect(self._emitSigMaskChanged) self._drawingMode = None # Store current drawing mode self._lastPencilPos = None self._multipleMasks = 'exclusive' self._maskFileDir = qt.QDir.home().absolutePath() self.plot.sigInteractiveModeChanged.connect( self._interactiveModeChanged) self._initWidgets() def _emitSigMaskChanged(self): """Notify mask changes""" self.sigMaskChanged.emit() def getSelectionMask(self, copy=True): """Get the current mask as a numpy array. :param bool copy: True (default) to get a copy of the mask. If False, the returned array MUST not be modified. :return: The mask (as an array of uint8) with dimension of the 'active' plot item. If there is no active image or scatter, it returns None. :rtype: Union[numpy.ndarray,None] """ mask = self._mask.getMask(copy=copy) return None if mask.size == 0 else mask def setSelectionMask(self, mask): """Set the mask: Must be implemented in subclass""" raise NotImplementedError() def resetSelectionMask(self): """Reset the mask: Must be implemented in subclass""" raise NotImplementedError() def multipleMasks(self): """Return the current mode of multiple masks support. See :meth:`setMultipleMasks` """ return self._multipleMasks def setMultipleMasks(self, mode): """Set the mode of multiple masks support. Available modes: - 'single': Edit a single level of mask - 'exclusive': Supports to 256 levels of non overlapping masks :param str mode: The mode to use """ assert mode in ('exclusive', 'single') if mode != self._multipleMasks: self._multipleMasks = mode self.levelWidget.setVisible(self._multipleMasks != 'single') self.clearAllBtn.setVisible(self._multipleMasks != 'single') @property def maskFileDir(self): """The directory from which to load/save mask from/to files.""" if not os.path.isdir(self._maskFileDir): self._maskFileDir = qt.QDir.home().absolutePath() return self._maskFileDir @maskFileDir.setter def maskFileDir(self, maskFileDir): self._maskFileDir = str(maskFileDir) @property def plot(self): """The :class:`.PlotWindow` this widget is attached to.""" plot = self._plotRef() if plot is None: raise RuntimeError( 'Mask widget attached to a PlotWidget that no longer exists') return plot def setDirection(self, direction=qt.QBoxLayout.LeftToRight): """Set the direction of the layout of the widget :param direction: QBoxLayout direction """ self.layout().setDirection(direction) def _initWidgets(self): """Create widgets""" layout = qt.QBoxLayout(qt.QBoxLayout.LeftToRight) layout.addWidget(self._initMaskGroupBox()) layout.addWidget(self._initDrawGroupBox()) layout.addWidget(self._initThresholdGroupBox()) layout.addWidget(self._initOtherToolsGroupBox()) layout.addStretch(1) self.setLayout(layout) @staticmethod def _hboxWidget(*widgets, **kwargs): """Place widgets in widget with horizontal layout :param widgets: Widgets to position horizontally :param bool stretch: True for trailing stretch (default), False for no trailing stretch :return: A QWidget with a QHBoxLayout """ stretch = kwargs.get('stretch', True) layout = qt.QHBoxLayout() layout.setContentsMargins(0, 0, 0, 0) for widget in widgets: layout.addWidget(widget) if stretch: layout.addStretch(1) widget = qt.QWidget() widget.setLayout(layout) return widget def _initTransparencyWidget(self): """ Init the mask transparency widget """ transparencyWidget = qt.QWidget(self) grid = qt.QGridLayout() grid.setContentsMargins(0, 0, 0, 0) self.transparencySlider = qt.QSlider(qt.Qt.Horizontal, parent=transparencyWidget) self.transparencySlider.setRange(3, 10) self.transparencySlider.setValue(8) self.transparencySlider.setToolTip( 'Set the transparency of the mask display') self.transparencySlider.valueChanged.connect(self._updateColors) grid.addWidget(qt.QLabel('Display:', parent=transparencyWidget), 0, 0) grid.addWidget(self.transparencySlider, 0, 1, 1, 3) grid.addWidget(qt.QLabel('<small><b>Transparent</b></small>', parent=transparencyWidget), 1, 1) grid.addWidget(qt.QLabel('<small><b>Opaque</b></small>', parent=transparencyWidget), 1, 3) transparencyWidget.setLayout(grid) return transparencyWidget def _initMaskGroupBox(self): """Init general mask operation widgets""" # Mask level self.levelSpinBox = qt.QSpinBox() self.levelSpinBox.setRange(1, self._maxLevelNumber) self.levelSpinBox.setToolTip( 'Choose which mask level is edited.\n' 'A mask can have up to 255 non-overlapping levels.') self.levelSpinBox.valueChanged[int].connect(self._updateColors) self.levelWidget = self._hboxWidget(qt.QLabel('Mask level:'), self.levelSpinBox) # Transparency self.transparencyWidget = self._initTransparencyWidget() # Buttons group invertBtn = qt.QPushButton('Invert') invertBtn.setShortcut(qt.Qt.CTRL + qt.Qt.Key_I) invertBtn.setToolTip('Invert current mask <b>%s</b>' % invertBtn.shortcut().toString()) invertBtn.clicked.connect(self._handleInvertMask) clearBtn = qt.QPushButton('Clear') clearBtn.setShortcut(qt.QKeySequence.Delete) clearBtn.setToolTip('Clear current mask level <b>%s</b>' % clearBtn.shortcut().toString()) clearBtn.clicked.connect(self._handleClearMask) invertClearWidget = self._hboxWidget( invertBtn, clearBtn, stretch=False) undoBtn = qt.QPushButton('Undo') undoBtn.setShortcut(qt.QKeySequence.Undo) undoBtn.setToolTip('Undo last mask change <b>%s</b>' % undoBtn.shortcut().toString()) self._mask.sigUndoable.connect(undoBtn.setEnabled) undoBtn.clicked.connect(self._mask.undo) redoBtn = qt.QPushButton('Redo') redoBtn.setShortcut(qt.QKeySequence.Redo) redoBtn.setToolTip('Redo last undone mask change <b>%s</b>' % redoBtn.shortcut().toString()) self._mask.sigRedoable.connect(redoBtn.setEnabled) redoBtn.clicked.connect(self._mask.redo) undoRedoWidget = self._hboxWidget(undoBtn, redoBtn, stretch=False) self.clearAllBtn = qt.QPushButton('Clear all') self.clearAllBtn.setToolTip('Clear all mask levels') self.clearAllBtn.clicked.connect(self.resetSelectionMask) loadBtn = qt.QPushButton('Load...') loadBtn.clicked.connect(self._loadMask) saveBtn = qt.QPushButton('Save...') saveBtn.clicked.connect(self._saveMask) self.loadSaveWidget = self._hboxWidget(loadBtn, saveBtn, stretch=False) layout = qt.QVBoxLayout() layout.addWidget(self.levelWidget) layout.addWidget(self.transparencyWidget) layout.addWidget(invertClearWidget) layout.addWidget(undoRedoWidget) layout.addWidget(self.clearAllBtn) layout.addWidget(self.loadSaveWidget) layout.addStretch(1) maskGroup = qt.QGroupBox('Mask') maskGroup.setLayout(layout) return maskGroup def isMaskInteractionActivated(self): """Returns true if any mask interaction is activated""" return self.drawActionGroup.checkedAction() is not None def _initDrawGroupBox(self): """Init drawing tools widgets""" layout = qt.QVBoxLayout() self.browseAction = PanModeAction(self.plot, self.plot) self.addAction(self.browseAction) # Draw tools self.rectAction = qt.QAction( icons.getQIcon('shape-rectangle'), 'Rectangle selection', None) self.rectAction.setToolTip( 'Rectangle selection tool: (Un)Mask a rectangular region <b>R</b>') self.rectAction.setShortcut(qt.QKeySequence(qt.Qt.Key_R)) self.rectAction.setCheckable(True) self.rectAction.triggered.connect(self._activeRectMode) self.addAction(self.rectAction) self.ellipseAction = qt.QAction( icons.getQIcon('shape-ellipse'), 'Circle selection', None) self.ellipseAction.setToolTip( 'Rectangle selection tool: (Un)Mask a circle region <b>R</b>') self.ellipseAction.setShortcut(qt.QKeySequence(qt.Qt.Key_R)) self.ellipseAction.setCheckable(True) self.ellipseAction.triggered.connect(self._activeEllipseMode) self.addAction(self.ellipseAction) self.polygonAction = qt.QAction( icons.getQIcon('shape-polygon'), 'Polygon selection', None) self.polygonAction.setShortcut(qt.QKeySequence(qt.Qt.Key_S)) self.polygonAction.setToolTip( 'Polygon selection tool: (Un)Mask a polygonal region <b>S</b><br>' 'Left-click to place new polygon corners<br>' 'Left-click on first corner to close the polygon') self.polygonAction.setCheckable(True) self.polygonAction.triggered.connect(self._activePolygonMode) self.addAction(self.polygonAction) self.pencilAction = qt.QAction( icons.getQIcon('draw-pencil'), 'Pencil tool', None) self.pencilAction.setShortcut(qt.QKeySequence(qt.Qt.Key_P)) self.pencilAction.setToolTip( 'Pencil tool: (Un)Mask using a pencil <b>P</b>') self.pencilAction.setCheckable(True) self.pencilAction.triggered.connect(self._activePencilMode) self.addAction(self.pencilAction) self.drawActionGroup = qt.QActionGroup(self) self.drawActionGroup.setExclusive(True) self.drawActionGroup.addAction(self.rectAction) self.drawActionGroup.addAction(self.ellipseAction) self.drawActionGroup.addAction(self.polygonAction) self.drawActionGroup.addAction(self.pencilAction) actions = (self.browseAction, self.rectAction, self.ellipseAction, self.polygonAction, self.pencilAction) drawButtons = [] for action in actions: btn = qt.QToolButton() btn.setDefaultAction(action) drawButtons.append(btn) container = self._hboxWidget(*drawButtons) layout.addWidget(container) # Mask/Unmask radio buttons maskRadioBtn = qt.QRadioButton('Mask') maskRadioBtn.setToolTip( 'Drawing masks with current level. Press <b>Ctrl</b> to unmask') maskRadioBtn.setChecked(True) unmaskRadioBtn = qt.QRadioButton('Unmask') unmaskRadioBtn.setToolTip( 'Drawing unmasks with current level. Press <b>Ctrl</b> to mask') self.maskStateGroup = qt.QButtonGroup() self.maskStateGroup.addButton(maskRadioBtn, 1) self.maskStateGroup.addButton(unmaskRadioBtn, 0) self.maskStateWidget = self._hboxWidget(maskRadioBtn, unmaskRadioBtn) layout.addWidget(self.maskStateWidget) self.maskStateWidget.setHidden(True) # Pencil settings self.pencilSetting = self._createPencilSettings(None) self.pencilSetting.setVisible(False) layout.addWidget(self.pencilSetting) layout.addStretch(1) drawGroup = qt.QGroupBox('Draw tools') drawGroup.setLayout(layout) return drawGroup def _createPencilSettings(self, parent=None): pencilSetting = qt.QWidget(parent) self.pencilSpinBox = qt.QSpinBox(parent=pencilSetting) self.pencilSpinBox.setRange(1, 1024) pencilToolTip = """Set pencil drawing tool size in pixels of the image on which to make the mask.""" self.pencilSpinBox.setToolTip(pencilToolTip) self.pencilSlider = qt.QSlider(qt.Qt.Horizontal, parent=pencilSetting) self.pencilSlider.setRange(1, 50) self.pencilSlider.setToolTip(pencilToolTip) pencilLabel = qt.QLabel('Pencil size:', parent=pencilSetting) layout = qt.QGridLayout() layout.addWidget(pencilLabel, 0, 0) layout.addWidget(self.pencilSpinBox, 0, 1) layout.addWidget(self.pencilSlider, 1, 1) pencilSetting.setLayout(layout) self.pencilSpinBox.valueChanged.connect(self._pencilWidthChanged) self.pencilSlider.valueChanged.connect(self._pencilWidthChanged) return pencilSetting def _initThresholdGroupBox(self): """Init thresholding widgets""" self.belowThresholdAction = qt.QAction( icons.getQIcon('plot-roi-below'), 'Mask below threshold', None) self.belowThresholdAction.setToolTip( 'Mask image where values are below given threshold') self.belowThresholdAction.setCheckable(True) self.belowThresholdAction.setChecked(True) self.betweenThresholdAction = qt.QAction( icons.getQIcon('plot-roi-between'), 'Mask within range', None) self.betweenThresholdAction.setToolTip( 'Mask image where values are within given range') self.betweenThresholdAction.setCheckable(True) self.aboveThresholdAction = qt.QAction( icons.getQIcon('plot-roi-above'), 'Mask above threshold', None) self.aboveThresholdAction.setToolTip( 'Mask image where values are above given threshold') self.aboveThresholdAction.setCheckable(True) self.thresholdActionGroup = qt.QActionGroup(self) self.thresholdActionGroup.setExclusive(True) self.thresholdActionGroup.addAction(self.belowThresholdAction) self.thresholdActionGroup.addAction(self.betweenThresholdAction) self.thresholdActionGroup.addAction(self.aboveThresholdAction) self.thresholdActionGroup.triggered.connect( self._thresholdActionGroupTriggered) self.loadColormapRangeAction = qt.QAction( icons.getQIcon('view-refresh'), 'Set min-max from colormap', None) self.loadColormapRangeAction.setToolTip( 'Set min and max values from current colormap range') self.loadColormapRangeAction.setCheckable(False) self.loadColormapRangeAction.triggered.connect( self._loadRangeFromColormapTriggered) widgets = [] for action in self.thresholdActionGroup.actions(): btn = qt.QToolButton() btn.setDefaultAction(action) widgets.append(btn) spacer = qt.QWidget() spacer.setSizePolicy(qt.QSizePolicy.Expanding, qt.QSizePolicy.Preferred) widgets.append(spacer) loadColormapRangeBtn = qt.QToolButton() loadColormapRangeBtn.setDefaultAction(self.loadColormapRangeAction) widgets.append(loadColormapRangeBtn) toolBar = self._hboxWidget(*widgets, stretch=False) config = qt.QGridLayout() config.setContentsMargins(0, 0, 0, 0) self.minLineLabel = qt.QLabel("Min:", self) self.minLineEdit = FloatEdit(self, value=0) config.addWidget(self.minLineLabel, 0, 0) config.addWidget(self.minLineEdit, 0, 1) self.maxLineLabel = qt.QLabel("Max:", self) self.maxLineEdit = FloatEdit(self, value=0) config.addWidget(self.maxLineLabel, 1, 0) config.addWidget(self.maxLineEdit, 1, 1) self.applyMaskBtn = qt.QPushButton('Apply mask') self.applyMaskBtn.clicked.connect(self._maskBtnClicked) layout = qt.QVBoxLayout() layout.addWidget(toolBar) layout.addLayout(config) layout.addWidget(self.applyMaskBtn) self.thresholdGroup = qt.QGroupBox('Threshold') self.thresholdGroup.setLayout(layout) # Init widget state self._thresholdActionGroupTriggered(self.belowThresholdAction) return self.thresholdGroup # track widget visibility and plot active image changes def _initOtherToolsGroupBox(self): layout = qt.QVBoxLayout() self.maskNanBtn = qt.QPushButton('Mask not finite values') self.maskNanBtn.setToolTip('Mask Not a Number and infinite values') self.maskNanBtn.clicked.connect(self._maskNotFiniteBtnClicked) layout.addWidget(self.maskNanBtn) self.otherToolGroup = qt.QGroupBox('Other tools') self.otherToolGroup.setLayout(layout) return self.otherToolGroup def changeEvent(self, event): """Reset drawing action when disabling widget""" if (event.type() == qt.QEvent.EnabledChange and not self.isEnabled() and self.drawActionGroup.checkedAction()): # Disable drawing tool by setting interaction to zoom self.browseAction.trigger() def save(self, filename, kind): """Save current mask in a file :param str filename: The file where to save to mask :param str kind: The kind of file to save in 'edf', 'tif', 'npy' :raise Exception: Raised if the process fails """ self._mask.save(filename, kind) def getCurrentMaskColor(self): """Returns the color of the current selected level. :rtype: A tuple or a python array """ currentLevel = self.levelSpinBox.value() if self._defaultColors[currentLevel]: return self._defaultOverlayColor else: return self._overlayColors[currentLevel].tolist() def _setMaskColors(self, level, alpha): """Set-up the mask colormap to highlight current mask level. :param int level: The mask level to highlight :param float alpha: Alpha level of mask in [0., 1.] """ assert 0 < level <= self._maxLevelNumber colors = numpy.empty((self._maxLevelNumber + 1, 4), dtype=numpy.float32) # Set color colors[:, :3] = self._defaultOverlayColor[:3] # check if some colors has been directly set by the user mask = numpy.equal(self._defaultColors, False) colors[mask, :3] = self._overlayColors[mask, :3] # Set alpha colors[:, -1] = alpha / 2. # Set highlighted level color colors[level, 3] = alpha # Set no mask level colors[0] = (0., 0., 0., 0.) self._colormap.setColormapLUT(colors) def resetMaskColors(self, level=None): """Reset the mask color at the given level to be defaultColors :param level: The index of the mask for which we want to reset the color. If none we will reset color for all masks. """ if level is None: self._defaultColors[level] = True else: self._defaultColors[:] = True self._updateColors() def setMaskColors(self, rgb, level=None): """Set the masks color :param rgb: The rgb color :param level: The index of the mask for which we want to change the color. If none set this color for all the masks """ rgb = rgba(rgb)[0:3] if level is None: self._overlayColors[:] = rgb self._defaultColors[:] = False else: self._overlayColors[level] = rgb self._defaultColors[level] = False self._updateColors() def getMaskColors(self): """masks colors getter""" return self._overlayColors def _updateColors(self, *args): """Rebuild mask colormap when selected level or transparency change""" self._setMaskColors(self.levelSpinBox.value(), self.transparencySlider.value() / self.transparencySlider.maximum()) self._updatePlotMask() self._updateInteractiveMode() def _pencilWidthChanged(self, width): old = self.pencilSpinBox.blockSignals(True) try: self.pencilSpinBox.setValue(width) finally: self.pencilSpinBox.blockSignals(old) old = self.pencilSlider.blockSignals(True) try: self.pencilSlider.setValue(width) finally: self.pencilSlider.blockSignals(old) self._updateInteractiveMode() def _updateInteractiveMode(self): """Update the current mode to the same if some cached data have to be updated. It is the case for the color for example. """ if self._drawingMode == 'rectangle': self._activeRectMode() elif self._drawingMode == 'ellipse': self._activeEllipseMode() elif self._drawingMode == 'polygon': self._activePolygonMode() elif self._drawingMode == 'pencil': self._activePencilMode() def _handleClearMask(self): """Handle clear button clicked: reset current level mask""" self._mask.clear(self.levelSpinBox.value()) self._mask.commit() def _handleInvertMask(self): """Invert the current mask level selection.""" self._mask.invert(self.levelSpinBox.value()) self._mask.commit() # Handle drawing tools UI events def _interactiveModeChanged(self, source): """Handle plot interactive mode changed: If changed from elsewhere, disable drawing tool """ if source is not self: self.pencilAction.setChecked(False) self.rectAction.setChecked(False) self.polygonAction.setChecked(False) self._releaseDrawingMode() self._updateDrawingModeWidgets() def _releaseDrawingMode(self): """Release the drawing mode if is was used""" if self._drawingMode is None: return self.plot.sigPlotSignal.disconnect(self._plotDrawEvent) self._drawingMode = None def _activeRectMode(self): """Handle rect action mode triggering""" self._releaseDrawingMode() self._drawingMode = 'rectangle' self.plot.sigPlotSignal.connect(self._plotDrawEvent) color = self.getCurrentMaskColor() self.plot.setInteractiveMode( 'draw', shape='rectangle', source=self, color=color) self._updateDrawingModeWidgets() def _activeEllipseMode(self): """Handle circle action mode triggering""" self._releaseDrawingMode() self._drawingMode = 'ellipse' self.plot.sigPlotSignal.connect(self._plotDrawEvent) color = self.getCurrentMaskColor() self.plot.setInteractiveMode( 'draw', shape='ellipse', source=self, color=color) self._updateDrawingModeWidgets() def _activePolygonMode(self): """Handle polygon action mode triggering""" self._releaseDrawingMode() self._drawingMode = 'polygon' self.plot.sigPlotSignal.connect(self._plotDrawEvent) color = self.getCurrentMaskColor() self.plot.setInteractiveMode('draw', shape='polygon', source=self, color=color) self._updateDrawingModeWidgets() def _getPencilWidth(self): """Returns the width of the pencil to use in data coordinates` :rtype: float """ return self.pencilSpinBox.value() def _activePencilMode(self): """Handle pencil action mode triggering""" self._releaseDrawingMode() self._drawingMode = 'pencil' self.plot.sigPlotSignal.connect(self._plotDrawEvent) color = self.getCurrentMaskColor() width = self._getPencilWidth() self.plot.setInteractiveMode( 'draw', shape='pencil', source=self, color=color, width=width) self._updateDrawingModeWidgets() def _updateDrawingModeWidgets(self): self.maskStateWidget.setVisible(self._drawingMode is not None) self.pencilSetting.setVisible(self._drawingMode == 'pencil') # Handle plot drawing events def _isMasking(self): """Returns true if the tool is used for masking, else it is used for unmasking. :rtype: bool""" # First draw event, use current modifiers for all draw sequence doMask = (self.maskStateGroup.checkedId() == 1) if qt.QApplication.keyboardModifiers() & qt.Qt.ControlModifier: doMask = not doMask return doMask # Handle threshold UI events def _thresholdActionGroupTriggered(self, triggeredAction): """Threshold action group listener.""" if triggeredAction is self.belowThresholdAction: self.minLineLabel.setVisible(True) self.maxLineLabel.setVisible(False) self.minLineEdit.setVisible(True) self.maxLineEdit.setVisible(False) self.applyMaskBtn.setText("Mask bellow") elif triggeredAction is self.betweenThresholdAction: self.minLineLabel.setVisible(True) self.maxLineLabel.setVisible(True) self.minLineEdit.setVisible(True) self.maxLineEdit.setVisible(True) self.applyMaskBtn.setText("Mask between") elif triggeredAction is self.aboveThresholdAction: self.minLineLabel.setVisible(False) self.maxLineLabel.setVisible(True) self.minLineEdit.setVisible(False) self.maxLineEdit.setVisible(True) self.applyMaskBtn.setText("Mask above") self.applyMaskBtn.setToolTip(triggeredAction.toolTip()) def _maskBtnClicked(self): if self.belowThresholdAction.isChecked(): if self.minLineEdit.text(): self._mask.updateBelowThreshold(self.levelSpinBox.value(), self.minLineEdit.value()) self._mask.commit() elif self.betweenThresholdAction.isChecked(): if self.minLineEdit.text() and self.maxLineEdit.text(): min_ = self.minLineEdit.value() max_ = self.maxLineEdit.value() self._mask.updateBetweenThresholds(self.levelSpinBox.value(), min_, max_) self._mask.commit() elif self.aboveThresholdAction.isChecked(): if self.maxLineEdit.text(): max_ = float(self.maxLineEdit.value()) self._mask.updateAboveThreshold(self.levelSpinBox.value(), max_) self._mask.commit() def _maskNotFiniteBtnClicked(self): """Handle not finite mask button clicked: mask NaNs and inf""" self._mask.updateNotFinite( self.levelSpinBox.value()) self._mask.commit()
def testVMinVMax(self): """Test getter and setter associated to vmin and vmax values""" vmin = 1.0 vmax = 2.0 colormapObject = Colormap(name='viridis', vmin=vmin, vmax=vmax, normalization=Colormap.LINEAR) with self.assertRaises(ValueError): colormapObject.setVMin(3) with self.assertRaises(ValueError): colormapObject.setVMax(-2) with self.assertRaises(ValueError): colormapObject.setVRange(3, -2) self.assertTrue(colormapObject.getColormapRange() == (1.0, 2.0)) self.assertTrue(colormapObject.isAutoscale() is False) colormapObject.setVRange(None, None) self.assertTrue(colormapObject.getVMin() is None) self.assertTrue(colormapObject.getVMax() is None) self.assertTrue(colormapObject.isAutoscale() is True)
def testLut(self): colormap = Colormap("test_8") colors = colormap.getNColors(8) self.assertEquals(len(colors), 8)
class TestColormapDialog(TestCaseQt, ParametricTestCase): """Test the ColormapDialog.""" def setUp(self): TestCaseQt.setUp(self) ParametricTestCase.setUp(self) self.colormap = Colormap(name='gray', vmin=10.0, vmax=20.0, normalization='linear') self.colormapDiag = ColormapDialog.ColormapDialog() self.colormapDiag.setAttribute(qt.Qt.WA_DeleteOnClose) def tearDown(self): del self.colormapDiag ParametricTestCase.tearDown(self) TestCaseQt.tearDown(self) def testGUIEdition(self): """Make sure the colormap is correctly edited and also that the modification are correctly updated if an other colormapdialog is editing the same colormap""" colormapDiag2 = ColormapDialog.ColormapDialog() colormapDiag2.setColormap(self.colormap) colormapDiag2.show() self.colormapDiag.setColormap(self.colormap) self.colormapDiag.show() self.colormapDiag._comboBoxColormap._setCurrentName('red') self.colormapDiag._normButtonLog.click() self.assertTrue(self.colormap.getName() == 'red') self.assertTrue(self.colormapDiag.getColormap().getName() == 'red') self.assertTrue(self.colormap.getNormalization() == 'log') self.assertTrue(self.colormap.getVMin() == 10) self.assertTrue(self.colormap.getVMax() == 20) # checked second colormap dialog self.assertTrue(colormapDiag2._comboBoxColormap.getCurrentName() == 'red') self.assertTrue(colormapDiag2._normButtonLog.isChecked()) self.assertTrue(int(colormapDiag2._minValue.getValue()) == 10) self.assertTrue(int(colormapDiag2._maxValue.getValue()) == 20) colormapDiag2.close() def testGUIModalOk(self): """Make sure the colormap is modified if gone through accept""" assert self.colormap.isAutoscale() is False self.colormapDiag.setModal(True) self.colormapDiag.show() self.colormapDiag.setColormap(self.colormap) self.assertTrue(self.colormap.getVMin() is not None) self.colormapDiag._minValue.setValue(None) self.assertTrue(self.colormap.getVMin() is None) self.colormapDiag._maxValue.setValue(None) self.mouseClick( widget=self.colormapDiag._buttonsModal.button(qt.QDialogButtonBox.Ok), button=qt.Qt.LeftButton ) self.assertTrue(self.colormap.getVMin() is None) self.assertTrue(self.colormap.getVMax() is None) self.assertTrue(self.colormap.isAutoscale() is True) def testGUIModalCancel(self): """Make sure the colormap is not modified if gone through reject""" assert self.colormap.isAutoscale() is False self.colormapDiag.setModal(True) self.colormapDiag.show() self.colormapDiag.setColormap(self.colormap) self.assertTrue(self.colormap.getVMin() is not None) self.colormapDiag._minValue.setValue(None) self.assertTrue(self.colormap.getVMin() is None) self.mouseClick( widget=self.colormapDiag._buttonsModal.button(qt.QDialogButtonBox.Cancel), button=qt.Qt.LeftButton ) self.assertTrue(self.colormap.getVMin() is not None) def testGUIModalClose(self): assert self.colormap.isAutoscale() is False self.colormapDiag.setModal(False) self.colormapDiag.show() self.colormapDiag.setColormap(self.colormap) self.assertTrue(self.colormap.getVMin() is not None) self.colormapDiag._minValue.setValue(None) self.assertTrue(self.colormap.getVMin() is None) self.mouseClick( widget=self.colormapDiag._buttonsNonModal.button(qt.QDialogButtonBox.Close), button=qt.Qt.LeftButton ) self.assertTrue(self.colormap.getVMin() is None) def testGUIModalReset(self): assert self.colormap.isAutoscale() is False self.colormapDiag.setModal(False) self.colormapDiag.show() self.colormapDiag.setColormap(self.colormap) self.assertTrue(self.colormap.getVMin() is not None) self.colormapDiag._minValue.setValue(None) self.assertTrue(self.colormap.getVMin() is None) self.mouseClick( widget=self.colormapDiag._buttonsNonModal.button(qt.QDialogButtonBox.Reset), button=qt.Qt.LeftButton ) self.assertTrue(self.colormap.getVMin() is not None) self.colormapDiag.close() def testGUIClose(self): """Make sure the colormap is modify if go through reject""" assert self.colormap.isAutoscale() is False self.colormapDiag.show() self.colormapDiag.setColormap(self.colormap) self.assertTrue(self.colormap.getVMin() is not None) self.colormapDiag._minValue.setValue(None) self.assertTrue(self.colormap.getVMin() is None) self.colormapDiag.close() self.assertTrue(self.colormap.getVMin() is None) def testSetColormapIsCorrect(self): """Make sure the interface fir the colormap when set a new colormap""" self.colormap.setName('red') self.colormapDiag.show() for norm in (Colormap.NORMALIZATIONS): for autoscale in (True, False): if autoscale is True: self.colormap.setVRange(None, None) else: self.colormap.setVRange(11, 101) self.colormap.setNormalization(norm) with self.subTest(colormap=self.colormap): self.colormapDiag.setColormap(self.colormap) self.assertTrue( self.colormapDiag._normButtonLinear.isChecked() == (norm is Colormap.LINEAR)) self.assertTrue( self.colormapDiag._comboBoxColormap.getCurrentName() == 'red') self.assertTrue( self.colormapDiag._minValue.isAutoChecked() == autoscale) self.assertTrue( self.colormapDiag._maxValue.isAutoChecked() == autoscale) if autoscale is False: self.assertTrue(self.colormapDiag._minValue.getValue() == 11) self.assertTrue(self.colormapDiag._maxValue.getValue() == 101) self.assertTrue(self.colormapDiag._minValue.isEnabled()) self.assertTrue(self.colormapDiag._maxValue.isEnabled()) else: self.assertFalse(self.colormapDiag._minValue._numVal.isEnabled()) self.assertFalse(self.colormapDiag._maxValue._numVal.isEnabled()) def testColormapDel(self): """Check behavior if the colormap has been deleted outside. For now we make sure the colormap is still running and nothing more""" self.colormapDiag.setColormap(self.colormap) self.colormapDiag.show() del self.colormap self.assertTrue(self.colormapDiag.getColormap() is None) self.colormapDiag._comboBoxColormap._setCurrentName('blue') def testColormapEditedOutside(self): """Make sure the GUI is still up to date if the colormap is modified outside""" self.colormapDiag.setColormap(self.colormap) self.colormapDiag.show() self.colormap.setName('red') self.assertTrue( self.colormapDiag._comboBoxColormap.getCurrentName() == 'red') self.colormap.setNormalization(Colormap.LOGARITHM) self.assertFalse(self.colormapDiag._normButtonLinear.isChecked()) self.colormap.setVRange(11, 201) self.assertTrue(self.colormapDiag._minValue.getValue() == 11) self.assertTrue(self.colormapDiag._maxValue.getValue() == 201) self.assertTrue(self.colormapDiag._minValue._numVal.isEnabled()) self.assertTrue(self.colormapDiag._maxValue._numVal.isEnabled()) self.assertFalse(self.colormapDiag._minValue.isAutoChecked()) self.assertFalse(self.colormapDiag._maxValue.isAutoChecked()) self.colormap.setVRange(None, None) self.assertFalse(self.colormapDiag._minValue._numVal.isEnabled()) self.assertFalse(self.colormapDiag._maxValue._numVal.isEnabled()) self.assertTrue(self.colormapDiag._minValue.isAutoChecked()) self.assertTrue(self.colormapDiag._maxValue.isAutoChecked()) def testSetColormapScenario(self): """Test of a simple scenario of a colormap dialog editing several colormap""" colormap1 = Colormap(name='gray', vmin=10.0, vmax=20.0, normalization='linear') colormap2 = Colormap(name='red', vmin=10.0, vmax=20.0, normalization='log') colormap3 = Colormap(name='blue', vmin=None, vmax=None, normalization='linear') self.colormapDiag.setColormap(self.colormap) self.colormapDiag.setColormap(colormap1) del colormap1 self.colormapDiag.setColormap(colormap2) del colormap2 self.colormapDiag.setColormap(colormap3) del colormap3 def testNotPreferredColormap(self): """Test that the colormapEditor is able to edit a colormap which is not part of the 'prefered colormap' """ def getFirstNotPreferredColormap(): cms = Colormap.getSupportedColormaps() preferred = preferredColormaps() for cm in cms: if cm not in preferred: return cm return None colormapName = getFirstNotPreferredColormap() assert colormapName is not None colormap = Colormap(name=colormapName) self.colormapDiag.setColormap(colormap) self.colormapDiag.show() cb = self.colormapDiag._comboBoxColormap self.assertTrue(cb.getCurrentName() == colormapName) cb.setCurrentIndex(0) index = cb.findLutName(colormapName) assert index is not 0 # if 0 then the rest of the test has no sense cb.setCurrentIndex(index) self.assertTrue(cb.getCurrentName() == colormapName) def testColormapEditableMode(self): """Test that the colormapDialog is correctly updated when changing the colormap editable status""" colormap = Colormap(normalization='linear', vmin=1.0, vmax=10.0) self.colormapDiag.show() self.colormapDiag.setColormap(colormap) for editable in (True, False): with self.subTest(editable=editable): colormap.setEditable(editable) self.assertTrue( self.colormapDiag._comboBoxColormap.isEnabled() is editable) self.assertTrue( self.colormapDiag._minValue.isEnabled() is editable) self.assertTrue( self.colormapDiag._maxValue.isEnabled() is editable) self.assertTrue( self.colormapDiag._normButtonLinear.isEnabled() is editable) self.assertTrue( self.colormapDiag._normButtonLog.isEnabled() is editable) # Make sure the reset button is also set to enable when edition mode is # False self.colormapDiag.setModal(False) colormap.setEditable(True) self.colormapDiag._normButtonLog.click() resetButton = self.colormapDiag._buttonsNonModal.button(qt.QDialogButtonBox.Reset) self.assertTrue(resetButton.isEnabled()) colormap.setEditable(False) self.assertFalse(resetButton.isEnabled()) def testImageData(self): data = numpy.random.rand(5, 5) self.colormapDiag.setData(data) def testEmptyData(self): data = numpy.empty((10, 0)) self.colormapDiag.setData(data) def testNoneData(self): data = numpy.random.rand(5, 5) self.colormapDiag.setData(data) self.colormapDiag.setData(None)