예제 #1
0
 def _createLabels(self, points, viewbox, logMode):
     for x, y in points:
         # fill the text
         xtext = self._getXText(x)
         ytext = self._getYText(y)
         text_item = TextItem()
         text_item.setHtml(("<div style='{}'> " + "<span><b>x=</b>{} " +
                            "<span><b>y=</b>{}</span> " + "</div>").format(
                                self._label_style, xtext, ytext))
         # add text_item in the right position (take into account log mode)
         if logMode[0]:
             x = numpy.log10(x)
         if logMode[1]:
             y = numpy.log10(y)
         text_item.setPos(x, y)
         self._labels.append(text_item)
         viewbox.addItem(text_item, ignoreBounds=True)
     # Add "highlight" marker at each point
     highlight = PlotDataItem(
         numpy.array(points),
         pen=None,
         symbol="s",
         symbolBrush="35393C88",
         pxMode=True,
         symbolSize=self.trigger_point_size,
     )
     # set log mode
     highlight.setLogMode(*logMode)
     # hack to make the CurvesPropertiesTool ignore the highlight points
     highlight._UImodifiable = False
     # Add it to the vbox and keep a reference
     viewbox.addItem(highlight, ignoreBounds=True)
     self._highlights.append(highlight)
 def _createLabels(self, points):
     for x, y in points:
         # create label at x,y
         _x = self._getXValue(x)
         _y = self._getYValue(y)
         text_item = TextItem()
         text_item.setPos(x, y)
         text_item.setHtml(("<div style='{}'> " + "<span><b>x=</b>{} " +
                            "<span><b>y=</b>{}</span> " + "</div>").format(
                                self._label_style, _x, _y))
         self._labels.append(text_item)
         self._plot_item.addItem(text_item, ignoreBounds=True)
     # Add "highlight" marker at each point
     self._highlights.setData(pos=points)
예제 #3
0
class MapViewWidget(DynImageView):
    sigShowSpectra = Signal(int)

    def __init__(self, *args, **kwargs):
        super(MapViewWidget, self).__init__(*args, **kwargs)
        # self.scene.sigMouseMoved.connect(self.showSpectra)
        self.scene.sigMouseClicked.connect(self.showSpectra)
        self.view.invertY(True)

        # add arrow
        # self.arrow = ArrowItem(angle=60, headLen=15, tipAngle=45, baseAngle=30, brush = (200, 80, 20))
        # self.arrow.setPos(0, 0)
        self.cross = PlotDataItem([0], [0],
                                  symbolBrush=(200, 0, 0),
                                  symbolPen=(200, 0, 0),
                                  symbol='+',
                                  symbolSize=16)

        self.view.addItem(self.cross)
        self.cross.hide()
        #add txt
        self.txt = TextItem('', anchor=(0, 0))
        self.addItem(self.txt)

    def setEnergy(self, lineobject):
        E = lineobject.value()
        # map E to index
        i = val2ind(E, self.wavenumbers)
        # print('E:', E, 'wav:', self.wavenumbers[i])
        self.setCurrentIndex(i)

    def showSpectra(self, event):

        pos = event.pos()
        if self.view.sceneBoundingRect().contains(
                pos
        ):  # Note, when axes are added, you must get the view with self.view.getViewBox()
            mousePoint = self.view.mapSceneToView(pos)
            x, y = int(mousePoint.x()), int(mousePoint.y())
            y = self.row - y - 1
            try:
                ind = self.rc2ind[(y, x)]
                self.sigShowSpectra.emit(ind)
                # print(x, y, ind, x + y * self.n_col)

                #update arrow
                self.cross.setData([x + 0.5], [self.row - y - 0.5])
                self.cross.show()
                # update text
                self.txt.setHtml(
                    f'<div style="text-align: center"><span style="color: #FFF; font-size: 8pt">X: {x}</div>\
            <div style="text-align: center"><span style="color: #FFF; font-size: 8pt">Y: {y}</div>\
            <div style="text-align: center"><span style="color: #FFF; font-size: 8pt">Point: #{ind}</div>'
                )
            except Exception:
                self.cross.hide()

    def setHeader(self, header: NonDBHeader, field: str, *args, **kwargs):
        self.header = header
        self.field = field

        imageEvent = next(header.events(fields=['image']))
        self.rc2ind = imageEvent['rc_index']
        self.wavenumbers = imageEvent['wavenumbers']
        # make lazy array from document
        data = None
        try:
            data = header.meta_array(field)
            self.row = data.shape[1]
            self.col = data.shape[2]
            self.txt.setPos(self.col, 0)
        except IndexError:
            msg.logMessage(
                'Header object contained no frames with field '
                '{field}'
                '.', msg.ERROR)

        if data is not None:
            # kwargs['transform'] = QTransform(1, 0, 0, -1, 0, data.shape[-2])
            self.setImage(img=data, *args, **kwargs)
            self._data = data

    def updateImage(self, autoHistogramRange=True):
        super(MapViewWidget, self).updateImage(autoHistogramRange)
        self.ui.roiPlot.setVisible(False)

    def setImage(self, img, **kwargs):
        super(MapViewWidget, self).setImage(img, **kwargs)
        self.ui.roiPlot.setVisible(False)

    def makeMask(self, thresholds):
        peak1550 = val2ind(1550, self.wavenumbers)
        thr1550 = thresholds[0]
        mask = self._data[peak1550] > thr1550
        mask = mask.astype(np.int)
        return mask
