def mouse_click(self, ev, line: InfiniteLine): line.setPos(ev.pos()) # don't refresh the histogram on click to stop the contrast for re-adjusting for each slice # it's much easier to see what's happening to the reconstruction if the slice doesn't # reset after every click self.parent.presenter.do_reconstruct_slice(slice_idx=CloseEnoughPoint(ev.pos()).y, refresh_recon_slice_histogram=False)
def add_crosshair(plot, render_measurements, color=Qt.gray): pen = mkPen(color=QColor(color), width=1) vline = InfiniteLine(angle=90, movable=False, pen=pen) hline = InfiniteLine(angle=0, movable=False, pen=pen) plot.addItem(vline, ignoreBounds=True) plot.addItem(hline, ignoreBounds=True) current_coordinates = None reference_coordinates = None def do_render(): render_measurements(current_coordinates, reference_coordinates) def update(pos): nonlocal current_coordinates if plot.sceneBoundingRect().contains(pos): mouse_point = plot.getViewBox().mapSceneToView(pos) current_coordinates = mouse_point.x(), mouse_point.y() vline.setPos(mouse_point.x()) hline.setPos(mouse_point.y()) do_render() def set_reference(ev): nonlocal reference_coordinates if ev.button() == Qt.LeftButton and current_coordinates is not None: reference_coordinates = current_coordinates do_render() plot.scene().sigMouseMoved.connect(update) plot.scene().sigMouseClicked.connect(set_reference)
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 removeSegment(self, line: pg.InfiniteLine, modify_track=True): index = self.segments.index(line) # would be silly to remove beginning or end line if index == 0 or index == len(self.segments) - 1: return label = self.names[index] self.segments.remove(line) self.names.remove(label) self.vb.removeItem(line) self.vb.removeItem(label) if modify_track: self.track.delete_merge_left(index) self.calcPartitionNamePlacement(self.names[index - 1], index - 1, emit_signal=False) self.updateBounds(self.segments[index - 1], index - 1) self.updateBounds(self.segments[index], index) if modify_track: self.item.delete_segment.emit(index) line.deleteLater() label.deleteLater()
def __init__(self, *args, **kwargs): kwargs['viewBox'] = ScanViewBox() # Use custom pg.ViewBox subclass super().__init__(*args, **kwargs) self.getViewBox().sigMouseAreaSelected.connect(self.sigMouseAreaSelected) self._min_crosshair_factor = 0.02 self._crosshair_size = (0, 0) self._crosshair_range = None self.getViewBox().sigRangeChanged.connect(self._constraint_crosshair_size) self.crosshair = ROI((0, 0), (0, 0), pen={'color': '#00ff00', 'width': 1}) self.hline = InfiniteLine(pos=0, angle=0, movable=True, pen={'color': '#00ff00', 'width': 1}, hoverPen={'color': '#ffff00', 'width': 1}) self.vline = InfiniteLine(pos=0, angle=90, movable=True, pen={'color': '#00ff00', 'width': 1}, hoverPen={'color': '#ffff00', 'width': 1}) self.vline.sigDragged.connect(self._update_pos_from_line) self.hline.sigDragged.connect(self._update_pos_from_line) self.crosshair.sigRegionChanged.connect(self._update_pos_from_roi) self.sigCrosshairDraggedPosChanged.connect(self.sigCrosshairPosChanged)
def _plot_cutpoint(self, x): """ Function plots the cutpoint. Parameters ---------- x : int Cutpoint location. """ if x is None: self._line = None return if self._line is None: # plot interactive vertical line self._line = InfiniteLine(angle=90, pos=x, movable=True, bounds=self.selection_limit if self.selection_limit is not None else (self.x.min(), self.x.max())) self._line.setCursor(Qt.SizeHorCursor) self._line.setPen(mkPen(QColor(Qt.black), width=2)) self._line.sigPositionChanged.connect(self._on_cut_changed) self.addItem(self._line) else: self._line.setValue(x) self._update_horizontal_lines()
def __init__(self, diff, parent=None): super(SideView, self).__init__(parent=parent) self.parent = parent self.brain = parent.brain self.diff = diff self.view1 = ViewBox() self.setCentralItem(self.view1) # Making Images out of data self.brain.section = (self.brain.section + self.diff) % 3 self.i = int(self.brain.shape[self.brain.section] / 2) data_slice = self.brain.get_data_slice(self.i) self.brain_img1 = ImageItem( data_slice, autoDownsample=False, compositionMode=QtGui.QPainter.CompositionMode_SourceOver) self.brain.section = (self.brain.section - self.diff) % 3 self.view1.addItem(self.brain_img1) self.view1.setAspectLocked(True) self.view1.setFixedHeight(250) self.view1.setFixedWidth(250) self.setMinimumHeight(250) self.vLine = InfiniteLine(angle=90, movable=False) self.hLine = InfiniteLine(angle=0, movable=False) self.vLine.setVisible(False) self.hLine.setVisible(False) self.view1.addItem(self.vLine, ignoreBounds=True) self.view1.addItem(self.hLine, ignoreBounds=True)
def set2ndFlowGui(self): #Create Ocean object: Operation and communication in parallel flow control self.SensorOcean_func(self.oceanPVname) #Instance: Determination of pressure data with data of graph''' self.graphdata = DataCalculate() # connect signals of SensorOcean -> PV of OceanOptics self.SensorOcean.signal.connect(self.searchPressure) #self.SensorOcean.finished.connect(self.finish) self.SensorOcean.error_message.connect(self.errorMessage) #Connect the most important signal (Acquire spectrogram) self.ui.btnAcquire.released.connect( self.managerUserInterfaceforacquisition_start) self.ui.btnAcquireStop.released.connect( self.managerUserInterfaceforacquisition_stop) #It does not break the program self.line = InfiniteLine() self.line_calc = InfiniteLine() self.ui.lcdPressure.setSmallDecimalPoint(True) self.ui.lcdPressure.setDigitCount(6) self.plotFlagDesired = None self.dPressure = None
def plotAutomaticLineOnGraph(self, plot=True, w_l=694.26, _label='PV'): ''' Plotting line on graph ''' try: if (plot): if self.ui.chkDark.isChecked(): self.ui.wvRaw.plotItem.removeItem(self.line) self.ui.wvDark.plotItem.removeItem(self.line) self.line = InfiniteLine(pos=w_l, angle=90, pen=mkPen('r', width=2), label=_label) self.ui.wvDark.plotItem.addItem(self.line) else: self.ui.wvRaw.plotItem.removeItem(self.line) self.ui.wvDark.plotItem.removeItem(self.line) self.line = InfiniteLine(pos=w_l, angle=90, pen=mkPen('r', width=2), label=_label) self.ui.wvRaw.plotItem.addItem(self.line) else: self.ui.wvRaw.plotItem.removeItem(self.line) self.ui.wvDark.plotItem.removeItem(self.line) except: self.showDialog("Error on pressure data processing", "Mode Automatic: Error on pressure data plotting")
def plotLine_nm_OnGraph(self, plot=True, w_l=694.26, _label='PV', _angle=90): try: if (plot): if ((w_l > 600) and (w_l < 800)): if self.ui.chkDark.isChecked(): self.ui.wvRaw.plotItem.removeItem(self.line_calc) self.ui.wvDark.plotItem.removeItem(self.line_calc) self.line_calc = InfiniteLine(pos=w_l, angle=_angle, pen=mkPen('g', width=2), label=_label) self.ui.wvDark.plotItem.addItem(self.line_calc) else: self.ui.wvRaw.plotItem.removeItem(self.line_calc) self.ui.wvDark.plotItem.removeItem(self.line_calc) self.line_calc = InfiniteLine(pos=w_l, angle=_angle, pen=mkPen('g', width=2), label=_label) self.ui.wvRaw.plotItem.addItem(self.line_calc) else: self.showDialog("Error plotting procedure", "Wavelength is out of range") else: self.ui.wvRaw.plotItem.removeItem(self.line_calc) self.ui.wvDark.plotItem.removeItem(self.line_calc) except: self.showDialog("Error on pressure data processing", "Mode Automatic: Error on pressure data plotting")
def uigetgraph(self, pln, size): """.""" graph = Graph(self) graph.doubleclick.connect(_part(self._set_enable_list, pln)) graph.plotItem.scene().sigMouseMoved.connect( _part(self._show_tooltip, pln=pln)) if self.is_orb: xlabel = 'BPM ' elif pln.lower().endswith('x'): xlabel = 'CH ' else: xlabel = 'CV ' xlabel += 'Position' graph.setLabel('bottom', text=xlabel, units='m') lab = 'Orbit' if self.is_orb else 'Kick Angle' unit = 'm' if self.is_orb else 'rad' graph.setLabel('left', text=lab, units=unit) graph.setObjectName(lab.replace(' ', '') + pln) for i, lname in enumerate(self.line_names): opts = dict(y_channel='A', x_channel='B', name=lname, color=self._get_color(pln, i), redraw_mode=2, lineStyle=1, lineWidth=2 if i else 3, symbol='o', symbolSize=10) graph.addChannel(**opts) pen = mkPen(opts['color'], width=opts['lineWidth']) pen.setStyle(4) cpstd = InfiniteLine(pos=0.0, pen=pen, angle=0) self.updater[i].ave_pstd[pln].connect(cpstd.setValue) graph.addItem(cpstd) cmstd = InfiniteLine(pos=0.0, pen=pen, angle=0) self.updater[i].ave_mstd[pln].connect(cmstd.setValue) graph.addItem(cmstd) pen.setStyle(2) cave = InfiniteLine(pos=0.0, pen=pen, angle=0) self.updater[i].ave[pln].connect(cave.setValue) graph.addItem(cave) cdta = graph.curveAtIndex(-1) self.updater[i].data_sig[pln].connect( _part(self._update_waveform, cdta, pln, i)) cdta.setVisible(not i) cdta.curve.setZValue(-4 * i) cdta.scatter.setZValue(-4 * i) for j, cur in enumerate((cpstd, cmstd, cave), 1): cur.setZValue(-4 * i - j) cur.setVisible(False) graph.plotItem.legend.removeItem('') graph.setStyleSheet(""" #{0}{{ min-width:{1}em; min-height:{2}em; }}""".format(lab.replace(' ', '') + pln, size[0], size[1])) return graph
def enableCrosshair(self, is_enabled, starting_x_pos, starting_y_pos, vertical_angle=90, horizontal_angle=0, vertical_movable=False, horizontal_movable=False): """ Enable the crosshair to be drawn on the ViewBox. Parameters ---------- is_enabled : bool True is to draw the crosshair, False is to not draw. starting_x_pos : float The x coordinate where to start the vertical crosshair line. starting_y_pos : float The y coordinate where to start the horizontal crosshair line. vertical_angle : float The angle to tilt the vertical crosshair line. Default at 90 degrees. horizontal_angle The angle to tilt the horizontal crosshair line. Default at 0 degrees. vertical_movable : bool True if the vertical line can be moved by the user; False is not. horizontal_movable False if the horizontal line can be moved by the user; False is not. """ if is_enabled: self.vertical_crosshair_line = InfiniteLine( pos=starting_x_pos, angle=vertical_angle, movable=vertical_movable) self.horizontal_crosshair_line = InfiniteLine( pos=starting_y_pos, angle=horizontal_angle, movable=horizontal_movable) self.plotItem.addItem(self.vertical_crosshair_line) self.plotItem.addItem(self.horizontal_crosshair_line) self.crosshair_movement_proxy = SignalProxy( self.plotItem.scene().sigMouseMoved, rateLimit=60, slot=self.mouseMoved) else: if self.vertical_crosshair_line: self.plotItem.removeItem(self.vertical_crosshair_line) if self.horizontal_crosshair_line: self.plotItem.removeItem(self.horizontal_crosshair_line) if self.crosshair_movement_proxy: # self.crosshair_movement_proxy.disconnect() proxy = self.crosshair_movement_proxy proxy.block = True try: proxy.signal.disconnect(proxy.signalReceived) proxy.sigDelayed.disconnect(proxy.slot) except: pass
def offsetDepthOnPlot(self, side): self.sideToOffset = side self.rightShelfBtn.deleteLater() self.leftShelfBtn.deleteLater() self.btnLay.deleteLater() self.btnLay, self.leftShelfBtn, self.rightShelfBtn = None, None, None self.offsetDepthLine = InfiniteLine(pen=mkPen(width=1.5, color='y')) self.btn3.setVisible(True) self.plotWidget.scene().sigMouseClicked.connect(self.firstClickOnPlot)
def __init__(self, parent, style="dark"): self._ySeries = None self.plotItem = None self.style = PlotStyle(style) self.setStyle(style) self.dateAxis = CustomDateAxisItem() self.plotItem = CustomPlotItem(viewBox=CustomViewBox(), axisItems={ 'bottom': self.dateAxis, 'left': CustomAxisItem('left') }) super().__init__(plotItem=self.plotItem) self.dateAxis.axisDoubleClicked.connect(self.setPlotRange) self.hgltPnt = None self.parent = parent self.plottable = ['speed', 'distance', 'time', 'calories'] self._initRightAxis() # axis labels self.plotItem.setLabel('bottom', text='Date') # show grid on left and bottom axes self.plotItem.getAxis('left').setGrid(255) self.plotItem.getAxis('bottom').setGrid(255) # cross hairs self.vLine = InfiniteLine(angle=90, movable=False) self.hLine = InfiniteLine(angle=0, movable=False) self.plotItem.addItem(self.vLine, ignoreBounds=True) self.plotItem.addItem(self.hLine, ignoreBounds=True) self.plotItem.scene().sigMouseMoved.connect(self.mouseMoved) self.plotItem.scene().sigMouseClicked.connect(self.plotClicked) # update second view box self.updateViews() self.plotItem.vb.sigResized.connect(self.updateViews) self.currentPoint = {} # all points that are/were PBs can be highlighted self._showPBs = False self._regenerateCachedPBs = {key: False for key in self.plottable} self.hgltPBs = {key: [] for key in self.plottable} self.viewMonths = None self.setYSeries('speed') self.plotTotalDistance()
def __init__(self, parent=None): super().__init__(parent) self.plot_item = self.addPlot() self.plot_item.setMenuEnabled(False) self.inf_line = InfiniteLine(0, pen=get_pen(color='red', style=Qt.DashLine)) self.plot_item.addItem(self.inf_line) self.plots = {} self.x_axis: Dict[int, List[int]] = {}
def updateBounds(self, line: pg.InfiniteLine, index: int): if index == 0 or index == len(self.segments) - 1: return last_partition = self.segments[index - 1].getXPos() next_partition = self.segments[index + 1].getXPos() cushion = self.calcCushion() min_bounds = last_partition + cushion max_bounds = next_partition - cushion line.setBounds((min_bounds, max_bounds)) self.item.updatePartitionBoundaries.emit(index, min_bounds, max_bounds)
def __init__(self, parent): super().__init__(parent) self.parent = parent self.projection, self.projection_vb, self.projection_hist = self.image_in_vb( "Projection") self.sinogram, self.sinogram_vb, self.sinogram_hist = self.image_in_vb( "Sinogram") self.recon, self.recon_vb, self.recon_hist = self.image_in_vb("Recon") self.slice_line = InfiniteLine(pos=1024, angle=0, bounds=[0, self.projection.width()], movable=True) self.projection_vb.addItem(self.slice_line) self.tilt_line = InfiniteLine(pos=1024, angle=90, pen=(255, 0, 0, 255), movable=True) image_layout = self.addLayout(colspan=4) image_layout.addItem(self.projection_vb, 0, 0) image_layout.addItem(self.projection_hist, 0, 1) image_layout.addItem(self.recon_vb, 0, 2, rowspan=3) image_layout.addItem(self.recon_hist, 0, 3, rowspan=3) projection_details = LabelItem("Value") image_layout.addItem(projection_details, 1, 0, 1, 2) image_layout.addItem(self.sinogram_vb, 2, 0) image_layout.addItem(self.sinogram_hist, 2, 1) sino_details = LabelItem("Value") image_layout.addItem(sino_details, 3, 0, 1, 2) recon_details = LabelItem("Value") image_layout.addItem(recon_details, 3, 2, 1, 2) msg_format = "Value: {:.6f}" self.display_formatted_detail = { self.projection: lambda val: projection_details.setText(msg_format.format(val)), self.sinogram: lambda val: sino_details.setText(msg_format.format(val)), self.recon: lambda val: recon_details.setText(msg_format.format(val)) } self.projection.hoverEvent = lambda ev: self.mouse_over( ev, self.projection) self.projection.mouseClickEvent = lambda ev: self.mouse_click( ev, self.slice_line) self.slice_line.sigPositionChangeFinished.connect( self.slice_line_moved) self.sinogram.hoverEvent = lambda ev: self.mouse_over( ev, self.sinogram) self.recon.hoverEvent = lambda ev: self.mouse_over(ev, self.recon)
def __init__(self, *args, **kwargs): PlotWidget.__init__(self, *args, **kwargs) self.fit_range_marker = InfiniteLine(movable=True, pen=mkPen('w', width=2)) self.text_no_data = TextItem('Press "Analyze" to display results', anchor=(0.5, 0.5)) self._log_mode = False self.showGrid(x=True, y=True) self.addItem(self.fit_range_marker) self.addItem(self.text_no_data) self.reset() self.fit_range_marker.sigPositionChangeFinished.connect( self.sigFitRangeChanged.emit)
def __init__(self, *args, **kwargs): super(Crosshair, self).__init__(*args, **kwargs) linepen = mkPen("#FFA500") self._vline = InfiniteLine((0, 0), angle=90, movable=False, pen=linepen) self._hline = InfiniteLine((0, 0), angle=0, movable=False, pen=linepen) self._vline.setVisible(False) self._hline.setVisible(False) self.addItem(self._vline) self.addItem(self._hline) self.scene.sigMouseMoved.connect(self.moveCrosshair)
def __init__(self, x: list, y: list, graphics_view: PlotWidget, labels: str, units=None, x_labels=None, width=0.4): """ Constructor / Instantiation of class Parameters ---------- x : list x-values y : list y-values graphics_view : PlotWidget widget to add items labels : str legend labels units : tuple measurement units for tuple width : int, float width of any bars x_labels : array-like array of dates, i.e. time-period """ super().__init__() Assertor.assert_data_types([x, y, graphics_view, labels, units, x_labels, width], [list, list, PlotWidget, str, (type(None), tuple), (type(None), list), (float, int)]) self.x = asarray(arange(1, len(x) + 1, 1)) self.y = asarray([float(val.replace(" ", "").replace("%", "")) if val else 0 for val in y]) self.graphics_view = graphics_view self.labels = labels self.units = units if units else tuple(["" for _ in range(10)]) self.x_time = x_labels self.width = width self.bar_item_1 = BarGraphItem(x=self.x, height=self.y, width=self.width, brush="#a8ccec") self.graphics_view.addItem(self.bar_item_1) self.bar_item_2 = None self.label = TextItem() pen = mkPen(color="#4c96d7", style=Qt.SolidLine, width=1) self.vertical_line = InfiniteLine(angle=90, movable=False, pen=pen) self.graphics_view.addItem(self.vertical_line) self.view_box = self.graphics_view.getViewBox() self.configure_cross_hair() self.graphics_view.plotItem.vb.setLimits(xMin=0, xMax=max(self.x) + 1) self.graphics_view.setMenuEnabled(False)
def __init__(self, parent): super().__init__(parent) self.parent = parent self.projection, self.projection_vb, self.projection_hist = self.image_in_vb("Projection") self.sinogram, self.sinogram_vb, self.sinogram_hist = self.image_in_vb("Sinogram") self.recon, self.recon_vb, self.recon_hist = self.image_in_vb("Recon") self.slice_line = InfiniteLine(pos=1024, angle=0, bounds=[0, self.projection.width()], movable=True) self.projection_vb.addItem(self.slice_line) self.tilt_line = InfiniteLine(pos=1024, angle=90, pen=(255, 0, 0, 255), movable=True) image_layout = self.addLayout(colspan=4) image_layout.addItem(self.projection_vb, 0, 0) image_layout.addItem(self.projection_hist, 0, 1) image_layout.addItem(self.recon_vb, 0, 2, rowspan=3) image_layout.addItem(self.recon_hist, 0, 3, rowspan=3) projection_details = LabelItem("Value") image_layout.addItem(projection_details, 1, 0, 1, 2) image_layout.addItem(self.sinogram_vb, 2, 0) image_layout.addItem(self.sinogram_hist, 2, 1) sino_details = LabelItem("Value") image_layout.addItem(sino_details, 3, 0, 1, 2) recon_details = LabelItem("Value") image_layout.addItem(recon_details, 3, 2, 1, 2) msg_format = "Value: {:.6f}" self.display_formatted_detail = { self.projection: lambda val: projection_details.setText(msg_format.format(val)), self.sinogram: lambda val: sino_details.setText(msg_format.format(val)), self.recon: lambda val: recon_details.setText(msg_format.format(val)) } self.projection.hoverEvent = lambda ev: self.mouse_over(ev, self.projection) self.projection.mouseClickEvent = lambda ev: self.mouse_click(ev, self.slice_line) self.slice_line.sigPositionChangeFinished.connect(self.slice_line_moved) self.sinogram.hoverEvent = lambda ev: self.mouse_over(ev, self.sinogram) self.recon.hoverEvent = lambda ev: self.mouse_over(ev, self.recon) # Work around for https://github.com/mantidproject/mantidimaging/issues/565 for scene in [ self.projection.scene(), self.projection_hist.scene(), self.sinogram.scene(), self.sinogram_hist.scene(), self.recon.scene(), self.recon_hist.scene(), ]: scene.contextMenu = [item for item in scene.contextMenu if "export" not in item.text().lower()]
def __init__(self, *args, **kwargs): super(SpectraPlotWidget, self).__init__(*args, **kwargs) self._data = None 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.setZValue(100) self.line.sigPositionChanged.connect(self.sigEnergyChanged) self.line.sigPositionChanged.connect(self.getEnergy) self.addItem(self.line) self.getViewBox().invertX(True) self.selectedPixels = None self._y = None
def plot_spectrum(self, ev): #clear if ev.button() == Qt.RightButton: return self.plot_widget_spectrum.clear() vb = self.plot_widget_tic.vb mouse_point = vb.mapSceneToView(ev.scenePos()) t = mouse_point.x() if self.inf_line_tic_item is None: self.inf_line_tic_item = InfiniteLine(pos=t, angle=90) self.plot_widget_tic.addItem(self.inf_line_tic_item) self.inf_line_tic_item.setMovable(True) else: self.inf_line_tic_item.setPos(t) min_mz, max_mz = 1e9, 0 min_int, max_int = 1e10, 0 for rawfile in self.rawfiles_by_short_path.values(): if not rawfile.is_checked: continue scan_id, mzs, intensities = rawfile.reader.get_scan_for_time(t) self.curr_scan_id_by_short_path[rawfile.short_path] = scan_id min_mz = min(min_mz, mzs[0]) max_mz = max(max_mz, mzs[-1]) min_int = min(min_int, min(intensities)) max_int = max(max_int, max(intensities)) item = BarGraphItem(x=mzs, height=intensities, width=0.01, pen=rawfile.qcolor, brush=rawfile.qcolor) self.plot_widget_spectrum.addItem(item) self.plot_widget_spectrum.setLimits(xMin=min_mz, xMax=max_mz, yMin=min_int, yMax=max_int)
def __init__(self, parent): super().__init__(parent) self.parent = parent self.imageview_projection = MIMiniImageView(name="Projection") self.imageview_sinogram = MIMiniImageView(name="Sinogram") self.imageview_recon = MIMiniImageView(name="Recon") self.projection, self.projection_vb, self.projection_hist = self.imageview_projection.get_parts( ) self.sinogram, self.sinogram_vb, self.sinogram_hist = self.imageview_sinogram.get_parts( ) self.recon, self.recon_vb, self.recon_hist = self.imageview_recon.get_parts( ) self.slice_line = InfiniteLine( pos=1024, angle=0, bounds=[0, self.imageview_projection.image_item.width()], movable=True) self.projection_vb.addItem(self.slice_line) self.tilt_line = InfiniteLine(pos=1024, angle=90, pen=(255, 0, 0, 255), movable=True) self.addItem(self.imageview_projection, 0, 0) self.addItem(self.imageview_recon, 0, 1, rowspan=2) self.addItem(self.imageview_sinogram, 1, 0) self.imageview_projection.image_item.mouseClickEvent = lambda ev: self.mouse_click( ev, self.slice_line) self.slice_line.sigPositionChangeFinished.connect( self.slice_line_moved) # 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.imageview_projection.enable_nan_check() self.imageview_sinogram.enable_nan_check() self.imageview_recon.enable_nan_check() self.imageview_projection.enable_nonpositive_check() self.imageview_sinogram.enable_nonpositive_check()
def __init__(self, slice_direction, xlink=None, ylink=None, parent=None): super(PlotView, self).__init__(parent=parent) self.slice_direction = slice_direction self._curve = self.plot() if slice_direction == 'horizontal': angle = 0 elif slice_direction in ['vertical', 'depth']: angle = 90 else: raise NotImplementedError self.crosshair = InfiniteLine(0, angle=angle, movable=True, markers=[('^', 0), ('v', 1)]) self.crosshair.sigPositionChanged.connect(self.sigCrosshairMoved) self.addItem(self.crosshair)
def __init__(self, *args, **kwargs): kwargs['viewBox'] = ScanViewBox() # Use custom pg.ViewBox subclass super().__init__(*args, **kwargs) self.getViewBox().sigMouseAreaSelected.connect( self.sigMouseAreaSelected) self._min_crosshair_factor = 0.02 self._crosshair_size = (0, 0) self._crosshair_range = None self.getViewBox().sigRangeChanged.connect( self._constraint_crosshair_size) self.crosshair = ROI((0, 0), (0, 0), pen={ 'color': '#00ff00', 'width': 1 }) self.hline = InfiniteLine(pos=0, angle=0, movable=True, pen={ 'color': '#00ff00', 'width': 1 }, hoverPen={ 'color': '#ffff00', 'width': 1 }) self.vline = InfiniteLine(pos=0, angle=90, movable=True, pen={ 'color': '#00ff00', 'width': 1 }, hoverPen={ 'color': '#ffff00', 'width': 1 }) self.vline.sigDragged.connect(self._update_pos_from_line) self.hline.sigDragged.connect(self._update_pos_from_line) self.crosshair.sigRegionChanged.connect(self._update_pos_from_roi) self.sigCrosshairDraggedPosChanged.connect(self.sigCrosshairPosChanged)
def prepare_plot(self) -> None: """ Method to prepare the plot :return: None """ # If the data array is empty, return if not self.data: return # Calculate the average av = np.average(self.data) # Get the unique elements of data and their counts unique, counts = np.unique(self.data, return_counts=True) # Calculate the occurence probability of all unique elements prob = [counts[x] / np.sum(counts) for x in range(len(counts))] # Calculate the probability of elements to occur according to the poisson distrubution poisson = self.poisson(av, np.arange(0, max(unique))) # Prepare bar graphs self.data_graph = pg.BarGraphItem(x=unique - 0.1, height=prob, width=0.2, brush=pg.mkBrush(color=(255, 50, 30, 255))) self.data_graph_line = pg.PlotDataItem(unique - 0.1, prob, pen=pg.mkPen(color=(255, 50, 30, 100), width=5)) self.poisson_graph = pg.BarGraphItem(x=np.arange(0, max(unique)) + 0.1, height=poisson, width=0.2, brush=pg.mkBrush(color=(85, 30, 255, 255))) self.poisson_graph_line = pg.PlotDataItem( np.arange(0, max(unique)) + 0.1, poisson, pen=pg.mkPen(color=(85, 30, 255, 100), width=5)) self.data_average_line = InfiniteLine(av, angle=90, pen=pg.mkPen(color=(0, 255, 0, 255))) # Add indicator for data average self.addItem(self.data_average_line) # self.addItem(self.data_graph_line) # self.addItem(self.poisson_graph_line) self.addItem(self.poisson_graph) self.addItem(self.data_graph) self.setToolTip( "Red: Data Distribution\nBlue: Poisson Distribution\nGreen: Average" ) # Add Legend # TODO """
class FilteratorImageView(ImageView): def __init__(self, parent=None): super().__init__(parent=parent) self.ui.histogram.hide() self.ui.roiBtn.hide() self.ui.menuBtn.hide() self.image_view_text = TextItem(text="", color=(255, 0, 0), anchor=(0, 0)) self.getView().addItem(self.image_view_text) self.image_view_vline = InfiniteLine(angle=90, movable=False) self.image_view_hline = InfiniteLine(angle=0, movable=False) self.getView().addItem(self.image_view_vline, ignoreBounds=True) self.getView().addItem(self.image_view_hline, ignoreBounds=True) self.image_view_proxy = SignalProxy( self.getView().scene().sigMouseMoved, rateLimit=60, slot=self.onMouseMoved) self.signals = FilteratorImageViewSignals() def setProcessed(self, status=True): if status == True: self.image_view_text.setText("") else: self.image_view_text.setText("Not processed!", color=(255, 0, 0)) def onMouseMoved(self, event): pos = event[0] item = self.getImageItem() viewbox = self.getView() if item.sceneBoundingRect().contains(pos): mouse_point = viewbox.mapSceneToView(pos) self.image_view_vline.setPos(mouse_point.x()) self.image_view_hline.setPos(mouse_point.y()) self.signals.mouse_pos_updated.emit( (mouse_point.x(), mouse_point.y()))
def movePartition(self, line: pg.InfiniteLine): index = self.segments.index(line) self.track.time[index] = int(round(line.getXPos() * self.track.fs)) self.calcPartitionNamePlacement(self.names[index - 1], index=index - 1, emit_signal=True) if index < len(self.segments) - 1: self.calcPartitionNamePlacement(self.names[index], index=index, emit_signal=True) self.item.updatePartitionPosition.emit(index)
def View_TOCSY_Data(self): try: self.plot.clear() ID = self.NMR_Data_View_Selector.currentText() TOCSY_DATA = pd.read_json(os.path.join(MasterOutput,ID,str(ID+"_TOCSY_Data.json"))) self.plot.plot(TOCSY_DATA.Ha,TOCSY_DATA.Hb,pen=None,symbol="o" ) self.plot.invertX(True) self.plot.invertY(True) vLine = InfiniteLine(angle=45, movable=False) self.plot.addItem(vLine) except: PopUP('Data not found','Selected Dataset not found. Please process in Topspin Prior to running MADByTE. For 2D Datasets, the displayed data is derived from peak picking lists.','Error')
def on_pushButton_3_clicked(self): """ Slot documentation goes here. """ # answers = [] # for answer in db['question_'+str(self.index)].find(): # text = answer['content'].replace('\n', '') # if 5 < len(text) < 100: # answers.append(text) answers = [ answer['content'].replace('\n', '') for answer in db['question_' + str(self.index)].find() ] Line1 = InfiniteLine(pos=0, pen=(255, 0, 0), angle=0, movable=False) Line2 = InfiniteLine(pos=0.5, pen=(0, 0, 255), angle=0, movable=False) Line3 = InfiniteLine(pos=1, pen=(0, 255, 0), angle=0, movable=False) import sys start = perf_counter() data = LSTM.get_result(answers, vec_path=sys.path[0] + '/lstm/vec_lstm.pkl', model_path=sys.path[0] + '/lstm/lstmModel.pkl') end = perf_counter() print('情感分析总用时:' + str(end - start) + 's') tricks = [(0, '消极'), (0.5, '中立'), (1, '积极')] strAxis = AxisItem(orientation='left', maxTickLength=3) strAxis.setTicks([ tricks, ]) visitor_count_plot = PlotWidget(axisItems={'left': strAxis}, background=None) visitor_count_plot.plot(y=data, pen=None, symbol='o') visitor_count_plot.showAxis('bottom', False) visitor_count_plot.addItem(Line1) visitor_count_plot.addItem(Line2) visitor_count_plot.addItem(Line3) visitor_count_plot.setObjectName("tab") # visitor_count_plot.enableAutoRange('x', x_axis_scale) self._add_analysis_tab(visitor_count_plot, '情感分析') self.pushButton_3.setEnabled(False)
def __init__(self, plots): """ Constructor arguments: - plots: the plots returns: the initialized class """ self.plots = plots self.cursor_x = [None] * 3 self.cursor_y = [None] * 3 self.cursor_label = [None] * 3 self.signal_proxy = [None] * 3 self.plot_data_items = [None] * 3 self._x = [None] * 3 self._y = [None] * 3 for num, plot in enumerate(plots): self.cursor_x[num] = InfiniteLine(angle=90, movable=False) self.cursor_y[num] = InfiniteLine(angle=0, movable=False) plot.addItem(self.cursor_x[num], ignoreBounds=True) plot.addItem(self.cursor_y[num], ignoreBounds=True) self.signal_proxy[num] = SignalProxy(plot.scene().sigMouseMoved, rateLimit=60, slot=self.update_cursor) self.cursor_label[num] = TextItem('', (255, 255, 255), anchor=(0, 0)) self.cursor_label[num].setPos(-10.4, 10) plot.addItem(self.cursor_label[num]) # Find the PlotDataItem displaying data for item in plot.getPlotItem().items: if isinstance(item, PlotDataItem): self.plot_data_items[num] = item self.hide_cursors()
def createIntersectionPoint(self): # TODO self.plotLength = self.model.projectData("length") * LENGTH_COEFFICIENT # create the horizontal plant line green = QColor(0, 144, 54) plantPen = pyqtgraph.mkPen(width=2, color=green) # Hochschule für Forstwirtschaft Rottenburg self.plantLine = InfiniteLine(self.model.projectData("count"), 0, plantPen, True) self.plantLine.sigPositionChanged.connect(self.updateCount) self.controlWidget.setCount(self.model.projectData("count")) self.controlWidget.countChanged.connect(self.plantLine.setValue) self.plantLabel = TextItem(html="<b><font color='" + green.name() + "'>Pflanzenzahl</font></b>", anchor=(-0.15, 0.9)) self.plantLabel.setParentItem(self.plantLine) self.plotWidget.addPlotItem(self.plantLine) # create the vertical fence line red = QColor(255, 0, 0) fencePen = pyqtgraph.mkPen(width=2, color=red) self.fenceLine = InfiniteLine(self.model.projectData("length"), 90, fencePen, True) self.fenceLine.sigPositionChanged.connect(self.updateLength) self.fenceLine.sigPositionChangeFinished.connect(self.updatePlotLength) self.controlWidget.setLength(self.model.projectData("length")) self.controlWidget.lengthChanged.connect(self.fenceLine.setValue) self.fenceLabel = TextItem(html="<b><font color='" + red.name() + "'>Zaunlänge</font></b>", anchor=(-2.5, 0.9), angle=-90) self.fenceLabel.setParentItem(self.fenceLine) self.plotWidget.addPlotItem(self.fenceLine) # create an arrow item as point of intersection self.arrowItem = ArrowItem(angle=-45, tipAngle=30, baseAngle=20, headLen=20, tailLen=None, pen={"color" : "#333", "width" : 2}, brush=QColor(255, 123, 0)) self.arrowItem.setPos(self.model.projectData("length"), self.model.projectData("count")) self.plotWidget.addPlotItem(self.arrowItem)
def __init__(self, *args, layout=None, include_line=False, **kwargs): # Load specviz plugins Application.load_local_plugins() super(SpecvizDataViewer, self).__init__(*args, **kwargs) self.statusBar().hide() # Instantiate workspace widget self.current_workspace = Workspace() self.hub = Hub(self.current_workspace) # Store a reference to the cubeviz layout instance self._layout = layout # Add an initially empty plot window self.current_workspace.add_plot_window() self.setCentralWidget(self.current_workspace) self.options.gridLayout.addWidget(self.current_workspace.list_view) # When a new data item is added to the specviz model, create a new # glue data component and add it to the glue data list # self.current_workspace.model.data_added.connect(self.reverse_add_data) self.current_workspace.mdi_area.setViewMode(QMdiArea.SubWindowView) self.current_workspace.current_plot_window.setWindowFlags(Qt.FramelessWindowHint) self.current_workspace.current_plot_window.showMaximized() # Create and attach a movable vertical line indicating the current # slice position in the cube if include_line: self._slice_indicator = InfiniteLine(0, movable=True, pen={'color': 'g', 'width': 3}) self.current_workspace.current_plot_window.plot_widget.addItem( self._slice_indicator)
class VariantPlotWidget(QWidget): """Creates a simple about dialog. The about dialog contains general information about the application and shows the copyright notice. That's why the class has no attributes or return values. """ AREA = 0 LINE = 1 curvePlotted = pyqtSignal(QModelIndex) plotReady = pyqtSignal() cleared = pyqtSignal() def __init__(self): super().__init__() # the plot widget is always # disabled at the first start self.setDisabled(True) ### TESTING ### self.model = None self.selectionModel = None self.view = 0 self.calc = False self.plotLength = 0 self.plotCount = 0 self.fenceLine = None self.plantLine = None self.arrowItem = None #self.lengthCoefficient = 1.5 # in model festlegen! #self.transparency = 0.3 ### TESTING ### self.controlWidget = PlotControlWidget() self.plotWidget = NaturalPlotView() layout = QVBoxLayout() layout.setContentsMargins(0, 0, 0, 0) layout.addWidget(self.controlWidget) layout.addWidget(self.plotWidget) self.setLayout(layout) # connect signals self.controlWidget.chartViewChanged.connect(self.updateChartView) self.controlWidget.countEnabled.connect(self.setPlantLineVisible) self.controlWidget.lengthEnabled.connect(self.setFenceLineVisible) def retranslateUi(self): # update the control widget self.controlWidget.retranslateUi() # translate the plot widget self.plotWidget.retranslateUi() def setModel(self, model): self.model = model self.model.dataChanged.connect(self.update) self.model.modelReset.connect(self.update) # das muss optimiert werden, weil dies private Signale sind # es dient dazu, dass gelöschte, oder veränderte (verschobene) Zeilen # nicht mehr ausgewählt werden können (selectionModel) self.model.rowsRemoved.connect(self.modelRemoveAction) self.model.rowsMoved.connect(self.modelRemoveAction) self.model.calculated.connect(self.calculate) def calculate(self): self.calc = True self.paintCalculation() def updateChartView(self, index): self.view = index # update calculation # möglicherweise sollte hier paintEvent() verwendet werden?! # # vorher muss hier noch eine Berechnung stattfinden if self.calc: self.paintCalculation() def setSelectionModel(self, selectionModel): # setup view's selectionModel self.selectionModel = selectionModel def modelRemoveAction(self): # TODO # wird benötigt, da sonst Fehler, wenn mit Enter bestätigt in Zaunlänge self.setDisabled(True) self.clear() def clear(self): # disconnect signals if isinstance(self.plantLine, InfiniteLine): self.plantLine.disconnect() self.plantLine = None if isinstance(self.fenceLine, InfiniteLine): self.fenceLine.disconnect() self.fenceLine = None self.plotWidget.clear() self.cleared.emit() def paintCalculation(self): if not self.calc: return # search for enabeld items # items contains at least one parent and one child # remove parents from children items = self.model.match(self.model.index(0, 0), TreeModel.StatusRole, True, -1, Qt.MatchRecursive) children = [item for item in items if item.parent().isValid()] if self.view == self.AREA: self.plotAreaChart(children) elif self.view == self.LINE: self.plotLineChart(children) def createIntersectionPoint(self): # TODO self.plotLength = self.model.projectData("length") * LENGTH_COEFFICIENT # create the horizontal plant line green = QColor(0, 144, 54) plantPen = pyqtgraph.mkPen(width=2, color=green) # Hochschule für Forstwirtschaft Rottenburg self.plantLine = InfiniteLine(self.model.projectData("count"), 0, plantPen, True) self.plantLine.sigPositionChanged.connect(self.updateCount) self.controlWidget.setCount(self.model.projectData("count")) self.controlWidget.countChanged.connect(self.plantLine.setValue) self.plantLabel = TextItem(html="<b><font color='" + green.name() + "'>Pflanzenzahl</font></b>", anchor=(-0.15, 0.9)) self.plantLabel.setParentItem(self.plantLine) self.plotWidget.addPlotItem(self.plantLine) # create the vertical fence line red = QColor(255, 0, 0) fencePen = pyqtgraph.mkPen(width=2, color=red) self.fenceLine = InfiniteLine(self.model.projectData("length"), 90, fencePen, True) self.fenceLine.sigPositionChanged.connect(self.updateLength) self.fenceLine.sigPositionChangeFinished.connect(self.updatePlotLength) self.controlWidget.setLength(self.model.projectData("length")) self.controlWidget.lengthChanged.connect(self.fenceLine.setValue) self.fenceLabel = TextItem(html="<b><font color='" + red.name() + "'>Zaunlänge</font></b>", anchor=(-2.5, 0.9), angle=-90) self.fenceLabel.setParentItem(self.fenceLine) self.plotWidget.addPlotItem(self.fenceLine) # create an arrow item as point of intersection self.arrowItem = ArrowItem(angle=-45, tipAngle=30, baseAngle=20, headLen=20, tailLen=None, pen={"color" : "#333", "width" : 2}, brush=QColor(255, 123, 0)) self.arrowItem.setPos(self.model.projectData("length"), self.model.projectData("count")) self.plotWidget.addPlotItem(self.arrowItem) def plotAreaChart(self, children): # check parents and children # the lists must contain only one item if not len(children) == 1: warning = QMessageBox(self) warning.setWindowModality(Qt.WindowModal) # check for mac only warning.setIcon(QMessageBox.Warning) warning.setStandardButtons(QMessageBox.Ok) warning.setWindowTitle(QApplication.translate("VariantPlotWidget", "Wuchshüllenrechner")) warning.setText("<b>" + QApplication.translate("VariantPlotWidget", "Too many variants are enabled!") + "</b>") warning.setInformativeText(QApplication.translate("VariantPlotWidget", "The area view allows you to set only one variant enabled " "at the same time. Please select the variant manually or " "choose the line view.")) warning.exec() return False (index,) = children # clear the plot widget self.clear() # plot the curve curve = EnhancedCurveItem(index, True) self.plotWidget.addPlotItem(curve) self.curvePlotted.emit(index) # create point of intersection self.createIntersectionPoint() # add the description to the view self.setEnabled(True) self.plotWidget.showDescription() self.plotReady.emit() def plotLineChart(self, children): # check parents and children # the lists must contain only one item if len(children) == 0: print("Fehler") return False # clear the plot widget self.clear() for child in children: # plot the curve curve = EnhancedCurveItem(child) self.plotWidget.addPlotItem(curve) self.curvePlotted.emit(child) # create point of intersection self.createIntersectionPoint() # add the description to the view self.setEnabled(True) self.plotWidget.showDescription() self.plotReady.emit() def updatePlotLength(self): length = self.fenceLine.value() hint = False # update the chart, if necessary if length >= self.plotLength: self.paintCalculation() hint = True elif length < self.plotLength / 5: self.paintCalculation() hint = True if hint: # notice the user about the update notice = QMessageBox(self) notice.setWindowModality(Qt.WindowModal) # check for mac only notice.setIcon(QMessageBox.Information) notice.setStandardButtons(QMessageBox.Ok) notice.setWindowTitle(QApplication.translate("VariantPlotWidget", "Wuchshüllenrechner")) notice.setText("<b>" + QApplication.translate("VariantPlotWidget", "Die Skalierung wurde verändert!") + "</b>") notice.setInformativeText(QApplication.translate("VariantPlotWidget", "Da sich die Zaunlänge geändert hat, wurde die Skalierung " "des Diagramms ebenfalls verändert.")) notice.exec() def updateCount(self, line): # save the new value in the model and # update the control widget count = int(self.plantLine.value()) self.model.setProjectData("count", count) self.controlWidget.setCount(count) # change the arrow item self.arrowItem.setPos(self.model.projectData("length"), self.model.projectData("count")) # update the legend self.plotReady.emit() def updateLength(self, line): # save the new value in the model and # update the control widget length = int(self.fenceLine.value()) self.model.setProjectData("length", length) self.controlWidget.setLength(length) # change the arrow item self.arrowItem.setPos(self.model.projectData("length"), self.model.projectData("count")) # update the legend self.plotReady.emit() def setPlantLineVisible(self, state): # check, if plant line is not None to avoid errors if not self.plantLine: return False self.plantLine.setVisible(state) def setFenceLineVisible(self, state): # check, if plant line is not None to avoid errors if not self.fenceLine: return False self.fenceLine.setVisible(state)
class Aditi(QMainWindow): def __init__(self): QMainWindow.__init__(self) # title self.setWindowTitle("Aditi") self.setDockOptions(QMainWindow.VerticalTabs | QMainWindow.AnimatedDocks) #self.showMaximized() # model self.rawfiles_by_short_path = {} self.xic_by_rawfile_short_path = {} self.tic_by_rawfile_short_path = {} self.spec_by_rawfile_short_path = {} self.inf_line_tic_item = None self.curr_scan_id_by_short_path = {} # menu self.file_menu = self.menuBar().addMenu('&File') #self.file_menu.setTearOffEnabled(False) open_action = QAction("&Open...", self) open_action.setToolTip("Open a rawfile") open_action.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_O)) self.file_menu.addAction(open_action) open_action.triggered.connect(self.show_open_dialog) exit_action = QAction("&Exit", self) exit_action.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_Q)) self.file_menu.addAction(exit_action) exit_action.triggered.connect(self.quit) self.tab_widget = QTabWidget(self) # spectrum plot Widget self.graphics_layout_widget = GraphicsLayoutWidget(parent=self.tab_widget) self.graphics_layout_widget.keyPressEvent = self.handle_key_press_event self.graphics_layout_widget.useOpenGL(False) self.graphics_layout_widget.setAntialiasing(False) self.plot_widget_tic = self.graphics_layout_widget.addPlot(title="TIC(s)", labels={'left': "Intensity", 'bottom': "Retention Time (sec)"}) self.plot_widget_tic.showGrid(x=True, y=True) self.graphics_layout_widget.nextRow() self.plot_widget_spectrum = self.graphics_layout_widget.addPlot(title="Spectrum", labels={'left': "Intensity", 'bottom': "m/z"}) self.plot_widget_spectrum.showGrid(x=True, y=True) # finally add tab self.tab_widget.addTab(self.graphics_layout_widget, "Spectrum") # Xic plotWidget self.plot_widget_xic = PlotWidget(name="MainPlot", labels={'left': "Intensity", 'bottom': "Retention Time (sec)"}) self.plot_widget_xic.showGrid(x=True, y=True) self.tab_widget.addTab(self.plot_widget_xic, "Xic extraction") self.setCentralWidget(self.tab_widget) self.statusBar().showMessage("Ready") # dock 1 self.rawfile_dock_widget = QDockWidget("Rawfiles") self.rawfile_table_view = QTableView() self.rawfile_table_view.horizontalHeader().setVisible(False) self.rawfile_table_view.horizontalHeader().setResizeMode(QHeaderView.ResizeToContents) self.rawfile_dock_widget.setWidget(self.rawfile_table_view) self.rawfile_model = QStandardItemModel() self.rawfile_model.setHorizontalHeaderLabels(["Rawfiles"]) self.rawfile_table_view.setModel(self.rawfile_model) self.rawfile_model.itemChanged.connect(self.item_changed) self.addDockWidget(0x2, self.rawfile_dock_widget) # xic dock widget extraction parameter self.xic_dock_widget = QDockWidget("Xic extraction") self.xic_widget = XicWidget() self.xic_widget.plotButton.clicked.connect(self.plot) self.xic_dock_widget.setWidget(self.xic_widget) self.addDockWidget(0x2, self.xic_dock_widget) def handle_key_press_event(self, evt): if self.inf_line_tic_item is None: return times = [] if evt.key() == Qt.Key_Left: for rawfile in self.rawfiles_by_short_path.values()[:1]: if not rawfile.is_checked: continue curr_scan_id = self.curr_scan_id_by_short_path[rawfile.short_path] scan_ids = rawfile.reader.rt_by_scan_id_by_ms_level[1].keys() idx = scan_ids.index(curr_scan_id) times.append(rawfile.reader.rt_by_scan_id_by_ms_level[1][scan_ids[idx - 1]]) self.curr_scan_id_by_short_path[rawfile.short_path] = scan_ids[idx - 1] elif evt.key() == Qt.Key_Right: for rawfile in self.rawfiles_by_short_path.values()[:1]: if not rawfile.is_checked: continue curr_scan_id = self.curr_scan_id_by_short_path[rawfile.short_path] scan_ids = rawfile.reader.rt_by_scan_id_by_ms_level[1].keys() idx = scan_ids.index(curr_scan_id) times.append(rawfile.reader.rt_by_scan_id_by_ms_level[1][scan_ids[idx + 1]]) self.curr_scan_id_by_short_path[rawfile.short_path] = scan_ids[idx + 1] self._plot_spectrum() if times: self.inf_line_tic_item.setPos(sum(times) / float(len(times))) def _plot_spectrum(self): self.plot_widget_spectrum.clear() min_mz, max_mz = 1e9, 0 min_int, max_int = 1e10, 0 for rawfile in self.rawfiles_by_short_path.values(): if not rawfile.is_checked: continue scan_id, mzs, intensities = rawfile.reader.get_scan(self.curr_scan_id_by_short_path[rawfile.short_path]) min_mz = min(min_mz, mzs[0]) max_mz = max(max_mz, mzs[-1]) min_int = min(min_int, min(intensities)) max_int = max(max_int, max(intensities)) item = BarGraphItem(x=mzs, height=intensities, width=0.01, pen=rawfile.qcolor, brush=rawfile.qcolor) self.plot_widget_spectrum.addItem(item) self.plot_widget_spectrum.setLimits(xMin=min_mz, xMax=max_mz, yMin=min_int, yMax=max_int) def plot_spectrum(self, ev): #clear if ev.button() == Qt.RightButton: return self.plot_widget_spectrum.clear() vb = self.plot_widget_tic.vb mouse_point = vb.mapSceneToView(ev.scenePos()) t = mouse_point.x() if self.inf_line_tic_item is None: self.inf_line_tic_item = InfiniteLine(pos=t, angle=90) self.plot_widget_tic.addItem(self.inf_line_tic_item) self.inf_line_tic_item.setMovable(True) else: self.inf_line_tic_item.setPos(t) min_mz, max_mz = 1e9, 0 min_int, max_int = 1e10, 0 for rawfile in self.rawfiles_by_short_path.values(): if not rawfile.is_checked: continue scan_id, mzs, intensities = rawfile.reader.get_scan_for_time(t) self.curr_scan_id_by_short_path[rawfile.short_path] = scan_id min_mz = min(min_mz, mzs[0]) max_mz = max(max_mz, mzs[-1]) min_int = min(min_int, min(intensities)) max_int = max(max_int, max(intensities)) item = BarGraphItem(x=mzs, height=intensities, width=0.01, pen=rawfile.qcolor, brush=rawfile.qcolor) self.plot_widget_spectrum.addItem(item) self.plot_widget_spectrum.setLimits(xMin=min_mz, xMax=max_mz, yMin=min_int, yMax=max_int) def item_changed(self, item): print "item changed", item.text() s = item.text() if item.checkState(): self.rawfiles_by_short_path[s].is_checked = True else: self.rawfiles_by_short_path[s].is_checked = False #self.qApp.emit(SIGNAL('redraw()')) self.update_plot_() def show_open_dialog(self): files = QFileDialog(self).getOpenFileNames() if files: preload = Preloader(files, self) preload.loaded.connect(self.update_rawfile_model) preload.start() def update_rawfile_model(self, obj): files, r = obj[0], obj[1] n = len(files) not_database = [] min_time, max_time = 1e9, 0 min_int, max_int = 1e9, 0 for i, f in enumerate(files): i_f = float(i) c = WithoutBlank.get_color(i_f / n, asQColor=True) c_ = WithoutBlank.get_color(i_f / n, asQColor=True) filename = f.split("\\")[-1] abs_path = str(f.replace("\\", "\\\\")) if r[i]: rawfile = Rawfile(abs_path, c, filename) self.rawfiles_by_short_path[filename] = rawfile #[MzDBReader(abs_path), c, True] self.rawfile_model.appendRow(Aditi.get_coloured_root_item(filename, c, c_)) times, intensities = rawfile.reader.get_tic() min_time = min(min_time, min(times)) max_time = max(max_time, max(times)) min_int = min(min_int, min(intensities)) max_int = max(max_int, max(intensities)) self.plot_widget_tic.plot(times, intensities, pen=mkPen(color=rawfile.qcolor, width=1.3)) else: not_database.append(str(filename)) self.plot_widget_tic.setLimits(xMin=min_time, xMax=max_time, yMin=min_int, yMax=max_int) self.plot_widget_tic.scene().sigMouseClicked.connect(self.plot_spectrum) if not_database: v = "\n".join(not_database) QMessageBox.information(self, "Error", "The following files are not valid sqlite database:\n" + v) @staticmethod def get_coloured_root_item(filepath, color, colorr): root = QStandardItem(filepath) gradient = QLinearGradient(-100, -100, 100, 100) gradient.setColorAt(0.7, colorr) gradient.setColorAt(1, color) root.setBackground(QBrush(gradient)) root.setEditable(False) root.setCheckState(Qt.Checked) root.setCheckable(True) return root def quit(self): res = QMessageBox.warning(self, "Exiting...", "Are you sure ?", QMessageBox.Ok | QMessageBox.Cancel) if res == QMessageBox.Cancel: return QtGui.qApp.quit() def plot(self): #clear pw self.plot_widget_xic.clear() # check sample checked checked_files = [rawfile for rawfile in self.rawfiles_by_short_path.values() if rawfile.is_checked] mz = self.xic_widget.mzSpinBox.value() mz_tol = self.xic_widget.mzTolSpinBox.value() mz_diff = mz * mz_tol / 1e6 min_mz, max_mz = mz - mz_diff, mz + mz_diff #Thread implementation not as fast # args = [(data[0], min_mz, max_mz, data[2]) for data in checked_files] # extractor_thread = Extractor(args, self) # extractor_thread.extracted.connect(self._plot) # extractor_thread.start() min_time_val, max_time_val = 10000, 0 min_int_val, max_int_val = 1e9, 0 for rawfile in checked_files: t1 = time.clock() times, intensities = rawfile.reader.get_xic(min_mz, max_mz) print "elapsed: ", time.clock() - t1 # min_time_val = min(min_time_val, times[0]) # max_time_val = max(max_time_val, times[-1]) # min_int_val = min(min_int_val, min(intensities)) # max_int_val = max(max_int_val, max(intensities)) item = self.plot_widget_xic.plot(times, intensities, pen=mkPen(color=rawfile.qcolor, width=1.3)) item.curve.setClickable(True) def on_curve_clicked(): if not rawfile.is_highlighted: item.setPen(mkPen(color=rawfile.qcolor, width=4)) rawfile.is_highlighted = True else: item.setPen(mkPen(color=rawfile.qcolor, width=2)) rawfile.is_highlighted = False item.sigClicked.connect(on_curve_clicked) #item.sigHovered = on_curve_clicked self.xic_by_rawfile_short_path[rawfile.short_path] = item self.plot_widget_xic.setTitle(title="Xic@" + str(mz)) #self.plot_widget_xic.setLimits(xMin=min_time_val, xMax=max_time_val, yMin=min_int_val, yMax=max_int_val) def update_plot_(self): for rawfile in self.rawfiles_by_short_path.viewvalues(): if rawfile.is_checked: try: self.plot_widget_xic.addItem(self.xic_by_rawfile_short_path[rawfile.short_path]) except KeyError: mz = self.xic_widget.mzSpinBox.value() mz_tol = self.xic_widget.mzTolSpinBox.value() mz_diff = mz * mz_tol / 1e6 min_mz, max_mz = mz - mz_diff, mz + mz_diff times, intensities = rawfile.reader.get_xic(min_mz, max_mz) item = self.plot_widget_xic.plot(times, intensities, pen=mkPen(color=rawfile.qcolor, width=2)) self.xic_by_rawfile_short_path[rawfile.short_path] = item else: try: #self.plot_widget_xic.removeItem(self.xic_by_rawfile_short_path[rawfile.short_path]) self.xic_by_rawfile_short_path[rawfile.short_path].hide() except KeyError: pass
class SpecvizDataViewer(DataViewer): """ """ LABEL = 'SpecViz viewer' _state_cls = SpecvizViewerState _options_cls = SpecvizViewerStateWidget _layer_style_widget_cls = SpecvizLayerStateWidget _data_artist_cls = SpecvizLayerArtist _subset_artist_cls = SpecvizLayerArtist _inherit_tools = False tools = [] subtools = {} def __init__(self, *args, layout=None, include_line=False, **kwargs): # Load specviz plugins Application.load_local_plugins() super(SpecvizDataViewer, self).__init__(*args, **kwargs) self.statusBar().hide() # Instantiate workspace widget self.current_workspace = Workspace() self.hub = Hub(self.current_workspace) # Store a reference to the cubeviz layout instance self._layout = layout # Add an initially empty plot window self.current_workspace.add_plot_window() self.setCentralWidget(self.current_workspace) self.options.gridLayout.addWidget(self.current_workspace.list_view) # When a new data item is added to the specviz model, create a new # glue data component and add it to the glue data list # self.current_workspace.model.data_added.connect(self.reverse_add_data) self.current_workspace.mdi_area.setViewMode(QMdiArea.SubWindowView) self.current_workspace.current_plot_window.setWindowFlags(Qt.FramelessWindowHint) self.current_workspace.current_plot_window.showMaximized() # Create and attach a movable vertical line indicating the current # slice position in the cube if include_line: self._slice_indicator = InfiniteLine(0, movable=True, pen={'color': 'g', 'width': 3}) self.current_workspace.current_plot_window.plot_widget.addItem( self._slice_indicator) def reverse_add_data(self, data_item): """ Adds data from specviz to glue. Parameters ---------- data_item : :class:`specviz.core.items.DataItem` The data item recently added to model. """ new_data = Data(label=data_item.name) new_data.coords = coordinates_from_header(data_item.spectrum.wcs) flux_component = Component(data_item.spectrum.flux, data_item.spectrum.flux.unit) new_data.add_component(flux_component, "Flux") disp_component = Component(data_item.spectrum.spectral_axis, data_item.spectrum.spectral_axis.unit) new_data.add_component(disp_component, "Dispersion") if data_item.spectrum.uncertainty is not None: uncert_component = Component(data_item.spectrum.uncertainty.array, data_item.spectrum.uncertainty.unit) new_data.add_component(uncert_component, "Uncertainty") self._session.data_collection.append(new_data) def add_data(self, data): """ Parameters ---------- data Returns ------- """ if not glue_data_has_spectral_axis(data): QMessageBox.critical(self, "Error", "Data is not a 1D spectrum", buttons=QMessageBox.Ok) return False return super(SpecvizDataViewer, self).add_data(data) def add_subset(self, subset): """ Parameters ---------- subset Returns ------- """ if not glue_data_has_spectral_axis(subset): QMessageBox.critical(self, "Error", "Subset is not a 1D spectrum", buttons=QMessageBox.Ok) return False return super(SpecvizDataViewer, self).add_subset(subset) def get_layer_artist(self, cls, layer=None, layer_state=None): """ Parameters ---------- cls layer layer_state Returns ------- """ return cls(self.current_workspace, self.state, layer=layer, layer_state=layer_state) def initialize_toolbar(self): """ """ # Merge the main tool bar and the plot tool bar to get back some # real estate self.current_workspace.addToolBar( self.current_workspace.current_plot_window.tool_bar) self.current_workspace.main_tool_bar.setIconSize(QSize(15, 15)) # Hide the first five actions in the default specviz tool bar for act in self.current_workspace.main_tool_bar.actions()[:6]: act.setVisible(False) # Hide the tabs of the mdiarea in specviz. self.current_workspace.mdi_area.setViewMode(QMdiArea.SubWindowView) self.current_workspace.current_plot_window.setWindowFlags(Qt.FramelessWindowHint) self.current_workspace.current_plot_window.showMaximized() if self._layout is not None: cube_ops = QAction(QIcon(":/icons/cube.svg"), "Cube Operations", self.current_workspace.main_tool_bar) self.current_workspace.main_tool_bar.addAction(cube_ops) self.current_workspace.main_tool_bar.addSeparator() button = self.current_workspace.main_tool_bar.widgetForAction(cube_ops) button.setPopupMode(QToolButton.InstantPopup) menu = QMenu(self.current_workspace.main_tool_bar) button.setMenu(menu) # Create operation actions menu.addSection("2D Operations") act = QAction("Simple Linemap", self) act.triggered.connect(lambda: simple_linemap(self)) menu.addAction(act) act = QAction("Fitted Linemap", self) act.triggered.connect(lambda: fitted_linemap(self)) menu.addAction(act) menu.addSection("3D Operations") act = QAction("Fit Spaxels", self) act.triggered.connect(lambda: fit_spaxels(self)) menu.addAction(act) act = QAction("Spectral Smoothing", self) act.triggered.connect(lambda: spectral_smoothing(self)) menu.addAction(act) def update_units(self, spectral_axis_unit=None, data_unit=None): """ Interface for data viewers to update the plotted axis units in specviz. Parameters ---------- spectral_axis_unit : str or :class:`~astropy.unit.Quantity` The spectral axis unit to convert to. data_unit : str or :class:`~astropy.unit.Quantity` The data axis unit to convert to. """ if spectral_axis_unit is not None: self.hub.plot_widget.spectral_axis_unit = spectral_axis_unit if data_unit is not None: self.hub.plot_widget.data_unit = data_unit def update_slice_indicator_position(self, pos): """ Updates the current position of the movable vertical slice indicator. Parameters ---------- pos : float The new position of the vertical line. """ if self._slice_indicator is not None: self._slice_indicator.blockSignals(True) self._slice_indicator.setPos(u.Quantity(pos).value) self._slice_indicator.blockSignals(False)
class ScanPlotWidget(PlotWidget): """ Extend the PlotWidget Class with more functionality used for qudi scan images. Supported features: - draggable/static crosshair with optional range and size constraints. - zoom feature by rubberband selection - rubberband area selection This class depends on the ScanViewBox class defined further below. This class can be promoted in the Qt designer. """ sigMouseAreaSelected = QtCore.Signal(QtCore.QRectF) # mapped rectangle mouse cursor selection sigCrosshairPosChanged = QtCore.Signal(QtCore.QPointF) sigCrosshairDraggedPosChanged = QtCore.Signal(QtCore.QPointF) def __init__(self, *args, **kwargs): kwargs['viewBox'] = ScanViewBox() # Use custom pg.ViewBox subclass super().__init__(*args, **kwargs) self.getViewBox().sigMouseAreaSelected.connect(self.sigMouseAreaSelected) self._min_crosshair_factor = 0.02 self._crosshair_size = (0, 0) self._crosshair_range = None self.getViewBox().sigRangeChanged.connect(self._constraint_crosshair_size) self.crosshair = ROI((0, 0), (0, 0), pen={'color': '#00ff00', 'width': 1}) self.hline = InfiniteLine(pos=0, angle=0, movable=True, pen={'color': '#00ff00', 'width': 1}, hoverPen={'color': '#ffff00', 'width': 1}) self.vline = InfiniteLine(pos=0, angle=90, movable=True, pen={'color': '#00ff00', 'width': 1}, hoverPen={'color': '#ffff00', 'width': 1}) self.vline.sigDragged.connect(self._update_pos_from_line) self.hline.sigDragged.connect(self._update_pos_from_line) self.crosshair.sigRegionChanged.connect(self._update_pos_from_roi) self.sigCrosshairDraggedPosChanged.connect(self.sigCrosshairPosChanged) @property def crosshair_enabled(self): items = self.items() return (self.vline in items) and (self.hline in items) and (self.crosshair in items) @property def crosshair_movable(self): return bool(self.crosshair.translatable) @property def crosshair_position(self): pos = self.vline.pos() pos[1] = self.hline.pos()[1] return tuple(pos) @property def crosshair_size(self): return tuple(self._crosshair_size) @property def crosshair_min_size_factor(self): return float(self._min_crosshair_factor) @property def crosshair_range(self): if self._crosshair_range is None: return None return tuple(self._crosshair_range) @property def selection_enabled(self): return bool(self.getViewBox().rectangle_selection) @property def zoom_by_selection_enabled(self): return bool(self.getViewBox().zoom_by_selection) def toggle_selection(self, enable): """ De-/Activate the rectangular rubber band selection tool. If active you can select a rectangular region within the ViewBox by dragging the mouse with the left button. Each selection rectangle in real-world data coordinates will be emitted by sigMouseAreaSelected. By using activate_zoom_by_selection you can optionally de-/activate zooming in on the selection. @param bool enable: Toggle selection on (True) or off (False) """ return self.getViewBox().toggle_selection(enable) def toggle_zoom_by_selection(self, enable): """ De-/Activate automatic zooming into a selection. See also: toggle_selection @param bool enable: Toggle zoom upon selection on (True) or off (False) """ return self.getViewBox().toggle_zoom_by_selection(enable) def _update_pos_from_line(self, obj): """ Called each time the position of the InfiniteLines has been changed by a user drag. Causes the crosshair rectangle to follow the lines. """ if obj not in (self.hline, self.vline): return pos = self.vline.pos() pos[1] = self.hline.pos()[1] size = self.crosshair.size() self.crosshair.blockSignals(True) self.crosshair.setPos((pos[0] - size[0] / 2, pos[1] - size[1] / 2)) self.crosshair.blockSignals(False) self.sigCrosshairDraggedPosChanged.emit(QtCore.QPointF(pos[0], pos[1])) return def _update_pos_from_roi(self, obj): """ Called each time the position of the rectangular ROI has been changed by a user drag. Causes the InfiniteLines to follow the ROI. """ if obj is not self.crosshair: return pos = self.crosshair.pos() size = self.crosshair.size() pos[0] += size[0] / 2 pos[1] += size[1] / 2 self.vline.setPos(pos[0]) self.hline.setPos(pos[1]) self.sigCrosshairDraggedPosChanged.emit(QtCore.QPointF(pos[0], pos[1])) return def toggle_crosshair(self, enable, movable=True): """ Disable/Enable the crosshair within the PlotWidget. Optionally also toggle if it can be dragged by the user. @param bool enable: enable crosshair (True), disable crosshair (False) @param bool movable: enable user drag (True), disable user drag (False) """ if not isinstance(enable, bool): raise TypeError('Positional argument "enable" must be bool type.') if not isinstance(movable, bool): raise TypeError('Optional argument "movable" must be bool type.') self.toggle_crosshair_movable(movable) is_enabled = self.crosshair_enabled if enable and not is_enabled: self.addItem(self.vline) self.addItem(self.hline) self.addItem(self.crosshair) elif not enable and is_enabled: self.removeItem(self.vline) self.removeItem(self.hline) self.removeItem(self.crosshair) return def toggle_crosshair_movable(self, enable): """ Toggle if the crosshair can be dragged by the user. @param bool enable: enable (True), disable (False) """ self.crosshair.translatable = bool(enable) self.vline.setMovable(enable) self.hline.setMovable(enable) return def set_crosshair_pos(self, pos): """ Set the crosshair center to the given coordinates. @param QPointF|float[2] pos: (x,y) position of the crosshair """ try: pos = tuple(pos) except TypeError: pos = (pos.x(), pos.y()) size = self.crosshair.size() self.crosshair.blockSignals(True) self.vline.blockSignals(True) self.hline.blockSignals(True) self.crosshair.setPos(pos[0] - size[0] / 2, pos[1] - size[1] / 2) self.vline.setPos(pos[0]) self.hline.setPos(pos[1]) self.crosshair.blockSignals(False) self.vline.blockSignals(False) self.hline.blockSignals(False) self.sigCrosshairPosChanged.emit(QtCore.QPointF(*pos)) return def set_crosshair_size(self, size, force_default=True): """ Set the default size of the crosshair rectangle (x, y) and update the display. @param QSize|float[2] size: the (x,y) size of the crosshair rectangle @param bool force_default: Set default crosshair size and enforce minimal size (True). Enforce displayed crosshair size while keeping default size untouched (False). """ try: size = tuple(size) except TypeError: size = (size.width(), size.height()) if force_default: if size[0] <= 0 and size[1] <= 0: self._crosshair_size = (0, 0) else: self._crosshair_size = size # Check if actually displayed size needs to be adjusted due to minimal size size = self._get_corrected_crosshair_size(size) pos = self.vline.pos() pos[1] = self.hline.pos()[1] - size[1] / 2 pos[0] -= size[0] / 2 if self._crosshair_range: crange = self._crosshair_range self.crosshair.maxBounds = QtCore.QRectF(crange[0][0] - size[0] / 2, crange[1][0] - size[1] / 2, crange[0][1] - crange[0][0] + size[0], crange[1][1] - crange[1][0] + size[1]) self.crosshair.blockSignals(True) self.crosshair.setSize(size) self.crosshair.setPos(pos) self.crosshair.blockSignals(False) return def set_crosshair_min_size_factor(self, factor): """ Sets the minimum crosshair size factor. This will determine the minimum size of the smallest edge of the crosshair center rectangle. This minimum size is calculated by taking the smallest visible axis of the ViewBox and multiplying it with the scale factor set by this method. The crosshair rectangle will be then scaled accordingly if the set crosshair size is smaller than this minimal size. @param float factor: The scale factor to set. If <= 0 no minimal crosshair size enforced. """ if factor <= 0: self._min_crosshair_factor = 0 elif factor <= 1: self._min_crosshair_factor = float(factor) else: raise ValueError('Crosshair min size factor must be a value <= 1.') return def set_crosshair_range(self, new_range): """ Sets a range boundary for the crosshair position. @param float[2][2] new_range: two min-max range value tuples (for x and y axis). If None set unlimited ranges. """ if new_range is None: self.vline.setBounds([None, None]) self.hline.setBounds([None, None]) self.crosshair.maxBounds = None else: self.vline.setBounds(new_range[0]) self.hline.setBounds(new_range[1]) size = self.crosshair.size() pos = self.crosshair_position self.crosshair.maxBounds = QtCore.QRectF(new_range[0][0] - size[0] / 2, new_range[1][0] - size[1] / 2, new_range[0][1] - new_range[0][0] + size[0], new_range[1][1] - new_range[1][0] + size[1]) self.crosshair.setPos(pos[0] - size[0] / 2, pos[1] - size[1] / 2) self._crosshair_range = new_range return def set_crosshair_pen(self, pen): """ Sets the pyqtgraph compatible pen to be used for drawing the crosshair lines. @param pen: pyqtgraph compatible pen to use """ self.crosshair.setPen(pen) self.vline.setPen(pen) self.hline.setPen(pen) return def _constraint_crosshair_size(self): if self._min_crosshair_factor == 0: return if self._crosshair_size[0] == 0 or self._crosshair_size[1] == 0: return corr_size = self._get_corrected_crosshair_size(self._crosshair_size) if corr_size != tuple(self.crosshair.size()): self.set_crosshair_size(corr_size, force_default=False) return def _get_corrected_crosshair_size(self, size): try: size = tuple(size) except TypeError: size = (size.width(), size.height()) min_size = min(size) if min_size == 0: return size vb_size = self.getViewBox().viewRect().size() short_index = int(vb_size.width() > vb_size.height()) min_vb_size = vb_size.width() if short_index == 0 else vb_size.height() min_vb_size *= self._min_crosshair_factor if min_size < min_vb_size: scale_factor = min_vb_size / min_size size = (size[0] * scale_factor, size[1] * scale_factor) return size
def onInit(): # connect to server ipAddress = TEST_SPECTROMETER_SERVER if DEBUG else SPECTROMETER_SERVER protocol = yield getProtocol(ipAddress) # create a client self.client = SpectrometerClient(protocol) self.wave = yield self.client.getWavelengths() self.numberToAverage = 1 self.numberAcquired = 0 self.darkSpectrum = np.zeros(NUM_PIXELS) self.specProcessed = np.zeros(NUM_PIXELS) self.gettingDark = False # set up overall layout: 1 large panel (plot) to left of 1 narrow / # panel (controls) all above 1 skinny panel (timestamp) fullLayout = QtGui.QVBoxLayout() self.layout().addLayout(fullLayout) topHalfLayout = QtGui.QHBoxLayout() fullLayout.addLayout(topHalfLayout) # define the plot self.plotWidget = PlotWidget() self.plot = self.plotWidget.plot() topHalfLayout.addWidget(self.plotWidget, 1) # define the controls panel cpLayout = QtGui.QVBoxLayout() topHalfLayout.addLayout(cpLayout) # define the capture controls (to go on controls panel) capLayout = QtGui.QVBoxLayout() def updatePlot(x, y): x = np.asarray(x) y = np.asarray(y) self.plotWidget.clear() self.plotWidget.plot(x, y, pen=mkPen("w", width=1)) self.plotWidget.addItem(self.cursorVert) self.plotWidget.addItem(self.cursorHori) vertLabel.setText(str(round(self.cursorVert.pos()[0], 2))) horiLabel.setText(str(round(self.cursorHori.pos()[1], 2))) def avgSpec(): oldAvgSpec = self.specProcessed addThis = self.spec - self.darkSpectrum self.numberAcquired += 1 if self.numberAcquired < self.numberToAverage: scale = self.numberAcquired else: scale = self.numberToAverage newAvg = ((scale - 1) * oldAvgSpec + addThis) / scale self.specProcessed = newAvg @inlineCallbacks def capture(): self.spec = yield self.client.getSpectrum() self.spec = np.asarray(self.spec) self.time = yield self.client.getLastTime() yield avgSpec() updatePlot(self.wave, self.specProcessed) self.timestamp.setText("last update: " + str(self.time)) @inlineCallbacks def forcePress(): self.numberAcquired = 0 yield capture() forceButton = QtGui.QPushButton("force") forceButton.clicked.connect(forcePress) capLayout.addWidget(forceButton) autoRunLayout = QtGui.QHBoxLayout() self.freeRunCall = LoopingCall(capture) self.freeRunStatus = False def freeRun(): if self.freeRunStatus: freeButton.setText("start auto") forceButton.setEnabled(True) self.freeRunCall.stop() self.freeRunStatus = False self.numberAcquired = 0 return if not self.freeRunStatus: freeButton.setText("stop auto") forceButton.setEnabled(False) self.freeRunCall.start(autoRateSpin.value(), now=True) self.freeRunStatus = True freeButton = QtGui.QPushButton("start auto") freeButton.clicked.connect(freeRun) autoRunLayout.addWidget(freeButton) def updateAutoRate(): if self.freeRunStatus: self.freeRunCall.stop() self.freeRunCall.start(autoRateSpin.value(), now=True) autoRateSpin = QtGui.QDoubleSpinBox() autoRateSpin.setRange(0.1, 10000.0) autoRateSpin.setValue(0.5) autoRateSpin.setSuffix("s") autoRateSpin.setSingleStep(0.1) autoRateSpin.valueChanged.connect(updateAutoRate) autoRunLayout.addWidget(autoRateSpin) capLayout.addLayout(autoRunLayout) cpLayout.addWidget(LabelWidget("capture", capLayout)) # define the cursor/analysis controls curLayout = QtGui.QVBoxLayout() cpLayout.addWidget(LabelWidget("analysis", curLayout)) self.cursorVert = InfiniteLine( pos=self.wave[NUM_PIXELS / 2], angle=90, pen=mkPen("g", width=0.5), movable=True ) self.cursorHori = InfiniteLine(pos=0, angle=0, pen=mkPen("g", width=0.5), movable=True) self.plotWidget.addItem(self.cursorVert) self.plotWidget.addItem(self.cursorHori) vertLayout = QtGui.QHBoxLayout() vertName = QtGui.QLabel() vertName.setText("wavelength: ") vertLayout.addWidget(vertName) vertLabel = QtGui.QLabel() vertLabel.setText(str(round(self.cursorVert.pos()[0], 2))) vertLayout.addWidget(vertLabel) curLayout.addLayout(vertLayout) horiLayout = QtGui.QHBoxLayout() horiName = QtGui.QLabel() horiName.setText("intensity: ") horiLayout.addWidget(horiName) horiLabel = QtGui.QLabel() horiLabel.setText(str(round(self.cursorHori.pos()[0], 2))) horiLayout.addWidget(horiLabel) curLayout.addLayout(horiLayout) # define the acquisition controls acqLayout = QtGui.QVBoxLayout() cpLayout.addWidget(LabelWidget("acquisition", acqLayout)) # integration integLayout = QtGui.QHBoxLayout() acqLayout.addLayout(integLayout) integTimeLabel = QtGui.QLabel() integTimeLabel.setText("integration: ") integLayout.addWidget(integTimeLabel) def integTimeUpdate(): newTime = integTimeSpin.value() self.client.setIntegrationTime(newTime) integTimeSpin = QtGui.QDoubleSpinBox() integTimeSpin.setRange(0.001, 10) integTimeSpin.setDecimals(3) integTimeSpin.setValue(0.100) integTimeSpin.setSingleStep(0.05) integTimeSpin.setSuffix("s") integTimeSpin.editingFinished.connect(integTimeUpdate) integLayout.addWidget(integTimeSpin) # averaging avgLayout = QtGui.QHBoxLayout() acqLayout.addLayout(avgLayout) avgLabel = QtGui.QLabel() avgLabel.setText("averaging: ") avgLayout.addWidget(avgLabel) def avgUpdate(): self.numberToAverage = avgSpin.value() avgSpin = QtGui.QSpinBox() avgSpin.setRange(1, 10000) avgSpin.setValue(1) avgSpin.valueChanged.connect(avgUpdate) avgLayout.addWidget(avgSpin) # dark spectrum darkLayout = QtGui.QHBoxLayout() acqLayout.addLayout(darkLayout) @inlineCallbacks def getDark(): resetDark() self.gettingDark = True self.numberAcquired = 0 wasInAuto = self.freeRunStatus if self.freeRunStatus: freeRun() # if in auto mode, stop it self.specProcessed = np.zeros(NUM_PIXELS) for specCount in range(self.numberToAverage): yield capture() self.darkSpectrum = self.specProcessed self.specProcessed = np.zeros(NUM_PIXELS) if wasInAuto: freeRun() self.numberAcquired = 0 self.gettingDark = False darkSpecButton = QtGui.QPushButton("dark") darkSpecButton.clicked.connect(getDark) darkLayout.addWidget(darkSpecButton) def resetDark(): self.darkSpectrum = np.zeros(NUM_PIXELS) self.specProcessed = np.zeros(NUM_PIXELS) resetDarkButton = QtGui.QPushButton("reset") resetDarkButton.clicked.connect(resetDark) darkLayout.addWidget(resetDarkButton) # define the timestamp panel self.timestamp = QtGui.QLabel() self.timestamp.setText("last update: never") self.timestamp.setAlignment(QtCore.Qt.AlignCenter) fullLayout.addWidget(self.timestamp)