Ejemplo n.º 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)
Ejemplo n.º 2
0
	def setData(self, **kwds):
		self.data = kwds
		if 'pos' in self.data:
			for n in range(kwds['pos'].shape[0]):
				text_item = TextItem(kwds['text'][n])
				text_pos = (kwds['pos'][n][0], kwds['pos'][n][1])
				text_item.setPos(*kwds['pos'][n])
				text_item.setParentItem(self)
		self.text = kwds.pop('text', [])
		GraphItem.setData(self, **self.data)
Ejemplo n.º 3
0
    def update(self,
               x,
               y,
               colors,
               cutpoint_x=None,
               selection_limit=None,
               names=None):
        """
        Function replots a graph.

        Parameters
        ----------
        x : np.ndarray
            One-dimensional array with X coordinates of the points
        y : array-like
            List of np.ndarrays that contains an array of Y values for each
            sequence.
        colors : array-like
            List of Qt colors (eg. Qt.red) for each sequence.
        cutpoint_x : int, optional
            A starting cutpoint - the location of the vertical line.
        selection_limit : tuple
            The tuple of two values that limit the range for selection.
        names : array-like
            The name of each sequence that shows in the legend, if None
            legend is not shown.
        legend_anchor : array-like
            The anchor of the legend in the graph
        """
        self.clear_plot()
        if names is None:
            names = [None] * len(y)

        self.sequences = y
        self.x = x
        self.selection_limit = selection_limit

        self.data_increasing = [np.sum(d[1:] - d[:-1]) > 0 for d in y]

        # plot sequence
        for s, c, n, inc in zip(y, colors, names, self.data_increasing):
            c = QColor(c)
            self.plot(x, s, pen=mkPen(c, width=2), antialias=True)

            if n is not None:
                label = TextItem(text=n,
                                 anchor=(0, 1),
                                 color=QColor(0, 0, 0, 128))
                label.setPos(x[-1], s[-1])
                self._set_anchor(label, len(x) - 1, inc)
                self.addItem(label)

        self._plot_cutpoint(cutpoint_x)
        self.autoRange()
Ejemplo n.º 4
0
 def calcPartitionNamePlacement(self,
                                label: pg.TextItem,
                                index: int,
                                emit_signal=False):
     start_point = self.segments[index].getXPos()
     end_point = self.segments[index + 1].getXPos()
     mid_point = start_point + ((end_point - start_point) / 2)
     label.setPos(mid_point, self.vertical_placement)
     label.updateTextPos()
     if emit_signal:
         self.item.updatePartitionValuePosition.emit(index, mid_point)
Ejemplo n.º 5
0
 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)
Ejemplo n.º 6
0
	def __init__(self, viewBox, el_net):
		
		self.arrows = []
		self.arrow_labels = []
		self.line_flows = relative_line_load(el_net)
		
		for l in self.line_flows:
			arrow = ArrowItem(angle = l['angle'], tipAngle = 40, headLen= 10, tailLen=0, pen={'color': 'w', 'width': 1}, brush = 'y', pxMode = True)
			arrow.setPos(*l['pos'])
			arrow_label = TextItem("{0:.0f}%".format(l['rel_load']))
			arrow_label.setPos(*l['pos'])
			viewBox.addItem(arrow)
			viewBox.addItem(arrow_label)
			self.arrows.append(arrow)
			self.arrow_labels.append(arrow_label)
Ejemplo n.º 7
0
    def update(self):
        self.p5main.clear()

        self.p5main.addItem(self.pointer)
        self.pointer.setData(
            pos=np.array([[glo_var.alpha, glo_var.beta]], dtype=float))
        self.pointer.legend(glo_var.alpha, glo_var.beta)

        self.value_declaration()

        if glo_var.alpha > 2 * glo_var.alpha_star:
            glo_var.alpha = 2 * glo_var.alpha_star
        if glo_var.beta > 2 * glo_var.beta_star:
            glo_var.beta = 2 * glo_var.beta_star

        HD = TextItem(html='HD',
                      anchor=(glo_var.alpha_star, 0.5 * glo_var.beta_star),
                      border='w',
                      fill=(255, 0, 0, 250))

        HD.setPos(glo_var.alpha_star, 0.5 * glo_var.beta_star)
        LD = TextItem(html='LD',
                      anchor=(glo_var.alpha_star * 0.3,
                              glo_var.beta_star * 1.3),
                      border='w',
                      fill=(0, 255, 0, 200))

        LD.setPos(glo_var.alpha_star * 0.3, glo_var.beta_star * 1.3)
        MC = TextItem(html='MC',
                      anchor=(glo_var.alpha_star * 1.2,
                              glo_var.beta_star * 1.3),
                      border='w',
                      fill=(0, 0, 255, 200))
        MC.setPos(glo_var.alpha_star * 1.2, glo_var.beta_star * 1.3)

        self.bounds1 = np.array([[glo_var.alpha_star, glo_var.beta_star],
                                 [1, glo_var.beta_star]])
        self.bounds2 = np.array([[glo_var.alpha_star, glo_var.beta_star],
                                 [glo_var.alpha_star, 1]])
        linspace = np.linspace(0, glo_var.alpha_star, 20)
        trans_line_val = []
        for i in linspace:
            trans_line_val += [self.trans_func(i)]
        self.p5main.plot(self.bounds1, pen='k')
        self.p5main.plot(self.bounds2, pen='k')
        self.p5main.plot(linspace, trans_line_val, pen='k')

        self.set_range()
