def minLabelDist(self, font): if not self.hasComponent(QwtAbstractScaleDraw.Labels): return 0 ticks = self.scaleDiv().ticks(QwtScaleDiv.MajorTick) if not ticks: return 0 fm = QFontMetrics(font) vertical = self.orientation() == Qt.Vertical bRect1 = QRectF() bRect2 = self.labelRect(font, ticks[0]) if vertical: bRect2.setRect(-bRect2.bottom(), 0., bRect2.height(), bRect2.width()) maxDist = 0. for tick in ticks: bRect1 = bRect2 bRect2 = self.labelRect(font, tick) if vertical: bRect2.setRect(-bRect2.bottom(), 0., bRect2.height(), bRect2.width()) dist = fm.leading() if bRect1.right() > 0: dist += bRect1.right() if bRect2.left() < 0: dist += -bRect2.left() if dist > maxDist: maxDist = dist angle = qwtRadians(self.labelRotation()) if vertical: angle += np.pi/2 sinA = np.sin(angle) if qFuzzyCompare(sinA+1., 1.): return np.ceil(maxDist) fmHeight = fm.ascent()-2 labelDist = fmHeight/np.sin(angle)*np.cos(angle) if labelDist < 0: labelDist = -labelDist if labelDist > maxDist: labelDist = maxDist if labelDist < fmHeight: labelDist = fmHeight return np.ceil(labelDist)
def qwtDrawStar1Symbols(painter, points, numPoints, symbol): size =symbol.size() painter.setPen(symbol.pen()) sqrt1_2 = np.sqrt(.5) r = QRectF(0, 0, size.width(), size.height()) for pos in points: r.moveCenter(pos.toPoint()) c = QPointF(r.center()) d1 = r.width()/2.*(1.-sqrt1_2) painter.drawLine(r.left()+d1, r.top()+d1, r.right()-d1, r.bottom()-d1) painter.drawLine(r.left()+d1, r.bottom()-d1, r.right()-d1, r.top()+d1) painter.drawLine(c.x(), r.top(), c.x(), r.bottom()) painter.drawLine(r.left(), c.y(), r.right(), c.y())
def renderItem(self, painter, widget, rect, fillBackground): """ Render a legend entry into a given rectangle. :param QPainter painter: Painter :param QWidget widget: Widget representing a legend entry :param QRectF rect: Bounding rectangle :param bool fillBackground: When true, fill rect with the widget background """ if fillBackground: if widget.autoFillBackground() or\ widget.testAttribute(Qt.WA_StyledBackground): QwtPainter.drawBackground(painter, rect, widget) label = widget #TODO: cast to QwtLegendLabel if label is not None: icon = label.data().icon() sz = icon.defaultSize() iconRect = QRectF(rect.x()+label.margin(), rect.center().y()-.5*sz.height(), sz.width(), sz.height()) icon.render(painter, iconRect, Qt.KeepAspectRatio) titleRect = QRectF(rect) titleRect.setX(iconRect.right()+2*label.spacing()) painter.setFont(label.font()) painter.setPen(label.palette().color(QPalette.Text)) label.drawText(painter, titleRect) #TODO: cast label to QwtLegendLabel
def colorBarRect(self, rect): """ Calculate the the rectangle for the color bar :param QRectF rect: Bounding rectangle for all components of the scale :return: Rectangle for the color bar """ cr = QRectF(rect) if self.__data.scaleDraw.orientation() == Qt.Horizontal: cr.setLeft(cr.left() + self.__data.borderDist[0]) cr.setWidth(cr.width() - self.__data.borderDist[1] + 1) else: cr.setTop(cr.top() + self.__data.borderDist[0]) cr.setHeight(cr.height() - self.__data.borderDist[1] + 1) sda = self.__data.scaleDraw.alignment() if sda == QwtScaleDraw.LeftScale: cr.setLeft(cr.right()-self.__data.margin-self.__data.colorBar.width) cr.setWidth(self.__data.colorBar.width) elif sda == QwtScaleDraw.RightScale: cr.setLeft(cr.left()+self.__data.margin) cr.setWidth(self.__data.colorBar.width) elif sda == QwtScaleDraw.BottomScale: cr.setTop(cr.top()+self.__data.margin) cr.setHeight(self.__data.colorBar.width) elif sda == QwtScaleDraw.TopScale: cr.setTop(cr.bottom()-self.__data.margin-self.__data.colorBar.width) cr.setHeight(self.__data.colorBar.width) return cr
def renderItem(self, painter, widget, rect, fillBackground): if fillBackground: if widget.autoFillBackground() or\ widget.testAttribute(Qt.WA_StyledBackground): QwtPainter.drawBackground(painter, rect, widget) label = widget #TODO: cast to QwtLegendLabel if label is not None: icon = label.data().icon() sz = icon.defaultSize() iconRect = QRectF(rect.x()+label.margin(), rect.center().y()-.5*sz.height(), sz.width(), sz.height()) icon.render(painter, iconRect, Qt.KeepAspectRatio) titleRect = QRectF(rect) titleRect.setX(iconRect.right()+2*label.spacing()) painter.setFont(label.font()) painter.setPen(label.palette().color(QPalette.Text)) label.drawText(painter, titleRect) #TODO: cast label to QwtLegendLabel
def setCornerRects(self, path): pos = QPointF(0., 0.) for i in range(path.elementCount()): el = path.elementAt(i) if el.type in (QPainterPath.MoveToElement, QPainterPath.LineToElement): pos.setX(el.x) pos.setY(el.y) elif el.type == QPainterPath.CurveToElement: r = QRectF(pos, QPointF(el.x, el.y)) self.clipRects += [r.normalized()] pos.setX(el.x) pos.setY(el.y) elif el.type == QPainterPath.CurveToDataElement: if self.clipRects: r = self.clipRects[-1] r.setCoords(min([r.left(), el.x]), min([r.top(), el.y]), max([r.right(), el.x]), max([r.bottom(), el.y])) self.clipRects[-1] = r.normalized()
def colorBarRect(self, rect): cr = QRectF(rect) if self.__data.scaleDraw.orientation() == Qt.Horizontal: cr.setLeft(cr.left() + self.__data.borderDist[0]) cr.setWidth(cr.width() - self.__data.borderDist[1] + 1) else: cr.setTop(cr.top() + self.__data.borderDist[0]) cr.setHeight(cr.height() - self.__data.borderDist[1] + 1) sda = self.__data.scaleDraw.alignment() if sda == QwtScaleDraw.LeftScale: cr.setLeft(cr.right()-self.__data.margin-self.__data.colorBar.width) cr.setWidth(self.__data.colorBar.width) elif sda == QwtScaleDraw.RightScale: cr.setLeft(cr.left()+self.__data.margin) cr.setWidth(self.__data.colorBar.width) elif sda == QwtScaleDraw.BottomScale: cr.setTop(cr.top()+self.__data.margin) cr.setHeight(self.__data.colorBar.width) elif sda == QwtScaleDraw.TopScale: cr.setTop(cr.bottom()-self.__data.margin-self.__data.colorBar.width) cr.setHeight(self.__data.colorBar.width) return cr
def qwtBoundingRectT(series, from_, to): boundingRect = QRectF(1.0, 1.0, -2.0, -2.0) if from_ < 0: from_ = 0 if to < 0: to = series.size() - 1 if to < from_: return boundingRect first_stage = True for i in range(from_, to + 1): rect = qwtBoundingRect(series.sample(i)) if rect.width() >= 0.0 and rect.height() >= 0.0: if first_stage: boundingRect = rect first_stage = False continue else: boundingRect.setLeft(min([boundingRect.left(), rect.left()])) boundingRect.setRight(max([boundingRect.right(), rect.right()])) boundingRect.setTop(min([boundingRect.top(), rect.top()])) boundingRect.setBottom(max([boundingRect.bottom(), rect.bottom()])) return boundingRect
def boundingRect(self): """ Calculate the bounding rectangle for a symbol at position (0,0). :return: Bounding rectangle """ rect = QRectF() pinPointTranslation = False if self.__data.style in (QwtSymbol.Ellipse, QwtSymbol.Rect, QwtSymbol.Hexagon): pw = 0. if self.__data.pen.style() != Qt.NoPen: pw = max([self.__data.pen.widthF(), 1.]) rect.setSize(self.__data.size+QSizeF(pw, pw)) rect.moveCenter(QPointF(0., 0.)) elif self.__data.style in (QwtSymbol.XCross, QwtSymbol.Diamond, QwtSymbol.Triangle, QwtSymbol.UTriangle, QwtSymbol.DTriangle, QwtSymbol.RTriangle, QwtSymbol.LTriangle, QwtSymbol.Star1, QwtSymbol.Star2): pw = 0. if self.__data.pen.style() != Qt.NoPen: pw = max([self.__data.pen.widthF(), 1.]) rect.setSize(QSizeF(self.__data.size)+QSizeF(2*pw, 2*pw)) rect.moveCenter(QPointF(0., 0.)) elif self.__data.style == QwtSymbol.Path: if self.__data.path.graphic.isNull(): self.__data.path.graphic = qwtPathGraphic( self.__data.path.path, self.__data.pen, self.__data.brush) rect = qwtScaleBoundingRect(self.__data.path.graphic, self.__data.size) pinPointTranslation = True elif self.__data.style == QwtSymbol.Pixmap: if self.__data.size.isEmpty(): rect.setSize(self.__data.pixmap.pixmap.size()) else: rect.setSize(self.__data.size) pinPointTranslation = True elif self.__data.style == QwtSymbol.Graphic: rect = qwtScaleBoundingRect(self.__data.graphic.graphic, self.__data.size) pinPointTranslation = True elif self.__data.style == QwtSymbol.SvgDocument: if self.__data.svg.renderer is not None: rect = self.__data.svg.renderer.viewBoxF() if self.__data.size.isValid() and not rect.isEmpty(): sz = QSizeF(rect.size()) sx = self.__data.size.width()/sz.width() sy = self.__data.size.height()/sz.height() transform = QTransform() transform.scale(sx, sy) rect = transform.mapRect(rect) pinPointTranslation = True else: rect.setSize(self.__data.size) rect.moveCenter(QPointF(0., 0.)) if pinPointTranslation: pinPoint = QPointF(0., 0.) if self.__data.isPinPointEnabled: pinPoint = rect.center()-self.__data.pinPoint rect.moveCenter(pinPoint) r = QRect() r.setLeft(np.floor(rect.left())) r.setTop(np.floor(rect.top())) r.setRight(np.floor(rect.right())) r.setBottom(np.floor(rect.bottom())) if self.__data.style != QwtSymbol.Pixmap: r.adjust(-1, -1, 1, 1) return r
def minLabelDist(self, font): """ Determine the minimum distance between two labels, that is necessary that the texts don't overlap. :param QFont font: Font :return: The maximum width of a label .. seealso:: :py:meth:`getBorderDistHint()` """ if not self.hasComponent(QwtAbstractScaleDraw.Labels): return 0 ticks = self.scaleDiv().ticks(QwtScaleDiv.MajorTick) if not ticks: return 0 fm = QFontMetrics(font) vertical = self.orientation() == Qt.Vertical bRect1 = QRectF() bRect2 = self.labelRect(font, ticks[0]) if vertical: bRect2.setRect(-bRect2.bottom(), 0., bRect2.height(), bRect2.width()) maxDist = 0. for tick in ticks: bRect1 = bRect2 bRect2 = self.labelRect(font, tick) if vertical: bRect2.setRect(-bRect2.bottom(), 0., bRect2.height(), bRect2.width()) dist = fm.leading() if bRect1.right() > 0: dist += bRect1.right() if bRect2.left() < 0: dist += -bRect2.left() if dist > maxDist: maxDist = dist angle = qwtRadians(self.labelRotation()) if vertical: angle += np.pi/2 sinA = np.sin(angle) if qFuzzyCompare(sinA+1., 1.): return np.ceil(maxDist) fmHeight = fm.ascent()-2 labelDist = fmHeight/np.sin(angle)*np.cos(angle) if labelDist < 0: labelDist = -labelDist if labelDist > maxDist: labelDist = maxDist if labelDist < fmHeight: labelDist = fmHeight return np.ceil(labelDist)
def activate(self, plot, plotRect, options=0x00): """ Recalculate the geometry of all components. :param qwt.plot.QwtPlot plot: Plot to be layout :param QRectF plotRect: Rectangle where to place the components :param options: Layout options """ self.invalidate() rect = QRectF(plotRect) self.__data.layoutData.init(plot, rect) if not (options & self.IgnoreLegend) and plot.legend() and\ not plot.legend().isEmpty(): self.__data.legendRect = self.layoutLegend(options, rect) region = QRegion(rect.toRect()) rect = region.subtracted(QRegion(self.__data.legendRect.toRect()) ).boundingRect() if self.__data.legendPos == QwtPlot.LeftLegend: rect.setLeft(rect.left()+self.__data.spacing) elif self.__data.legendPos == QwtPlot.RightLegend: rect.setRight(rect.right()-self.__data.spacing) elif self.__data.legendPos == QwtPlot.TopLegend: rect.setTop(rect.top()+self.__data.spacing) elif self.__data.legendPos == QwtPlot.BottomLegend: rect.setBottom(rect.bottom()-self.__data.spacing) # +---+-----------+---+ # | Title | # +---+-----------+---+ # | | Axis | | # +---+-----------+---+ # | A | | A | # | x | Canvas | x | # | i | | i | # | s | | s | # +---+-----------+---+ # | | Axis | | # +---+-----------+---+ # | Footer | # +---+-----------+---+ # title, footer and axes include text labels. The height of each # label depends on its line breaks, that depend on the width # for the label. A line break in a horizontal text will reduce # the available width for vertical texts and vice versa. # expandLineBreaks finds the height/width for title, footer and axes # including all line breaks. dimTitle, dimFooter, dimAxes = self.expandLineBreaks(options, rect) if dimTitle > 0: self.__data.titleRect.setRect(rect.left(), rect.top(), rect.width(), dimTitle) rect.setTop(self.__data.titleRect.bottom()+self.__data.spacing) if self.__data.layoutData.scale[QwtPlot.yLeft].isEnabled !=\ self.__data.layoutData.scale[QwtPlot.yRight].isEnabled: self.__data.titleRect.setX(rect.left()+dimAxes[QwtPlot.yLeft]) self.__data.titleRect.setWidth(rect.width()\ -dimAxes[QwtPlot.yLeft]-dimAxes[QwtPlot.yRight]) if dimFooter > 0: self.__data.footerRect.setRect(rect.left(), rect.bottom()-dimFooter, rect.width(), dimFooter) rect.setBottom(self.__data.footerRect.top()-self.__data.spacing) if self.__data.layoutData.scale[QwtPlot.yLeft].isEnabled !=\ self.__data.layoutData.scale[QwtPlot.yRight].isEnabled: self.__data.footerRect.setX(rect.left()+dimAxes[QwtPlot.yLeft]) self.__data.footerRect.setWidth(rect.width()\ -dimAxes[QwtPlot.yLeft]-dimAxes[QwtPlot.yRight]) self.__data.canvasRect.setRect( rect.x()+dimAxes[QwtPlot.yLeft], rect.y()+dimAxes[QwtPlot.xTop], rect.width()-dimAxes[QwtPlot.yRight]-dimAxes[QwtPlot.yLeft], rect.height()-dimAxes[QwtPlot.xBottom]-dimAxes[QwtPlot.xTop]) for axis in QwtPlot.validAxes: if dimAxes[axis]: dim = dimAxes[axis] scaleRect = self.__data.scaleRect[axis] scaleRect.setRect(*self.__data.canvasRect.getRect()) if axis == QwtPlot.yLeft: scaleRect.setX(self.__data.canvasRect.left()-dim) scaleRect.setWidth(dim) elif axis == QwtPlot.yRight: scaleRect.setX(self.__data.canvasRect.right()) scaleRect.setWidth(dim) elif axis == QwtPlot.xBottom: scaleRect.setY(self.__data.canvasRect.bottom()) scaleRect.setHeight(dim) elif axis == QwtPlot.xTop: scaleRect.setY(self.__data.canvasRect.top()-dim) scaleRect.setHeight(dim) scaleRect = scaleRect.normalized() # +---+-----------+---+ # | <- Axis -> | # +-^-+-----------+-^-+ # | | | | | | # | | | | # | A | | A | # | x | Canvas | x | # | i | | i | # | s | | s | # | | | | # | | | | | | # +-V-+-----------+-V-+ # | <- Axis -> | # +---+-----------+---+ # The ticks of the axes - not the labels above - should # be aligned to the canvas. So we try to use the empty # corners to extend the axes, so that the label texts # left/right of the min/max ticks are moved into them. self.alignScales(options, self.__data.canvasRect, self.__data.scaleRect) if not self.__data.legendRect.isEmpty(): self.__data.legendRect = self.alignLegend(self.__data.canvasRect, self.__data.legendRect)
def activate(self, plot, plotRect, options=0x00): self.invalidate() rect = QRectF(plotRect) self.__data.layoutData.init(plot, rect) if not (options & self.IgnoreLegend) and plot.legend() and\ not plot.legend().isEmpty(): self.__data.legendRect = self.layoutLegend(options, rect) region = QRegion(rect.toRect()) rect = region.subtracted(QRegion(self.__data.legendRect.toRect()) ).boundingRect() if self.__data.legendPos == QwtPlot.LeftLegend: rect.setLeft(rect.left()+self.__data.spacing) elif self.__data.legendPos == QwtPlot.RightLegend: rect.setRight(rect.right()-self.__data.spacing) elif self.__data.legendPos == QwtPlot.TopLegend: rect.setTop(rect.top()+self.__data.spacing) elif self.__data.legendPos == QwtPlot.BottomLegend: rect.setBottom(rect.bottom()-self.__data.spacing) # +---+-----------+---+ # | Title | # +---+-----------+---+ # | | Axis | | # +---+-----------+---+ # | A | | A | # | x | Canvas | x | # | i | | i | # | s | | s | # +---+-----------+---+ # | | Axis | | # +---+-----------+---+ # | Footer | # +---+-----------+---+ dimTitle, dimFooter, dimAxes = self.expandLineBreaks(options, rect) if dimTitle > 0: self.__data.titleRect.setRect(rect.left(), rect.top(), rect.width(), dimTitle) rect.setTop(self.__data.titleRect.bottom()+self.__data.spacing) if self.__data.layoutData.scale[QwtPlot.yLeft].isEnabled !=\ self.__data.layoutData.scale[QwtPlot.yRight].isEnabled: self.__data.titleRect.setX(rect.left()+dimAxes[QwtPlot.yLeft]) self.__data.titleRect.setWidth(rect.width()\ -dimAxes[QwtPlot.yLeft]-dimAxes[QwtPlot.yRight]) if dimFooter > 0: self.__data.footerRect.setRect(rect.left(), rect.bottom()-dimFooter, rect.width(), dimFooter) rect.setBottom(self.__data.footerRect.top()-self.__data.spacing) if self.__data.layoutData.scale[QwtPlot.yLeft].isEnabled !=\ self.__data.layoutData.scale[QwtPlot.yRight].isEnabled: self.__data.footerRect.setX(rect.left()+dimAxes[QwtPlot.yLeft]) self.__data.footerRect.setWidth(rect.width()\ -dimAxes[QwtPlot.yLeft]-dimAxes[QwtPlot.yRight]) self.__data.canvasRect.setRect( rect.x()+dimAxes[QwtPlot.yLeft], rect.y()+dimAxes[QwtPlot.xTop], rect.width()-dimAxes[QwtPlot.yRight]-dimAxes[QwtPlot.yLeft], rect.height()-dimAxes[QwtPlot.xBottom]-dimAxes[QwtPlot.xTop]) for axis in range(QwtPlot.axisCnt): if dimAxes[axis]: dim = dimAxes[axis] scaleRect = self.__data.scaleRect[axis] scaleRect.setRect(*self.__data.canvasRect.getRect()) if axis == QwtPlot.yLeft: scaleRect.setX(self.__data.canvasRect.left()-dim) scaleRect.setWidth(dim) elif axis == QwtPlot.yRight: scaleRect.setX(self.__data.canvasRect.right()) scaleRect.setWidth(dim) elif axis == QwtPlot.xBottom: scaleRect.setY(self.__data.canvasRect.bottom()) scaleRect.setHeight(dim) elif axis == QwtPlot.xTop: scaleRect.setY(self.__data.canvasRect.top()-dim) scaleRect.setHeight(dim) scaleRect = scaleRect.normalized() # +---+-----------+---+ # | <- Axis -> | # +-^-+-----------+-^-+ # | | | | | | # | | | | # | A | | A | # | x | Canvas | x | # | i | | i | # | s | | s | # | | | | # | | | | | | # +-V-+-----------+-V-+ # | <- Axis -> | # +---+-----------+---+ self.alignScales(options, self.__data.canvasRect, self.__data.scaleRect) if not self.__data.legendRect.isEmpty(): self.__data.legendRect = self.alignLegend(self.__data.canvasRect, self.__data.legendRect)
def minLabelDist(self, font): """ Determine the minimum distance between two labels, that is necessary that the texts don't overlap. :param QFont font: Font :return: The maximum width of a label .. seealso:: :py:meth:`getBorderDistHint()` """ if not self.hasComponent(QwtAbstractScaleDraw.Labels): return 0 ticks = self.scaleDiv().ticks(QwtScaleDiv.MajorTick) if not ticks: return 0 fm = QFontMetrics(font) vertical = self.orientation() == Qt.Vertical bRect1 = QRectF() bRect2 = self.labelRect(font, ticks[0]) if vertical: bRect2.setRect(-bRect2.bottom(), 0., bRect2.height(), bRect2.width()) maxDist = 0. for tick in ticks: bRect1 = bRect2 bRect2 = self.labelRect(font, tick) if vertical: bRect2.setRect(-bRect2.bottom(), 0., bRect2.height(), bRect2.width()) dist = fm.leading() if bRect1.right() > 0: dist += bRect1.right() if bRect2.left() < 0: dist += -bRect2.left() if dist > maxDist: maxDist = dist angle = qwtRadians(self.labelRotation()) if vertical: angle += np.pi / 2 sinA = np.sin(angle) if qFuzzyCompare(sinA + 1., 1.): return np.ceil(maxDist) fmHeight = fm.ascent() - 2 labelDist = fmHeight / np.sin(angle) * np.cos(angle) if labelDist < 0: labelDist = -labelDist if labelDist > maxDist: labelDist = maxDist if labelDist < fmHeight: labelDist = fmHeight return np.ceil(labelDist)