class PreviewWidget(GraphicsLayoutWidget): def __init__(self): super(PreviewWidget, self).__init__() self.setMinimumHeight(250) self.setMinimumWidth(250) self.view = self.addViewBox(lockAspect=True, enableMenu=False) self.imageitem = ImageItem() self.textitem = TextItem(anchor=(0.5, 0)) self.textitem.setFont(QFont("Zero Threes")) self.imgdata = None self.imageitem.setOpts(axisOrder="row-major") self.view.addItem(self.imageitem) self.view.addItem(self.textitem) self.textitem.hide() self.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum) # def textItemBounds(axis, frac=1.0, orthoRange=None): # b = self.textitem.boundingRect() # sx, sy = self.view.viewPixelSize() # x, y = sx*b.width(), sy*b.height() # if axis == 0: return (-x/2, x/2) # if axis == 1: return (0, y) # # self.textitem.dataBounds = textItemBounds def sizeHint(self): return QSize(250, 250) def preview_header(self, header: NonDBHeader): try: data = header.meta_array()[0] self.setImage(data) except IndexError: self.imageitem.clear() self.setText("UNKNOWN DATA FORMAT") def setImage(self, imgdata): self.imageitem.clear() self.textitem.hide() self.imgdata = imgdata self.imageitem.setImage(np.log(self.imgdata * (self.imgdata > 0) + (self.imgdata < 1)), autoLevels=True) self.imageitem.setTransform( QTransform(1, 0, 0, -1, 0, self.imgdata.shape[-2])) self.view.autoRange() def setText(self, text): self.textitem.setText(text) self.imageitem.clear() self.textitem.setVisible(True) self.view.autoRange()
class CameraPlotWidget(GraphicsLayoutWidget): """This class manages and displays the camera CCD frame. Attributes ---------- image : numpy.array The data frame to display. """ def __init__(self, parent=None): """Initialize the class. Parameters ---------- parent : None, optional Top-level widget. """ super().__init__(parent) p1 = self.addPlot() p1.setAspectLocked(True) self.image = ImageItem() self.image.setOpts(axisOrder='row-major') p1.addItem(self.image)
def __new_map_item(z): map_item = ImageItem(autoLevels=False) map_item.setOpts(axisOrder='row-major') map_item.setZValue(z) return map_item
class SliceableGraphicsView(GraphicsView, SlicingView): sigToggleHorizontalSlice = Signal(bool) sigToggleVerticalSlice = Signal(bool) sigToggleDepthSlice = Signal(bool) sigMakePrimary = Signal(object, object) sigCrosshairMoved = Signal() SUPPORTED_NDIM = 2 def __init__(self, slice_direction, parent=None, xlink=None, ylink=None): super(SliceableGraphicsView, self).__init__(parent=parent) self.slice_direction = slice_direction self.setContentsMargins(0, 0, 0, 0) # Add axes self.view = SliceableAxes(slice_direction) self.view.axes["left"]["item"].setZValue(10) self.view.axes["top"]["item"].setZValue(10) self.setCentralItem(self.view) for sig in [ 'sigToggleVerticalSlice', 'sigToggleHorizontalSlice', 'sigToggleDepthSlice', 'sigMakePrimary' ]: if hasattr(self.view, sig): getattr(self.view, sig).connect(getattr(self, sig)) # Add imageitem self.image_item = ImageItem(axisOrder='row-major') self.image_item.setOpts() self.view.addItem(self.image_item) # add crosshair self.crosshair = BetterCrosshairROI((0, 0), parent=self.view, resizable=False) self.crosshair.sigMoved.connect(self.sigCrosshairMoved) self.view.getViewBox().addItem(self.crosshair) # find top-level parent NDImageView while not isinstance(parent, NDImageView): parent = parent.parent() # Initialize lut, levels self.image_item.setLevels(parent.levels, update=True) self.image_item.setLookupTable(parent.lut, update=True) # Link axes if ylink: self.view.vb.setYLink(ylink) if xlink: self.view.vb.setXLink(xlink) def setData(self, data): # Constrain squareness when units match is_square = data.dims[-2].split('(')[-1] == data.dims[-1].split( '(')[-1] self.view.vb.setAspectLocked(is_square) xvals = data.coords[data.dims[-1]] yvals = data.coords[data.dims[-2]] xmin = float(xvals.min()) xmax = float(xvals.max()) ymin = float(yvals.min()) ymax = float(yvals.max()) # Position the image according to coords shape = data.shape a = [(0, shape[-2]), (shape[-1], shape[-2]), (shape[-1], 0), (0, 0)] # b = [(ymin, xmax), (ymax, xmax), (ymax, xmin), (ymin, xmin)] if self.slice_direction in ['horizontal', 'depth']: b = [(xmin, ymin), (xmax, ymin), (xmax, ymax), (xmin, ymax)] elif self.slice_direction == 'vertical': b = [(xmax, ymax), (xmin, ymax), (xmin, ymin), (xmax, ymin)] quad1 = QPolygonF() quad2 = QPolygonF() for p, q in zip(a, b): quad1.append(QPointF(*p)) quad2.append(QPointF(*q)) transform = QTransform() QTransform.quadToQuad(quad1, quad2, transform) # Bind coords from the xarray to the timeline axis # super(SliceableGraphicsView, self).setImage(img, autoRange, autoLevels, levels, axes, np.asarray(img.coords[img.dims[0]]), pos, scale, transform, autoHistogramRange, levelMode) self.image_item.setImage(np.asarray(data), autoLevels=False) self.image_item.setTransform(transform) # Label the image axes self.view.setLabel('left', data.dims[-2]) self.view.setLabel('bottom', data.dims[-1]) def resetCrosshair(self): transform = self.image_item.viewTransform() new_pos = transform.map(self.image_item.boundingRect().center()) self.crosshair.setPos(new_pos) # self.crosshair.sigMoved.emit(new_pos) def updateImage(self, autoHistogramRange=True): ## Redraw image on screen if self.image is None: return image = self.getProcessedImage() if autoHistogramRange: self.ui.histogram.setHistogramRange(self.levelMin, self.levelMax) # Transpose image into order expected by ImageItem if self.imageItem.axisOrder == 'col-major': axorder = ['t', 'x', 'y', 'c'] else: axorder = ['t', 'y', 'x', 'c'] axorder = [ self.axes[ax] for ax in axorder if self.axes[ax] is not None ] ax_swap = [image.dims[ax_index] for ax_index in axorder] image = image.transpose(*ax_swap) # Select time index if self.axes['t'] is not None: self.ui.roiPlot.show() image = image[self.currentIndex] self.imageItem.updateImage(np.asarray(image)) def updateCrosshair(self, x, y): self.crosshair.setPos(x, y) def quickMinMax(self, data): """ Estimate the min/max values of *data* by subsampling. MODIFIED TO USE THE 99TH PERCENTILE instead of max. """ if data is None: return 0, 0 sl = slice(None, None, max(1, int(data.size // 1e6))) data = np.asarray(data[sl]) levels = (np.nanmin(data), np.nanpercentile( np.where(data < np.nanmax(data), data, np.nanmin(data)), 99)) return [levels]
class PreviewWidget(GraphicsLayoutWidget): def __init__(self): super(PreviewWidget, self).__init__() self.setMinimumHeight(250) self.setMinimumWidth(250) self.view = self.addViewBox(lockAspect=True, enableMenu=False) self.imageitem = ImageItem() self.textitem = TextItem(anchor=(0.5, 0)) self.textitem.setFont(QFont("Zero Threes")) self.imgdata = None self.imageitem.setOpts(axisOrder="row-major") self.view.addItem(self.imageitem) self.view.addItem(self.textitem) self.textitem.hide() self.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum) # def textItemBounds(axis, frac=1.0, orthoRange=None): # b = self.textitem.boundingRect() # sx, sy = self.view.viewPixelSize() # x, y = sx*b.width(), sy*b.height() # if axis == 0: return (-x/2, x/2) # if axis == 1: return (0, y) # # self.textitem.dataBounds = textItemBounds def sizeHint(self): return QSize(250, 250) @threads.method(threadkey="preview", showBusy=False) def preview(self, data): if isinstance(data, NonDBHeader): self.preview_header(data) else: self.preview_catalog(data) @staticmethod def guess_stream_field(catalog: BlueskyRun): # TODO: use some metadata (techniques?) for guidance about how to get a preview streams = bluesky_utils.streams_from_run(catalog) if "primary" in streams: streams.remove("primary") streams.insert(0, "primary") for stream in streams: descriptor = bluesky_utils.descriptors_from_stream( catalog, stream)[0] fields = bluesky_utils.fields_from_descriptor(descriptor) for field in fields: field_ndims = bluesky_utils.ndims_from_descriptor( descriptor, field) if field_ndims > 1: return stream, field def preview_catalog(self, catalog: BlueskyRun): threads.invoke_in_main_thread(self.setText, "LOADING...") try: stream, field = self.guess_stream_field(catalog) data = getattr(catalog, stream).to_dask()[field].squeeze() for i in range(len(data.shape) - 2): data = data[0] threads.invoke_in_main_thread(self.setImage, np.asarray(data.compute())) except Exception as ex: msg.logError(ex) threads.invoke_in_main_thread(self.imageitem.clear) threads.invoke_in_main_thread(self.setText, "UNKNOWN DATA FORMAT") def preview_header(self, header: NonDBHeader): try: data = header.meta_array()[0] threads.invoke_in_main_thread(self.setImage, data) except IndexError: threads.invoke_in_main_thread(self.imageitem.clear) threads.invoke_in_main_thread(self.setText, "UNKNOWN DATA FORMAT") def setImage(self, imgdata): self.imageitem.clear() self.textitem.hide() self.imgdata = imgdata self.imageitem.setImage(np.log(self.imgdata * (self.imgdata > 0) + (self.imgdata < 1)), autoLevels=True) self.imageitem.setTransform( QTransform(1, 0, 0, -1, 0, self.imgdata.shape[-2])) self.view.autoRange() def setText(self, text): self.textitem.setText(text) self.imageitem.clear() self.textitem.setVisible(True) self.view.autoRange()
class PsdWaterfallPlotWidget(GraphicsLayoutWidget): """This class manages and displays the power spectrum distribution (PSD) data in a waterfall plot. Attributes ---------- arraySize : int The size of the data array to display. boundingRect : QtCore.QRectF The actual coordinate space base on frequency and time of acquisition. data : numpy.ndarray The 2D array for the PSD data. image : pyqtgraph.ImageItem The instance of the image item for display. timeScale : float The total time for the buffer to accumulate at the ROI FPS. """ def __init__(self, parent=None): """Initialize the class. Parameters ---------- parent : None, optional Top-level widget. """ super().__init__(parent) self.plot = self.addPlot() self.plot.invertY() self.image = ImageItem() self.image.setOpts(axisOrder='row-major') self.plot.addItem(self.image) self.data = None self.arraySize = None self.boundingRect = None self.timeScale = None self.colorMap = 'viridis' self.image.setLookupTable(getLutFromColorMap(self.colorMap)) def clearPlot(self): """Reset all data and clear the plot. """ self.data = None self.boundingRect = None self.image.clear() def getConfiguration(self): """Get the current plot configuration. Returns ------- int, str The set of current configuration parameters. """ return self.arraySize, self.colorMap def setConfiguration(self, config): """Set the new parameters into the widget. Parameters ---------- config : `config.PsdPlotConfig` The new parameters to apply. """ numBins = config.numWaterfallBins if self.arraySize != numBins: self.arraySize = numBins # Invalidate data self.data = None self.boundingRect = None colorMap = config.waterfallColorMap if self.colorMap != colorMap: self.colorMap = colorMap self.image.setLookupTable(getLutFromColorMap(self.colorMap)) def setTimeScale(self, timeScale): """Update the stored timescale and invalidate data and bounding rect. Parameters ---------- timeScale : float The new timescale. """ self.timeScale = timeScale self.data = None self.boundingRect = None def setup(self, arraySize, timeScale, axisLabel): """Setup the widget with the array size. Parameters ---------- arraySize : int The size fo the data array to display in terms of history. timeScale : float The total time for the buffer to accumulate at the ROI FPS. axisLabel : str Label for particular centroid coordinate. """ self.arraySize = arraySize self.timeScale = timeScale self.plot.setLabel('bottom', '{} {}'.format(axisLabel, HTML_NU), units='Hz') self.plot.setLabel('left', 'Time', units='s') def updatePlot(self, psd, freqs): """Update the current plot with the given data. Parameters ---------- psd : numpy.array The PSD data of a given centroid coordinate. freqs : numpy.array The frequency array associated with the PSD data. """ if self.data is None: self.data = np.zeros((self.arraySize, psd.size)) else: self.data[1:, ...] = self.data[:-1, ...] self.data[0, ...] = np.log(psd) self.image.setImage(self.data) if self.boundingRect is None: self.boundingRect = QtCore.QRectF(0, 0, freqs[-1], self.arraySize * self.timeScale) self.image.setRect(self.boundingRect)
class PreviewWidget(GraphicsLayoutWidget): def __init__(self): super(PreviewWidget, self).__init__() self.setMinimumHeight(250) self.setMinimumWidth(250) self.view = self.addViewBox(lockAspect=True, enableMenu=False) self.imageitem = ImageItem() self.textitem = TextItem(anchor=(0.5, 0)) self.textitem.setFont(QFont("Zero Threes")) self.imageitem.setOpts(axisOrder="row-major") self.view.addItem(self.imageitem) self.view.addItem(self.textitem) self.textitem.hide() self.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum) # def textItemBounds(axis, frac=1.0, orthoRange=None): # b = self.textitem.boundingRect() # sx, sy = self.view.viewPixelSize() # x, y = sx*b.width(), sy*b.height() # if axis == 0: return (-x/2, x/2) # if axis == 1: return (0, y) # # self.textitem.dataBounds = textItemBounds def sizeHint(self): return QSize(250, 250) @threads.method(threadkey="preview", showBusy=False) def preview(self, data): if isinstance(data, NonDBHeader): self.preview_header(data) else: self.preview_catalog(data) def preview_catalog(self, catalog: BlueskyRun): threads.invoke_in_main_thread(self.setText, "LOADING...") try: stream, field = bluesky_utils.guess_stream_field(catalog) data = bluesky_utils.preview(catalog, stream, field) threads.invoke_in_main_thread(self.setImage, data) except Exception as ex: msg.logError(ex) threads.invoke_in_main_thread(self.imageitem.clear) threads.invoke_in_main_thread(self.setText, "UNKNOWN DATA FORMAT") def preview_header(self, header: NonDBHeader): try: data = header.meta_array()[0] threads.invoke_in_main_thread(self.setImage, data) except IndexError: threads.invoke_in_main_thread(self.imageitem.clear) threads.invoke_in_main_thread(self.setText, "UNKNOWN DATA FORMAT") def setImage(self, imgdata): self.imageitem.clear() self.textitem.hide() self.imageitem.setImage(np.log(imgdata * (imgdata > 0) + (imgdata < 1)), autoLevels=True) self.imageitem.setTransform( QTransform(1, 0, 0, -1, 0, imgdata.shape[-2])) self.view.autoRange() def setText(self, text): self.textitem.setText(text) self.imageitem.clear() self.textitem.setVisible(True) self.view.autoRange()
class PreviewWidget(GraphicsLayoutWidget): def __init__(self): super(PreviewWidget, self).__init__() self.setMinimumHeight(250) self.setMinimumWidth(250) self.view = self.addViewBox(lockAspect=True, enableMenu=False) self.imageitem = ImageItem() self.textitem = TextItem(anchor=(0.5, 0)) self.textitem.setFont(QFont("Zero Threes")) self.imgdata = None self.imageitem.setOpts(axisOrder="row-major") self.view.addItem(self.imageitem) self.view.addItem(self.textitem) self.textitem.hide() self.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum) # def textItemBounds(axis, frac=1.0, orthoRange=None): # b = self.textitem.boundingRect() # sx, sy = self.view.viewPixelSize() # x, y = sx*b.width(), sy*b.height() # if axis == 0: return (-x/2, x/2) # if axis == 1: return (0, y) # # self.textitem.dataBounds = textItemBounds def sizeHint(self): return QSize(250, 250) def preview(self, data): if isinstance(data, NonDBHeader): self.preview_header(data) else: self.preview_catalog(data) def preview_catalog(self, catalog: BlueskyRun): try: dask_array = catalog.primary.to_dask() fields = dask_array.keys() # Filter out seq num and uid field = next(field for field in fields if not field in ["seq_num", "uid"]) data = dask_array[field] for i in range(len(data.shape) - 2): data = data[0] self.setImage(np.asarray(data.compute())) except IndexError: self.imageitem.clear() self.setText("UNKNOWN DATA FORMAT") def preview_header(self, header: NonDBHeader): try: data = header.meta_array()[0] self.setImage(data) except IndexError: self.imageitem.clear() self.setText("UNKNOWN DATA FORMAT") def setImage(self, imgdata): self.imageitem.clear() self.textitem.hide() self.imgdata = imgdata self.imageitem.setImage(np.log(self.imgdata * (self.imgdata > 0) + (self.imgdata < 1)), autoLevels=True) self.imageitem.setTransform(QTransform(1, 0, 0, -1, 0, self.imgdata.shape[-2])) self.view.autoRange() def setText(self, text): self.textitem.setText(text) self.imageitem.clear() self.textitem.setVisible(True) self.view.autoRange()
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)
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)