def __new_map_item(z): map_item = ImageItem(autoLevels=False) map_item.setOpts(axisOrder='row-major') map_item.setZValue(z) return map_item
class FilterPreviews(GraphicsLayoutWidget): image_before: ImageItem image_after: ImageItem image_diff: ImageItem histogram_before: Optional[PlotItem] histogram_after: Optional[PlotItem] histogram: Optional[PlotItem] def __init__(self, parent=None, **kwargs): super(FilterPreviews, self).__init__(parent, **kwargs) widget_location = self.mapToGlobal(QPoint(self.width() / 2, 0)) # allow the widget to take up to 80% of the desktop's height self.ALLOWED_HEIGHT: QRect = QGuiApplication.screenAt(widget_location).availableGeometry().height() * 0.8 self.before_histogram_data = None self.after_histogram_data = None self.histogram = None self.before_histogram = None self.after_histogram = None self.combined_histograms = True self.histogram_legend_visible = True self.addLabel("Image before") self.addLabel("Image after") self.addLabel("Image difference") self.nextRow() self.image_before, self.image_before_vb, self.image_before_hist = self.image_in_vb(name="before") self.image_after, self.image_after_vb, self.image_after_hist = self.image_in_vb(name="after") self.image_difference, self.image_difference_vb, self.image_difference_hist = self.image_in_vb( name="difference") self.image_after_overlay = ImageItem() self.image_after_overlay.setZValue(10) self.image_after_vb.addItem(self.image_after_overlay) # Ensure images resize equally self.image_layout: GraphicsLayout = self.addLayout(colspan=6) self.image_layout.addItem(self.image_before_vb, 0, 0) self.image_layout.addItem(self.image_before_hist, 0, 1) self.image_layout.addItem(self.image_after_vb, 0, 2) self.image_layout.addItem(self.image_after_hist, 0, 3) self.image_layout.addItem(self.image_difference_vb, 0, 4) self.image_layout.addItem(self.image_difference_hist, 0, 5) self.nextRow() before_details = self.addLabel("") after_details = self.addLabel("") difference_details = self.addLabel("") self.display_formatted_detail = { self.image_before: lambda val: before_details.setText(f"Before: {val:.6f}"), self.image_after: lambda val: after_details.setText(f"After: {val:.6f}"), self.image_difference: lambda val: difference_details.setText(f"Difference: {val:.6f}"), } for img in self.image_before, self.image_after, self.image_difference: img.hoverEvent = lambda ev: self.mouse_over(ev) self.init_histogram() def resizeEvent(self, ev: QResizeEvent): if ev is not None: size = ev.size() self.image_layout.setFixedHeight(min(size.height() * 0.7, self.ALLOWED_HEIGHT)) super().resizeEvent(ev) def image_in_vb(self, name=None): im = ImageItem() vb = ViewBox(invertY=True, lockAspect=True, name=name) vb.addItem(im) hist = HistogramLUTItem(im) return im, vb, hist def clear_items(self): self.image_before.clear() self.image_after.clear() self.image_difference.clear() self.image_after_overlay.clear() def init_histogram(self): self.histogram = self.addPlot(row=histogram_coords["combined"].row, col=histogram_coords["combined"].col, labels=histogram_axes_labels, lockAspect=True, colspan=3) self.addLabel("Pixel values", row=label_coords["combined"].row, col=label_coords["combined"].col) self.legend = self.histogram.addLegend() def update_histogram_data(self): # Plot any histogram that has data, and add a legend if both exist before_data = self.image_before.getHistogram() after_data = self.image_after.getHistogram() if _data_valid_for_histogram(before_data): if self.combined_histograms: before_plot = self.histogram.plot(*before_data, pen=before_pen, clear=True) self.legend.addItem(before_plot, "Before") else: self.before_histogram.plot(*before_data, pen=before_pen, clear=True) if _data_valid_for_histogram(after_data): if self.combined_histograms: after_plot = self.histogram.plot(*after_data, pen=after_pen) self.legend.addItem(after_plot, "After") else: self.after_histogram.plot(*after_data, pen=after_pen, clear=True) def init_separate_histograms(self): hc = histogram_coords self.before_histogram = self.addPlot(row=hc["before"].row, col=hc["before"].col, labels=histogram_axes_labels, lockAspect=True) self.after_histogram = self.addPlot(row=hc["after"].row, col=hc["after"].col, labels=histogram_axes_labels, lockAspect=True) lc = label_coords self.addLabel("Pixel values before", row=lc["before"].row, col=lc["before"].col) self.addLabel("Pixel values after", row=lc["after"].row, col=lc["after"].col) if _data_valid_for_histogram(self.before_histogram_data): self.before_histogram.plot(*self.before_histogram_data, pen=before_pen) if _data_valid_for_histogram(self.after_histogram_data): self.after_histogram.plot(*self.after_histogram_data, pen=after_pen) def delete_histograms(self): coords = set(c for c in histogram_coords.values()) histograms = (self.getItem(*coord) for coord in coords) for histogram in filter(lambda h: h is not None, histograms): self.removeItem(histogram) self.histogram = None self.before_histogram = None self.after_histogram = None def delete_histogram_labels(self): coords = set(c for c in label_coords.values()) labels = (self.getItem(*coord) for coord in coords) for label in filter(lambda h: h is not None, labels): self.removeItem(label) @property def histogram_legend(self) -> Optional[LegendItem]: if self.histogram and self.histogram.legend: return self.histogram.legend return None def mouse_over(self, ev): # Ignore events triggered by leaving window or right clicking if ev.exit: return pos = CloseEnoughPoint(ev.pos()) for img in self.image_before, self.image_after, self.image_difference: if img.image is not None and pos.x < img.image.shape[0] and pos.y < img.image.shape[1]: pixel_value = img.image[pos.y, pos.x] self.display_formatted_detail[img](pixel_value) def link_all_views(self): for view1, view2 in [[self.image_before_vb, self.image_after_vb], [self.image_after_vb, self.image_difference_vb], [self.image_after_hist.vb, self.image_before_hist.vb]]: view1.linkView(ViewBox.XAxis, view2) view1.linkView(ViewBox.YAxis, view2) def unlink_all_views(self): for view in self.image_before_vb, self.image_after_vb, self.image_after_hist.vb: view.linkView(ViewBox.XAxis, None) view.linkView(ViewBox.YAxis, None) def add_difference_overlay(self, diff): diff = -diff diff[diff > 0.0] = 1.0 pos = np.array([0, 1]) color = np.array([[0, 0, 0, 0], [255, 0, 0, 255]], dtype=np.ubyte) map = ColorMap(pos, color) self.image_after_overlay.setOpacity(1) self.image_after_overlay.setImage(diff) lut = map.getLookupTable(0, 1, 2) self.image_after_overlay.setLookupTable(lut) def hide_difference_overlay(self): self.image_after_overlay.setOpacity(0) def auto_range(self): # This will cause the previews to all show by just causing autorange on self.image_before_vb self.image_before_vb.autoRange()
class FilterPreviews(GraphicsLayoutWidget): image_before: ImageItem image_after: ImageItem image_diff: ImageItem histogram_before: Optional[PlotItem] histogram_after: Optional[PlotItem] histogram: Optional[PlotItem] def __init__(self, parent=None, **kwargs): super(FilterPreviews, self).__init__(parent, **kwargs) self.before_histogram_data = None self.after_histogram_data = None self.histogram = None self.before_histogram = None self.after_histogram = None self.combined_histograms = True self.histogram_legend_visible = True self.addLabel("Image before") self.addLabel("Image after") self.addLabel("Image difference") self.nextRow() self.image_before, self.image_before_vb = self.image_in_vb( name="before") self.image_after, self.image_after_vb = self.image_in_vb(name="after") self.image_difference, self.image_difference_vb = self.image_in_vb( name="difference") self.image_after_overlay = ImageItem() self.image_after_overlay.setZValue(10) self.image_after_vb.addItem(self.image_after_overlay) # Ensure images resize equally image_layout = self.addLayout(colspan=3) image_layout.addItem(self.image_before_vb, 0, 0) image_layout.addItem(self.image_after_vb, 0, 1) image_layout.addItem(self.image_difference_vb, 0, 2) self.nextRow() before_details = self.addLabel("") after_details = self.addLabel("") difference_details = self.addLabel("") self.display_formatted_detail = { self.image_before: lambda val: before_details.setText(f"Before: {val:.6f}"), self.image_after: lambda val: after_details.setText(f"After: {val:.6f}"), self.image_difference: lambda val: difference_details.setText(f"Difference: {val:.6f}"), } for img in self.image_before, self.image_after, self.image_difference: img.hoverEvent = lambda ev: self.mouse_over(ev) def image_in_vb(self, name=None): im = ImageItem() im.setAutoDownsample(False) vb = ViewBox(invertY=True, lockAspect=True, name=name) vb.addItem(im) return im, vb def clear_items(self): self.image_before.clear() self.image_after.clear() self.image_difference.clear() self.image_after_overlay.clear() self.delete_histograms() # There seems to be a bug with pyqtgraph.PlotDataItem.setData not forcing a redraw. # We work around this by redrawing everything completely every time, which is unreasonably fast anyway. def redraw_histograms(self): self.delete_histograms() self.delete_histogram_labels() if self.combined_histograms: self.draw_combined_histogram() else: self.draw_separate_histograms() def delete_histograms(self): coords = set(c for c in histogram_coords.values()) histograms = (self.getItem(*coord) for coord in coords) for histogram in filter(lambda h: h is not None, histograms): self.removeItem(histogram) self.histogram = None self.before_histogram = None self.after_histogram = None self.diff_histogram = None def delete_histogram_labels(self): coords = set(c for c in label_coords.values()) labels = (self.getItem(*coord) for coord in coords) for label in filter(lambda h: h is not None, labels): self.removeItem(label) def draw_combined_histogram(self): self.histogram = self.addPlot(row=histogram_coords["combined"].row, col=histogram_coords["combined"].col, labels=histogram_axes_labels, lockAspect=True, colspan=3) self.addLabel("Pixel values", row=label_coords["combined"].row, col=label_coords["combined"].col) legend = self.histogram.addLegend() # Plot any histogram that has data, and add a legend if both exist if _data_valid_for_histogram(self.before_histogram_data): before_plot = self.histogram.plot(*self.before_histogram_data, pen=before_pen) legend.addItem(before_plot, "Before") if _data_valid_for_histogram(self.after_histogram_data): after_plot = self.histogram.plot(*self.after_histogram_data, pen=after_pen) legend.addItem(after_plot, "After") def draw_separate_histograms(self): hc = histogram_coords self.before_histogram = self.addPlot(row=hc["before"].row, col=hc["before"].col, labels=histogram_axes_labels, lockAspect=True) self.after_histogram = self.addPlot(row=hc["after"].row, col=hc["after"].col, labels=histogram_axes_labels, lockAspect=True) lc = label_coords self.addLabel("Pixel values before", row=lc["before"].row, col=lc["before"].col) self.addLabel("Pixel values after", row=lc["after"].row, col=lc["after"].col) if _data_valid_for_histogram(self.before_histogram_data): self.before_histogram.plot(*self.before_histogram_data, pen=before_pen) if _data_valid_for_histogram(self.after_histogram_data): self.after_histogram.plot(*self.after_histogram_data, pen=after_pen) def set_before_histogram(self, data: Tuple[ndarray]): self.before_histogram_data = data self.redraw_histograms() def set_after_histogram(self, data: Tuple[ndarray]): self.after_histogram_data = data self.redraw_histograms() @property def histogram_legend(self) -> Optional[LegendItem]: if self.histogram and self.histogram.legend: return self.histogram.legend return None def mouse_over(self, ev): # Ignore events triggered by leaving window or right clicking if ev.exit: return pos = CloseEnoughPoint(ev.pos()) for img in self.image_before, self.image_after, self.image_difference: if img.image is not None and pos.x < img.image.shape[ 0] and pos.y < img.image.shape[1]: pixel_value = img.image[pos.y, pos.x] self.display_formatted_detail[img](pixel_value) def link_all_views(self): for view1, view2 in zip( [self.image_before_vb, self.image_after_vb], [self.image_after_vb, self.image_difference_vb]): view1.linkView(ViewBox.XAxis, view2) view1.linkView(ViewBox.YAxis, view2) def unlink_all_views(self): for view in self.image_before_vb, self.image_after_vb, self.image_difference_vb: view.linkView(ViewBox.XAxis, None) view.linkView(ViewBox.YAxis, None) def add_difference_overlay(self, diff): diff = -diff diff[diff > 0.0] = 1.0 pos = np.array([0, 1]) color = np.array([[0, 0, 0, 0], [255, 0, 0, 255]], dtype=np.ubyte) map = ColorMap(pos, color) self.image_after_overlay.setOpacity(1) self.image_after_overlay.setImage(diff) lut = map.getLookupTable(0, 1, 2) self.image_after_overlay.setLookupTable(lut) def hide_difference_overlay(self): self.image_after_overlay.setOpacity(0)
def __init__(self, directory='.', **kwargs): super(astraPlotWidget, self).__init__(**kwargs) self.beam = raf.beam() self.twiss = rtf.twiss() self.directory = directory ''' twissPlotWidget ''' self.twissPlotView = GraphicsView(useOpenGL=True) self.twissPlotWidget = GraphicsLayout() self.twissPlotView.setCentralItem(self.twissPlotWidget) self.latticePlotData = imageio.imread('lattice_plot.png') self.latticePlots = {} self.twissPlots = {} i = -1 for entry in self.twissplotLayout: if entry == 'next_row': self.twissPlotWidget.nextRow() else: i += 1 p = self.twissPlotWidget.addPlot(title=entry['name']) p.showGrid(x=True, y=True) vb = p.vb vb.setYRange(*entry['range']) latticePlot = ImageItem(self.latticePlotData) latticePlot.setOpts(axisOrder='row-major') vb.addItem(latticePlot) latticePlot.setZValue(-1) # make sure this image is on top # latticePlot.setOpacity(0.5) self.twissPlots[entry['name']] = p.plot( pen=mkPen('b', width=3)) self.latticePlots[p.vb] = latticePlot p.vb.sigRangeChanged.connect(self.scaleLattice) ''' beamPlotWidget ''' self.beamPlotWidget = QWidget() self.beamPlotLayout = QVBoxLayout() self.item = ImageItem() self.beamPlotWidget.setLayout(self.beamPlotLayout) self.beamPlotView = ImageView(imageItem=self.item) self.rainbow = rainbow() self.item.setLookupTable(self.rainbow) self.item.setLevels([0, 1]) # self.beamPlotWidgetGraphicsLayout = GraphicsLayout() # p = self.beamPlotWidgetGraphicsLayout.addPlot(title='beam') # p.showGrid(x=True, y=True) # self.beamPlot = p.plot(pen=None, symbol='+') # self.beamPlotView.setCentralItem(self.beamPlotWidgetGraphicsLayout) self.beamPlotXAxisCombo = QComboBox() self.beamPlotXAxisCombo.addItems( ['x', 'y', 'zn', 'cpx', 'cpy', 'BetaGamma']) self.beamPlotYAxisCombo = QComboBox() self.beamPlotYAxisCombo.addItems( ['x', 'y', 'zn', 'cpx', 'cpy', 'BetaGamma']) self.beamPlotNumberBins = QSpinBox() self.beamPlotNumberBins.setRange(10, 500) self.beamPlotNumberBins.setSingleStep(10) self.histogramBins = 100 self.beamPlotNumberBins.setValue(self.histogramBins) self.beamPlotAxisWidget = QWidget() self.beamPlotAxisLayout = QHBoxLayout() self.beamPlotAxisWidget.setLayout(self.beamPlotAxisLayout) self.beamPlotAxisLayout.addWidget(self.beamPlotXAxisCombo) self.beamPlotAxisLayout.addWidget(self.beamPlotYAxisCombo) self.beamPlotAxisLayout.addWidget(self.beamPlotNumberBins) self.beamPlotXAxisCombo.currentIndexChanged.connect(self.plotDataBeam) self.beamPlotYAxisCombo.currentIndexChanged.connect(self.plotDataBeam) self.beamPlotNumberBins.valueChanged.connect(self.plotDataBeam) # self.beamPlotXAxisCombo.setCurrentIndex(2) # self.beamPlotYAxisCombo.setCurrentIndex(5) self.beamPlotLayout.addWidget(self.beamPlotAxisWidget) self.beamPlotLayout.addWidget(self.beamPlotView) ''' slicePlotWidget ''' self.sliceParams = [ { 'name': 'slice_normalized_horizontal_emittance', 'units': 'm-rad', 'text': 'enx' }, { 'name': 'slice_normalized_vertical_emittance', 'units': 'm-rad', 'text': 'eny' }, { 'name': 'slice_peak_current', 'units': 'A', 'text': 'PeakI' }, { 'name': 'slice_relative_momentum_spread', 'units': '%', 'text': 'sigma-p' }, ] self.slicePlotWidget = QWidget() self.slicePlotLayout = QVBoxLayout() self.slicePlotWidget.setLayout(self.slicePlotLayout) # self.slicePlotView = GraphicsView(useOpenGL=True) self.slicePlotWidgetGraphicsLayout = GraphicsLayoutWidget() # self.slicePlots = {} self.slicePlotCheckbox = {} self.curve = {} self.sliceaxis = {} self.slicePlotCheckboxWidget = QWidget() self.slicePlotCheckboxLayout = QVBoxLayout() self.slicePlotCheckboxWidget.setLayout(self.slicePlotCheckboxLayout) self.slicePlot = self.slicePlotWidgetGraphicsLayout.addPlot( title='Slice', row=0, col=50) self.slicePlot.showAxis('left', False) self.slicePlot.showGrid(x=True, y=True) i = -1 colors = ['b', 'r', 'g', 'k'] for param in self.sliceParams: i += 1 axis = AxisItem("left") labelStyle = {'color': '#' + colorStr(mkColor(colors[i]))[0:-2]} axis.setLabel(text=param['text'], units=param['units'], **labelStyle) viewbox = ViewBox() axis.linkToView(viewbox) viewbox.setXLink(self.slicePlot.vb) self.sliceaxis[param['name']] = [axis, viewbox] self.curve[param['name']] = PlotDataItem(pen=colors[i], symbol='+') viewbox.addItem(self.curve[param['name']]) col = self.findFirstEmptyColumnInGraphicsLayout() self.slicePlotWidgetGraphicsLayout.ci.addItem(axis, row=0, col=col, rowspan=1, colspan=1) self.slicePlotWidgetGraphicsLayout.ci.addItem(viewbox, row=0, col=50) p.showGrid(x=True, y=True) # self.slicePlots[param] = self.slicePlot.plot(pen=colors[i], symbol='+') self.slicePlotCheckbox[param['name']] = QCheckBox(param['text']) self.slicePlotCheckboxLayout.addWidget( self.slicePlotCheckbox[param['name']]) self.slicePlotCheckbox[param['name']].stateChanged.connect( self.plotDataSlice) # self.slicePlotView.setCentralItem(self.slicePlotWidgetGraphicsLayout) self.slicePlotSliceWidthWidget = QSpinBox() self.slicePlotSliceWidthWidget.setMaximum(1000) self.slicePlotSliceWidthWidget.setValue(100) self.slicePlotSliceWidthWidget.setSingleStep(10) self.slicePlotSliceWidthWidget.setSuffix("fs") self.slicePlotSliceWidthWidget.setSpecialValueText('Automatic') self.slicePlotAxisWidget = QWidget() self.slicePlotAxisLayout = QHBoxLayout() self.slicePlotAxisWidget.setLayout(self.slicePlotAxisLayout) self.slicePlotAxisLayout.addWidget(self.slicePlotCheckboxWidget) self.slicePlotAxisLayout.addWidget(self.slicePlotSliceWidthWidget) # self.slicePlotXAxisCombo.currentIndexChanged.connect(self.plotDataSlice) self.slicePlotSliceWidthWidget.valueChanged.connect( self.changeSliceLength) # self.beamPlotXAxisCombo.setCurrentIndex(2) # self.beamPlotYAxisCombo.setCurrentIndex(5) self.slicePlotLayout.addWidget(self.slicePlotAxisWidget) self.slicePlotLayout.addWidget(self.slicePlotWidgetGraphicsLayout) self.layout = QVBoxLayout() self.setLayout(self.layout) self.tabWidget = QTabWidget() self.folderButton = QPushButton('Select Directory') self.folderLineEdit = QLineEdit() self.folderLineEdit.setReadOnly(True) self.folderLineEdit.setText(self.directory) self.reloadButton = QPushButton() self.reloadButton.setIcon(qApp.style().standardIcon( QStyle.SP_BrowserReload)) self.folderWidget = QGroupBox() self.folderLayout = QHBoxLayout() self.folderLayout.addWidget(self.folderButton) self.folderLayout.addWidget(self.folderLineEdit) self.folderLayout.addWidget(self.reloadButton) self.folderWidget.setLayout(self.folderLayout) self.folderWidget.setMaximumWidth(800) self.reloadButton.clicked.connect( lambda: self.changeDirectory(self.directory)) self.folderButton.clicked.connect(self.changeDirectory) self.fileSelector = QComboBox() self.fileSelector.currentIndexChanged.connect(self.updateScreenCombo) self.screenSelector = QComboBox() self.screenSelector.currentIndexChanged.connect(self.changeScreen) self.beamWidget = QGroupBox() self.beamLayout = QHBoxLayout() self.beamLayout.addWidget(self.fileSelector) self.beamLayout.addWidget(self.screenSelector) self.beamWidget.setLayout(self.beamLayout) self.beamWidget.setMaximumWidth(800) self.beamWidget.setVisible(False) self.folderBeamWidget = QWidget() self.folderBeamLayout = QHBoxLayout() self.folderBeamLayout.setAlignment(Qt.AlignLeft) self.folderBeamWidget.setLayout(self.folderBeamLayout) self.folderBeamLayout.addWidget(self.folderWidget) self.folderBeamLayout.addWidget(self.beamWidget) self.tabWidget.addTab(self.twissPlotView, 'Twiss Plots') self.tabWidget.addTab(self.beamPlotWidget, 'Beam Plots') self.tabWidget.addTab(self.slicePlotWidget, 'Slice Beam Plots') self.tabWidget.currentChanged.connect(self.changeTab) self.layout.addWidget(self.folderBeamWidget) self.layout.addWidget(self.tabWidget) self.plotType = 'Twiss' self.changeDirectory(self.directory)
class FilterPreviews(GraphicsLayoutWidget): image_before: ImageItem image_after: ImageItem image_diff: ImageItem histogram: Optional[PlotItem] def __init__(self, parent=None, **kwargs): super().__init__(parent, **kwargs) widget_location = self.mapToGlobal(QPoint(self.width() // 2, 0)) # allow the widget to take up to 80% of the desktop's height if QGuiApplication.screenAt(widget_location) is not None: screen_height = QGuiApplication.screenAt( widget_location).availableGeometry().height() else: screen_height = max( QGuiApplication.primaryScreen().availableGeometry().height(), 600) LOG.info( "Unable to detect current screen. Setting screen height to %s" % screen_height) self.ALLOWED_HEIGHT: QRect = screen_height * 0.8 self.histogram = None self.addLabel("Image before") self.addLabel("Image after") self.addLabel("Image difference") self.nextRow() self.imageview_before = MIMiniImageView(name="before") self.imageview_after = MIMiniImageView(name="after") self.imageview_difference = MIMiniImageView(name="difference") self.all_imageviews = [ self.imageview_before, self.imageview_after, self.imageview_difference ] MIMiniImageView.set_siblings(self.all_imageviews, axis=True) MIMiniImageView.set_siblings( [self.imageview_before, self.imageview_after], hist=True) self.image_before, self.image_before_vb, self.image_before_hist = self.imageview_before.get_parts( ) self.image_after, self.image_after_vb, self.image_after_hist = self.imageview_after.get_parts( ) self.image_difference, self.image_difference_vb, self.image_difference_hist = \ self.imageview_difference.get_parts() self.all_histograms = [ self.image_before_hist, self.image_after_hist, self.image_difference_hist ] self.image_diff_overlay = ImageItem() self.image_diff_overlay.setZValue(10) self.image_after_vb.addItem(self.image_diff_overlay) # Ensure images resize equally self.image_layout: GraphicsLayout = self.addLayout(colspan=3) self.image_layout.addItem(self.imageview_before) self.image_layout.addItem(self.imageview_after) self.image_layout.addItem(self.imageview_difference) self.nextRow() self.init_histogram() # Work around for https://github.com/mantidproject/mantidimaging/issues/565 self.scene().contextMenu = [ item for item in self.scene().contextMenu if "export" not in item.text().lower() ] self.auto_colour_actions = [] self._add_auto_colour_action(self.image_before_hist, self.image_before) self._add_auto_colour_action(self.image_after_hist, self.image_after) self._add_auto_colour_action(self.image_difference_hist, self.image_difference) self.imageview_before.link_sibling_axis() self.imageview_before.enable_nan_check() self.imageview_after.enable_nan_check() def resizeEvent(self, ev: QResizeEvent): if ev is not None and isinstance(self.histogram, PlotItem): size = ev.size() self.histogram.setFixedHeight( min(size.height() * 0.7, self.ALLOWED_HEIGHT) * 0.25) super().resizeEvent(ev) def clear_items(self, clear_before: bool = True): if clear_before: self.imageview_before.clear() self.imageview_after.clear() self.imageview_difference.clear() self.image_diff_overlay.clear() def init_histogram(self): self.histogram = self.addPlot(row=histogram_coords.row, col=histogram_coords.col, labels=histogram_axes_labels, lockAspect=True, colspan=3) self.addLabel("Pixel values", row=label_coords.row, col=label_coords.col) self.legend = self.histogram.addLegend() self.legend.setOffset((0, 1)) def update_histogram_data(self): # Plot any histogram that has data, and add a legend if both exist before_data = self.imageview_before.image_item.getHistogram() after_data = self.imageview_after.image_item.getHistogram() if _data_valid_for_histogram(before_data): before_plot = self.histogram.plot(*before_data, pen=before_pen, clear=True) self.legend.addItem(before_plot, "Before") if _data_valid_for_histogram(after_data): after_plot = self.histogram.plot(*after_data, pen=after_pen) self.legend.addItem(after_plot, "After") @property def histogram_legend(self) -> Optional[LegendItem]: if self.histogram and self.histogram.legend: return self.histogram.legend return None def link_all_views(self): self.imageview_before.link_sibling_axis() def unlink_all_views(self): self.imageview_before.unlink_sibling_axis() def add_difference_overlay(self, diff, nan_change): diff = np.absolute(diff) diff[diff > OVERLAY_THRESHOLD] = 1.0 diff[nan_change] = 1.0 pos = np.array([0, 1]) color = np.array([[0, 0, 0, 0], OVERLAY_COLOUR_DIFFERENCE], dtype=np.ubyte) map = ColorMap(pos, color) self.image_diff_overlay.setVisible(True) self.image_diff_overlay.setImage(diff) lut = map.getLookupTable(0, 1, 2) self.image_diff_overlay.setLookupTable(lut) def add_negative_overlay(self): self.imageview_after.enable_nonpositive_check() def hide_difference_overlay(self): self.image_diff_overlay.setVisible(False) def hide_negative_overlay(self): self.imageview_after.enable_nonpositive_check(False) def auto_range(self): # This will cause the previews to all show by just causing autorange on self.image_before_vb self.image_before_vb.autoRange() def record_histogram_regions(self): self.before_region = self.image_before_hist.region.getRegion() self.diff_region = self.image_difference_hist.region.getRegion() self.after_region = self.image_after_hist.region.getRegion() def restore_histogram_regions(self): self.image_before_hist.region.setRegion(self.before_region) self.image_difference_hist.region.setRegion(self.diff_region) self.image_after_hist.region.setRegion(self.after_region) def link_before_after_histogram_scales(self, create_link: bool): """ Connects or disconnects the scales of the before/after histograms. :param create_link: Whether the link should be created or removed. """ if create_link: self.imageview_after.link_sibling_histogram() else: self.imageview_after.unlink_sibling_histogram() def set_histogram_log_scale(self): """ Sets the y-values of the before and after histogram plots to a log scale. """ set_histogram_log_scale(self.image_before_hist) set_histogram_log_scale(self.image_after_hist) def _add_auto_colour_action(self, histogram: HistogramLUTItem, image: ImageItem): """ Adds an "Auto" action to the histogram right-click menu. :param histogram: The HistogramLUTItem :param image: The ImageItem to have the Jenks/Otsu algorithm performed on it. """ self.auto_colour_actions.append(QAction("Auto")) self.auto_colour_actions[-1].triggered.connect( lambda: self._on_change_colour_palette(histogram, image)) action = histogram.gradient.menu.actions()[12] histogram.gradient.menu.insertAction(action, self.auto_colour_actions[-1]) histogram.gradient.menu.insertSeparator(self.auto_colour_actions[-1]) def _on_change_colour_palette(self, main_histogram: HistogramLUTItem, image: ImageItem): """ Creates a Palette Changer window when the "Auto" option has been selected. :param main_histogram: The HistogramLUTItem. :param image: The ImageItem. """ other_histograms = self.all_histograms[:] other_histograms.remove(main_histogram) change_colour_palette = PaletteChangerView(self, main_histogram, image.image, other_histograms) change_colour_palette.show()
def __init__(self, directory='.', **kwargs): super(astraPlotWidget, self).__init__(**kwargs) self.beam = raf.beam() self.twiss = rtf.twiss() self.directory = directory ''' twissPlotWidget ''' self.twissPlotView = GraphicsView(useOpenGL=True) self.twissPlotWidget = GraphicsLayout() self.twissPlotView.setCentralItem(self.twissPlotWidget) self.latticePlotData = imageio.imread( os.path.dirname(os.path.abspath(__file__)) + '/lattice_plot.png') self.latticePlots = {} self.twissPlots = {} i = -1 for entry in self.twissplotLayout: if entry == 'next_row': self.twissPlotWidget.nextRow() else: i += 1 p = self.twissPlotWidget.addPlot(title=entry['name']) p.showGrid(x=True, y=True) vb = p.vb vb.setYRange(*entry['range']) latticePlot = ImageItem(self.latticePlotData) latticePlot.setOpts(axisOrder='row-major') vb.addItem(latticePlot) latticePlot.setZValue(-1) # make sure this image is on top # latticePlot.setOpacity(0.5) self.twissPlots[entry['name']] = p.plot( pen=mkPen('b', width=3)) self.latticePlots[p.vb] = latticePlot p.vb.sigRangeChanged.connect(self.scaleLattice) ''' beamPlotWidget ''' self.beamPlotWidget = QWidget() self.beamPlotLayout = QVBoxLayout() self.beamPlotWidget.setLayout(self.beamPlotLayout) # # self.beamPlotChoice = # self.beamPlotAxisWidget = QWidget() self.beamPlotAxisWidget.setMaximumHeight(100) Form = self.beamPlotAxisWidget self.beamPlotXAxisDict = OrderedDict() self.beamPlotXAxisDict['x'] = {'scale': 1e3, 'axis': 'x [mm]'} self.beamPlotXAxisDict['y'] = {'scale': 1e3, 'axis': 'y [mm]'} self.beamPlotXAxisDict['z'] = { 'scale': 1e6, 'axis': 'z [micron]', 'norm': True } self.beamPlotXAxisDict['t'] = { 'scale': 1e12, 'axis': 't [ps]', 'norm': True } self.beamPlotXAxisDict['cpx'] = {'scale': 1e3, 'axis': 'cpx [keV]'} self.beamPlotXAxisDict['cpy'] = {'scale': 1e3, 'axis': 'cpy [keV]'} self.beamPlotXAxisDict['BetaGamma'] = { 'scale': 0.511, 'axis': 'cp [MeV]' } # Form.setObjectName(("Form")) # Form.resize(874, 212) sizePolicy = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(Form.sizePolicy().hasHeightForWidth()) Form.setSizePolicy(sizePolicy) self.horizontalLayout = QHBoxLayout(Form) self.horizontalLayout.setObjectName("horizontalLayout") self.beamPlotXAxisCombo = QComboBox(Form) self.beamPlotXAxisCombo.addItems(list(self.beamPlotXAxisDict.keys())) self.beamPlotXAxisCombo.setCurrentIndex(2) self.horizontalLayout.addWidget(self.beamPlotXAxisCombo) self.beamPlotYAxisCombo = QComboBox(Form) self.beamPlotYAxisCombo.addItems(list(self.beamPlotXAxisDict.keys())) self.beamPlotYAxisCombo.setCurrentIndex(6) self.horizontalLayout.addWidget(self.beamPlotYAxisCombo) self.groupBox = QGroupBox(Form) self.groupBox.setObjectName("groupBox") self.formLayout = QFormLayout(self.groupBox) self.formLayout.setFieldGrowthPolicy(QFormLayout.AllNonFixedFieldsGrow) self.formLayout.setObjectName("formLayout") self.chooseSliceWidth = QRadioButton(self.groupBox) self.chooseSliceWidth.setObjectName(("chooseSliceWidth")) self.formLayout.setWidget(0, QFormLayout.LabelRole, self.chooseSliceWidth) self.sliceWidth = QDoubleSpinBox(self.groupBox) self.sliceWidth.setDecimals(6) self.sliceWidth.setObjectName("sliceWidth") self.formLayout.setWidget(0, QFormLayout.FieldRole, self.sliceWidth) self.chooseSliceNumber = QRadioButton(self.groupBox) self.chooseSliceNumber.setChecked(True) self.chooseSliceNumber.setObjectName("chooseSliceNumber") self.formLayout.setWidget(1, QFormLayout.LabelRole, self.chooseSliceNumber) self.sliceNumber = QSpinBox(self.groupBox) self.sliceNumber.setObjectName(("sliceNumber")) self.formLayout.setWidget(1, QFormLayout.FieldRole, self.sliceNumber) self.horizontalLayout.addWidget(self.groupBox) self.chooseSliceWidth.setText(_translate("Form", "Slice Width", None)) self.chooseSliceNumber.setText( _translate("Form", "Number of Slices", None)) self.sliceWidth.setRange(1e-6, 1) self.sliceWidth.setSingleStep(0.00001) self.histogramWidth = 0.0005 self.sliceWidth.setValue(self.histogramWidth) # self.sliceNumber = QSpinBox() self.sliceNumber.setRange(10, 10000) self.sliceNumber.setSingleStep(10) self.histogramBins = 100 self.sliceNumber.setValue(self.histogramBins) # self.beamPlotXAxisCombo = QComboBox() # self.beamPlotAxisLayout = QHBoxLayout() # self.beamPlotAxisWidget.setLayout(self.beamPlotAxisLayout) # self.beamPlotAxisLayout.addWidget(self.beamPlotXAxisCombo) # self.beamPlotAxisLayout.addWidget(self.beamPlotYAxisCombo) # self.beamPlotAxisLayout.addWidget(self.beamPlotNumberBins) self.beamPlotXAxisCombo.currentIndexChanged.connect(self.plotDataBeam) self.beamPlotYAxisCombo.currentIndexChanged.connect(self.plotDataBeam) self.chooseSliceNumber.toggled.connect(self.plotDataBeam) self.sliceNumber.valueChanged.connect(self.plotDataBeam) self.sliceWidth.valueChanged.connect(self.plotDataBeam) # self.beamPlotXAxisCombo.setCurrentIndex(2) # self.beamPlotYAxisCombo.setCurrentIndex(5) self.canvasWidget = QWidget() l = QVBoxLayout(self.canvasWidget) self.sc = MyStaticMplCanvas(self.canvasWidget, width=1, height=1, dpi=150) l.addWidget(self.sc) self.beamPlotLayout.addWidget(self.beamPlotAxisWidget) self.beamPlotLayout.addWidget(self.canvasWidget) ''' slicePlotWidget ''' self.sliceParams = [ { 'name': 'slice_normalized_horizontal_emittance', 'units': 'm-rad', 'text': 'enx' }, { 'name': 'slice_normalized_vertical_emittance', 'units': 'm-rad', 'text': 'eny' }, { 'name': 'slice_peak_current', 'units': 'A', 'text': 'PeakI' }, { 'name': 'slice_relative_momentum_spread', 'units': '%', 'text': 'sigma-p' }, { 'name': 'slice_beta_x', 'units': 'm', 'text': 'beta_x' }, { 'name': 'slice_beta_y', 'units': 'm', 'text': 'beta_y' }, ] self.slicePlotWidget = QWidget() self.slicePlotLayout = QVBoxLayout() self.slicePlotWidget.setLayout(self.slicePlotLayout) # self.slicePlotView = GraphicsView(useOpenGL=True) self.slicePlotWidgetGraphicsLayout = GraphicsLayoutWidget() # self.slicePlots = {} self.slicePlotCheckbox = {} self.curve = {} self.sliceaxis = {} self.slicePlotCheckboxWidget = QWidget() self.slicePlotCheckboxLayout = QVBoxLayout() self.slicePlotCheckboxWidget.setLayout(self.slicePlotCheckboxLayout) self.slicePlot = self.slicePlotWidgetGraphicsLayout.addPlot( title='Slice', row=0, col=50) self.slicePlot.showAxis('left', False) self.slicePlot.showGrid(x=True, y=True) i = -1 colors = ['b', 'r', 'g', 'k', 'y', 'm', 'c'] for param in self.sliceParams: i += 1 axis = AxisItem("left") labelStyle = {'color': '#' + colorStr(mkColor(colors[i]))[0:-2]} axis.setLabel(text=param['text'], units=param['units'], **labelStyle) viewbox = ViewBox() axis.linkToView(viewbox) viewbox.setXLink(self.slicePlot.vb) self.sliceaxis[param['name']] = [axis, viewbox] self.curve[param['name']] = PlotDataItem(pen=colors[i], symbol='+') viewbox.addItem(self.curve[param['name']]) col = self.findFirstEmptyColumnInGraphicsLayout() self.slicePlotWidgetGraphicsLayout.ci.addItem(axis, row=0, col=col, rowspan=1, colspan=1) self.slicePlotWidgetGraphicsLayout.ci.addItem(viewbox, row=0, col=50) p.showGrid(x=True, y=True) # self.slicePlots[param] = self.slicePlot.plot(pen=colors[i], symbol='+') self.slicePlotCheckbox[param['name']] = QCheckBox(param['text']) self.slicePlotCheckboxLayout.addWidget( self.slicePlotCheckbox[param['name']]) self.slicePlotCheckbox[param['name']].stateChanged.connect( self.plotDataSlice) # self.slicePlotView.setCentralItem(self.slicePlotWidgetGraphicsLayout) self.slicePlotSliceWidthWidget = QSpinBox() self.slicePlotSliceWidthWidget.setMaximum(500) self.slicePlotSliceWidthWidget.setValue(100) self.slicePlotSliceWidthWidget.setSingleStep(10) self.slicePlotSliceWidthWidget.setSuffix(" slices") self.slicePlotSliceWidthWidget.setSpecialValueText('Automatic') self.slicePlotAxisWidget = QWidget() self.slicePlotAxisLayout = QHBoxLayout() self.slicePlotAxisWidget.setLayout(self.slicePlotAxisLayout) self.slicePlotAxisLayout.addWidget(self.slicePlotCheckboxWidget) self.slicePlotAxisLayout.addWidget(self.slicePlotSliceWidthWidget) # self.slicePlotXAxisCombo.currentIndexChanged.connect(self.plotDataSlice) self.slicePlotSliceWidthWidget.valueChanged.connect( self.changeSliceLength) # self.beamPlotXAxisCombo.setCurrentIndex(2) # self.beamPlotYAxisCombo.setCurrentIndex(5) self.slicePlotLayout.addWidget(self.slicePlotAxisWidget) self.slicePlotLayout.addWidget(self.slicePlotWidgetGraphicsLayout) self.layout = QVBoxLayout() self.setLayout(self.layout) self.tabWidget = QTabWidget() self.folderButton = QPushButton('Select Directory') self.folderLineEdit = QLineEdit() self.folderLineEdit.setReadOnly(True) self.folderLineEdit.setText(self.directory) self.reloadButton = QPushButton() self.reloadButton.setIcon(qApp.style().standardIcon( QStyle.SP_BrowserReload)) self.folderWidget = QGroupBox() self.folderLayout = QHBoxLayout() self.folderLayout.addWidget(self.folderButton) self.folderLayout.addWidget(self.folderLineEdit) self.folderLayout.addWidget(self.reloadButton) self.folderWidget.setLayout(self.folderLayout) self.folderWidget.setMaximumWidth(800) self.reloadButton.clicked.connect( lambda: self.changeDirectory(self.directory)) self.folderButton.clicked.connect(self.changeDirectory) self.fileSelector = QComboBox() self.fileSelector.currentIndexChanged.connect(self.updateScreenCombo) self.screenSelector = QComboBox() self.screenSelector.currentIndexChanged.connect(self.changeScreen) self.beamWidget = QGroupBox() self.beamLayout = QHBoxLayout() self.beamLayout.addWidget(self.fileSelector) self.beamLayout.addWidget(self.screenSelector) self.beamWidget.setLayout(self.beamLayout) self.beamWidget.setMaximumWidth(800) self.beamWidget.setVisible(False) self.folderBeamWidget = QWidget() self.folderBeamLayout = QHBoxLayout() self.folderBeamLayout.setAlignment(Qt.AlignLeft) self.folderBeamWidget.setLayout(self.folderBeamLayout) self.folderBeamLayout.addWidget(self.folderWidget) self.folderBeamLayout.addWidget(self.beamWidget) self.tabWidget.addTab(self.twissPlotView, 'Twiss Plots') self.tabWidget.addTab(self.beamPlotWidget, 'Beam Plots') self.tabWidget.addTab(self.slicePlotWidget, 'Slice Beam Plots') # self.log = lw.loggerWidget() # self.log.addLogger(logger) # sys.stdout = lw.redirectLogger(self.log, 'stdout') # self.tabWidget.addTab(self.log,'Log') self.tabWidget.currentChanged.connect(self.changeTab) self.layout.addWidget(self.folderBeamWidget) self.layout.addWidget(self.tabWidget) self.plotType = 'Twiss' self.changeDirectory(self.directory)