示例#1
0
 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")
示例#2
0
    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()
示例#3
0
    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
示例#4
0
 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)
示例#5
0
 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)
示例#6
0
文件: colorutils.py 项目: kif/pyFAI
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
示例#7
0
 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)))))
示例#8
0
    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({})
示例#9
0
 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)
示例#10
0
    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)
示例#11
0
    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'])
示例#12
0
 def getFirstNotPreferredColormap():
     cms = Colormap.getSupportedColormaps()
     preferred = preferredColormaps()
     for cm in cms:
         if cm not in preferred:
             return cm
     return None
示例#13
0
    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)))
示例#14
0
    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)
示例#15
0
    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())
示例#16
0
    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')
示例#17
0
    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)
示例#18
0
 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']
示例#19
0
    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)
示例#21
0
 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"))
示例#23
0
    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")
示例#25
0
    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)
示例#26
0
    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))
示例#27
0
    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()
示例#28
0
 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"
示例#29
0
    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)
示例#30
0
    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"))
示例#31
0
 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 = {}
示例#32
0
    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)
示例#33
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)
示例#34
0
    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)
示例#35
0
    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])
示例#36
0
    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()
示例#37
0
    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)))
示例#40
0
    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)
示例#42
0
    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)
示例#43
0
文件: test_sx.py 项目: t20100/silx
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 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)
示例#45
0
    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)
示例#46
0
    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()
示例#47
0
    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)
示例#48
0
    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)
示例#49
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)
示例#50
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)
示例#51
0
    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)
示例#52
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())
示例#53
0
 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)
示例#54
0
    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.))
示例#55
0
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()
示例#56
0
    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)
示例#57
0
 def testLut(self):
     colormap = Colormap("test_8")
     colors = colormap.getNColors(8)
     self.assertEquals(len(colors), 8)
示例#58
0
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)