Esempio n. 1
0
 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)
Esempio n. 2
0
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)
Esempio n. 3
0
 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
Esempio n. 4
0
    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()
Esempio n. 5
0
    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)
Esempio n. 6
0
    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()
Esempio n. 7
0
    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)
Esempio n. 8
0
    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
Esempio n. 9
0
 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")
Esempio n. 10
0
    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")
Esempio n. 11
0
    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
Esempio n. 12
0
    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)
Esempio n. 14
0
    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()
Esempio n. 15
0
 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]] = {}
Esempio n. 16
0
 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)
Esempio n. 17
0
    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)
Esempio n. 18
0
 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)
Esempio n. 19
0
    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)
Esempio n. 20
0
    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)
Esempio n. 21
0
    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()]
Esempio n. 22
0
 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
Esempio n. 23
0
    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)
Esempio n. 24
0
    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()
Esempio n. 25
0
    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)
Esempio n. 26
0
    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)
Esempio n. 27
0
    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
        """
Esempio n. 28
0
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()))
Esempio n. 29
0
 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)
Esempio n. 30
0
 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')
Esempio n. 31
0
    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)
Esempio n. 32
0
    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)
Esempio n. 34
0
    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)
Esempio n. 36
0
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
Esempio n. 37
0
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)
Esempio n. 38
0
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)