예제 #4
0
class DoubleCrossHair(QObject):
    """
    Double cross hair implementation

    """

    def __init__(self, x_1: ndarray, y_1: ndarray, x_2: ndarray, y_2: ndarray,
                 plot_widget_1: PlotWidget, plot_widget_2: PlotWidget, labels: tuple, units=None,
                 precision=0, width=1, x_labels=None, display=int, highlight_bars=True):
        """
        Constructor / Instantiation of class

        Parameters
        ----------
        x_1               : np.ndarray
                            x-values
        y_1               : np.ndarray
                            y-values
        x_2               : np.ndarray
                            x-values
        y_2               : np.ndarray
                            y-values
        plot_widget_1     : PlotWidget
                            graphics view to place chart
        plot_widget_2     : PlotWidget
                            graphics view to place chart
        labels            : tuple
                            labels for legend
        precision         : int
                            precision for rounding, default is zero
        width             : int, float
                            width of any bars
        x_labels          : array-like
                            array of dates, i.e. time-period or other labels
        display           : type
                            display dtype for labels
        highlight_bars    : bool
                            whether to highlight bars in plot

        """
        super().__init__(parent=None)
        Assertor.assert_data_types(
            [x_1, y_1, x_2, y_2, plot_widget_1, plot_widget_2, labels, precision, width],
            [ndarray, ndarray, ndarray, ndarray, PlotWidget,
             PlotWidget, tuple, int, (int, float)])
        self.x_1, self.y_1 = x_1, y_1
        self.x_2, self.y_2 = x_2, y_2

        self.plot_widget_1 = plot_widget_1
        self.plot_widget_2 = plot_widget_2
        self.precision = precision
        self.width = width
        self.x_time = x_labels
        self.display = display

        self.bar_item_1 = None
        self.bar_item_2 = None
        self.highlight_bars = highlight_bars

        pen = mkPen(color="#4c96d7", style=Qt.SolidLine, width=1)
        self.vertical_line_1 = InfiniteLine(angle=90, movable=False, pen=pen)
        self.vertical_line_2 = InfiniteLine(angle=90, movable=False, pen=pen)
        self.label_1 = TextItem()
        self.label_2 = TextItem()
        self.labels = labels
        self.units = units if units else tuple(["" for _ in range(10)])

        if self.highlight_bars:
            self.plot_widget_1.addItem(self.vertical_line_1)
            self.plot_widget_2.addItem(self.vertical_line_2)

        self.view_box_1 = self.plot_widget_1.getViewBox()
        self.view_box_2 = self.plot_widget_2.getViewBox()
        self.configure_cross_hair()

    def configure_cross_hair(self):
        """
        method for configuring cross hair

        """
        place = percentile(insert(array(self.x_1), 0, 0), 2)

        self.label_1.setPos(place, int(abs(max(self.y_1, key=abs)) * 1.5))
        self.label_2.setPos(place, int(abs(max(self.y_2, key=abs)) * 1.5))
        self.plot_widget_1.addItem(self.label_1)
        self.plot_widget_2.addItem(self.label_2)

    def move_vertical_lines(self, pos):
        """
        method for moving the vertical lines on the plot

        """
        mouse_point_1 = self.view_box_1.mapSceneToView(pos)
        mouse_point_2 = self.view_box_2.mapSceneToView(pos)

        x_val_1 = int(round(mouse_point_1.x(), self.precision))
        x_val_2 = int(round(mouse_point_2.x(), self.precision))
        x_idx_1 = where(self.x_1 == x_val_1)
        x_idx_2 = where(self.x_2 == x_val_2)
        y_val_1 = self.display(self.y_1[x_idx_1]) if self.y_1[x_idx_1] else 0
        y_val_2 = self.display(self.y_2[x_idx_2]) if self.y_2[x_idx_2] else 0

        self.vertical_line_1.setPos(x_val_1)
        self.vertical_line_2.setPos(x_val_1)
        limits = min(self.x_1) <= x_val_1 <= max(self.x_1)

        if len(self.plot_widget_1.getViewBox().allChildren()) > 3 and limits \
                and self.highlight_bars:
            self.highlight_bar_items(x_val_1, y_val_1, x_val_2, y_val_2)

        return x_val_1, y_val_1, x_val_2, y_val_2, limits

    def highlight_bar_items(self, x_val_1, y_val_1, x_val_2, y_val_2):
        """
        method for highlighting bar items

        """
        self.plot_widget_1.removeItem(self.bar_item_1)
        self.plot_widget_2.removeItem(self.bar_item_2)
        self.bar_item_1 = BarGraphItem(x=[x_val_1], height=y_val_1, width=self.width,
                                       brush="#69a8de")
        self.bar_item_2 = BarGraphItem(x=[x_val_2], height=y_val_2, width=self.width,
                                       brush="#69a8de")
        self.plot_widget_1.addItem(self.bar_item_1)
        self.plot_widget_2.addItem(self.bar_item_2)

    def mouse_moved(self, evt):
        """
        method for moving the vertical lines based on mouse placement

        """
        pos = evt[0]
        if self.plot_widget_1.sceneBoundingRect().contains(pos) or \
                self.plot_widget_2.sceneBoundingRect().contains(pos):
            x_val_1, y_val_1, x_val_2, y_val_2, limits = self.move_vertical_lines(pos)

            x_label_idx = where(array(self.x_1) == x_val_1)[0]
            x_label_1 = self.x_time[x_label_idx.item()] + self.units[0] if \
                self.x_time and x_label_idx.size != 0 else \
                Amount(str(x_val_1)).amount + self.units[0]
            y_label_1 = Amount(str(y_val_1)).amount + self.units[1]

            x_label_2 = self.x_time[x_label_idx.item()] + self.units[0] if \
                self.x_time and x_label_idx.size != 0 else \
                Amount(str(x_val_2)).amount + self.units[2]
            y_label_2 = Amount(str(y_val_2)).amount + self.units[3]

            if limits:
                self.label_1.setHtml('<div style="text-align: center">'
                                     '<span style="font-size: 10pt">{}</span><br>'
                                     '<span style="font-size: 10pt">{}</span><br>'
                                     '<span style="font-size: 10pt">({})</span>'
                                     '</div>'.format(self.labels[0], x_label_1, y_label_1))
                self.label_2.setHtml('<div style="text-align: center">'
                                     '<span style="font-size: 10pt">{}</span><br>'
                                     '<span style="font-size: 10pt">{}</span><br>'
                                     '<span style="font-size: 10pt">({})</span>'
                                     '</div>'.format(self.labels[1], x_label_2, y_label_2))
