dylab/HelperClasses/Plotting/WidgetFakeColorPlot.py

436 lines
18 KiB
Python

import numpy as np
from .DataExtractorLyse import DataExtractorManager
from .WidgetPlot import WidgetPlot
import pyqtgraph as pg
from pyqtgraph import OrderedDict
from PyQt5.QtWidgets import QLabel, QLineEdit
from pyqtgraph import Qt
from pyqtgraph.Qt import QtCore
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import QRegExpValidator
from PyQt5.QtCore import QRegExp
from PIL import ImageColor
color_palette_html = ['#1f77b4',
'#ff7f0e',
'#2ca02c',
'#d62728',
'#9467bd',
'#8c564b',
'#e377c2',
'#7f7f7f',
'#bcbd22',
'#17becf']
color_palette = [ImageColor.getcolor(color, "RGB") for color in color_palette_html]
Gradients = OrderedDict([
('bw', {'ticks': [(0.0, (0, 0, 0, 255)), (1, (255, 255, 255, 255))], 'mode': 'rgb'}),
('hot', {'ticks': [(0.3333, (185, 0, 0, 255)), (0.6666, (255, 220, 0,
255)), (1, (255, 255, 255, 255)), (0, (0, 0, 0, 255))],
'mode': 'rgb'}),
('jet0', {'ticks': [(1, (166, 0, 0, 255)),
(0.32247191011235954, (0, 255, 255, 255)),
(0.11348314606741573, (0, 68, 255, 255)),
(0.6797752808988764, (255, 255, 0, 255)),
(0.902247191011236, (255, 0, 0, 255)),
(0.5022471910112359, (0, 255, 0, 255)),
(0.0, (0, 0, 166, 255))],
'mode': 'rgb'}),
('jet', {'ticks': [(1, (128, 0, 0, 255)),
(0.878431372549020, (255, 0, 0, 255)),
(0.627450980392157, (255, 255, 0, 255)),
(0.376470588235294, (0, 255, 255, 255)),
(0.125490196078431, (0, 0, 255, 255)),
(0.0, (0, 0, 131, 255))],
'mode': 'rgb'}),
('summer', {'ticks': [(1, (255, 255, 0, 255)), (0.0, (0, 170, 127, 255))], 'mode': 'rgb'}),
('space', {'ticks': [(0.562, (75, 215, 227, 255)), (0.087, (255, 170, 0, 254)), (0.332, (0, 255, 0, 255)),
(0.77, (85, 0, 255, 255)), (0.0, (255, 0, 0, 255)), (1.0, (255, 0, 127, 255))],
'mode': 'rgb'}),
('winter', {'ticks': [(1, (0, 255, 127, 255)), (0.0, (0, 0, 255, 255))], 'mode': 'rgb'})
])
class WidgetFakeColorPlot(WidgetPlot):
def __init__(self, title, data_path=None, data_group=None, Isocurve=False, Roi=True, HistogramLUT=False, colorbarText=True, **kwargs):
super().__init__(title, **kwargs)
self.colorbarText = colorbarText
self.analyse_panel_update = None
# set data extractor
if data_group is None or data_group == 'results':
self.data_extractor_manager = DataExtractorManager(data_path)
self.data_extractor_manager.add_data_extractor('data_img', 'array', data_path)
self.data_extractor_manager.add_data_extractor('x', 'array', (data_path[0], 'x'))
self.data_extractor_manager.add_data_extractor('y', 'array', (data_path[0], 'y'))
self.data_extractor_manager.add_data_extractor('warning', 'single', (data_path[0], 'warning'))
else:
self.data_extractor_manager = DataExtractorManager(data_path)
self.data_extractor_manager.add_data_extractor('data_img', 'image', (data_group, data_path[0], data_path[1]))
self.data_image = None
self.setMinimumHeight(550)
self.setMinimumWidth(550)
if Roi is True:
# Add y-axis data slider
self.axsumy = self.plots.addPlot(title="")
self.axsumy.setFixedWidth(300)
self.sumy = self.axsumy.plot()
self.sumy_data = self.axsumy.plot(pen=pg.mkPen(style=QtCore.Qt.DashLine, color=color_palette[1]))
# Add imaging
self.aximg = self.plots.addPlot(title="")
self.img = pg.ImageItem()
self.aximg.addItem(self.img)
# fixe the y-axis
if Roi is True:
self.axsumy.setYLink(self.aximg)
# Contrast/color control
self.colorbar = None
if HistogramLUT is True:
self.colorbar = pg.HistogramLUTItem()
self.colorbar.setImageItem(self.img)
self.colormap = Gradients['jet']
self.colorbar.gradient.restoreState(self.colormap)
self.plots.addItem(self.colorbar)
else:
colormap = pg.colormap.getFromMatplotlib('jet')
self.colorbar = pg.ColorBarItem(cmap=colormap, values=(0, 1))
self.colorbar.setImageItem(self.img, insert_in=self.aximg)
self.iso = None
self.roi = None
if Isocurve is True:
# Isocurve draplotsg
self.iso = pg.IsocurveItem(level=0, pen=color_palette[2])
self.iso.setParentItem(self.img)
self.iso.setZValue(5)
# Draggable line for setting isocurve level
self.isoLine = pg.InfiniteLine(angle=0, movable=True, pen=color_palette[2])
self.colorbar.vb.addItem(self.isoLine)
self.colorbar.vb.setMouseEnabled(y=False) # makes user interaction a little easier
self.isoLine.setValue(1000)
self.isoLine.setZValue(1000) # bring iso line above contrast controls
self.isoLine.sigDragged.connect(self.updateIsocurve)
self.plots.nextRow()
if Roi is True:
# Custom ROI for selecting an image region
self.roi = pg.ROI([500, 500], [300, 300], pen={'color': 'k', 'width': 4})
self.roi.addScaleHandle([1, 0], [0.5, 0.5])
self.roi.addScaleHandle([0, 1], [0.5, 0.5])
self.aximg.addItem(self.roi)
self.roi.setZValue(10) # make sure ROI is drawn above image
self.roi_ax = self.plots.addPlot()
self.roi_ax.setFixedHeight(300)
self.roi_ax.setFixedWidth(300)
self.roi_img = pg.ImageItem()
self.roi_ax.addItem(self.roi_img)
roi_colormap = pg.colormap.getFromMatplotlib('jet')
self.roi_img.setColorMap(roi_colormap)
self.roi.sigRegionChanged.connect(self.updateROI)
self.colorbar.sigLevelsChanged.connect(self.updateROI)
# Add x-axis data slider
self.axsumx = self.plots.addPlot()
self.axsumx.setFixedHeight(300)
self.axsumx.setXLink(self.aximg)
self.sumx = self.axsumx.plot()
self.sumx_data = self.axsumx.plot(pen=pg.mkPen(style=QtCore.Qt.DashLine, color=color_palette[1]))
# Monkey-patch the image to use our custom hover function.
# This is generally discouraged (you should subclass ImageItem instead),
# but it works for a very simple use like this.
self.img.hoverEvent = self.imageHoverEvent
self.plots.nextRow()
self.plots.nextColumn()
self.img.translate(-0.5, -0.5)
self.scalex = 1
self.scaley = 1
self.cx = 0
self.cy = 0
#Add text box for colorbar and ROI
self.colorbar_ROI_box = QSplitter()
self.colorbar_ROI_box.setOrientation(Qt.Horizontal)
if colorbarText is True:
# Add text box for colorbar
self.colorbar_box = QSplitter()
self.colorbar_box.setOrientation(Qt.Vertical)
self.colorbar_title = QLabel('Color Bar')
self.colorbar_title.setAlignment(Qt.AlignCenter)
self.colorbar_box_container = QSplitter()
self.colorbar_box_container.setOrientation(Qt.Horizontal)
self.colorbar_box_max_label = QLabel(' Max: ')
self.colorbar_box_max_label.setAlignment(Qt.AlignCenter)
self.colorbar_box_max_line = QLineEdit(self)
double_regex = QRegExp("^[-+0-9.]+$")
double_validator = QRegExpValidator(double_regex, self.colorbar_box_max_line)
self.colorbar_box_max_line.setValidator(double_validator)
self.colorbar_box_max_line.setAlignment(Qt.AlignLeft)
self.colorbar_box_min_label = QLabel(' Min: ')
self.colorbar_box_min_label.setAlignment(Qt.AlignCenter)
self.colorbar_box_min_line = QLineEdit(self)
double_regex = QRegExp("^[-+0-9.]+$")
double_validator = QRegExpValidator(double_regex, self.colorbar_box_min_line)
self.colorbar_box_min_line.setValidator(double_validator)
self.colorbar_box_min_line.setAlignment(Qt.AlignLeft)
self.colorbar_box_label = QSplitter()
self.colorbar_box_label.setOrientation(Qt.Vertical)
self.colorbar_box_line = QSplitter()
self.colorbar_box_line.setOrientation(Qt.Vertical)
self.colorbar_box_label.addWidget(self.colorbar_box_max_label)
self.colorbar_box_label.addWidget(self.colorbar_box_min_label)
self.colorbar_box_line.addWidget(self.colorbar_box_max_line)
self.colorbar_box_line.addWidget(self.colorbar_box_min_line)
self.colorbar_box_container.addWidget(self.colorbar_box_label)
self.colorbar_box_container.addWidget(self.colorbar_box_line)
self.colorbar_box.addWidget(self.colorbar_title)
self.colorbar_box.addWidget(self.colorbar_box_container)
self.colorbar_box_max_line.editingFinished.connect(self.update_colorbar_text)
self.colorbar_box_min_line.editingFinished.connect(self.update_colorbar_text)
if Roi is True:
#Add text box for ROI
self.roi_box = QSplitter()
self.roi_box.setOrientation(Qt.Vertical)
self.roi_box_title = QLabel('Region of Interest')
self.roi_box_title.setAlignment(Qt.AlignCenter)
self.roi_box_container = QSplitter()
self.roi_box_container.setOrientation(Qt.Horizontal)
self.roi_center_container = QSplitter()
self.roi_center_container.setOrientation(Qt.Horizontal)
self.roi_span_container = QSplitter()
self.roi_span_container.setOrientation(Qt.Horizontal)
self.roi_center_label = QSplitter()
self.roi_center_label.setOrientation(Qt.Vertical)
self.roi_center_line = QSplitter()
self.roi_center_line.setOrientation(Qt.Vertical)
self.roi_span_label = QSplitter()
self.roi_span_label.setOrientation(Qt.Vertical)
self.roi_span_line = QSplitter()
self.roi_span_line.setOrientation(Qt.Vertical)
self.roi_center_x_label = QLabel(' X: ')
self.roi_center_x_label.setAlignment(Qt.AlignCenter)
self.roi_center_x_line = QLineEdit(self)
double_regex = QRegExp("^[-+0-9.]+$")
double_validator = QRegExpValidator(double_regex, self.roi_center_x_line)
self.roi_center_x_line.setValidator(double_validator)
self.roi_center_x_line.setAlignment(Qt.AlignLeft)
self.roi_center_y_label = QLabel(' Y: ')
self.roi_center_y_label.setAlignment(Qt.AlignCenter)
self.roi_center_y_line = QLineEdit(self)
double_regex = QRegExp("^[-+0-9.]+$")
double_validator = QRegExpValidator(double_regex, self.roi_center_y_line)
self.roi_center_y_line.setValidator(double_validator)
self.roi_center_y_line.setAlignment(Qt.AlignLeft)
self.roi_span_x_label = QLabel(' X Span: ')
self.roi_span_x_label.setAlignment(Qt.AlignCenter)
self.roi_span_x_line = QLineEdit(self)
double_regex = QRegExp("^[-+0-9.]+$")
double_validator = QRegExpValidator(double_regex, self.roi_span_x_line)
self.roi_span_x_line.setValidator(double_validator)
self.roi_span_x_line.setAlignment(Qt.AlignLeft)
self.roi_span_y_label = QLabel(' Y Span: ')
self.roi_span_y_label.setAlignment(Qt.AlignCenter)
self.roi_span_y_line = QLineEdit(self)
double_regex = QRegExp("^[-+0-9.]+$")
double_validator = QRegExpValidator(double_regex, self.roi_span_y_line)
self.roi_span_y_line.setValidator(double_validator)
self.roi_span_y_line.setAlignment(Qt.AlignLeft)
self.roi_center_label.addWidget(self.roi_center_x_label)
self.roi_center_label.addWidget(self.roi_center_y_label)
self.roi_center_line.addWidget(self.roi_center_x_line)
self.roi_center_line.addWidget(self.roi_center_y_line)
self.roi_span_label.addWidget(self.roi_span_x_label)
self.roi_span_label.addWidget(self.roi_span_y_label)
self.roi_span_line.addWidget(self.roi_span_x_line)
self.roi_span_line.addWidget(self.roi_span_y_line)
self.roi_center_container.addWidget(self.roi_center_label)
self.roi_center_container.addWidget(self.roi_center_line)
self.roi_span_container.addWidget(self.roi_span_label)
self.roi_span_container.addWidget(self.roi_span_line)
self.roi_box_container.addWidget(self.roi_center_container)
self.roi_box_container.addWidget(self.roi_span_container)
self.roi_box.addWidget(self.roi_box_title)
self.roi_box.addWidget(self.roi_box_container)
self.roi_center_x_line.editingFinished.connect(self.updateROI_text)
self.roi_center_y_line.editingFinished.connect(self.updateROI_text)
self.roi_span_x_line.editingFinished.connect(self.updateROI_text)
self.roi_span_y_line.editingFinished.connect(self.updateROI_text)
self.colorbar_ROI_box.addWidget(self.colorbar_box)
self.colorbar_ROI_box.addWidget(self.roi_box)
self.bottom.addWidget(self.colorbar_ROI_box)
def update(self, h5_path):
data = self.data_extractor_manager.get_data(h5_path)
self.data_image = data['data_img']
try:
x = data['x']
y = data['y']
warning = data['warning']
except:
x = None
y = None
warning = None
if x is None:
x = np.linspace(0, self.data_image.shape[0], self.data_image.shape[0])
if y is None:
y = np.linspace(0, self.data_image.shape[1], self.data_image.shape[1])
# update plots
if self.colorbarText is True:
self.img.setImage(self.data_image.T, autoLevels=False)
else:
self.img.setImage(self.data_image.T, autoLevels=True)
self.colorbar.setLevels((np.min(self.data_image), np.max(self.data_image)))
if self.iso is not None:
self.iso.setData(self.data_image.T)
# set position and scale of image
newscalex = x[1] - x[0]
newscaley = y[1] - y[0]
transx = (x[0] - (self.cx - 0.5 * self.scalex)) / newscalex - 0.5
transy = (y[0] - (self.cy - 0.5 * self.scaley)) / newscaley - 0.5
self.img.scale(newscalex / self.scalex, newscaley / self.scaley)
self.img.translate(transx, transy)
self.scalex = newscalex
self.scaley = newscaley
self.cx = x[0]
self.cy = y[0]
# update the region of interest
if self.roi is not None:
self.updateROI()
# update table and warning
self.update_warning(warning)
if self.analyse_panel_update is not None:
self.analyse_panel_update()
def updateIsocurve(self):
self.iso.setLevel(self.isoLine.value())
def update_colorbar_text(self):
colorbar_max = self.colorbar_box_max_line.text()
colorbar_min = self.colorbar_box_min_line.text()
colorbar_max = float(colorbar_max)
colorbar_min = float(colorbar_min)
try:
self.colorbar.setLevels(min=colorbar_min, max=colorbar_max)
except:
self.colorbar.setLevels(low=colorbar_min, high=colorbar_max)
if self.roi is not None:
self.updateROI()
def updateROI(self):
selected = self.roi.getArrayRegion(self.data_image.T, self.img)
try:
levels = self.colorbar.getLevels()
except:
levels = self.colorbar.levels()
self.roi_img.setImage(selected, levels=levels)
colorbar_min, colorbar_max = levels
self.colorbar_box_max_line.setText(str(colorbar_max))
self.colorbar_box_min_line.setText(str(colorbar_min))
x_center, y_center = self.roi.pos()
x_span, y_span = self.roi.size()
x_center = x_center + x_span / 2
y_center = y_center + y_span / 2
self.roi_center_x_line.setText(str(x_center))
self.roi_center_y_line.setText(str(y_center))
self.roi_span_x_line.setText(str(x_span))
self.roi_span_y_line.setText(str(y_span))
roi_pos = self.roi.pos()
pos = int(selected.shape[0]/2)
x = np.linspace(roi_pos[1], roi_pos[1] + selected.shape[1], selected.shape[1])
self.sumy_data.setData(x=np.squeeze(selected[pos:pos+1, :]), y=x)
pos = int(selected.shape[1] / 2)
x = np.linspace(roi_pos[0], roi_pos[0] + selected.shape[0], selected.shape[0])
self.sumx_data.setData(x=x, y=np.squeeze(selected[:, pos:pos + 1]))
def updateROI_text(self):
x_center = float(self.roi_center_x_line.text())
y_center = float(self.roi_center_y_line.text())
x_span = float(self.roi_span_x_line.text())
y_span = float(self.roi_span_y_line.text())
x = x_center - x_span / 2
y = y_center - y_span / 2
self.roi.setPos((x, y))
self.roi.setSize((x_span, y_span))
def imageHoverEvent(self, event):
"""Show the position, pixel, and value under the mouse cursor.
"""
if event.isExit():
self.aximg.setTitle("")
return
pos = event.pos()
i, j = pos.y(), pos.x()
i = int(np.clip(i, 0, self.data_image.shape[0] - 1))
j = int(np.clip(j, 0, self.data_image.shape[1] - 1))
val = self.data_image[i, j]
ppos = self.img.mapToParent(pos)
x, y = ppos.x(), ppos.y()
self.aximg.setTitle("pos: (%0.1f, %0.1f) value: %g" % (x, y, val))