Ejemplo n.º 8
0
class verticalScaleBar(GraphicsObject, GraphicsWidgetAnchor):
    """
    Displays a rectangular bar to indicate the relative scale of objects on the view.
    """
    def __init__(self,
                 size,
                 width=5,
                 brush=None,
                 pen=None,
                 suffix='m',
                 offset=None):
        GraphicsObject.__init__(self)
        GraphicsWidgetAnchor.__init__(self)
        self.setFlag(self.ItemHasNoContents)
        self.setAcceptedMouseButtons(QtCore.Qt.NoButton)

        if brush is None:
            brush = getConfigOption('foreground')
        self.brush = fn.mkBrush(brush)
        self.pen = fn.mkPen(pen)
        self._width = width
        self.size = size
        if offset == None:
            offset = (0, 0)
        self.offset = offset

        self.bar = QtGui.QGraphicsRectItem()
        self.bar.setPen(self.pen)
        self.bar.setBrush(self.brush)
        self.bar.setParentItem(self)

        self.text = TextItem(text=fn.siFormat(size, suffix=suffix),
                             anchor=(0.5, 1),
                             angle=90,
                             color=(0, 0, 0))
        self.text.setParentItem(self)

    def parentChanged(self):
        view = self.parentItem()
        if view is None:
            return
        view.sigRangeChanged.connect(self.updateBar)
        self.updateBar()

    def updateBar(self):
        view = self.parentItem()
        if view is None:
            return
        p1 = view.mapFromViewToItem(self, QtCore.QPointF(0, 0))
        p2 = view.mapFromViewToItem(self, QtCore.QPointF(0, self.size))
        w = (p2 - p1).y()
        self.bar.setRect(QtCore.QRectF(0, 0, self._width, w))
        self.text.setPos(0, w / 2.)

    def boundingRect(self):
        return QtCore.QRectF()

    def setParentItem(self, p):
        ret = GraphicsObject.setParentItem(self, p)
        if self.offset is not None:
            offset = Point(self.offset)
            anchorx = 1 if offset[0] <= 0 else 0
            anchory = 1 if offset[1] <= 0 else 0
            anchor = (anchorx, anchory)
            self.anchor(itemPos=anchor, parentPos=anchor, offset=offset)
        return ret
Ejemplo n.º 9
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
Ejemplo n.º 10
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)
Ejemplo n.º 11
0
class jalpha:
	def __init__(self, dalpha, rh):

		self.dalpha = dalpha
		self.p3main = glo_var.MyPW(x="\u03b1",y1="J",y2= "\u27e8\u2374\u27e9", set_range = self.set_range)
		# self.p3main._rescale = self.set_range
		self.p3 = self.p3main.plotItem

		self.rh=rh


		self.na = "ha"


		self.p3.setLabel('bottom',"\u03b1",**glo_var.labelstyle)
		self.p3.setLabel('left',"J",**glo_var.labelstyle)
		self.p3.setLabel('right',"\u27e8\u2374\u27e9",**glo_var.labelstyle)

		self.p3.addLegend = glo_var.myaddLegend
		self.p3.addLegend(self.p3, offset = (20,20))