예제 #5
0
class baselinePlotWidget(SpectraPlotWidget):
    def __init__(self):
        super(baselinePlotWidget, self).__init__()
        self.line.setValue(800)
        self.txt = TextItem('', anchor=(0, 0))
        self.cross = PlotDataItem([800], [0], symbolBrush=(255, 255, 0), symbolPen=(255, 255, 0),
                                  symbol='+',symbolSize=20)
        self.line.sigPositionChanged.connect(self.getMu)
        self._mu = None

    def plot(self, x, y, *args, **kwargs):
        # set up infinity line and get its position
        self.plotItem.plot(x, y, *args, **kwargs)
        self.addItem(self.line)
        self.addItem(self.cross)
        x_val = self.line.value()
        if x_val == 0:
            y_val = 0
        else:
            idx = val2ind(x_val, self.wavenumbers)
            x_val = self.wavenumbers[idx]
            y_val = y[idx]

        if not self._meanSpec:
            txt_html = f'<div style="text-align: center"><span style="color: #FFF; font-size: 12pt">\
                            Spectrum #{self.spectrumInd}</div>'
        else:
            txt_html = f'<div style="text-align: center"><span style="color: #FFF; font-size: 12pt">\
                             {self._mean_title}</div>'

        txt_html += f'<div style="text-align: center"><span style="color: #FFF; font-size: 12pt">\
                             X = {x_val: .2f}, Y = {y_val: .4f}</div>'
        self.txt = TextItem(html=txt_html, anchor=(0, 0))
        ymax = np.max(y)
        self._y = y
        r = self.txtPosRatio
        self.txt.setPos(r * x[-1] + (1 - r) * x[0], 0.95 * ymax)
        self.cross.setData([x_val], [y_val])
        self.addItem(self.txt)

    def getMu(self):
        if self._mu is not None:
            x_val = self.line.value()
            if x_val == 0:
                y_val = 0
            else:
                idx = val2ind(x_val, self._x)
                x_val = self._x[idx]
                y_val = self._mu[idx]
            txt_html = f'<div style="text-align: center"><span style="color: #FFF; font-size: 12pt">\
                                                 X = {x_val: .2f}, Y = {y_val: .4f}</div>'
            self.txt.setHtml(txt_html)
            self.cross.setData([x_val], [y_val])

    def addDataCursor(self, x, y):
        self.addItem(self.line)
        self.addItem(self.cross)
        ymax = np.max(y)
        self.txt.setText('')
        r = self.txtPosRatio
        self.txt.setPos(r * x[-1] + (1 - r) * x[0], 0.95 * ymax)
        self.addItem(self.txt)
        self.getMu()

    def plotBase(self, dataGroup, plotType='raw'):
        """
        make plots for Larch Group object
        :param dataGroup: Larch Group object
        :return:
        """
        # add legend
        self.plotItem.addLegend(offset=(-1, -1))
        x = self._x = dataGroup.energy # self._x, self._mu for getEnergy
        y = self._mu = dataGroup.specTrim
        n = len(x) # array length
        self._y = None  # disable getEnergy func
        if plotType == 'raw':
            self.plotItem.plot(x, y, name='Raw', pen=mkPen('w', width=2))
        elif plotType == 'rubber_base':
            self.plotItem.plot(x, y, name='Raw', pen=mkPen('w', width=2))
            self.plotItem.plot(x, dataGroup.rubberBaseline, name='Rubberband baseline', pen=mkPen('g', style=Qt.DotLine, width=2))
            self.plotItem.plot(dataGroup.wav_anchor, dataGroup.spec_anchor, symbol='o', symbolPen='r', symbolBrush=0.5)
        elif plotType == 'kohler_base':
            self.plotItem.plot(x, y, name='Raw', pen=mkPen('w', width=2))
            self.plotItem.plot(x, dataGroup.kohlerBaseline, name='Kohler EMSC baseline', pen=mkPen('g', style=Qt.DotLine, width=2))
        elif plotType == 'rubberband':
            y = self._mu = dataGroup.rubberDebased
            self.plotItem.plot(x, y, name='Rubberband debased', pen=mkPen('r', width=2))
        elif plotType == 'kohler':
            y = self._mu = dataGroup.kohlerDebased
            self.plotItem.plot(x, y, name='Kohler EMSC debased', pen=mkPen('r', width=2))
        elif plotType == 'deriv2_rubberband':
            y = self._mu = dataGroup.rubberDebased # for data cursor
            scale, offset = self.alignTwoCurve(dataGroup.rubberDebased[n//4:n*3//4], dataGroup.deriv2_rubber[n//4:n*3//4])
            deriv2Scaled = dataGroup.deriv2_rubber * scale + offset
            ymin, ymax = np.min(y), np.max(y)
            self.getViewBox().setYRange(ymin, ymax, padding=0.1)
            self.plotItem.plot(x, y, name='Rubberband debased', pen=mkPen('r', width=2))
            self.plotItem.plot(x, deriv2Scaled, name='2nd derivative (scaled, Rubberband)', pen=mkPen('g', width=2))
        elif plotType == 'deriv2_kohler':
            y = self._mu = dataGroup.kohlerDebased
            scale, offset = self.alignTwoCurve(dataGroup.kohlerDebased[n//4:n*3//4], dataGroup.deriv2_kohler[n//4:n*3//4])
            deriv2Scaled = dataGroup.deriv2_kohler * scale + offset
            ymin, ymax = np.min(y), np.max(y)
            self.getViewBox().setYRange(ymin, ymax, padding=0.1)
            self.plotItem.plot(x, y, name='Rubberband debased', pen=mkPen('r', width=2))
            self.plotItem.plot(x, deriv2Scaled, name='2nd derivative (scaled, Kohler)', pen=mkPen('g', width=2))
        # add infinityline, cross
        self.addDataCursor(x, y)

    def alignTwoCurve(self, y1, y2):
        """
        Align the scale of y2 to that of y1
        :param y1: the main curve
        :param y2: the curve to be aligned
        :return:
        scale: scale factor
        offset: y offset
        """
        y1Range, y2Range = np.max(y1) - np.min(y1), np.max(y2) - np.min(y2)
        scale = y1Range / y2Range
        y = y2 * scale
        offset = np.max(y1) - np.max(y)
        return scale, offset
예제 #6
0
class SpectraPlotWidget(PlotWidget):
    sigEnergyChanged = Signal(object)

    def __init__(self, linePos=650, txtPosRatio=0.35, invertX=True, *args, **kwargs):
        """
        A widget to display a 1D spectrum
        :param linePos: the initial position of the InfiniteLine
        :param txtPosRatio: a coefficient that determines the relative position of the textItem
        :param invertX: whether to invert X-axis
        """
        super(SpectraPlotWidget, self).__init__(*args, **kwargs)
        self._data = None
        assert (txtPosRatio >= 0) and (txtPosRatio <= 1), 'Please set txtPosRatio value between 0 and 1.'
        self.txtPosRatio = txtPosRatio
        self.positionmap = dict()
        self.wavenumbers = None
        self._meanSpec = True  # whether current spectrum is a mean spectrum
        self.line = InfiniteLine(movable=True)
        self.line.setPen((255, 255, 0, 200))
        self.line.setValue(linePos)
        self.line.sigPositionChanged.connect(self.sigEnergyChanged)
        self.line.sigPositionChanged.connect(self.getEnergy)
        self.addItem(self.line)
        self.cross = PlotDataItem([linePos], [0], symbolBrush=(255, 0, 0), symbolPen=(255, 0, 0), symbol='+',
                                  symbolSize=20)
        self.cross.setZValue(100)
        self.addItem(self.cross)
        self.txt = TextItem()
        self.getViewBox().invertX(invertX)
        self.spectrumInd = 0
        self.selectedPixels = None
        self._y = None

    def getEnergy(self, lineobject):
        if self._y is not None:
            x_val = lineobject.value()
            idx = val2ind(x_val, self.wavenumbers)
            x_val = self.wavenumbers[idx]
            y_val = self._y[idx]
            if not self._meanSpec:
                txt_html = toHtml(f'Spectrum #{self.spectrumInd}')
            else:
                txt_html = toHtml(f'{self._mean_title}')

            txt_html += toHtml(f'X = {x_val: .2f}, Y = {y_val: .4f}')
            self.txt.setHtml(txt_html)
            self.cross.setData([x_val], [y_val])

    def setHeader(self, header: NonDBHeader, field: str, *args, **kwargs):
        self.header = header
        self.field = field
        # get wavenumbers
        spectraEvent = next(header.events(fields=['spectra']))
        self.wavenumbers = spectraEvent['wavenumbers']
        self.N_w = len(self.wavenumbers)
        self.rc2ind = spectraEvent['rc_index']
        # make lazy array from document
        data = None
        try:
            data = header.meta_array(field)
        except IndexError:
            msg.logMessage(f'Header object contained no frames with field {field}.', msg.ERROR)

        if data is not None:
            # kwargs['transform'] = QTransform(1, 0, 0, -1, 0, data.shape[-2])
            self._data = data

    def showSpectra(self, i=0):
        if (self._data is not None) and (i < len(self._data)):
            self.getViewBox().clear()
            self._meanSpec = False
            self.spectrumInd = i
            self.plot(self.wavenumbers, self._data[i])

    def getSelectedPixels(self, selectedPixels):
        self.selectedPixels = selectedPixels
        # print(selectedPixels)

    def clearAll(self):
        # remove legend
        _legend = self.plotItem.legend
        if (_legend is not None) and (_legend.scene() is not None):
            _legend.scene().removeItem(_legend)
        self.getViewBox().clear()

    def showMeanSpectra(self):
        self._meanSpec = True
        self.getViewBox().clear()
        if self.selectedPixels is not None:
            n_spectra = len(self.selectedPixels)
            tmp = np.zeros((n_spectra, self.N_w))
            for j in range(n_spectra):  # j: jth selected pixel
                row_col = tuple(self.selectedPixels[j])
                tmp[j, :] = self._data[self.rc2ind[row_col]]
            self._mean_title = f'ROI mean of {n_spectra} spectra'
        else:
            n_spectra = len(self._data)
            tmp = np.zeros((n_spectra, self.N_w))
            for j in range(n_spectra):
                tmp[j, :] = self._data[j]
            self._mean_title = f'Total mean of {n_spectra} spectra'
        if n_spectra > 0:
            meanSpec = np.mean(tmp, axis=0)
        else:
            meanSpec = np.zeros_like(self.wavenumbers) + 1e-3
        self.plot(self.wavenumbers, meanSpec)

    def plot(self, x, y, *args, **kwargs):
        # set up infinity line and get its position
        self.plotItem.plot(x, y, *args, **kwargs)
        self.addItem(self.line)
        self.addItem(self.cross)
        x_val = self.line.value()
        if x_val == 0:
            y_val = 0
        else:
            idx = val2ind(x_val, self.wavenumbers)
            x_val = self.wavenumbers[idx]
            y_val = y[idx]

        if not self._meanSpec:
            txt_html = toHtml(f'Spectrum #{self.spectrumInd}')
        else:
            txt_html = toHtml(f'{self._mean_title}')

        txt_html += toHtml(f'X = {x_val: .2f}, Y = {y_val: .4f}')
        self.txt.setHtml(txt_html)
        ymax = np.max(y)
        self._y = y
        r = self.txtPosRatio
        self.txt.setPos(r * x[-1] + (1 - r) * x[0], ymax)
        self.cross.setData([x_val], [y_val])
        self.addItem(self.txt)
class NaturalPlotView(GraphicsView):
    """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.

    """

    def __init__(self):
        super().__init__()

        # settings
        self.setBackground("#fff")
        self.setFrameStyle(QFrame.StyledPanel|QFrame.Sunken)
        self.setAntialiasing(True)

        # create custom view box
        view_box = ViewBox()
        view_box.setMouseEnabled(False, False)
        view_box.setLimits(xMin=0, yMin=0, minXRange=10, minYRange=100)
        view_box.setRange(xRange=(0, 400), yRange=(0, 5000))
        view_box.enableAutoRange()

        # create natural axis items
        self.x_axis = NaturalAxis("bottom")
        self.x_axis.setLabel(QApplication.translate("NaturalPlotView", "Fence length"), "m")
        self.y_axis = NaturalAxis("left")
        self.y_axis.setLabel(QApplication.translate("NaturalPlotView", "Number of plants"))

        # create fence information text
        self.fenceItem = TextItem(border=pyqtgraph.mkPen(width=2, color="#555"),
                fill=pyqtgraph.mkBrush((255, 255, 255, 200)))

        # create tube information text
        self.tubeItem = TextItem(border=pyqtgraph.mkPen(width=2, color="#555"),
                fill=pyqtgraph.mkBrush((255, 255, 255, 200)),
                anchor=(1,1))

        # create plot item with custom view box and natural axis items
        self.plotItem = PlotItem(viewBox=view_box,
                axisItems={"bottom" : self.x_axis, "left" : self.y_axis}, enableMenu=False)
        self.plotItem.setContentsMargins(5, 5, 12, 5)
        self.plotItem.hideButtons()
        self.plotItem.hide()
        self.setCentralWidget(self.plotItem)

        # connect actions
        view_box.sigResized.connect(self.updateTubeLegendPosition)

        # translate the plot item
        self.retranslateUi()

    def retranslateUi(self):
        # title label
        titleStyle = "color: #111; font-size: 15px; font-weight: bold"
        titleLabel = "<span style='{style}'>{title}</span>".format(style=titleStyle,
                title="Ergebnis: Funktion(en) der Kostengleichheit")
        self.plotItem.setTitle(titleLabel)

        # axis items
        #self.x_axis.setLabel(QApplication.translate("NaturalPlotView", "Fence length"), "m")
        #self.y_axis.setLabel(QApplication.translate("NaturalPlotView", "Number of plants"))

        # fence hint
        self.fenceItem.setHtml("<p style='margin: 0; color: #555'><b>" +
                QApplication.translate("NaturalPlotView", "Pfeil über Funktion(en):") + "</b> " +
                QApplication.translate("NaturalPlotView", "Zaun günstiger") + "</p>")

        # tube hint
        self.tubeItem.setHtml("<p style='margin: 0; color: #555'><b>" +
                QApplication.translate("NaturalPlotView", "Pfeil unter Funktion(en):") + "</b> " +
                QApplication.translate("NaturalPlotView", "Wuchshülle günstiger") + "</p>")


    def addPlotItem(self, item, *args, **kwargs):
        # first show the plot item
        if not self.plotItem.isVisible():
            self.plotItem.show()

        self.plotItem.addItem(item, *args, **kwargs)

    def removePlotItem(self, item):
        self.plotItem.removeItem(item)

    #TODO:
    def clear(self):
        self.plotItem.hide()
        self.plotItem.clear()

    def showDescription(self):
        viewBox = self.plotItem.getViewBox()

        self.fenceItem.setPos(15, 10)
        self.fenceItem.setParentItem(viewBox)

        rect = viewBox.screenGeometry()
        self.tubeItem.setPos(rect.width() - 15, rect.height() - 10)
        self.tubeItem.setParentItem(viewBox)

    def updateTubeLegendPosition(self):
        rect = self.plotItem.getViewBox().screenGeometry()
        self.tubeItem.setPos(rect.width() - 15, rect.height() - 10)

    def export(self, gfxfile):
        exporter = TestImageExporter(self.plotItem)
        exporter.parameters()["width"] = 2007.0   # 17 cm / 300 DPI

        # export the graphics to the selected file
        exporter.export(gfxfile)
예제 #8
0
class BarChartWithLine(Chart):
    """
    Implementation of the Bar chart with line graphics

    """
    def __init__(self,
                 x: list,
                 y: list,
                 graphics_view: PlotWidget,
                 table_view: QTableView,
                 legend: str = "",
                 width=0.5,
                 reverse=True):
        """
        Constructor / Instantiation of class

        Parameters
        ----------
        x               : list
                          x-values
        y               : list
                          y-values
        graphics_view   : PlotWidget
                          graphics view to place chart
        table_view      : QTableView
                          table view to link graphics_view
        legend          : HTML str
                          legend
        width           : int, float
                          width of bars
        reverse         : bool
                          reverse selection in table

        """
        Assertor.assert_data_types(
            [x, y, graphics_view, table_view, legend, width],
            [list, list, PlotWidget, QTableView, str, (int, float)])
        super().__init__()
        self.x = x
        self.y = y
        self.graphics_view = graphics_view
        self.table_view = table_view
        self.label = TextItem()
        self.width = width
        self.reverse = reverse

        place = percentile(insert(array(self.x), 0, 0), 2)
        self.label.setPos(place, int(max(y) * 1.5))

        self.label.setHtml(legend)
        self.graphics_view.addItem(self.label, ignore_bounds=True)

        self.bar_item = BarGraphItem(x=self.x,
                                     height=self.y,
                                     width=self.width,
                                     brush="#d2e5f5")
        self.graphics_view.addItem(self.bar_item)
        pen = mkPen(color="#d2e5f5", style=Qt.DotLine, width=2)
        self.graphics_view.plot(x=self.x,
                                y=self.y,
                                pen=pen,
                                symbol='+',
                                symbolSize=14)

        self.graphics_view.plotItem.vb.setLimits(xMin=min(self.x) - width,
                                                 xMax=max(self.x) + width)
        self.graphics_view.setMenuEnabled(False)
        self.graphics_view.getViewBox().enableAutoRange()

    def table_view_mapping(self):
        """
        method for mapping table rows to chart bars

        """
        self.table_view.clicked.connect(self.row_clicked)

    def row_clicked(self, item):
        """
        method for accessing row in table_view

        """
        pen_1 = mkPen(color="#69a8de", style=Qt.DotLine, width=2)
        pen_2 = mkPen(color="#d2e5f5", style=Qt.DotLine, width=2)
        bar_item = BarGraphItem(x=self.x,
                                height=self.y,
                                width=self.width,
                                brush="#d2e5f5")
        chart_item = PlotDataItem(x=self.x,
                                  y=self.y,
                                  pen=pen_1,
                                  symbol='+',
                                  symbolSize=14)
        clear_line = PlotDataItem(x=self.x,
                                  y=self.y,
                                  pen=pen_2,
                                  symbol='+',
                                  symbolSize=14)

        if item.row() < len(self.x):
            row = len(self.x) - 1 - item.row() if self.reverse else item.row()

            clicked_item = BarGraphItem(x=[self.x[row]],
                                        height=self.y[row],
                                        width=self.width,
                                        brush="#69a8de")
            self.graphics_view.addItem(bar_item)
            self.graphics_view.addItem(clicked_item)
            self.graphics_view.addItem(chart_item)
        else:
            self.graphics_view.addItem(bar_item)
            self.graphics_view.addItem(clear_line)

    @staticmethod
    def clear_graphics(graphics_view: PlotWidget, table_view: QTableView):
        """
        static method for clearing content in all graphics

        Parameters
        ----------
        graphics_view   : PlotWidget
                          graphics view to place chart
        table_view      : QTableView
                          table view to link graphics_view

        """
        Assertor.assert_data_types([graphics_view, table_view],
                                   [PlotWidget, QTableView])
        table_view.setModel(None)
        table_view.clearSpans()
        graphics_view.clear()
예제 #9
0
class ChangeBarChart(Chart):

    def __init__(self, x: list, y: list, graphics_view: PlotWidget, labels: str,
                 units=None, x_labels=None, width=0.4):
        """
        Constructor / Instantiation of class

        Parameters
        ----------
        x               : list
                          x-values
        y               : list
                          y-values
        graphics_view   : PlotWidget
                          widget to add items
        labels          : str
                          legend labels
        units           : tuple
                          measurement units for tuple
        width           : int, float
                          width of any bars
        x_labels        : array-like
                          array of dates, i.e. time-period

        """
        super().__init__()
        Assertor.assert_data_types([x, y, graphics_view, labels, units, x_labels, width],
                                   [list, list, PlotWidget, str, (type(None), tuple),
                                    (type(None), list), (float, int)])
        self.x = asarray(arange(1, len(x) + 1, 1))
        self.y = asarray([float(val.replace(" ", "").replace("%", "")) if val else 0 for val in y])
        self.graphics_view = graphics_view
        self.labels = labels
        self.units = units if units else tuple(["" for _ in range(10)])
        self.x_time = x_labels
        self.width = width

        self.bar_item_1 = BarGraphItem(x=self.x, height=self.y, width=self.width, brush="#a8ccec")
        self.graphics_view.addItem(self.bar_item_1)
        self.bar_item_2 = None

        self.label = TextItem()
        pen = mkPen(color="#4c96d7", style=Qt.SolidLine, width=1)
        self.vertical_line = InfiniteLine(angle=90, movable=False, pen=pen)
        self.graphics_view.addItem(self.vertical_line)

        self.view_box = self.graphics_view.getViewBox()
        self.configure_cross_hair()

        self.graphics_view.plotItem.vb.setLimits(xMin=0, xMax=max(self.x) + 1)
        self.graphics_view.setMenuEnabled(False)

    def configure_cross_hair(self):
        """
        method for configuring cross hair

        """
        place = percentile(array(insert(self.x, 0, 0)), 2)

        self.label.setPos(place, int(abs(max(self.y, key=abs)) * 1.5))
        self.graphics_view.addItem(self.label)

    def move_vertical_lines(self, pos):
        """
        method for moving the vertical lines on the plot

        """
        mouse_point = self.view_box.mapSceneToView(pos)

        x_val = int(round(mouse_point.x()))
        x_idx = where(self.x == x_val)

        y_val = int(self.y[x_idx]) if self.y[x_idx] else 0
        self.vertical_line.setPos(x_val)
        limits = min(self.x) <= x_val <= max(self.x)
        if len(self.graphics_view.getViewBox().allChildren()) > 3 and limits:
            self.highlight_bar_items(x_val, y_val)

        return x_val, y_val

    def highlight_bar_items(self, x_val, y_val):
        """
        method for highlighting bar items

        """
        self.graphics_view.removeItem(self.bar_item_2)
        self.bar_item_2 = BarGraphItem(x=[x_val], height=y_val, width=self.width,
                                       brush="#69a8de")
        self.graphics_view.addItem(self.bar_item_2)

    def mouse_moved(self, evt):
        """
        method for moving the vertical lines based on mouse placement

        """
        pos = evt[0]
        x_val, y_val = self.move_vertical_lines(pos)

        x_label_idx = where(array(self.x) == x_val)[0]
        x_label = self.x_time[x_label_idx.item()] if \
            self.x_time and x_label_idx.size != 0 else \
            Amount(str(x_val)).amount + self.units[0]
        y_label = str(y_val) + self.units[1]

        if min(self.x) <= x_val <= max(self.x):
            self.label.setHtml('<div style="text-align: center">'
                               '<span style="font-size: 10pt">{}</span><br>'
                               '<span style="font-size: 10pt">{}</span><br>'
                               '<span style="font-size: 10pt">({})</span>'
                               '</div>'.format(self.labels, x_label, y_label))
예제 #10
0
class RatioChart(Chart):
    """
    Implementation of the RatioChart graphics used for visualizing the ratio between sqm-prices
    in area vs municipality.

    """
    def __init__(self,
                 x: list,
                 y_1: list,
                 y_2: list,
                 graphics_view: PlotWidget,
                 labels: str,
                 units=None,
                 x_labels=None,
                 precision=0,
                 width=0.4):
        """
        Constructor / Instantiate the class

        Parameters
        ----------
        x               : list
                          x-values
        y_1             : np.ndarray
                          y-values
        y_2             : np.ndarray
                          y-values
        graphics_view   : PlotWidget
                          widget to add items
        labels          : str
                          legend labels
        units           : tuple
                          measurement units for tuple
        x_labels        : array-like
                          array of x_labels
        precision       : int
                          precision for rounding, default is zero
        width           : int, float
                          width of any bars

        """
        Assertor.assert_data_types([
            x, y_1, y_2, graphics_view, labels, units, x_labels, precision,
            width
        ], [
            list, list, list, PlotWidget, str, (type(None), tuple),
            (type(None), list), (float, int), (float, int)
        ])
        super().__init__()
        self.y_1, self.x = self.create_bins(x, y_1, bins=x)
        self.y_2, self.x = self.create_bins(x, y_2, bins=x)

        self.x = self.x[:-1]

        self.labels = labels
        self.units = units if units else ("", "")
        self.precision = precision

        self.ratio = (self.y_1 / self.y_2) * 100
        self.x_labels = x_labels if x_labels else self.ratio

        self.graphics_view = graphics_view
        self.view_box = self.graphics_view.getViewBox()

        self.width = width
        self.label = TextItem()
        self.bar_item_1 = BarGraphItem(x=self.x,
                                       height=self.ratio,
                                       width=self.width,
                                       brush="#a8ccec")
        self.graphics_view.addItem(self.bar_item_1)
        self.configure_cross_hair()

        self.bar_item_2 = None
        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.graphics_view.plotItem.vb.setLimits(xMin=min(self.x) - width,
                                                 xMax=max(self.x) + width)
        self.graphics_view.setMenuEnabled(False)

    def configure_cross_hair(self):
        """
        method for configuring cross hair

        """
        place = percentile(array(insert(self.x, 0, 0)), 2)

        self.label.setPos(place, int(abs(max(self.ratio, key=abs)) * 1.5))
        self.graphics_view.addItem(self.label)

    def move_vertical_lines(self, pos):
        """
        method for moving the vertical lines on the plot

        """
        mouse_point = self.view_box.mapSceneToView(pos)

        x_val = int(round(mouse_point.x(), self.precision))
        x_idx = where(self.x == x_val)

        y_val = self.ratio[x_idx] if self.ratio[x_idx] else 0
        self.vertical_line.setPos(x_val)
        limits = min(self.x) <= x_val <= max(self.x)

        if len(self.graphics_view.getViewBox().allChildren()) > 3 and limits:
            self.highlight_bar_items(x_val, y_val)

        return x_val, y_val

    def highlight_bar_items(self, x_val, y_val):
        """
        method for highlighting bar items

        """
        self.graphics_view.removeItem(self.bar_item_2)
        self.bar_item_2 = BarGraphItem(x=[x_val],
                                       height=y_val,
                                       width=self.width,
                                       brush="#69a8de")
        self.graphics_view.addItem(self.bar_item_2)

    def mouse_moved(self, evt):
        """
        method for moving the vertical lines based on mouse placement

        """
        pos = evt[0]
        if self.graphics_view.sceneBoundingRect().contains(pos):
            x_val, y_val = self.move_vertical_lines(pos)

            percent = Percent(
                str(y_val / 100).replace("[", "").replace("]", ""))

            if min(self.x) <= x_val <= max(self.x):
                self.label.setHtml(
                    '<div style="text-align: center">'
                    '<span style="font-size: 10pt">{}</span><br>'
                    '<span style="font-size: 10pt">{} {}</span><br>'
                    '<span style="font-size: 10pt">({})</span>'
                    '</div>'.format(self.labels,
                                    Amount(str(x_val)).amount, self.units[0],
                                    percent.value))