#/*##########################################################################
# Copyright (C) 2004-2015 V.A. Sole, European Synchrotron Radiation Facility
#
# This file is part of the PyMca X-ray Fluorescence Toolkit developed at
# the ESRF by the Software group.
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
#############################################################################*/
__author__ = "V.A. Sole - ESRF Data Analysis"
__contact__ = "sole@esrf.fr"
__license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import sys
from PyMca5.PyMcaGui import PyMcaQt as qt
from . import PlotWidget
QTVERSION = qt.qVersion()
DEBUG = 0
[docs]class MyQLineEdit(qt.QLineEdit):
def __init__(self,parent=None,name=""):
qt.QLineEdit.__init__(self,parent)
[docs] def focusInEvent(self,event):
self.setPaletteBackgroundColor(qt.QColor('yellow'))
[docs] def focusOutEvent(self,event):
self.setPaletteBackgroundColor(qt.QColor('white'))
self.returnPressed[()].emit()
[docs] def setPaletteBackgroundColor(self, color):
if DEBUG:
print("setPalettebackgroundColor not implemented yet")
pass
"""
Manage colormap Widget class
"""
[docs]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.PlotWidget(self, backend=None)
self.c.setGraphXLabel("Data Values")
self.c.setZoomModeEnabled(False)
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.insertXMarker(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())
[docs] 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='pink', # TODO: Change fill color
symbol='s',
linestyle='-', # Line style
#fill=True,
yaxis='right')
# TODO: Do not use info!
def _update(self):
if DEBUG:
print("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.insertXMarker(self.__x[i],
legend=key,
text=label,
draggable=draggable,
color=color)
self.c.replot()
self.sendColormap()
[docs] 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()
[docs] def chval(self, ddict):
if DEBUG:
print("Received ", 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
"""
[docs] def setColormap(self, colormap):
self.colormapIndex = colormap
if QTVERSION < '4.0.0':
self.combo.setCurrentItem(colormap)
else:
self.combo.setCurrentIndex(colormap)
[docs] def colormapChange(self, colormap):
self.colormapIndex = colormap
self.sendColormap()
# AUTOSCALE
"""
Autoscale
"""
[docs] def autoscaleChange(self, val):
self.autoscale = val
self.setAutoscale(val)
self.sendColormap()
[docs] def setAutoscale(self, val):
if DEBUG:
print("setAutoscale called", 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(0)
#self.c.disablemarkermode()
else:
self.autoScaleButton.setChecked(False)
self.autoScale90Button.setChecked(False)
self.minText.setEnabled(1)
self.maxText.setEnabled(1)
self.c.setEnabled(1)
#self.c.enablemarkermode()
"""
set rangeValues to dataMin ; dataMax-10%
"""
[docs] def autoscale90Change(self, val):
self.autoscale90 = val
self.setAutoscale90(val)
self.sendColormap()
[docs] 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(0)
else:
self.autoScale90Button.setChecked(False)
self.minText.setEnabled(1)
self.maxText.setEnabled(1)
self.c.setEnabled(1)
self.c.setFocus()
# MINIMUM
"""
change min value and update colormap
"""
[docs] 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.insertXMarker(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
"""
[docs] 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
"""
[docs] 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.insertXMarker(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
"""
[docs] 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.insertXMarker(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
"""
[docs] 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
"""
[docs] 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.insertXMarker(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
"""
[docs] 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()
[docs] 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
"""
[docs] def sendColormap(self):
if DEBUG:
print("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])
[docs]def test():
app = qt.QApplication(sys.argv)
app.lastWindowClosed.connect(app.quit)
demo = ColormapDialog()
# Histogram demo
import numpy as np
x = np.linspace(-10, 10, 50)
y = abs(9. * np.exp(-x**2) + np.random.randn(len(x)) + 1.)
demo.plotHistogram((x,y))
def call(*var):
print("Received", var)
demo.sigColormapChanged.connect(call)
demo.setAutoscale(1)
demo.show()
app.exec_()
if __name__ == "__main__":
test()