# to use it as coordinate label
		self.p3main.tempplotitem = PlotItem()
		# self.p3main.set_range = self.set_range
		self.p3_2 = self.p3main.tempplotitem.vb
		self.p3.showAxis('right')
		self.p3.scene().addItem(self.p3_2)
		self.p3.getAxis('right').linkToView(self.p3_2)
		self.p3_2.setXLink(self.p3)
		self.p3_2.setBackgroundColor('w')

		self.rho_dash = mkPen(color=(16,52,166),width=glo_var.line_width,style=QtCore.Qt.DashLine)
		self.dash = mkPen('r',width=glo_var.line_width ,style=QtCore.Qt.DashLine)
		self.jpen = mkPen('k',width=glo_var.line_width)
		self.alpha_pen = mkPen('k',width = glo_var.line_width)
		self.p3main.coordinate_label = QtGui.QLabel()
		self.frame = glo_var.setframe(self.p3main, width = 1, coordinate_label = self.p3main.coordinate_label)

		self.dalpha.addWidget(self.frame)


		self.p3.vb.setLimits(xMin = 0, yMin = 0, xMax = 1, yMax = 1)
		self.p3_2.setLimits(xMin = 0, yMin = 0, xMax = 1, yMax = 1)

		self.p3.vb.sigResized.connect(self.updateview)

		self.update()
		self.legend()
	
	def set_range(self):
		self.uplim1 = min(self.jpost * 1.3, 1)
		self.lolim1 = 0
		self.uplim2 = min(1, max(max(self.rho_avg_pre)*1.4,max(self.rho_avg_post)*1.4))
		self.lolim2 = max(0, min(min(self.rho_avg_pre)*0.6,min(self.rho_avg_post)*0.6))

		self.p3.vb.setRange(xRange=[0,3*self.trans_point],yRange=[self.lolim1,self.uplim1],padding =0)
		self.p3_2.setRange(xRange=[0,3*self.trans_point],yRange=[self.lolim2,self.uplim2], padding = 0)

	def checkbox(self):
		self.alphline = QtGui.QCheckBox('\u03B1 line')
		self.alphline.stateChanged.connect(self.alphstate)
		self.alproxy=QtGui.QGraphicsProxyWidget()
		self.alproxy.setWidget(self.alphline)

		self.p3_w = self.win.addLayout(row=2,col=0)

		self.p3_w.addItem(self.alproxy,row=0,col=1)

	def update(self):
		self.p3.clear()
		self.p3_2.clear()
		self.value_declaration()
		self.vlim = 1/pow(1+sqrt(glo_var.l),2)


		self.trans_point = self.trans_func(glo_var.beta)
		
		self.alphas_pre = np.linspace(0,self.trans_point - 0.000001,20)
		# explain here in the meeting
		# self.alphas_to_add = np.array([self.trans_point-0.000001, self.trans_point, self.trans_point+0.000001]) 
		# self.alphas_pre = np.concatenate((self.alphas_pre_pre[:-1],self.alphas_to_add))
		self.alphas_post=np.array([self.trans_point+ 0.000001, 1])
		self.j_l_values=np.array([i*(self.lambda_0-i)/(self.lambda_0 + (glo_var.l-1)*i) for i in self.alphas_pre])
		
		self.rho_avg_pre = []
		for i in self.alphas_pre:
			self.rho_avg_pre += [self.cal_rho(self.js(i,glo_var.beta))]
		self.rho_avg_post = []
		for i in self.alphas_post:
			self.rho_avg_post += [self.cal_rho(self.js(i,glo_var.beta))]

		self.num=30
		self.xs =np.linspace(0,self.trans_point, self.num)
	
		# minused 0.00000001 since it is not working
		
		self.p3.plot(self.alphas_pre,self.j_l_values, pen = self.jpen)

		# Can alpha_star be 0? then I need to add conner case
		if glo_var.beta >= glo_var.beta_star:
			self.jpost= self.j_c
		else:
			self.jpost= self.j_r
		
		self.p3.plot([self.trans_point,1],[self.jpost,self.jpost],pen = self.jpen)

		self.trans_line = self.p3.plot([self.trans_point,self.trans_point],[0,1],pen=self.dash)
		if self.alphacheck == 1:
			self.text = TextItem(html='<span style="color: #1034A6; font-size: 16pt;">\u03b1</span></div>', anchor=(0.5,1.5))
			self.p3.addItem(self.text)
			self.arrow = ArrowItem(pos=(glo_var.alpha,0),angle=-90)
			self.p3.addItem(self.arrow)
			self.alphacheck=0
		self.text.setPos(glo_var.alpha,0)
		self.arrow.setPos(glo_var.alpha,0)

		self.make_right_axis()
		self.set_range()
		if self.jpost < 0.1:
			self.set_range()

	def legend(self):
		self.p3.plot(pen=self.jpen, name='J')
		self.p3.plot(pen=self.rho_dash, name='\u27e8\u2374\u27e9')

	def updateview(self):
		self.p3_2.setGeometry(self.p3.vb.sceneBoundingRect())
		self.p3_2.linkedViewChanged(self.p3.vb, self.p3_2.XAxis)

	def make_right_axis(self):
		self.p3_2.addItem(PlotCurveItem(self.alphas_pre,self.rho_avg_pre,pen=self.rho_dash))
		self.p3_2.addItem(PlotCurveItem(self.alphas_post,self.rho_avg_post,pen=self.rho_dash))

	def trans_func(self, point):
		if point >= glo_var.beta_star:
			return glo_var.alpha_star
		self.B = point*(self.lambda_1 - point)/(self.lambda_1 + (glo_var.l -1) * point)
		self.trans_b = - self.lambda_0 +(glo_var.l-1)*self.B
		self.trans_intercal = 0 if pow(self.trans_b,2) - 4*self.B*self.lambda_0 < 0.00001 else sqrt(pow(self.trans_b,2) - 4*self.B*self.lambda_0)
		self.trans = (-self.trans_b - self.trans_intercal)/2
		return self.trans

	def cal_rho(self,jval):
		self.xperlambdas = round(150/glo_var.lambdas_degree)
		self.rhointercal=[]
		self.rho_l = []
		self.rho_r = []
		for lambda_x in self.rh.lambdas_yval:
			if lambda_x !=0:
				self.intercal1 = 1/(2*self.l) + jval*(self.l-1)/(2*self.l*lambda_x)
				self.intercal2 = pow(1/(2*self.l) + jval*(self.l-1)/(2*self.l*lambda_x),2) - jval/(self.l*lambda_x)
				self.rhointercal+=[(self.intercal1,self.intercal2)]
			else:
				print('lambda_x cannot be 0')
		for x,y in self.rhointercal:
			self.inter_y=sqrt(0 if y < 0.000001 else y)
			self.rho_l += [x - self.inter_y] 
			self.rho_r += [x + self.inter_y]
		self.plot_scat(self.rh.scat_step)
		return sum(self.scat_ys)/len(self.scat_ys)

	def check_two_mins(self):
		self.minlocation = []
		self.maxlocation = []
		counter=0
		
		for i in self.lambdas_ys:
			if i == self.lambda_min:
				self.minlocation+=[counter]
			counter += 1
		num=len(self.minlocation)
		if num > 1:
			for j in range(num - 1):
				val = max(self.lambdas_ys[self.minlocation[j]:self.minlocation[j+1]])
				self.maxlocation += [self.lambdas_ys.index(val,self.minlocation[j])]
		return num

	def plot_scat(self,steps):
		self.num_mins = self.check_two_mins()
		self.scat_ys = []
		self.scat_xs = []
		if self.region == 3:
			if self.num_mins > 1:
				self.index1 = self.minlocation[0]*self.xperlambdas
				self.scat_xs += self.getscatarray(self.rh.lambdas_xval[:self.index1],steps)
				self.scat_ys += self.getscatarray(self.rho_r[:self.index1],steps)
				for i in range(1, self.num_mins):
					self.index1 = self.minlocation[i - 1]*self.xperlambdas
					self.index2 = self.minlocation[i]*self.xperlambdas
					self.indexmax = self.maxlocation[i - 1]*self.xperlambdas
					self.scat_xs += self.getscatarray(self.rh.lambdas_xval[self.index1:self.indexmax],steps)
					self.scat_ys += self.getscatarray(self.rho_l[self.index1:self.indexmax],steps)
					self.scat_xs += self.getscatarray(self.rh.lambdas_xval[self.indexmax:self.index2],steps)
					self.scat_ys += self.getscatarray(self.rho_r[self.indexmax:self.index2],steps)
				self.scat_xs += self.getscatarray(self.rh.lambdas_xval[self.index2:],steps)
				self.scat_ys += self.getscatarray(self.rho_l[self.index2:],steps)

			else :
				self.index = self.minlocation[0]*self.xperlambdas
				self.scat_xs += self.getscatarray(self.rh.lambdas_xval[:self.index],steps) + self.getscatarray(self.rh.lambdas_xval[self.index:],steps)
				self.scat_ys += self.getscatarray(self.rho_r[:self.index],steps) + self.getscatarray(self.rho_l[self.index:],steps)

		elif self.region == 2:
			self.scat_xs = self.getscatarray(self.rh.lambdas_xval,steps)
			self.scat_ys = self.getscatarray(self.rho_r,steps)
		else:
			self.scat_xs = self.getscatarray(self.rh.lambdas_xval,steps)
			self.scat_ys = self.getscatarray(self.rho_l,steps)



	def getscatarray(self,array,step):
		return array[::step]

	def js(self, alpha, beta):
		# LD 1, HD 2, MC 3 
		if beta >= self.beta_star:
			if alpha <= self.alpha_star:
				self.region = 1
				return alpha*(self.lambda_0-alpha)/(self.lambda_0+(self.l-1)*alpha)
			else :
				self.region = 3
				return self.lambda_min/pow((1+sqrt(self.l)),2)
		elif beta < self.beta_star:
			if alpha < self.alpha_star:
				self.jl = alpha*(self.lambda_0-alpha)/(self.lambda_0+(self.l-1)*alpha)
				self.jr = beta*(self.lambda_1-beta)/(self.lambda_1+(self.l-1)*beta)
				if self.jl <= self.jr:
					self.region = 1 
					return self.jl
				else :
					self.region = 2
					return self.jr
			else :
				self.region = 2
				return beta*(self.lambda_1-beta)/(self.lambda_1+(self.l-1)*beta)

	def value_declaration(self):
		self.lambdas_xs, self.lambdas_ys = zip(*sorted(glo_var.lambdas))
		self.lambda_min = min(self.lambdas_ys)
		self.lambda_0 = glo_var.lambdas[0][1]
		self.lambda_1 = glo_var.lambdas[-1][1]
		self.j_c = self.lambda_min/pow(1 + sqrt(glo_var.l),2)
		self.j_r = glo_var.beta*(self.lambda_1-glo_var.beta)/(self.lambda_1 + (glo_var.l-1)*glo_var.beta)
		self.alpha_star = glo_var.alpha_star
		self.beta_star = glo_var.beta_star
		self.alpha=glo_var.alpha
		self.beta=glo_var.beta
		self.l=glo_var.l
		self.alphacheck = 1
		self.transcheck = 1




	def plot_sum_rho(self):
		self.basic_1 = 1/(2*glo_var.l)
		self.basic_2 = (glo_var.l - 1)/pow((1+sqrt(glo_var.l)),2)
		self.inter_sum = 0
		self.rho_sum=[]
		self.domain = np.concatenate((self.alphas_pre,self.alphas_post))
		for i in self.domain:
			self.j_inter=self.js(i,glo_var.beta)
			if self.region == 1:
				for j in range(self.rh.min_location_1):
					self.inter_cal =  pow((self.basic_1 + self.j_inter*self.basic_2),2) - self.j_inter/(glo_var.l*self.lambdas_ys[j]) 
					self.inter_sum -=  0 if self.inter_cal < 0.0001 else sqrt(self.inter_cal) 
				
				for q in range(self.rh.min_location_1,glo_var.lambdas_degree):
					self.inter_cal =  pow((self.basic_1 + self.j_inter*self.basic_2),2) - self.j_inter/(glo_var.l*self.lambdas_ys[q]) 
					self.inter_sum +=  0 if self.inter_cal < 0.0001 else sqrt(self.inter_cal) 
			else :
				for j in range(self.rh.min_location_1):
					self.inter_cal =  pow((self.basic_1 + self.j_inter*self.basic_2),2) - self.j_inter/(glo_var.l*self.lambdas_ys[j]) 
					self.inter_sum +=  0 if self.inter_cal < 0.0001 else sqrt(self.inter_cal) 
				
				for q in range(self.rh.min_location_1,glo_var.lambdas_degree):
					self.inter_cal =  pow((self.basic_1 + self.j_inter*self.basic_2),2) - self.j_inter/(glo_var.l*self.lambdas_ys[q]) 
					self.inter_sum -=  0 if self.inter_cal < 0.0001 else sqrt(self.inter_cal)

			self.rho_sum += [self.basic_1 + self.j_inter*self.basic_2 +pow(-1,self.region == 1) * self.inter_sum/glo_var.lambdas_degree]
			self.inter_sum = 0
