class ComponentPlotWidget(SpectraPlotWidget): def __init__(self, *args, **kwargs): super(ComponentPlotWidget, self).__init__(linePos=800, txtPosRatio=0.35, *args, **kwargs) self.cross = PlotDataItem([800], [0], symbolBrush=(255, 255, 255), symbolPen=(255, 255, 255), symbol='+', symbolSize=25) self._x, self._y = None, None self.ymax, self.zmax = 0, 100 def getEnergy(self): if self._y is not None: x_val = self.line.value() idx = val2ind(x_val, self._x) x_val = self._x[idx] y_val = self._y[idx] txt_html = f'<div style="text-align: center"><span style="color: #FFF; font-size: 12pt">\ X = {x_val: .2f}, Y = {y_val: .4f}</div>' self.txt.setHtml(txt_html) self.cross.setData([x_val], [y_val]) def plot(self, x, y, *args, **kwargs): # set up infinity line and get its position plot_item = self.plotItem.plot(x, y, *args, **kwargs) self.addItem(self.line) self.addItem(self.cross) x_val = self.line.value() idx = val2ind(x_val, x) x_val = x[idx] y_val = y[idx] txt_html = f'<div style="text-align: center"><span style="color: #FFF; font-size: 12pt">\ X = {x_val: .2f}, Y = {y_val: .4f}</div>' self.txt.setHtml(txt_html) self.txt.setZValue(self.zmax - 1) self.cross.setData([x_val], [y_val]) self.cross.setZValue(self.zmax) ymax = max(y) if ymax > self.ymax: self.ymax = ymax self._x, self._y = x, y r = self.txtPosRatio self.txt.setPos(r * x[-1] + (1 - r) * x[0], self.ymax) self.addItem(self.txt) return plot_item
class SpectraPlotWidget(PlotWidget): sigEnergyChanged = Signal(object) def __init__(self, linePos=650, txtPosRatio=0.35, invertX=True, *args, **kwargs): """ A widget to display a 1D spectrum :param linePos: the initial position of the InfiniteLine :param txtPosRatio: a coefficient that determines the relative position of the textItem :param invertX: whether to invert X-axis """ super(SpectraPlotWidget, self).__init__(*args, **kwargs) self._data = None assert (txtPosRatio >= 0) and (txtPosRatio <= 1), 'Please set txtPosRatio value between 0 and 1.' self.txtPosRatio = txtPosRatio self.positionmap = dict() self.wavenumbers = None self._meanSpec = True # whether current spectrum is a mean spectrum self.line = InfiniteLine(movable=True) self.line.setPen((255, 255, 0, 200)) self.line.setValue(linePos) self.line.sigPositionChanged.connect(self.sigEnergyChanged) self.line.sigPositionChanged.connect(self.getEnergy) self.addItem(self.line) self.cross = PlotDataItem([linePos], [0], symbolBrush=(255, 0, 0), symbolPen=(255, 0, 0), symbol='+', symbolSize=20) self.cross.setZValue(100) self.addItem(self.cross) self.txt = TextItem() self.getViewBox().invertX(invertX) self.spectrumInd = 0 self.selectedPixels = None self._y = None def getEnergy(self, lineobject): if self._y is not None: x_val = lineobject.value() idx = val2ind(x_val, self.wavenumbers) x_val = self.wavenumbers[idx] y_val = self._y[idx] if not self._meanSpec: txt_html = toHtml(f'Spectrum #{self.spectrumInd}') else: txt_html = toHtml(f'{self._mean_title}') txt_html += toHtml(f'X = {x_val: .2f}, Y = {y_val: .4f}') self.txt.setHtml(txt_html) self.cross.setData([x_val], [y_val]) def setHeader(self, header: NonDBHeader, field: str, *args, **kwargs): self.header = header self.field = field # get wavenumbers spectraEvent = next(header.events(fields=['spectra'])) self.wavenumbers = spectraEvent['wavenumbers'] self.N_w = len(self.wavenumbers) self.rc2ind = spectraEvent['rc_index'] # make lazy array from document data = None try: data = header.meta_array(field) except IndexError: msg.logMessage(f'Header object contained no frames with field {field}.', msg.ERROR) if data is not None: # kwargs['transform'] = QTransform(1, 0, 0, -1, 0, data.shape[-2]) self._data = data def showSpectra(self, i=0): if (self._data is not None) and (i < len(self._data)): self.getViewBox().clear() self._meanSpec = False self.spectrumInd = i self.plot(self.wavenumbers, self._data[i]) def getSelectedPixels(self, selectedPixels): self.selectedPixels = selectedPixels # print(selectedPixels) def clearAll(self): # remove legend _legend = self.plotItem.legend if (_legend is not None) and (_legend.scene() is not None): _legend.scene().removeItem(_legend) self.getViewBox().clear() def showMeanSpectra(self): self._meanSpec = True self.getViewBox().clear() if self.selectedPixels is not None: n_spectra = len(self.selectedPixels) tmp = np.zeros((n_spectra, self.N_w)) for j in range(n_spectra): # j: jth selected pixel row_col = tuple(self.selectedPixels[j]) tmp[j, :] = self._data[self.rc2ind[row_col]] self._mean_title = f'ROI mean of {n_spectra} spectra' else: n_spectra = len(self._data) tmp = np.zeros((n_spectra, self.N_w)) for j in range(n_spectra): tmp[j, :] = self._data[j] self._mean_title = f'Total mean of {n_spectra} spectra' if n_spectra > 0: meanSpec = np.mean(tmp, axis=0) else: meanSpec = np.zeros_like(self.wavenumbers) + 1e-3 self.plot(self.wavenumbers, meanSpec) def plot(self, x, y, *args, **kwargs): # set up infinity line and get its position self.plotItem.plot(x, y, *args, **kwargs) self.addItem(self.line) self.addItem(self.cross) x_val = self.line.value() if x_val == 0: y_val = 0 else: idx = val2ind(x_val, self.wavenumbers) x_val = self.wavenumbers[idx] y_val = y[idx] if not self._meanSpec: txt_html = toHtml(f'Spectrum #{self.spectrumInd}') else: txt_html = toHtml(f'{self._mean_title}') txt_html += toHtml(f'X = {x_val: .2f}, Y = {y_val: .4f}') self.txt.setHtml(txt_html) ymax = np.max(y) self._y = y r = self.txtPosRatio self.txt.setPos(r * x[-1] + (1 - r) * x[0], ymax) self.cross.setData([x_val], [y_val]) self.addItem(self.txt)