class ColormapDialog(qt.QDialog): sigColormapChanged = qt.pyqtSignal(object) def __init__(self, parent=None, name="Colormap Dialog"): qt.QDialog.__init__(self, parent) self.setWindowTitle(name) self.title = name self.colormapList = ["Greyscale", "Reverse Grey", "Temperature", "Red", "Green", "Blue", "Many"] # histogramData is tupel(bins, counts) self.histogramData = None # default values self.dataMin = -10 self.dataMax = 10 self.minValue = 0 self.maxValue = 1 self.colormapIndex = 2 self.colormapType = 0 self.autoscale = False self.autoscale90 = False # main layout vlayout = qt.QVBoxLayout(self) vlayout.setContentsMargins(10, 10, 10, 10) vlayout.setSpacing(0) # layout 1 : -combo to choose colormap # -autoscale button # -autoscale 90% button hbox1 = qt.QWidget(self) hlayout1 = qt.QHBoxLayout(hbox1) vlayout.addWidget(hbox1) hlayout1.setContentsMargins(0, 0, 0, 0) hlayout1.setSpacing(10) # combo self.combo = qt.QComboBox(hbox1) for colormap in self.colormapList: self.combo.addItem(colormap) self.combo.activated[int].connect(self.colormapChange) hlayout1.addWidget(self.combo) # autoscale self.autoScaleButton = qt.QPushButton("Autoscale", hbox1) self.autoScaleButton.setCheckable(True) self.autoScaleButton.setAutoDefault(False) self.autoScaleButton.toggled[bool].connect(self.autoscaleChange) hlayout1.addWidget(self.autoScaleButton) # autoscale 90% self.autoScale90Button = qt.QPushButton("Autoscale 90%", hbox1) self.autoScale90Button.setCheckable(True) self.autoScale90Button.setAutoDefault(False) self.autoScale90Button.toggled[bool].connect(self.autoscale90Change) hlayout1.addWidget(self.autoScale90Button) # hlayout hbox0 = qt.QWidget(self) self.__hbox0 = hbox0 hlayout0 = qt.QHBoxLayout(hbox0) hlayout0.setContentsMargins(0, 0, 0, 0) hlayout0.setSpacing(0) vlayout.addWidget(hbox0) #hlayout0.addStretch(10) self.buttonGroup = qt.QButtonGroup() g1 = qt.QCheckBox(hbox0) g1.setText("Linear") g2 = qt.QCheckBox(hbox0) g2.setText("Logarithmic") g3 = qt.QCheckBox(hbox0) g3.setText("Gamma") self.buttonGroup.addButton(g1, 0) self.buttonGroup.addButton(g2, 1) self.buttonGroup.addButton(g3, 2) self.buttonGroup.setExclusive(True) if self.colormapType == 1: self.buttonGroup.button(1).setChecked(True) elif self.colormapType == 2: self.buttonGroup.button(2).setChecked(True) else: self.buttonGroup.button(0).setChecked(True) hlayout0.addWidget(g1) hlayout0.addWidget(g2) hlayout0.addWidget(g3) vlayout.addWidget(hbox0) self.buttonGroup.buttonClicked[int].connect(self.buttonGroupChange) vlayout.addSpacing(20) hboxlimits = qt.QWidget(self) hboxlimitslayout = qt.QHBoxLayout(hboxlimits) hboxlimitslayout.setContentsMargins(0, 0, 0, 0) hboxlimitslayout.setSpacing(0) self.slider = None vlayout.addWidget(hboxlimits) vboxlimits = qt.QWidget(hboxlimits) vboxlimitslayout = qt.QVBoxLayout(vboxlimits) vboxlimitslayout.setContentsMargins(0, 0, 0, 0) vboxlimitslayout.setSpacing(0) hboxlimitslayout.addWidget(vboxlimits) # hlayout 2 : - min label # - min texte hbox2 = qt.QWidget(vboxlimits) self.__hbox2 = hbox2 hlayout2 = qt.QHBoxLayout(hbox2) hlayout2.setContentsMargins(0, 0, 0, 0) hlayout2.setSpacing(0) #vlayout.addWidget(hbox2) vboxlimitslayout.addWidget(hbox2) hlayout2.addStretch(10) self.minLabel = qt.QLabel(hbox2) self.minLabel.setText("Minimum") hlayout2.addWidget(self.minLabel) hlayout2.addSpacing(5) hlayout2.addStretch(1) self.minText = MyQLineEdit(hbox2) self.minText.setFixedWidth(150) self.minText.setAlignment(qt.Qt.AlignRight) self.minText.returnPressed[()].connect(self.minTextChanged) hlayout2.addWidget(self.minText) # hlayout 3 : - min label # - min text hbox3 = qt.QWidget(vboxlimits) self.__hbox3 = hbox3 hlayout3 = qt.QHBoxLayout(hbox3) hlayout3.setContentsMargins(0, 0, 0, 0) hlayout3.setSpacing(0) #vlayout.addWidget(hbox3) vboxlimitslayout.addWidget(hbox3) hlayout3.addStretch(10) self.maxLabel = qt.QLabel(hbox3) self.maxLabel.setText("Maximum") hlayout3.addWidget(self.maxLabel) hlayout3.addSpacing(5) hlayout3.addStretch(1) self.maxText = MyQLineEdit(hbox3) self.maxText.setFixedWidth(150) self.maxText.setAlignment(qt.Qt.AlignRight) self.maxText.returnPressed[()].connect(self.maxTextChanged) hlayout3.addWidget(self.maxText) # Graph widget for color curve... self.c = PlotWidget(self, backend=None) self.c.setGraphXLabel("Data Values") self.c.setInteractiveMode('select') self.marge = (abs(self.dataMax) + abs(self.dataMin)) / 6.0 self.minmd = self.dataMin - self.marge self.maxpd = self.dataMax + self.marge self.c.setGraphXLimits(self.minmd, self.maxpd) self.c.setGraphYLimits(-11.5, 11.5) x = [self.minmd, self.dataMin, self.dataMax, self.maxpd] y = [-10, -10, 10, 10 ] self.c.addCurve(x, y, legend="ConstrainedCurve", color='black', symbol='o', linestyle='-') self.markers = [] self.__x = x self.__y = y labelList = ["","Min", "Max", ""] for i in range(4): if i in [1, 2]: draggable = True color = "blue" else: draggable = False color = "black" #TODO symbol legend = "%d" % i self.c.addXMarker(x[i], legend=legend, text=labelList[i], draggable=draggable, color=color) self.markers.append((legend, "")) self.c.setMinimumSize(qt.QSize(250,200)) vlayout.addWidget(self.c) self.c.sigPlotSignal.connect(self.chval) # colormap window can not be resized self.setFixedSize(vlayout.minimumSize()) def plotHistogram(self, data=None): if data is not None: self.histogramData = data if self.histogramData is None: return False bins, counts = self.histogramData self.c.addCurve(bins, counts, "Histogram", color='darkYellow', histogram='center', yaxis='right', fill=True) def _update(self): _logger.debug("colormap _update called") self.marge = (abs(self.dataMax) + abs(self.dataMin)) / 6.0 self.minmd = self.dataMin - self.marge self.maxpd = self.dataMax + self.marge self.c.setGraphXLimits(self.minmd, self.maxpd) self.c.setGraphYLimits( -11.5, 11.5) self.__x = [self.minmd, self.dataMin, self.dataMax, self.maxpd] self.__y = [-10, -10, 10, 10] self.c.addCurve(self.__x, self.__y, legend="ConstrainedCurve", color='black', symbol='o', linestyle='-') self.c.clearMarkers() for i in range(4): if i in [1, 2]: draggable = True color = "blue" else: draggable = False color = "black" key = self.markers[i][0] label = self.markers[i][1] self.c.addXMarker(self.__x[i], legend=key, text=label, draggable=draggable, color=color) self.sendColormap() def buttonGroupChange(self, val): _logger.debug("buttonGroup asking to update colormap") self.setColormapType(val, update=True) self._update() def setColormapType(self, val, update=False): self.colormapType = val if self.colormapType == 1: self.buttonGroup.button(1).setChecked(True) elif self.colormapType == 2: self.buttonGroup.button(2).setChecked(True) else: self.colormapType = 0 self.buttonGroup.button(0).setChecked(True) if update: self._update() def chval(self, ddict): _logger.debug("Received %s", ddict) if ddict['event'] == 'markerMoving': diam = int(ddict['label']) x = ddict['x'] if diam == 1: self.setDisplayedMinValue(x) elif diam == 2: self.setDisplayedMaxValue(x) elif ddict['event'] == 'markerMoved': diam = int(ddict['label']) x = ddict['x'] if diam == 1: self.setMinValue(x) if diam == 2: self.setMaxValue(x) """ Colormap """ def setColormap(self, colormap): self.colormapIndex = colormap if QTVERSION < '4.0.0': self.combo.setCurrentItem(colormap) else: self.combo.setCurrentIndex(colormap) def colormapChange(self, colormap): self.colormapIndex = colormap self.sendColormap() # AUTOSCALE """ Autoscale """ def autoscaleChange(self, val): self.autoscale = val self.setAutoscale(val) self.sendColormap() def setAutoscale(self, val): _logger.debug("setAutoscale called %s", val) if val: self.autoScaleButton.setChecked(True) self.autoScale90Button.setChecked(False) #self.autoScale90Button.setDown(False) self.setMinValue(self.dataMin) self.setMaxValue(self.dataMax) self.maxText.setEnabled(0) self.minText.setEnabled(0) self.c.setEnabled(False) #self.c.disablemarkermode() else: self.autoScaleButton.setChecked(False) self.autoScale90Button.setChecked(False) self.minText.setEnabled(1) self.maxText.setEnabled(1) self.c.setEnabled(True) #self.c.enablemarkermode() """ set rangeValues to dataMin ; dataMax-10% """ def autoscale90Change(self, val): self.autoscale90 = val self.setAutoscale90(val) self.sendColormap() def setAutoscale90(self, val): if val: self.autoScaleButton.setChecked(False) self.setMinValue(self.dataMin) self.setMaxValue(self.dataMax - abs(self.dataMax/10)) self.minText.setEnabled(0) self.maxText.setEnabled(0) self.c.setEnabled(False) else: self.autoScale90Button.setChecked(False) self.minText.setEnabled(1) self.maxText.setEnabled(1) self.c.setEnabled(True) self.c.setFocus() # MINIMUM """ change min value and update colormap """ def setMinValue(self, val): v = float(str(val)) self.minValue = v self.minText.setText("%g" % v) self.__x[1] = v key = self.markers[1][0] label = self.markers[1][1] self.c.addXMarker(v, legend=key, text=label, color="blue", draggable=True) self.c.addCurve(self.__x, self.__y, legend="ConstrainedCurve", color='black', symbol='o', linestyle='-') self.sendColormap() """ min value changed by text """ def minTextChanged(self): text = str(self.minText.text()) if not len(text): return val = float(text) self.setMinValue(val) if self.minText.hasFocus(): self.c.setFocus() """ change only the displayed min value """ def setDisplayedMinValue(self, val): val = float(val) self.minValue = val self.minText.setText("%g"%val) self.__x[1] = val key = self.markers[1][0] label = self.markers[1][1] self.c.addXMarker(val, legend=key, text=label, color="blue", draggable=True) self.c.addCurve(self.__x, self.__y, legend="ConstrainedCurve", color='black', symbol='o', linestyle='-') # MAXIMUM """ change max value and update colormap """ def setMaxValue(self, val): v = float(str(val)) self.maxValue = v self.maxText.setText("%g"%v) self.__x[2] = v key = self.markers[2][0] label = self.markers[2][1] self.c.addXMarker(v, legend=key, text=label, color="blue", draggable=True) self.c.addCurve(self.__x, self.__y, legend="ConstrainedCurve", color='black', symbol='o', linestyle='-') self.sendColormap() """ max value changed by text """ def maxTextChanged(self): text = str(self.maxText.text()) if not len(text):return val = float(text) self.setMaxValue(val) if self.maxText.hasFocus(): self.c.setFocus() """ change only the displayed max value """ def setDisplayedMaxValue(self, val): val = float(val) self.maxValue = val self.maxText.setText("%g"%val) self.__x[2] = val key = self.markers[2][0] label = self.markers[2][1] self.c.addXMarker(val, legend=key, text=label, color="blue", draggable=True) self.c.addCurve(self.__x, self.__y, legend="ConstrainedCurve", color='black', symbol='o', linestyle='-') # DATA values """ set min/max value of data source """ def setDataMinMax(self, minVal, maxVal, update=True): if minVal is not None: vmin = float(str(minVal)) self.dataMin = vmin if maxVal is not None: vmax = float(str(maxVal)) self.dataMax = vmax if update: # are current values in the good range ? self._update() def getColormap(self): if self.minValue > self.maxValue: vmax = self.minValue vmin = self.maxValue else: vmax = self.maxValue vmin = self.minValue cmap = [self.colormapIndex, self.autoscale, vmin, vmax, self.dataMin, self.dataMax, self.colormapType] return cmap """ send 'ColormapChanged' signal """ def sendColormap(self): _logger.debug("sending colormap") try: cmap = self.getColormap() self.sigColormapChanged.emit(cmap) except: sys.excepthook(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2])
class ColormapDialog(QDialog): sigColormapChanged = pyqtSignal(object) def __init__(self, parent=None, name="Colormap Dialog"): QDialog.__init__(self, parent) self.setWindowTitle(name) self.title = name self.colormapList = [ 'Greys', 'Purples', 'Blues', 'Greens', 'Oranges', 'Reds', 'YlOrBr', 'YlOrRd', 'OrRd', 'PuRd', 'RdPu', 'BuPu', 'GnBu', 'PuBu', 'YlGnBu', 'PuBuGn', 'BuGn', 'YlGn' ] # histogramData is tupel(bins, counts) self.histogramData = None # default values self.dataMin = -10 self.dataMax = 10 self.minValue = 0 self.maxValue = 1 self.colormapIndex = 2 self.colormapType = 0 self.autoscale = False self.autoscale90 = False # main layout vlayout = QVBoxLayout(self) vlayout.setContentsMargins(10, 10, 10, 10) vlayout.setSpacing(0) # layout 1 : -combo to choose colormap # -autoscale button # -autoscale 90% button hbox1 = QWidget(self) hlayout1 = QHBoxLayout(hbox1) vlayout.addWidget(hbox1) hlayout1.setContentsMargins(0, 0, 0, 0) hlayout1.setSpacing(10) # combo self.combo = QComboBox(hbox1) for colormap in self.colormapList: self.combo.addItem(colormap) self.combo.activated[int].connect(self.colormapChange) hlayout1.addWidget(self.combo) # autoscale self.autoScaleButton = QPushButton("Autoscale", hbox1) self.autoScaleButton.setCheckable(True) self.autoScaleButton.setAutoDefault(False) self.autoScaleButton.toggled[bool].connect(self.autoscaleChange) hlayout1.addWidget(self.autoScaleButton) # autoscale 90% self.autoScale90Button = QPushButton("Autoscale 90%", hbox1) self.autoScale90Button.setCheckable(True) self.autoScale90Button.setAutoDefault(False) self.autoScale90Button.toggled[bool].connect(self.autoscale90Change) hlayout1.addWidget(self.autoScale90Button) # hlayout hbox0 = QWidget(self) self.__hbox0 = hbox0 hlayout0 = QHBoxLayout(hbox0) hlayout0.setContentsMargins(0, 0, 0, 0) hlayout0.setSpacing(0) vlayout.addWidget(hbox0) #hlayout0.addStretch(10) self.buttonGroup = QButtonGroup() g1 = QCheckBox(hbox0) g1.setText("Linear") g2 = QCheckBox(hbox0) g2.setText("Logarithmic") g3 = QCheckBox(hbox0) g3.setText("Gamma") self.buttonGroup.addButton(g1, 0) self.buttonGroup.addButton(g2, 1) self.buttonGroup.addButton(g3, 2) self.buttonGroup.setExclusive(True) if self.colormapType == 1: self.buttonGroup.button(1).setChecked(True) elif self.colormapType == 2: self.buttonGroup.button(2).setChecked(True) else: self.buttonGroup.button(0).setChecked(True) hlayout0.addWidget(g1) hlayout0.addWidget(g2) hlayout0.addWidget(g3) vlayout.addWidget(hbox0) self.buttonGroup.buttonClicked[int].connect(self.buttonGroupChange) vlayout.addSpacing(20) hboxlimits = QWidget(self) hboxlimitslayout = QHBoxLayout(hboxlimits) hboxlimitslayout.setContentsMargins(0, 0, 0, 0) hboxlimitslayout.setSpacing(0) self.slider = None vlayout.addWidget(hboxlimits) vboxlimits = QWidget(hboxlimits) vboxlimitslayout = QVBoxLayout(vboxlimits) vboxlimitslayout.setContentsMargins(0, 0, 0, 0) vboxlimitslayout.setSpacing(0) hboxlimitslayout.addWidget(vboxlimits) # hlayout 2 : - min label # - min texte hbox2 = QWidget(vboxlimits) self.__hbox2 = hbox2 hlayout2 = QHBoxLayout(hbox2) hlayout2.setContentsMargins(0, 0, 0, 0) hlayout2.setSpacing(0) #vlayout.addWidget(hbox2) vboxlimitslayout.addWidget(hbox2) hlayout2.addStretch(10) self.minLabel = QLabel(hbox2) self.minLabel.setText("Minimum") hlayout2.addWidget(self.minLabel) hlayout2.addSpacing(5) hlayout2.addStretch(1) self.minText = MyQLineEdit(hbox2) self.minText.setFixedWidth(150) self.minText.setAlignment(QtCore.Qt.AlignRight) self.minText.returnPressed[()].connect(self.minTextChanged) hlayout2.addWidget(self.minText) # hlayout 3 : - min label # - min text hbox3 = QWidget(vboxlimits) self.__hbox3 = hbox3 hlayout3 = QHBoxLayout(hbox3) hlayout3.setContentsMargins(0, 0, 0, 0) hlayout3.setSpacing(0) #vlayout.addWidget(hbox3) vboxlimitslayout.addWidget(hbox3) hlayout3.addStretch(10) self.maxLabel = QLabel(hbox3) self.maxLabel.setText("Maximum") hlayout3.addWidget(self.maxLabel) hlayout3.addSpacing(5) hlayout3.addStretch(1) self.maxText = MyQLineEdit(hbox3) self.maxText.setFixedWidth(150) self.maxText.setAlignment(QtCore.Qt.AlignRight) self.maxText.returnPressed[()].connect(self.maxTextChanged) hlayout3.addWidget(self.maxText) # Graph widget for color curve... self.c = PlotWidget(self, backend=None) self.c.setGraphXLabel("Data Values") self.c.setInteractiveMode('select') self.marge = (abs(self.dataMax) + abs(self.dataMin)) / 6.0 self.minmd = self.dataMin - self.marge self.maxpd = self.dataMax + self.marge self.c.setGraphXLimits(self.minmd, self.maxpd) self.c.setGraphYLimits(-11.5, 11.5) x = [self.minmd, self.dataMin, self.dataMax, self.maxpd] y = [-10, -10, 10, 10] self.c.addCurve(x, y, legend="ConstrainedCurve", color='black', symbol='o', linestyle='-') self.markers = [] self.__x = x self.__y = y labelList = ["", "Min", "Max", ""] for i in range(4): if i in [1, 2]: draggable = True color = "blue" else: draggable = False color = "black" #TODO symbol legend = "%d" % i self.c.addXMarker(x[i], legend=legend, text=labelList[i], draggable=draggable, color=color) self.markers.append((legend, "")) self.c.setMinimumSize(QSize(250, 200)) vlayout.addWidget(self.c) self.c.sigPlotSignal.connect(self.chval) # colormap window can not be resized self.setFixedSize(vlayout.minimumSize()) self.buttonBox = QDialogButtonBox() self.buttonBox.setOrientation(QtCore.Qt.Horizontal) self.buttonBox.setStandardButtons(QDialogButtonBox.Cancel | QDialogButtonBox.Ok) self.buttonBox.setObjectName("buttonBox") vlayout.addWidget(self.buttonBox) self.buttonBox.accepted.connect(self.accept) self.buttonBox.rejected.connect(self.reject) def plotHistogram(self, data=None): if data is not None: self.histogramData = data if self.histogramData is None: return False bins, counts = self.histogramData self.c.addCurve(bins, counts, "Histogram", color='darkYellow', histogram='center', yaxis='right', fill=True) def _update(self): _logger.debug("colormap _update called") self.marge = (abs(self.dataMax) + abs(self.dataMin)) / 6.0 self.minmd = self.dataMin - self.marge self.maxpd = self.dataMax + self.marge self.c.setGraphXLimits(self.minmd, self.maxpd) self.c.setGraphYLimits(-11.5, 11.5) self.__x = [self.minmd, self.dataMin, self.dataMax, self.maxpd] self.__y = [-10, -10, 10, 10] self.c.addCurve(self.__x, self.__y, legend="ConstrainedCurve", color='black', symbol='o', linestyle='-') self.c.clearMarkers() for i in range(4): if i in [1, 2]: draggable = True color = "blue" else: draggable = False color = "black" key = self.markers[i][0] label = self.markers[i][1] self.c.addXMarker(self.__x[i], legend=key, text=label, draggable=draggable, color=color) self.sendColormap() def buttonGroupChange(self, val): _logger.debug("buttonGroup asking to update colormap") self.setColormapType(val, update=True) self._update() def setColormapType(self, val, update=False): self.colormapType = val if self.colormapType == 1: self.buttonGroup.button(1).setChecked(True) elif self.colormapType == 2: self.buttonGroup.button(2).setChecked(True) else: self.colormapType = 0 self.buttonGroup.button(0).setChecked(True) if update: self._update() def chval(self, ddict): _logger.debug("Received %s", ddict) if ddict['event'] == 'markerMoving': diam = int(ddict['label']) x = ddict['x'] if diam == 1: self.setDisplayedMinValue(x) elif diam == 2: self.setDisplayedMaxValue(x) elif ddict['event'] == 'markerMoved': diam = int(ddict['label']) x = ddict['x'] if diam == 1: self.setMinValue(x) if diam == 2: self.setMaxValue(x) """ Colormap """ def setColormap(self, colormap): self.colormapIndex = colormap if QTVERSION < '4.0.0': self.combo.setCurrentItem(colormap) else: self.combo.setCurrentIndex(colormap) def colormapChange(self, colormap): self.colormapIndex = colormap self.sendColormap() # AUTOSCALE """ Autoscale """ def autoscaleChange(self, val): self.autoscale = val self.setAutoscale(val) self.sendColormap() def setAutoscale(self, val): _logger.debug("setAutoscale called %s", val) if val: self.autoScaleButton.setChecked(True) self.autoScale90Button.setChecked(False) #self.autoScale90Button.setDown(False) self.setMinValue(self.dataMin) self.setMaxValue(self.dataMax) self.maxText.setEnabled(0) self.minText.setEnabled(0) self.c.setEnabled(False) #self.c.disablemarkermode() else: self.autoScaleButton.setChecked(False) self.autoScale90Button.setChecked(False) self.minText.setEnabled(1) self.maxText.setEnabled(1) self.c.setEnabled(True) #self.c.enablemarkermode() """ set rangeValues to dataMin ; dataMax-10% """ def autoscale90Change(self, val): self.autoscale90 = val self.setAutoscale90(val) self.sendColormap() def setAutoscale90(self, val): if val: self.autoScaleButton.setChecked(False) self.setMinValue(self.dataMin) self.setMaxValue(self.dataMax - abs(self.dataMax / 10)) self.minText.setEnabled(0) self.maxText.setEnabled(0) self.c.setEnabled(False) else: self.autoScale90Button.setChecked(False) self.minText.setEnabled(1) self.maxText.setEnabled(1) self.c.setEnabled(True) self.c.setFocus() # MINIMUM """ change min value and update colormap """ def setMinValue(self, val): v = float(str(val)) self.minValue = v self.minText.setText("%g" % v) self.__x[1] = v key = self.markers[1][0] label = self.markers[1][1] self.c.addXMarker(v, legend=key, text=label, color="blue", draggable=True) self.c.addCurve(self.__x, self.__y, legend="ConstrainedCurve", color='black', symbol='o', linestyle='-') self.sendColormap() """ min value changed by text """ def minTextChanged(self): text = str(self.minText.text()) if not len(text): return val = float(text) self.setMinValue(val) if self.minText.hasFocus(): self.c.setFocus() """ change only the displayed min value """ def setDisplayedMinValue(self, val): val = float(val) self.minValue = val self.minText.setText("%g" % val) self.__x[1] = val key = self.markers[1][0] label = self.markers[1][1] self.c.addXMarker(val, legend=key, text=label, color="blue", draggable=True) self.c.addCurve(self.__x, self.__y, legend="ConstrainedCurve", color='black', symbol='o', linestyle='-') # MAXIMUM """ change max value and update colormap """ def setMaxValue(self, val): v = float(str(val)) self.maxValue = v self.maxText.setText("%g" % v) self.__x[2] = v key = self.markers[2][0] label = self.markers[2][1] self.c.addXMarker(v, legend=key, text=label, color="blue", draggable=True) self.c.addCurve(self.__x, self.__y, legend="ConstrainedCurve", color='black', symbol='o', linestyle='-') self.sendColormap() """ max value changed by text """ def maxTextChanged(self): text = str(self.maxText.text()) if not len(text): return val = float(text) self.setMaxValue(val) if self.maxText.hasFocus(): self.c.setFocus() """ change only the displayed max value """ def setDisplayedMaxValue(self, val): val = float(val) self.maxValue = val self.maxText.setText("%g" % val) self.__x[2] = val key = self.markers[2][0] label = self.markers[2][1] self.c.addXMarker(val, legend=key, text=label, color="blue", draggable=True) self.c.addCurve(self.__x, self.__y, legend="ConstrainedCurve", color='black', symbol='o', linestyle='-') # DATA values """ set min/max value of data source """ def setDataMinMax(self, minVal, maxVal, update=True): if minVal is not None: vmin = float(str(minVal)) self.dataMin = vmin if maxVal is not None: vmax = float(str(maxVal)) self.dataMax = vmax if update: # are current values in the good range ? self._update() def getColormap(self): if self.minValue > self.maxValue: vmax = self.minValue vmin = self.maxValue else: vmax = self.maxValue vmin = self.minValue cmap = [ self.colormapIndex, self.autoscale, vmin, vmax, self.dataMin, self.dataMax, self.colormapType ] return cmap if self.exec_() else None """ send 'ColormapChanged' signal """ def sendColormap(self): _logger.debug("sending colormap") try: cmap = self.getColormap() self.sigColormapChanged.emit(cmap) except: sys.excepthook(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2]) def colormapListToDict(colormapList): """Convert colormap from this dialog to :class:`PlotBackend`. :param colormapList: Colormap as returned by :meth:`getColormap`. :type colormapList: list or tuple :return: Colormap as used in :class:`PlotBackend`. :rtype: dict """ index, autoscale, vMin, vMax, dataMin, dataMax, cmapType = colormapList # Warning, gamma cmapType is not supported in plot backend # Here it is silently replaced by linear as the default colormap return { 'name': _COLORMAP_NAMES[index], 'autoscale': autoscale, 'vmin': vMin, 'vmax': vMax, 'normalization': 'log' if cmapType == 1 else 'linear', 'colors': 256 } def getColormap_name(self): self.getColormap() return _COLORMAP_NAMES[self.colormapIndex] def getColor(self): return _COLOR_NAMES[self.colormapIndex] def colormapDictToList(colormapDict): """Convert colormap from :class:`PlotBackend` to this dialog. :param dict colormapDict: Colormap as used in :class:`PlotBackend`. :return: Colormap as returned by :meth:`getColormap`. :rtype: list """ cmapIndex = _COLORMAP_NAMES.index(colormapDict['name']) cmapType = 1 if colormapDict['normalization'].startswith('log') else 0 return [ cmapIndex, colormapDict['autoscale'], colormapDict['vmin'], colormapDict['vmax'], 0, # dataMin is not defined in PlotBackend colormap 0, # dataMax is not defined in PlotBackend colormap cmapType ]
class RGBCorrelatorGraph(qt.QWidget): sigProfileSignal = qt.pyqtSignal(object) def __init__(self, parent=None, backend=None, selection=False, aspect=True, colormap=False, imageicons=False, standalonesave=True, standalonezoom=True, profileselection=False, polygon=False): qt.QWidget.__init__(self, parent) self.mainLayout = qt.QVBoxLayout(self) self.mainLayout.setContentsMargins(0, 0, 0, 0) self.mainLayout.setSpacing(0) self._keepDataAspectRatioFlag = False self.graph = PlotWidget(parent=self, backend=backend) self.graph.setGraphXLabel("Column") self.graph.setGraphYLabel("Row") self.graph.setYAxisAutoScale(True) self.graph.setXAxisAutoScale(True) plotArea = self.graph.getWidgetHandle() plotArea.setContextMenuPolicy(qt.Qt.CustomContextMenu) plotArea.customContextMenuRequested.connect(self._zoomBack) self._buildToolBar(selection, colormap, imageicons, standalonesave, standalonezoom=standalonezoom, profileselection=profileselection, aspect=aspect, polygon=polygon) if profileselection: if len(self._pickerSelectionButtons): self.graph.sigPlotSignal.connect(\ self._graphPolygonSignalReceived) self._pickerSelectionWidthValue.valueChanged[int].connect( \ self.setPickerSelectionWith) self.saveDirectory = os.getcwd() self.mainLayout.addWidget(self.graph) def sizeHint(self): return qt.QSize(1.5 * qt.QWidget.sizeHint(self).width(), qt.QWidget.sizeHint(self).height()) def _buildToolBar(self, selection=False, colormap=False, imageicons=False, standalonesave=True, standalonezoom=True, profileselection=False, aspect=False, polygon=False): self.solidCircleIcon = qt.QIcon(qt.QPixmap(IconDict["solidcircle"])) self.solidEllipseIcon = qt.QIcon(qt.QPixmap(IconDict["solidellipse"])) self.colormapIcon = qt.QIcon(qt.QPixmap(IconDict["colormap"])) self.selectionIcon = qt.QIcon(qt.QPixmap(IconDict["normal"])) self.zoomResetIcon = qt.QIcon(qt.QPixmap(IconDict["zoomreset"])) self.polygonIcon = qt.QIcon(qt.QPixmap(IconDict["polygon"])) self.printIcon = qt.QIcon(qt.QPixmap(IconDict["fileprint"])) self.saveIcon = qt.QIcon(qt.QPixmap(IconDict["filesave"])) self.xAutoIcon = qt.QIcon(qt.QPixmap(IconDict["xauto"])) self.yAutoIcon = qt.QIcon(qt.QPixmap(IconDict["yauto"])) self.hFlipIcon = qt.QIcon(qt.QPixmap(IconDict["gioconda16mirror"])) self.imageIcon = qt.QIcon(qt.QPixmap(IconDict["image"])) self.eraseSelectionIcon = qt.QIcon(qt.QPixmap(IconDict["eraseselect"])) self.rectSelectionIcon = qt.QIcon(qt.QPixmap(IconDict["boxselect"])) self.brushSelectionIcon = qt.QIcon(qt.QPixmap(IconDict["brushselect"])) self.brushIcon = qt.QIcon(qt.QPixmap(IconDict["brush"])) self.additionalIcon = qt.QIcon(qt.QPixmap( IconDict["additionalselect"])) self.hLineIcon = qt.QIcon(qt.QPixmap(IconDict["horizontal"])) self.vLineIcon = qt.QIcon(qt.QPixmap(IconDict["vertical"])) self.lineIcon = qt.QIcon(qt.QPixmap(IconDict["diagonal"])) self.copyIcon = silx_icons.getQIcon("edit-copy") self.toolBar = qt.QWidget(self) self.toolBarLayout = qt.QHBoxLayout(self.toolBar) self.toolBarLayout.setContentsMargins(0, 0, 0, 0) self.toolBarLayout.setSpacing(0) self.mainLayout.addWidget(self.toolBar) #Autoscale if standalonezoom: tb = self._addToolButton(self.zoomResetIcon, self.__zoomReset, 'Auto-Scale the Graph') else: tb = self._addToolButton(self.zoomResetIcon, None, 'Auto-Scale the Graph') self.zoomResetToolButton = tb #y Autoscale tb = self._addToolButton(self.yAutoIcon, self._yAutoScaleToggle, 'Toggle Autoscale Y Axis (On/Off)', toggle=True, state=True) tb.setDown(True) self.yAutoScaleToolButton = tb tb.setDown(True) #x Autoscale tb = self._addToolButton(self.xAutoIcon, self._xAutoScaleToggle, 'Toggle Autoscale X Axis (On/Off)', toggle=True, state=True) self.xAutoScaleToolButton = tb tb.setDown(True) #Aspect ratio if aspect: self.aspectButton = self._addToolButton(self.solidCircleIcon, self._aspectButtonSignal, 'Keep data aspect ratio', toggle=False) self.aspectButton.setChecked(False) #colormap if colormap: tb = self._addToolButton(self.colormapIcon, None, 'Change Colormap') self.colormapToolButton = tb #flip tb = self._addToolButton(self.hFlipIcon, None, 'Flip Horizontal') self.hFlipToolButton = tb #save if standalonesave: tb = self._addToolButton(self.saveIcon, self._saveIconSignal, 'Save Graph') else: tb = self._addToolButton(self.saveIcon, None, 'Save') self.saveToolButton = tb self.copyToolButton = self._addToolButton(self.copyIcon, self._copyIconSignal, "Copy graph to clipboard") #Selection if selection: tb = self._addToolButton(self.selectionIcon, None, 'Toggle Selection Mode', toggle=True, state=False) tb.setDown(False) self.selectionToolButton = tb #image selection icons if imageicons: tb = self._addToolButton(self.imageIcon, None, 'Reset') self.imageToolButton = tb tb = self._addToolButton(self.eraseSelectionIcon, None, 'Erase Selection') self.eraseSelectionToolButton = tb tb = self._addToolButton(self.rectSelectionIcon, None, 'Rectangular Selection') self.rectSelectionToolButton = tb tb = self._addToolButton(self.brushSelectionIcon, None, 'Brush Selection') self.brushSelectionToolButton = tb tb = self._addToolButton(self.brushIcon, None, 'Select Brush') self.brushToolButton = tb if polygon: tb = self._addToolButton( self.polygonIcon, None, 'Polygon selection\nRight click to finish') self.polygonSelectionToolButton = tb tb = self._addToolButton(self.additionalIcon, None, 'Additional Selections Menu') self.additionalSelectionToolButton = tb else: if polygon: tb = self._addToolButton( self.polygonIcon, None, 'Polygon selection\nRight click to finish') self.polygonSelectionToolButton = tb self.imageToolButton = None #picker selection self._pickerSelectionButtons = [] if profileselection: self._profileSelection = True self._polygonSelection = False self._pickerSelectionButtons = [] if self._profileSelection: tb = self._addToolButton(self.hLineIcon, self._hLineProfileClicked, 'Horizontal Profile Selection', toggle=True, state=False) self.hLineProfileButton = tb self._pickerSelectionButtons.append(tb) tb = self._addToolButton(self.vLineIcon, self._vLineProfileClicked, 'Vertical Profile Selection', toggle=True, state=False) self.vLineProfileButton = tb self._pickerSelectionButtons.append(tb) tb = self._addToolButton(self.lineIcon, self._lineProfileClicked, 'Line Profile Selection', toggle=True, state=False) self.lineProfileButton = tb self._pickerSelectionButtons.append(tb) self._pickerSelectionWidthLabel = qt.QLabel(self.toolBar) self._pickerSelectionWidthLabel.setText("W:") self.toolBar.layout().addWidget( self._pickerSelectionWidthLabel) self._pickerSelectionWidthValue = qt.QSpinBox(self.toolBar) self._pickerSelectionWidthValue.setMinimum(0) self._pickerSelectionWidthValue.setMaximum(1000) self._pickerSelectionWidthValue.setValue(1) self.toolBar.layout().addWidget( self._pickerSelectionWidthValue) #tb = self._addToolButton(None, # self._lineProfileClicked, # 'Line Profile Selection', # toggle=True, # state=False) #tb.setText = "W:" #self.lineWidthProfileButton = tb #self._pickerSelectionButtons.append(tb) if self._polygonSelection: _logger.info("Polygon selection not implemented yet") #hide profile selection buttons if imageicons: for button in self._pickerSelectionButtons: button.hide() self.infoWidget = qt.QWidget(self.toolBar) self.infoWidget.mainLayout = qt.QHBoxLayout(self.infoWidget) self.infoWidget.mainLayout.setContentsMargins(0, 0, 0, 0) self.infoWidget.mainLayout.setSpacing(0) self.infoWidget.label = qt.QLabel(self.infoWidget) self.infoWidget.label.setText("X = ???? Y = ???? Z = ????") self.infoWidget.mainLayout.addWidget(self.infoWidget.label) self.toolBarLayout.addWidget(self.infoWidget) self.infoWidget.hide() self.toolBarLayout.addWidget(qt.HorizontalSpacer(self.toolBar)) # ---print self.printPreview = SingletonPrintPreviewToolButton(parent=self, plot=self.graph) self.printPreview.setIcon(self.printIcon) self.toolBarLayout.addWidget(self.printPreview) def _aspectButtonSignal(self): _logger.debug("_aspectButtonSignal") if self._keepDataAspectRatioFlag: self.keepDataAspectRatio(False) else: self.keepDataAspectRatio(True) def keepDataAspectRatio(self, flag=True): if flag: self._keepDataAspectRatioFlag = True self.aspectButton.setIcon(self.solidEllipseIcon) self.aspectButton.setToolTip("Set free data aspect ratio") else: self._keepDataAspectRatioFlag = False self.aspectButton.setIcon(self.solidCircleIcon) self.aspectButton.setToolTip("Keep data aspect ratio") self.graph.setKeepDataAspectRatio(self._keepDataAspectRatioFlag) def showInfo(self): self.infoWidget.show() def hideInfo(self): self.infoWidget.hide() def setInfoText(self, text): self.infoWidget.label.setText(text) def setMouseText(self, text=""): try: if len(text): qt.QToolTip.showText(self.cursor().pos(), text, self, qt.QRect()) else: qt.QToolTip.hideText() except: _logger.warning("Error trying to show mouse text <%s>" % text) def focusOutEvent(self, ev): qt.QToolTip.hideText() def infoText(self): return self.infoWidget.label.text() def setXLabel(self, label="Column"): return self.graph.setGraphXLabel(label) def setYLabel(self, label="Row"): return self.graph.setGraphYLabel(label) def getXLabel(self): return self.graph.getGraphXLabel() def getYLabel(self): return self.graph.getGraphYLabel() def hideImageIcons(self): if self.imageToolButton is None: return self.imageToolButton.hide() self.eraseSelectionToolButton.hide() self.rectSelectionToolButton.hide() self.brushSelectionToolButton.hide() self.brushToolButton.hide() if hasattr(self, "polygonSelectionToolButton"): self.polygonSelectionToolButton.hide() self.additionalSelectionToolButton.hide() def showImageIcons(self): if self.imageToolButton is None: return self.imageToolButton.show() self.eraseSelectionToolButton.show() self.rectSelectionToolButton.show() self.brushSelectionToolButton.show() self.brushToolButton.show() if hasattr(self, "polygonSelectionToolButton"): self.polygonSelectionToolButton.show() self.additionalSelectionToolButton.show() def _hLineProfileClicked(self): for button in self._pickerSelectionButtons: if button != self.hLineProfileButton: button.setChecked(False) if self.hLineProfileButton.isChecked(): self._setPickerSelectionMode("HORIZONTAL") else: self._setPickerSelectionMode(None) def _vLineProfileClicked(self): for button in self._pickerSelectionButtons: if button != self.vLineProfileButton: button.setChecked(False) if self.vLineProfileButton.isChecked(): self._setPickerSelectionMode("VERTICAL") else: self._setPickerSelectionMode(None) def _lineProfileClicked(self): for button in self._pickerSelectionButtons: if button != self.lineProfileButton: button.setChecked(False) if self.lineProfileButton.isChecked(): self._setPickerSelectionMode("LINE") else: self._setPickerSelectionMode(None) def setPickerSelectionWith(self, intValue): self._pickerSelectionWidthValue.setValue(intValue) #get the current mode mode = "NONE" for button in self._pickerSelectionButtons: if button.isChecked(): if button == self.hLineProfileButton: mode = "HORIZONTAL" elif button == self.vLineProfileButton: mode = "VERTICAL" elif button == self.lineProfileButton: mode = "LINE" ddict = {} ddict['event'] = "profileWidthChanged" ddict['pixelwidth'] = self._pickerSelectionWidthValue.value() ddict['mode'] = mode self.sigProfileSignal.emit(ddict) def hideProfileSelectionIcons(self): if not len(self._pickerSelectionButtons): return for button in self._pickerSelectionButtons: button.setChecked(False) button.hide() self._pickerSelectionWidthLabel.hide() self._pickerSelectionWidthValue.hide() if self.graph.getInteractiveMode()['mode'] == 'draw': self.graph.setInteractiveMode('select') def showProfileSelectionIcons(self): if not len(self._pickerSelectionButtons): return for button in self._pickerSelectionButtons: button.show() self._pickerSelectionWidthLabel.show() self._pickerSelectionWidthValue.show() def getPickerSelectionMode(self): if not len(self._pickerSelectionButtons): return None if self.hLineProfileButton.isChecked(): return "HORIZONTAL" if self.vLineProfileButton.isChecked(): return "VERTICAL" if self.lineProfileButton.isChecked(): return "LINE" return None def _setPickerSelectionMode(self, mode=None): if mode is None: self.graph.setInteractiveMode('zoom') else: if mode == "HORIZONTAL": shape = "hline" elif mode == "VERTICAL": shape = "vline" else: shape = "line" self.graph.setInteractiveMode('draw', shape=shape, label=mode) ddict = {} if mode is None: mode = "NONE" ddict['event'] = "profileModeChanged" ddict['mode'] = mode self.sigProfileSignal.emit(ddict) def _graphPolygonSignalReceived(self, ddict): _logger.debug("PolygonSignal Received") for key in ddict.keys(): _logger.debug("%s: %s", key, ddict[key]) if ddict['event'] not in ['drawingProgress', 'drawingFinished']: return label = ddict['parameters']['label'] if label not in ['HORIZONTAL', 'VERTICAL', 'LINE']: return ddict['mode'] = label ddict['pixelwidth'] = self._pickerSelectionWidthValue.value() self.sigProfileSignal.emit(ddict) def _addToolButton(self, icon, action, tip, toggle=None, state=None, position=None): tb = qt.QToolButton(self.toolBar) if icon is not None: tb.setIcon(icon) tb.setToolTip(tip) if toggle is not None: if toggle: tb.setCheckable(1) if state is not None: if state: tb.setChecked(state) else: tb.setChecked(False) if position is not None: self.toolBarLayout.insertWidget(position, tb) else: self.toolBarLayout.addWidget(tb) if action is not None: tb.clicked.connect(action) return tb def __zoomReset(self): self._zoomReset() def _zoomReset(self, replot=None): _logger.debug("_zoomReset") if self.graph is not None: self.graph.resetZoom() def _yAutoScaleToggle(self): if self.graph is not None: self.yAutoScaleToolButton.setDown( not self.graph.isYAxisAutoScale()) self.graph.setYAxisAutoScale(not self.graph.isYAxisAutoScale()) def _xAutoScaleToggle(self): if self.graph is not None: self.xAutoScaleToolButton.setDown( not self.graph.isXAxisAutoScale()) self.graph.setXAxisAutoScale(not self.graph.isXAxisAutoScale()) def _copyIconSignal(self): pngFile = BytesIO() self.graph.saveGraph(pngFile, fileFormat='png') pngFile.flush() pngFile.seek(0) pngData = pngFile.read() pngFile.close() image = qt.QImage.fromData(pngData, 'png') qt.QApplication.clipboard().setImage(image) def _saveIconSignal(self): self.saveDirectory = PyMcaDirs.outputDir fileTypeList = [ "Image *.png", "Image *.jpg", "ZoomedImage *.png", "ZoomedImage *.jpg", "Widget *.png", "Widget *.jpg" ] outfile = qt.QFileDialog(self) outfile.setModal(1) outfile.setWindowTitle("Output File Selection") if hasattr(qt, "QStringList"): strlist = qt.QStringList() else: strlist = [] for f in fileTypeList: strlist.append(f) if hasattr(outfile, "setFilters"): outfile.setFilters(strlist) else: outfile.setNameFilters(strlist) outfile.setFileMode(outfile.AnyFile) outfile.setAcceptMode(qt.QFileDialog.AcceptSave) outfile.setDirectory(self.saveDirectory) ret = outfile.exec_() if not ret: return if hasattr(outfile, "selectedFilter"): filterused = qt.safe_str(outfile.selectedFilter()).split() else: filterused = qt.safe_str(outfile.selectedNameFilter()).split() filetype = filterused[0] extension = filterused[1] outstr = qt.safe_str(outfile.selectedFiles()[0]) try: outputFile = os.path.basename(outstr) except: outputFile = outstr outputDir = os.path.dirname(outstr) self.saveDirectory = outputDir PyMcaDirs.outputDir = outputDir #always overwrite for the time being if len(outputFile) < len(extension[1:]): outputFile += extension[1:] elif outputFile[-4:] != extension[1:]: outputFile += extension[1:] outputFile = os.path.join(outputDir, outputFile) if os.path.exists(outputFile): try: os.remove(outputFile) except: qt.QMessageBox.critical(self, "Save Error", "Cannot overwrite existing file") return if filetype.upper() == "IMAGE": self.saveGraphImage(outputFile, original=True) elif filetype.upper() == "ZOOMEDIMAGE": self.saveGraphImage(outputFile, original=False) else: self.saveGraphWidget(outputFile) def saveGraphImage(self, filename, original=False): format_ = filename[-3:].upper() activeImage = self.graph.getActiveImage() rgbdata = activeImage.getRgbaImageData() # silx to pymca scale convention (a + b x) xScale = activeImage.getOrigin()[0], activeImage.getScale()[0] yScale = activeImage.getOrigin()[1], activeImage.getScale()[1] if original: # save whole image bgradata = numpy.array(rgbdata, copy=True) bgradata[:, :, 0] = rgbdata[:, :, 2] bgradata[:, :, 2] = rgbdata[:, :, 0] else: shape = rgbdata.shape[:2] xmin, xmax = self.graph.getGraphXLimits() ymin, ymax = self.graph.getGraphYLimits() # save zoomed image, for that we have to get the limits r0, c0 = convertToRowAndColumn(xmin, ymin, shape, xScale=xScale, yScale=yScale, safe=True) r1, c1 = convertToRowAndColumn(xmax, ymax, shape, xScale=xScale, yScale=yScale, safe=True) row0 = int(min(r0, r1)) row1 = int(max(r0, r1)) col0 = int(min(c0, c1)) col1 = int(max(c0, c1)) if row1 < shape[0]: row1 += 1 if col1 < shape[1]: col1 += 1 tmpArray = rgbdata[row0:row1, col0:col1, :] bgradata = numpy.array(tmpArray, copy=True, dtype=rgbdata.dtype) bgradata[:, :, 0] = tmpArray[:, :, 2] bgradata[:, :, 2] = tmpArray[:, :, 0] if self.graph.isYAxisInverted(): qImage = qt.QImage(bgradata, bgradata.shape[1], bgradata.shape[0], qt.QImage.Format_ARGB32) else: qImage = qt.QImage(bgradata, bgradata.shape[1], bgradata.shape[0], qt.QImage.Format_ARGB32).mirrored(False, True) pixmap = qt.QPixmap.fromImage(qImage) if pixmap.save(filename, format_): return else: qt.QMessageBox.critical(self, "Save Error", "%s" % sys.exc_info()[1]) return def saveGraphWidget(self, filename): format_ = filename[-3:].upper() if hasattr(qt.QPixmap, "grabWidget"): # Qt4 pixmap = qt.QPixmap.grabWidget(self.graph.getWidgetHandle()) else: # Qt5 pixmap = self.graph.getWidgetHandle().grab() if pixmap.save(filename, format_): return else: qt.QMessageBox.critical(self, "Save Error", "%s" % sys.exc_info()[1]) return def setSaveDirectory(self, wdir): if os.path.exists(wdir): self.saveDirectory = wdir return True else: return False def selectColormap(self): qt.QMessageBox.information(self, "Open", "Not implemented (yet)") def _zoomBack(self, pos): self.graph.getLimitsHistory().pop()
class RGBCorrelatorGraph(qt.QWidget): sigProfileSignal = qt.pyqtSignal(object) def __init__(self, parent = None, backend=None, selection=False, aspect=True, colormap=False, imageicons=False, standalonesave=True, standalonezoom=True, profileselection=False, polygon=False): qt.QWidget.__init__(self, parent) self.mainLayout = qt.QVBoxLayout(self) self.mainLayout.setContentsMargins(0, 0, 0, 0) self.mainLayout.setSpacing(0) self._keepDataAspectRatioFlag = False self.graph = PlotWidget(parent=self, backend=backend) self.graph.setGraphXLabel("Column") self.graph.setGraphYLabel("Row") self.graph.setYAxisAutoScale(True) self.graph.setXAxisAutoScale(True) plotArea = self.graph.getWidgetHandle() plotArea.setContextMenuPolicy(qt.Qt.CustomContextMenu) plotArea.customContextMenuRequested.connect(self._zoomBack) self._buildToolBar(selection, colormap, imageicons, standalonesave, standalonezoom=standalonezoom, profileselection=profileselection, aspect=aspect, polygon=polygon) if profileselection: if len(self._pickerSelectionButtons): self.graph.sigPlotSignal.connect(\ self._graphPolygonSignalReceived) self._pickerSelectionWidthValue.valueChanged[int].connect( \ self.setPickerSelectionWith) self.saveDirectory = os.getcwd() self.mainLayout.addWidget(self.graph) def sizeHint(self): return qt.QSize(1.5 * qt.QWidget.sizeHint(self).width(), qt.QWidget.sizeHint(self).height()) def _buildToolBar(self, selection=False, colormap=False, imageicons=False, standalonesave=True, standalonezoom=True, profileselection=False, aspect=False, polygon=False): self.solidCircleIcon = qt.QIcon(qt.QPixmap(IconDict["solidcircle"])) self.solidEllipseIcon = qt.QIcon(qt.QPixmap(IconDict["solidellipse"])) self.colormapIcon = qt.QIcon(qt.QPixmap(IconDict["colormap"])) self.selectionIcon = qt.QIcon(qt.QPixmap(IconDict["normal"])) self.zoomResetIcon = qt.QIcon(qt.QPixmap(IconDict["zoomreset"])) self.polygonIcon = qt.QIcon(qt.QPixmap(IconDict["polygon"])) self.printIcon = qt.QIcon(qt.QPixmap(IconDict["fileprint"])) self.saveIcon = qt.QIcon(qt.QPixmap(IconDict["filesave"])) self.xAutoIcon = qt.QIcon(qt.QPixmap(IconDict["xauto"])) self.yAutoIcon = qt.QIcon(qt.QPixmap(IconDict["yauto"])) self.hFlipIcon = qt.QIcon(qt.QPixmap(IconDict["gioconda16mirror"])) self.imageIcon = qt.QIcon(qt.QPixmap(IconDict["image"])) self.eraseSelectionIcon = qt.QIcon(qt.QPixmap(IconDict["eraseselect"])) self.rectSelectionIcon = qt.QIcon(qt.QPixmap(IconDict["boxselect"])) self.brushSelectionIcon = qt.QIcon(qt.QPixmap(IconDict["brushselect"])) self.brushIcon = qt.QIcon(qt.QPixmap(IconDict["brush"])) self.additionalIcon = qt.QIcon(qt.QPixmap(IconDict["additionalselect"])) self.hLineIcon = qt.QIcon(qt.QPixmap(IconDict["horizontal"])) self.vLineIcon = qt.QIcon(qt.QPixmap(IconDict["vertical"])) self.lineIcon = qt.QIcon(qt.QPixmap(IconDict["diagonal"])) self.copyIcon = silx_icons.getQIcon("edit-copy") self.toolBar = qt.QWidget(self) self.toolBarLayout = qt.QHBoxLayout(self.toolBar) self.toolBarLayout.setContentsMargins(0, 0, 0, 0) self.toolBarLayout.setSpacing(0) self.mainLayout.addWidget(self.toolBar) #Autoscale if standalonezoom: tb = self._addToolButton(self.zoomResetIcon, self.__zoomReset, 'Auto-Scale the Graph') else: tb = self._addToolButton(self.zoomResetIcon, None, 'Auto-Scale the Graph') self.zoomResetToolButton = tb #y Autoscale tb = self._addToolButton(self.yAutoIcon, self._yAutoScaleToggle, 'Toggle Autoscale Y Axis (On/Off)', toggle = True, state=True) tb.setDown(True) self.yAutoScaleToolButton = tb tb.setDown(True) #x Autoscale tb = self._addToolButton(self.xAutoIcon, self._xAutoScaleToggle, 'Toggle Autoscale X Axis (On/Off)', toggle = True, state=True) self.xAutoScaleToolButton = tb tb.setDown(True) #Aspect ratio if aspect: self.aspectButton = self._addToolButton(self.solidCircleIcon, self._aspectButtonSignal, 'Keep data aspect ratio', toggle=False) self.aspectButton.setChecked(False) #colormap if colormap: tb = self._addToolButton(self.colormapIcon, None, 'Change Colormap') self.colormapToolButton = tb #flip tb = self._addToolButton(self.hFlipIcon, None, 'Flip Horizontal') self.hFlipToolButton = tb #save if standalonesave: tb = self._addToolButton(self.saveIcon, self._saveIconSignal, 'Save Graph') else: tb = self._addToolButton(self.saveIcon, None, 'Save') self.saveToolButton = tb self.copyToolButton = self._addToolButton(self.copyIcon, self._copyIconSignal, "Copy graph to clipboard") #Selection if selection: tb = self._addToolButton(self.selectionIcon, None, 'Toggle Selection Mode', toggle = True, state = False) tb.setDown(False) self.selectionToolButton = tb #image selection icons if imageicons: tb = self._addToolButton(self.imageIcon, None, 'Reset') self.imageToolButton = tb tb = self._addToolButton(self.eraseSelectionIcon, None, 'Erase Selection') self.eraseSelectionToolButton = tb tb = self._addToolButton(self.rectSelectionIcon, None, 'Rectangular Selection') self.rectSelectionToolButton = tb tb = self._addToolButton(self.brushSelectionIcon, None, 'Brush Selection') self.brushSelectionToolButton = tb tb = self._addToolButton(self.brushIcon, None, 'Select Brush') self.brushToolButton = tb if polygon: tb = self._addToolButton(self.polygonIcon, None, 'Polygon selection\nRight click to finish') self.polygonSelectionToolButton = tb tb = self._addToolButton(self.additionalIcon, None, 'Additional Selections Menu') self.additionalSelectionToolButton = tb else: if polygon: tb = self._addToolButton(self.polygonIcon, None, 'Polygon selection\nRight click to finish') self.polygonSelectionToolButton = tb self.imageToolButton = None #picker selection self._pickerSelectionButtons = [] if profileselection: self._profileSelection = True self._polygonSelection = False self._pickerSelectionButtons = [] if self._profileSelection: tb = self._addToolButton(self.hLineIcon, self._hLineProfileClicked, 'Horizontal Profile Selection', toggle=True, state=False) self.hLineProfileButton = tb self._pickerSelectionButtons.append(tb) tb = self._addToolButton(self.vLineIcon, self._vLineProfileClicked, 'Vertical Profile Selection', toggle=True, state=False) self.vLineProfileButton = tb self._pickerSelectionButtons.append(tb) tb = self._addToolButton(self.lineIcon, self._lineProfileClicked, 'Line Profile Selection', toggle=True, state=False) self.lineProfileButton = tb self._pickerSelectionButtons.append(tb) self._pickerSelectionWidthLabel = qt.QLabel(self.toolBar) self._pickerSelectionWidthLabel.setText("W:") self.toolBar.layout().addWidget(self._pickerSelectionWidthLabel) self._pickerSelectionWidthValue = qt.QSpinBox(self.toolBar) self._pickerSelectionWidthValue.setMinimum(0) self._pickerSelectionWidthValue.setMaximum(1000) self._pickerSelectionWidthValue.setValue(1) self.toolBar.layout().addWidget(self._pickerSelectionWidthValue) #tb = self._addToolButton(None, # self._lineProfileClicked, # 'Line Profile Selection', # toggle=True, # state=False) #tb.setText = "W:" #self.lineWidthProfileButton = tb #self._pickerSelectionButtons.append(tb) if self._polygonSelection: _logger.info("Polygon selection not implemented yet") #hide profile selection buttons if imageicons: for button in self._pickerSelectionButtons: button.hide() self.infoWidget = qt.QWidget(self.toolBar) self.infoWidget.mainLayout = qt.QHBoxLayout(self.infoWidget) self.infoWidget.mainLayout.setContentsMargins(0, 0, 0, 0) self.infoWidget.mainLayout.setSpacing(0) self.infoWidget.label = qt.QLabel(self.infoWidget) self.infoWidget.label.setText("X = ???? Y = ???? Z = ????") self.infoWidget.mainLayout.addWidget(self.infoWidget.label) self.toolBarLayout.addWidget(self.infoWidget) self.infoWidget.hide() self.toolBarLayout.addWidget(qt.HorizontalSpacer(self.toolBar)) # ---print self.printPreview = SingletonPrintPreviewToolButton(parent=self, plot=self.graph) self.printPreview.setIcon(self.printIcon) self.toolBarLayout.addWidget(self.printPreview) def _aspectButtonSignal(self): _logger.debug("_aspectButtonSignal") if self._keepDataAspectRatioFlag: self.keepDataAspectRatio(False) else: self.keepDataAspectRatio(True) def keepDataAspectRatio(self, flag=True): if flag: self._keepDataAspectRatioFlag = True self.aspectButton.setIcon(self.solidEllipseIcon) self.aspectButton.setToolTip("Set free data aspect ratio") else: self._keepDataAspectRatioFlag = False self.aspectButton.setIcon(self.solidCircleIcon) self.aspectButton.setToolTip("Keep data aspect ratio") self.graph.setKeepDataAspectRatio(self._keepDataAspectRatioFlag) def showInfo(self): self.infoWidget.show() def hideInfo(self): self.infoWidget.hide() def setInfoText(self, text): self.infoWidget.label.setText(text) def setMouseText(self, text=""): try: if len(text): qt.QToolTip.showText(self.cursor().pos(), text, self, qt.QRect()) else: qt.QToolTip.hideText() except: _logger.warning("Error trying to show mouse text <%s>" % text) def focusOutEvent(self, ev): qt.QToolTip.hideText() def infoText(self): return self.infoWidget.label.text() def setXLabel(self, label="Column"): return self.graph.setGraphXLabel(label) def setYLabel(self, label="Row"): return self.graph.setGraphYLabel(label) def getXLabel(self): return self.graph.getGraphXLabel() def getYLabel(self): return self.graph.getGraphYLabel() def hideImageIcons(self): if self.imageToolButton is None:return self.imageToolButton.hide() self.eraseSelectionToolButton.hide() self.rectSelectionToolButton.hide() self.brushSelectionToolButton.hide() self.brushToolButton.hide() if hasattr(self, "polygonSelectionToolButton"): self.polygonSelectionToolButton.hide() self.additionalSelectionToolButton.hide() def showImageIcons(self): if self.imageToolButton is None:return self.imageToolButton.show() self.eraseSelectionToolButton.show() self.rectSelectionToolButton.show() self.brushSelectionToolButton.show() self.brushToolButton.show() if hasattr(self, "polygonSelectionToolButton"): self.polygonSelectionToolButton.show() self.additionalSelectionToolButton.show() def _hLineProfileClicked(self): for button in self._pickerSelectionButtons: if button != self.hLineProfileButton: button.setChecked(False) if self.hLineProfileButton.isChecked(): self._setPickerSelectionMode("HORIZONTAL") else: self._setPickerSelectionMode(None) def _vLineProfileClicked(self): for button in self._pickerSelectionButtons: if button != self.vLineProfileButton: button.setChecked(False) if self.vLineProfileButton.isChecked(): self._setPickerSelectionMode("VERTICAL") else: self._setPickerSelectionMode(None) def _lineProfileClicked(self): for button in self._pickerSelectionButtons: if button != self.lineProfileButton: button.setChecked(False) if self.lineProfileButton.isChecked(): self._setPickerSelectionMode("LINE") else: self._setPickerSelectionMode(None) def setPickerSelectionWith(self, intValue): self._pickerSelectionWidthValue.setValue(intValue) #get the current mode mode = "NONE" for button in self._pickerSelectionButtons: if button.isChecked(): if button == self.hLineProfileButton: mode = "HORIZONTAL" elif button == self.vLineProfileButton: mode = "VERTICAL" elif button == self.lineProfileButton: mode = "LINE" ddict = {} ddict['event'] = "profileWidthChanged" ddict['pixelwidth'] = self._pickerSelectionWidthValue.value() ddict['mode'] = mode self.sigProfileSignal.emit(ddict) def hideProfileSelectionIcons(self): if not len(self._pickerSelectionButtons): return for button in self._pickerSelectionButtons: button.setChecked(False) button.hide() self._pickerSelectionWidthLabel.hide() self._pickerSelectionWidthValue.hide() if self.graph.getInteractiveMode()['mode'] == 'draw': self.graph.setInteractiveMode('select') def showProfileSelectionIcons(self): if not len(self._pickerSelectionButtons): return for button in self._pickerSelectionButtons: button.show() self._pickerSelectionWidthLabel.show() self._pickerSelectionWidthValue.show() def getPickerSelectionMode(self): if not len(self._pickerSelectionButtons): return None if self.hLineProfileButton.isChecked(): return "HORIZONTAL" if self.vLineProfileButton.isChecked(): return "VERTICAL" if self.lineProfileButton.isChecked(): return "LINE" return None def _setPickerSelectionMode(self, mode=None): if mode is None: self.graph.setInteractiveMode('zoom') else: if mode == "HORIZONTAL": shape = "hline" elif mode == "VERTICAL": shape = "vline" else: shape = "line" self.graph.setInteractiveMode('draw', shape=shape, label=mode) ddict = {} if mode is None: mode = "NONE" ddict['event'] = "profileModeChanged" ddict['mode'] = mode self.sigProfileSignal.emit(ddict) def _graphPolygonSignalReceived(self, ddict): _logger.debug("PolygonSignal Received") for key in ddict.keys(): _logger.debug("%s: %s", key, ddict[key]) if ddict['event'] not in ['drawingProgress', 'drawingFinished']: return label = ddict['parameters']['label'] if label not in ['HORIZONTAL', 'VERTICAL', 'LINE']: return ddict['mode'] = label ddict['pixelwidth'] = self._pickerSelectionWidthValue.value() self.sigProfileSignal.emit(ddict) def _addToolButton(self, icon, action, tip, toggle=None, state=None, position=None): tb = qt.QToolButton(self.toolBar) if icon is not None: tb.setIcon(icon) tb.setToolTip(tip) if toggle is not None: if toggle: tb.setCheckable(1) if state is not None: if state: tb.setChecked(state) else: tb.setChecked(False) if position is not None: self.toolBarLayout.insertWidget(position, tb) else: self.toolBarLayout.addWidget(tb) if action is not None: tb.clicked.connect(action) return tb def __zoomReset(self): self._zoomReset() def _zoomReset(self, replot=None): _logger.debug("_zoomReset") if self.graph is not None: self.graph.resetZoom() def _yAutoScaleToggle(self): if self.graph is not None: self.yAutoScaleToolButton.setDown( not self.graph.isYAxisAutoScale()) self.graph.setYAxisAutoScale( not self.graph.isYAxisAutoScale()) def _xAutoScaleToggle(self): if self.graph is not None: self.xAutoScaleToolButton.setDown( not self.graph.isXAxisAutoScale()) self.graph.setXAxisAutoScale( not self.graph.isXAxisAutoScale()) def _copyIconSignal(self): pngFile = BytesIO() self.graph.saveGraph(pngFile, fileFormat='png') pngFile.flush() pngFile.seek(0) pngData = pngFile.read() pngFile.close() image = qt.QImage.fromData(pngData, 'png') qt.QApplication.clipboard().setImage(image) def _saveIconSignal(self): self.saveDirectory = PyMcaDirs.outputDir fileTypeList = ["Image *.png", "Image *.jpg", "ZoomedImage *.png", "ZoomedImage *.jpg", "Widget *.png", "Widget *.jpg"] outfile = qt.QFileDialog(self) outfile.setModal(1) outfile.setWindowTitle("Output File Selection") if hasattr(qt, "QStringList"): strlist = qt.QStringList() else: strlist = [] for f in fileTypeList: strlist.append(f) if hasattr(outfile, "setFilters"): outfile.setFilters(strlist) else: outfile.setNameFilters(strlist) outfile.setFileMode(outfile.AnyFile) outfile.setAcceptMode(qt.QFileDialog.AcceptSave) outfile.setDirectory(self.saveDirectory) ret = outfile.exec_() if not ret: return if hasattr(outfile, "selectedFilter"): filterused = qt.safe_str(outfile.selectedFilter()).split() else: filterused = qt.safe_str(outfile.selectedNameFilter()).split() filetype = filterused[0] extension = filterused[1] outstr = qt.safe_str(outfile.selectedFiles()[0]) try: outputFile = os.path.basename(outstr) except: outputFile = outstr outputDir = os.path.dirname(outstr) self.saveDirectory = outputDir PyMcaDirs.outputDir = outputDir #always overwrite for the time being if len(outputFile) < len(extension[1:]): outputFile += extension[1:] elif outputFile[-4:] != extension[1:]: outputFile += extension[1:] outputFile = os.path.join(outputDir, outputFile) if os.path.exists(outputFile): try: os.remove(outputFile) except: qt.QMessageBox.critical(self, "Save Error", "Cannot overwrite existing file") return if filetype.upper() == "IMAGE": self.saveGraphImage(outputFile, original=True) elif filetype.upper() == "ZOOMEDIMAGE": self.saveGraphImage(outputFile, original=False) else: self.saveGraphWidget(outputFile) def saveGraphImage(self, filename, original=False): format_ = filename[-3:].upper() activeImage = self.graph.getActiveImage() rgbdata = activeImage.getRgbaImageData() # silx to pymca scale convention (a + b x) xScale = activeImage.getOrigin()[0], activeImage.getScale()[0] yScale = activeImage.getOrigin()[1], activeImage.getScale()[1] if original: # save whole image bgradata = numpy.array(rgbdata, copy=True) bgradata[:, :, 0] = rgbdata[:, :, 2] bgradata[:, :, 2] = rgbdata[:, :, 0] else: shape = rgbdata.shape[:2] xmin, xmax = self.graph.getGraphXLimits() ymin, ymax = self.graph.getGraphYLimits() # save zoomed image, for that we have to get the limits r0, c0 = convertToRowAndColumn(xmin, ymin, shape, xScale=xScale, yScale=yScale, safe=True) r1, c1 = convertToRowAndColumn(xmax, ymax, shape, xScale=xScale, yScale=yScale, safe=True) row0 = int(min(r0, r1)) row1 = int(max(r0, r1)) col0 = int(min(c0, c1)) col1 = int(max(c0, c1)) if row1 < shape[0]: row1 += 1 if col1 < shape[1]: col1 += 1 tmpArray = rgbdata[row0:row1, col0:col1, :] bgradata = numpy.array(tmpArray, copy=True, dtype=rgbdata.dtype) bgradata[:, :, 0] = tmpArray[:, :, 2] bgradata[:, :, 2] = tmpArray[:, :, 0] if self.graph.isYAxisInverted(): qImage = qt.QImage(bgradata, bgradata.shape[1], bgradata.shape[0], qt.QImage.Format_ARGB32) else: qImage = qt.QImage(bgradata, bgradata.shape[1], bgradata.shape[0], qt.QImage.Format_ARGB32).mirrored(False, True) pixmap = qt.QPixmap.fromImage(qImage) if pixmap.save(filename, format_): return else: qt.QMessageBox.critical(self, "Save Error", "%s" % sys.exc_info()[1]) return def saveGraphWidget(self, filename): format_ = filename[-3:].upper() if hasattr(qt.QPixmap, "grabWidget"): # Qt4 pixmap = qt.QPixmap.grabWidget(self.graph.getWidgetHandle()) else: # Qt5 pixmap = self.graph.getWidgetHandle().grab() if pixmap.save(filename, format_): return else: qt.QMessageBox.critical(self, "Save Error", "%s" % sys.exc_info()[1]) return def setSaveDirectory(self, wdir): if os.path.exists(wdir): self.saveDirectory = wdir return True else: return False def selectColormap(self): qt.QMessageBox.information(self, "Open", "Not implemented (yet)") def _zoomBack(self, pos): self.graph.getLimitsHistory().pop()