Ejemplo n.º 12
0
class SpectraPlotWidget(PlotWidget):
    sigEnergyChanged = Signal(object)

    def __init__(self, *args, **kwargs):
        super(SpectraPlotWidget, self).__init__(*args, **kwargs)
        self._data = None
        self.positionmap = dict()
        self.wavenumbers = None
        self._meanSpec = True # whether current spectrum is a mean spectrum
        self.line = InfiniteLine(movable=True)
        self.line.setPen((255, 255, 0, 200))
        self.line.setZValue(100)
        self.line.sigPositionChanged.connect(self.sigEnergyChanged)
        self.line.sigPositionChanged.connect(self.getEnergy)
        self.addItem(self.line)
        self.getViewBox().invertX(True)
        self.selectedPixels = None
        self._y = None

    def 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 = 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.setHtml(txt_html)

    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('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:
            self.clear()
            self._meanSpec = False
            self.spectrumInd = i
            self.plot(self.wavenumbers, self._data[i])

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

    def showMeanSpectra(self):
        self._meanSpec = True
        self.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)
        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 = max(y)
        self._y = y
        self.txt.setPos(1500, 0.95 * ymax)
        self.addItem(self.txt)
Ejemplo n.º 13
0
    def update_peak_finding(self):
        try:
            if len(self.raw_datas) != 0:
                peak_options = []

                for channel in self.filenames:

                    opts = dict([])
                    for child in self.settings.child(('peak_options')):
                        if child.child(('channel')).value() == channel:
                            children = [
                                ch.name() for ch in child.children()
                                if not (ch.name() == 'use_opts'
                                        or ch.name() == 'channel')
                            ]
                            if child.child(('use_opts')).value():
                                param_opt = child.child((children[0]))
                                opts[param_opt.name()] = param_opt.value()
                    if len(opts) != 0:
                        peak_options.append(dict(channel=channel, opts=opts))

                self.peak_indexes = []
                self.peak_amplitudes = []
                if len(peak_options) != 0:
                    for option in peak_options:
                        peak_indexes, properties = find_peaks(
                            self.raw_datas[option['channel']],
                            **option['opts'])
                        self.peak_indexes.extend(list(peak_indexes))
                        self.peak_amplitudes.extend(
                            list(self.raw_datas[option['channel']]
                                 [peak_indexes]))

                    self.peak_indexes = np.array(self.peak_indexes)
                    self.peak_amplitudes = np.array(self.peak_amplitudes)

                    arg_sorted_indexes = np.argsort(self.peak_indexes)

                    self.peak_indexes = self.peak_indexes[arg_sorted_indexes]
                    self.peak_amplitudes = self.peak_amplitudes[
                        arg_sorted_indexes]

                    if len(self.peak_indexes) != 0:
                        self.viewer_data.viewer.plotwidget.plotItem.removeItem(
                            self.plot_peak_item)
                        while len(self.text_peak_items) != 0:
                            self.viewer_data.viewer.plotwidget.plotItem.removeItem(
                                self.text_peak_items.pop(0))
                            self.viewer_data.viewer.plotwidget.plotItem.removeItem(
                                self.arrow_peak_items.pop(0))

                        self.plot_peak_item = self.viewer_data.viewer.plotwidget.plot(
                            self.raw_axis[self.peak_indexes],
                            self.peak_amplitudes,
                            pen=None,
                            symbol='+')

                        for ind, peak_index in enumerate(self.peak_indexes):
                            item = TextItem('({:.00f},{:.02f})'.format(
                                self.raw_axis[peak_index],
                                self.peak_amplitudes[ind]),
                                            angle=45,
                                            color='w',
                                            anchor=(0, 1))
                            size = self.viewer_data.viewer.plotwidget.plotItem.vb.itemBoundingRect(
                                item)
                            item.setPos(
                                self.raw_axis[peak_index],
                                self.peak_amplitudes[ind] + size.height())
                            self.text_peak_items.append(item)

                            item_ar = ArrowItem(
                                pos=(self.raw_axis[peak_index],
                                     self.peak_amplitudes[ind] +
                                     size.height() / 5),
                                angle=-90,
                                tipAngle=30,
                                baseAngle=20,
                                headLen=10,
                                tailLen=20,
                                tailWidth=1,
                                pen=None,
                                brush='w')
                            self.arrow_peak_items.append(item_ar)
                            self.viewer_data.viewer.plotwidget.plotItem.addItem(
                                item)
                            self.viewer_data.viewer.plotwidget.plotItem.addItem(
                                item_ar)

                        self.table_model = PandasModel(
                            pd.DataFrame([[False, ind, 0]
                                          for ind in self.peak_indexes],
                                         columns=[
                                             'Use', 'Pxl',
                                             self.settings.child(
                                                 'fit_options',
                                                 'fit_units').value()
                                         ]))
                        self.settings.child(
                            ('peaks_table')).setValue(self.table_model)
        except Exception as e:
            logger.exception(str(e))
Ejemplo n.º 14
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))
Ejemplo n.º 15
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))
Ejemplo n.º 16
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))
Ejemplo n.º 17
0
class ClusterSpectraWidget(SpectraPlotWidget):
    def __init__(self):
        super(ClusterSpectraWidget, self).__init__(txtPosRatio=0.35)
        self._x = None
        self.ymax, self.zmax = 0, 100
        self._plots = []

    def getEnergy(self):
        if self._y is not None:
            x_val = self.line.value()
            idx = val2ind(x_val, self._x)
            x_val = self._x[idx]
            y_val = self._y[idx]
            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 setColors(self, colorLUT):
        self.colorLUT = colorLUT.copy()
        # self.colorLUT[0, :] = np.ones(3) * 255

    def plotClusterSpectra(self):
        if self._data is not None:
            if self._plots:
                self.clearAll()
                self._plots = []
            self.ymax = 0
            self.plotItem.addLegend(offset=(1, 1))
            self.nSpectra = len(self._data)
            for i in range(self.nSpectra):
                name = 'Cluster #' + str(i + 1)
                tmp = self.plot(self.wavenumbers,
                                self._data[i],
                                pen=mkPen(self.colorLUT[i + 1], width=2),
                                name=name)
                tmp.curve.setClickable(True)
                tmp.curve.sigClicked.connect(partial(self.curveHighLight, i))
                self._plots.append(tmp)
            self.addItem(self.txt)

    def curveHighLight(self, k):
        for i in range(self.nSpectra):
            if i == k:
                self._plots[i].setPen(mkPen(self.colorLUT[k + 1], width=6))
                self._plots[i].setZValue(50)
            else:
                self._plots[i].setPen(mkPen(self.colorLUT[i + 1], width=2))
                self._plots[i].setZValue(0)
        self._x, self._y = self._plots[k].getData()
        ymin, ymax = np.min(self._y), np.max(self._y)
        self.getViewBox().setYRange(ymin, ymax, padding=0.1)
        r = self.txtPosRatio
        self.txt.setPos(r * self._x[-1] + (1 - r) * self._x[0], ymax)
        self.getEnergy()

    def plot(self, x, y, *args, **kwargs):
        # set up infinity line and get its position
        plot_item = self.plotItem.plot(x, y, *args, **kwargs)
        self.addItem(self.line)
        self.addItem(self.cross)
        x_val = self.line.value()
        idx = val2ind(x_val, x)
        x_val = x[idx]
        y_val = y[idx]
        txt_html = toHtml(f'X = {x_val: .2f}, Y = {y_val: .4f}')
        self.txt = TextItem(html=txt_html, anchor=(0, 0))
        self.txt.setZValue(self.zmax - 1)
        self.cross.setData([x_val], [y_val])
        self.cross.setZValue(self.zmax)
        ymax = np.max(y)
        if ymax > self.ymax:
            self.ymax = ymax
        self._x, self._y = x, y
        r = self.txtPosRatio
        self.txt.setPos(r * x[-1] + (1 - r) * x[0], self.ymax)
        return plot_item
Ejemplo n.º 18
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()
Ejemplo n.º 19
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
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)
Ejemplo n.º 21
0
class FanDiagram(QtGui.QWidget):
    """
    Produces a fan diagram
    alphas/gammas should be the matrices saved from the FanCompiler, of form:

    arb     | niralpha1 | niralpha2 | niralpha3 | niralpha4 | ...
    1st sb  | 1sb alpha | 1sb alpha |     .
    2nd sb  | 2sb alpha | 2sb alpha |     .
    3rd sb  | 3sb alpha | 3sb alpha |     .
      .
      .
      .

    Assumes both alphas/gammas are the same shape

    Alternatively, pass nirAlpha and SBs as 1st/2nd args (as 1D arrays) to have it
    create the fan without any data

    Or, if alphaData and gammaData are strings, assumes they're paths to data files to plot
    :param alphas:
    :param gammas:
    :param kwargs:
    :return:
    """
    def __init__(self, alphaData, gammaData=None, view=None):
        super(FanDiagram, self).__init__()
        if gammaData is None and isinstance(alphaData, FanCompiler):
            alphaData, gammaData = alphaData.build(withErrors=False)[:2]

        self.layout = QtWidgets.QHBoxLayout()

        self.histAlpha = HistogramLUTWidget(self)
        self.centralView = GraphicsView()
        self.histGamma = HistogramLUTWidget(self)

        self.histAlpha.setMinimumWidth(150)
        self.histGamma.setMinimumWidth(150)

        self.layout.addWidget(self.histGamma)
        self.layout.addWidget(self.centralView)
        self.layout.addWidget(self.histAlpha)
        self.layout.setContentsMargins(0,0,0,0)
        self.layout.setSpacing(0)
        self.setLayout(self.layout)

        if view is None:
            self.view = ViewBox()
        else:
            self.view = view


        self.centralView.setCentralItem(self.view)
        self.view.setAspectLocked(True)
        self.view.invertY(True)

        if isinstance(alphaData, str) and isinstance(gammaData, str):
            alphaData = np.genfromtxt(alphaData, delimiter=',')
            gammaData = np.genfromtxt(gammaData, delimiter=',')

        if alphaData.ndim == gammaData.ndim == 1:
            # Assume you just want it to be created, and will later populate it
            nirAlphas = alphaData
            sbs = gammaData

            alphaData = np.ones((sbs.shape[0] + 1, nirAlphas.shape[0] + 1)) * -1
            alphaData[1:, 0] = sbs
            alphaData[0, 1:] = nirAlphas

            gammas = np.ones((sbs.shape[0] + 1, nirAlphas.shape[0] + 1)) * -1
            gammas[1:, 0] = sbs
            gammas[0, 1:] = nirAlphas

        sbs = alphaData[1:, 0]
        maxSB = sbs.max()
        nirAlphas = alphaData[0, 1:]


        self.alphaItem = PolarImageItem(r=sbs, theta=nirAlphas)
        self.alphaItem.setImage(alphaData[1:,1:])
        # nirAlphas+180 is what causes the gamma angles to appear on the left side of the
        # fan. This seemed easier than doing some sort of coordinate inversion/flipping
        # on the plot itself.
        self.gammaItem = PolarImageItem(sbs, nirAlphas+180, gammaData[1:,1:])

        self.view.addItem(self.alphaItem)
        self.view.addItem(self.gammaItem)

        self.histAlpha.setImageItem(self.alphaItem)
        self.histGamma.setImageItem(self.gammaItem)

        # manually set the default state to the black-gold-white-green-black. Not sure
        # if it's necessary to have this be a free parameter vs being hardcoded
        self.histAlpha.gradient.restoreState({
            "mode": "rgb",
            "ticks": [
                (0, (0, 0, 0, 255)),
                (.25, (128, 128, 0, 255)),
                (.5, (255, 255, 255, 255)),
                (.75, (0, 128, 0, 255)),
                (1, (0, 0, 0, 255))
            ]
        })

        # Set the default spacings for the alpha color axis. Again, not sure if it's
        # better to leave the 18pt font hard-coded or not, but I am
        self.histAlpha.axis.setTickFont(QtGui.QFont("Arial", 18))
        self.histAlpha.axis.setTickSpacing(30, 15)
        self.histAlpha.axis.setLabel("&alpha; (&deg;)", **{'font-family': 'Times',
                                                           "font-size":  "18pt"})

        # As with alpha, hard code the initial color space for gamma (blue-white-red)
        # and the font spacings and stuff
        self.histGamma.gradient.restoreState({
            "mode": "rgb",
            "ticks": [
                (0, (255, 0, 0, 255)),
                (.5, (255, 255, 255, 255)),
                (1, (0, 0, 255, 255))
            ]
        })
        self.histGamma.axis.setTickFont(QtGui.QFont("Arial", 18))
        self.histGamma.axis.setTickSpacing(15, 15)
        self.histGamma.axis.setLabel("&gamma; (&deg;)", **{'font-family': 'Times',
                                                           "font-size":  "18pt"})

        self.histAlpha.item.setLevels(-90, 90)
        self.histGamma.item.setLevels(-45, 45)

        self.histAlpha.autoHistogramRange()
        self.histGamma.autoHistogramRange()

        # Make it the right dimensions, making sure that the width is appropriate.
        # This makes it easier to automate plotting/saving fans and making sure
        # their dimensions are consistent.
        g = self.geometry()
        # I found these by eye, there's not very much important about them
        g.setWidth(773)
        g.setHeight(480)
        # Manually center it on the screen, since geometry isn't well defined at this point
        # before events are processed
        g.moveCenter(QtWidgets.QApplication.desktop().screenGeometry().center())
        self.setGeometry(g)

        # Add in the radial axes for it
        self.axes = {
            "radial": PolarAxis("radial"),
            "azimuthal": PolarAxis("azimuthal")
        }
        # Lighten the radial font to make it distinct from the other
        p = self.axes["radial"].pen()
        p.setColor(mkColor("#666666"))
        self.axes["radial"].setPen(p)

        for a in self.axes.values():
            # Make sure the axes sit on top of all other items
            a.setZValue(10000)
            # make sure that they scale appropriately, instead of just floating on top
            a.linkToView(self.view)
            # Ignore bounds prevents the window from resizing to try and fit in
            # the axes items
            self.addItem(a, ignoreBounds=True)

        # manually set the positions and string values for alpha angles. [-90, 90] work
        # well. The other half needs the +-180 to make sure the gamma angles have the
        # correctly labeled with respect to alpha_nir
        self.axes["azimuthal"].setTicks(
            [
                [(ii, str(ii)) for ii in np.arange(-90, 91, 30)] + # alpha side (Q1+Q4)
                [(ii, str(ii + 180)) for ii in np.arange(-180, -91, 30)] + #Q3
                [(ii, str(ii - 180)) for ii in np.arange(120, 151, 30)], #Q1
            ]
        )

        # add a title (without text)
        self.titleItem = TextItem()
        self.titleItem.setAnchor(Point(0.5, 1)) # anchor on bottom-center
        # Again, not sure if it's necessary to have the font color/size being
        # a free parameter
        self.titleItem.setColor("k")
        self.titleItem.setFont(QtGui.QFont("Arial", 15))
        # Ignore bounds so that the view won't try to account for it (which
        # causes a conflict because the title is placed with respect to the
        # view region)
        self.view.addItem(self.titleItem, ignoreBounds=True)
        
        self.show()
        # Arbitrary forcing updates to try and track down why some things don't
        # update correctly
        QtWidgets.QApplication.processEvents()
        self.view.updateViewRange(True, True)

    def setAlphaImage(self, img):
        self.alphaItem.setImage(img)

    def setGammaImage(self, img):
        self.gammaItem.setImage(img)

    def setImages(self, alpha, gamma):
        self.setAlphaImage(alpha)
        self.setGammaImage(gamma)

    def export(self, fname, hideHistograms=True,
               pngScale = 4):
        """
        Save fan diagrams to file, with the full image, and color bars on the alpha/gamma
        values
        :param fname: the fname to save as
        hideHistograms - (True) Prevent rendering the histograms, often ncier for
            figures/presentations

        If fname.endswith(".svg"), it outputs as an SVG. Howver, it's not the cleanest
            thing (the files are quite large/unoptimized, and I can't think of an
            easy way to correct that). Also, when the svg is converted to pdf via
            Inkscape, things get f****d up for some reasons (axes get thicker, fonts
            get borked, pixels get messed up). So, it kinda works, but there's
            stuff seriously wrong.

        One thing to make things cleaner is to use this site:
            https://jakearchibald.github.io/svgomg/
        which optimizies the svg and makes it a lot easier to work with
        :return:
        """

        # defaults = {
        #     "hideHistograms": False
        # }
        #
        # defaults.update(kwargs)

        doSvg = fname.endswith(".svg")

        if hideHistograms:
            # Hide the histogram data (and shrink the plot)
            # to avoid confusing people
            self.histAlpha.plot.hide()
            self.histAlpha.vb.setMaximumWidth(20)
            self.histGamma.plot.hide()
            self.histGamma.vb.setMaximumWidth(20)


        QtWidgets.QApplication.processEvents()

        self.histGamma.axis.setRange(-46.75, 46.75)
        self.histAlpha.axis.setRange(-94, 94)
        width, height = self.width(), self.height()


        if doSvg:
            from PyQt5 import QtSvg
            outputImage = QtSvg.QSvgGenerator()
            outputImage.setFileName(fname)
            outputImage.setSize(QtCore.QSize(int(width), int(height)))
            # I'm not sure why it has to be this, but the axis on the histogrm
            # were fuckingup without it
            outputImage.setResolution(96)
        else:
            outputImage = QtGui.QImage(width * pngScale, height * pngScale,
                                       QtGui.QImage.Format_ARGB32)
            # outputImage.setDotsPerMeterX(650 * 100 / 2.54)
            # outputImage.setDotsPerMeterY(650 * 100 / 2.54)
            # this gives a moderatly high quality image
            outputImage.setDevicePixelRatio(pngScale)
            outputImage.fill(QtGui.QColor("white"))

        outputPainter = QtGui.QPainter(outputImage)

        self.render(outputPainter)

        if not doSvg:
            ret = outputImage.save(fname)

        outputPainter.end()

    def addItem(self, item, ignoreBounds=False):
        self.view.addItem(item, ignoreBounds)

    def setViewRadius(self, r):
        # Set the view range of the fan diagram such that radius r is visible
        self.view.setRange(QtCore.QRect(-r, -r, 2*r, 2*r), padding=0)

    def hideHistogramAxes(self, hideTicks=True):
        # Hide the histogram region item and plots and all that for
        # less cluttered plots. Definitely useful if export is called with
        # hideHistograms=True, where the regions are useless.

        # Hide the linear regions
        self.histGamma.region.hide()
        self.histAlpha.region.hide()
        # Keep a reference to the old paint methods so you can reverse it if desired
        # This stops the painting of the bars which go from the linear region to the
        # gradient editor
        self.histGamma.item.oldPaint = self.histGamma.item.paint
        self.histAlpha.item.oldPaint = self.histAlpha.item.paint
        # Overwriting the functions to return None causes all the other rendering
        # things to abort
        self.histGamma.item.paint = lambda *x: None
        self.histAlpha.item.paint = lambda *x: None

        if hideTicks:
            # Hide the ticks which can be used for changing the stops/colors of
            # the gradients, which are rather ugly
            # Note: Since this only hides ticks which are present, I don't think
            [ii.hide() for ii in self.histAlpha.item.gradient.ticks.keys()]
            [ii.hide() for ii in self.histGamma.item.gradient.ticks.keys()]

        QtWidgets.QApplication.processEvents()
        # Hard coded numbers which make it look like the axes values line up with
        # the gradient item, which is more in-line with how color bars are interpreted
        self.histGamma.axis.setRange(-46.75, 46.75)
        self.histAlpha.axis.setRange(-94, 94)

    def showHistogramAxes(self, showTicks=True):
        try:
            self.histGamma.item.paint = self.histGamma.item.oldPaint
            self.histAlpha.item.paint = self.histAlpha.item.oldPaint
            del self.histAlpha.item.oldPaint
            del self.histGamma.item.oldPaint
        except AttributeError:
            # You didn't hide them first (or at least not here
            return
        self.histGamma.region.show()
        self.histAlpha.region.show()


        if showTicks:
            [ii.show() for ii in self.histAlpha.item.gradient.ticks.keys()]
            [ii.show() for ii in self.histGamma.item.gradient.ticks.keys()]

    @staticmethod
    def fromTMatrix(tMatrix, angle = 45, sbs=None):
        """
        Create a fan diagram from T matrices directly. The angle needs to be specified
        so the T matrix can be converted to a J matrix. The angle is relative to what's
        specified in the qwp.extractMatrices.makeU function.

        if you pass a string, it assumes it's a file name from a saved one. It'll load
        that and plot it. If you also pass values to sbs, it'll make sure only the passed
        values are plotted. Otherwise, it'll plot all the sbs in the file

        If you pass a tMatrix as returned from the fitting routines, you also need
        to pass the sbs directly in this case, since the tMatrices don't include them.
        :param tMatrix:
        :param angle:
        :param sbs:
        :return:
        """
        if isinstance(tMatrix, str):
            # a file is passed
            if sbs is not None:
                # Pass an array of sbs with a string, and this'll parse
                # out the sidebands which aren't included in  the passed array
                wantsbs = sbs
            else:
                wantsbs = None
            tMatrix, sbs = loadT(tMatrix)
            # Handle if only a select number of sidebands is specified
            if wantsbs is not None:
                try:
                    # Find the indices of the desired sidebands within the array of
                    # sidebands actually loaded
                    wantIdx = [sbs.tolist().index(ii) for ii in wantsbs]
                    # Cull it to only those specified
                    sbs = sbs[wantIdx]
                    # tMatrix is multidimensional (tMatrix.ndim>2), so ellipses cut
                    # out the other axes
                    tMatrix = tMatrix[..., wantIdx]
                    # Ensure that you got everything you want. Could happen if sidebands
                    # are requested (passed to the function) and not found
                    assert np.all(wantsbs == sbs)
                except ValueError as e:
                    raise IndexError("Invalid sideband requested ({} is not in loaded)".format(
                        e.args[0].split(' ')[0]
                    ))
                except AssertionError:
                    raise IndexError("Invalid sideband requested")


        jMatrix = makeJfromT(tMatrix, angle)
        if sbs is None:
            raise RuntimeWarning("Desired sidebands to plot should be specified as kwarg sbs")
            sbs = np.arange(8, 38, 2)

        alpha, gamma = jonesToFans(sbs = sbs, J=jMatrix)
        return FanDiagram(alpha, gamma)

    def setTitle(self, title="", adjustBounds=True):
        """
        Sets the title of the fan diagram, positioning the text right above the center
        of the fan
        :param title:
        :param adjustBounds:
        :return:
        """
        self.titleItem.setText(title)

        # Move the title so the bottom is at the top of the outer axis
        self.titleItem.setPos(0, self.axes["azimuthal"].fullBoundingRect.top())
        QtWidgets.QApplication.processEvents()
        # Double up because of some weird f*****g issue with Qt not appropriately
        # updating things when requested
        self.titleItem.setPos(0, self.axes["azimuthal"].fullBoundingRect.top())
        QtWidgets.QApplication.processEvents()
        # print(self.titleItem.mapRectToView(self.titleItem.boundingRect()))

        if adjustBounds:
            # Readjust the viewbox to frame the fan better

            # Find the top, based on the coordinates of the top of the title
            top = self.titleItem.mapRectToView(self.titleItem.boundingRect()).top()
            # Bottom is defiend by the bottom of the axes (includes the text)
            # Note: this assumes the
            bottom = self.axes["azimuthal"].fullBoundingRect.bottom()
            # print("bottom", bottom)
            w = abs(top-bottom)
            # print("new rect", QtCore.QRectF(-w/2, top, w, w))
            self.view.setRange(QtCore.QRectF(-w/2, top, w, w), padding=0)
            self.view.setRange(QtCore.QRectF(-w/2, top, w, w), padding=0)
            # self.view.update()

    def setMaxRadius(self, radius=40):
        # Set the maximum value for both of the axes to the value specified.
        # The 1e-6 is to prevent it from producing an "r=0" label and stuff
        self.axes["azimuthal"]._bounds["radial"] = [1e-6, radius]
        self.axes["radial"]._bounds["radial"] = [1e-6, radius]

        # Need to invalidate the cache for the axes, forcing it to redraw and update
        # the bounding rect and stuff
        self.axes["azimuthal"].picture = None
        self.axes["radial"].picture = None
Ejemplo n.º 22
0
    def setNewTraces(self, waveform_traces, plot_event):
        """
        Function for scaling and plotting waveform traces
        """
        self.plot_widget.getPlotItem().clear()

        offset = 0
        first_event_timestamp = None
        pick_dict = {}

        for pick in plot_event.data:
            if pick.station_code not in pick_dict:
                pick_dict[pick.station_code] = []

            pick_dict[pick.station_code].append(pick)

        for key in waveform_traces.keys():
            for tr in waveform_traces[key]:
                if first_event_timestamp is None:
                    first_event_timestamp = tr.stats['starttime']
                elif first_event_timestamp > tr.stats['starttime']:
                    first_event_timestamp = tr.stats['starttime']

        for key in waveform_traces.keys():
            for tr in waveform_traces[key]:
                tr_filter = self.filter_stats.getCurrentFilter()
                tr_copy = filterTrace(tr_filter, tr)

                data_array = tr_copy.data
                time_array = tr_copy.times()
                time_offset = tr_copy.stats['starttime'] - first_event_timestamp

                min_value = numpy.amin(data_array)
                max_value = numpy.amax(data_array) - min_value
                data_array = ((data_array - min_value) / max_value) - offset

                time_array += time_offset

                self.plot_widget.getPlotItem().plot(time_array,
                                                    data_array,
                                                    pen=self.plot_pen)
                channel_text_item = TextItem("{0} - {1}".format(
                    key, tr.stats['channel']))
                self.plot_widget.getPlotItem().addItem(channel_text_item)
                channel_text_item.setPos(-20, 0.5 - offset)
                offset += 1

            if key in pick_dict:
                for pick in pick_dict[key]:
                    if pick.phase_type[0] not in ['S', 'P', 'M']:
                        continue

                    tr_size = len(waveform_traces[key])
                    time_pos = UTCDateTime(
                        pick.observation_time) - first_event_timestamp

                    if pick.phase_type[0] == 'S':
                        pick_pen = self.s_pick_pen
                    elif pick.phase_type[0] == 'P':
                        pick_pen = self.p_pick_pen
                    else:
                        pick_pen = self.msg_pick_pen

                    pick_bar = ErrorBarItem(
                        x=numpy.array([time_pos]),
                        y=numpy.array([float(tr_size) / 2 - offset + 1]),
                        height=tr_size,
                        pen=pick_pen)

                    pick_text = TextItem(pick.phase_type,
                                         color=pick_pen.color())
                    self.plot_widget.getPlotItem().addItem(pick_bar)
                    self.plot_widget.getPlotItem().addItem(pick_text)
                    pick_text.setPos(time_pos, 1.1 + tr_size - offset)