def _errorBarsCurve(style, xmin, xmax, ymin, ymax, xplotter, yplotter, s, painter, clip): """Draw curve around error region.""" if None not in (xmin, xmax, ymin, ymax): # non-filling brush painter.setBrush(qt4.QBrush()) for xp, yp, xmn, ymn, xmx, ymx in itertools.izip( xplotter, yplotter, xmin, ymin, xmax, ymax): # break up curve into four arcs (for asym error bars) # qt geometry means we have to calculate lots # the big numbers are in 1/16 degrees painter.drawArc( qt4.QRectF(xp - (xmx - xp), yp - (yp - ymx), (xmx - xp) * 2, (yp - ymx) * 2), 0, 1440) painter.drawArc( qt4.QRectF(xp - (xp - xmn), yp - (yp - ymx), (xp - xmn) * 2, (yp - ymx) * 2), 1440, 1440) painter.drawArc( qt4.QRectF(xp - (xp - xmn), yp - (ymn - yp), (xp - xmn) * 2, (ymn - yp) * 2), 2880, 1440) painter.drawArc( qt4.QRectF(xp - (xmx - xp), yp - (ymn - yp), (xmx - xp) * 2, (ymn - yp) * 2), 4320, 1440)
def drawShape(self, painter, rect): """Draw image.""" s = self.settings # draw border and fill painter.drawRect(rect) # check to see whether image needs reloading image = None if s.filename != '' and os.path.isfile(s.filename): if (self.cachefilename != s.filename or os.stat(s.filename) != self.cachestat): # update the image cache self.updateCachedImage() # clear any embedded image data self.settings.get('embeddedImageData').set('') image = self.cacheimage # or needs recreating from embedded data if s.filename == '{embedded}': if s.embeddedImageData is not self.cacheembeddata: self.updateCachedEmbedded() image = self.cacheimage # if no image, then use default image if (not image or image.isNull() or image.width() == 0 or image.height() == 0): # load replacement image fname = os.path.join(utils.imagedir, 'button_imagefile.svg') r = qt4.QSvgRenderer(fname) r.render(painter, rect) else: # image rectangle irect = qt4.QRectF(image.rect()) # preserve aspect ratio if s.aspect: xr = rect.width() / irect.width() yr = rect.height() / irect.height() if xr > yr: rect = qt4.QRectF( rect.left() + (rect.width() - irect.width() * yr) * 0.5, rect.top(), irect.width() * yr, rect.height()) else: rect = qt4.QRectF( rect.left(), rect.top() + (rect.height() - irect.height() * xr) * 0.5, rect.width(), irect.height() * xr) # finally draw image painter.drawImage(rect, image, irect)
def render(self): """Render the text.""" if self.calcbounds is None: self.getBounds() p = self.painter p.save() if self.mmldoc is not None: p.translate(self.xi, self.yi) p.rotate(self.angle) # is drawn from bottom of box, not top p.translate(0, -self.size.height()) p.scale(self.drawscale, self.drawscale) self.record.play(p) else: # display an error - must be a better way to do this p.setFont(qt4.QFont()) p.setPen(qt4.QPen(qt4.QColor("red"))) p.drawText( qt4.QRectF(self.xi, self.yi, 200, 200), qt4.Qt.AlignLeft | qt4.Qt.AlignTop | qt4.Qt.TextWordWrap, self.error) p.restore() return self.calcbounds
def drawKeySymbol(self, number, painter, x, y, width, height): """Draw the plot symbol and/or line.""" painter.save() cliprect = qt4.QRectF(qt4.QPointF(x, y), qt4.QPointF(x + width, y + height)) painter.setClipRect(cliprect) # draw sample error bar s = self.settings size = s.get('markerSize').convert(painter) style = s.errorStyle # make some fake error bar data to plot xv = s.get('xData').getData(self.document) yv = s.get('yData').getData(self.document) yp = y + height / 2 xpts = N.array([x - width, x + width / 2, x + 2 * width]) ypts = N.array([yp, yp, yp]) # size of error bars in key errorsize = height * 0.4 # make points for error bars (if any) if xv and xv.hasErrors(): xneg = N.array( [x - width, x + width / 2 - errorsize, x + 2 * width]) xpos = N.array( [x - width, x + width / 2 + errorsize, x + 2 * width]) else: xneg = xpos = xpts if yv and yv.hasErrors(): yneg = N.array([yp - errorsize, yp - errorsize, yp - errorsize]) ypos = N.array([yp + errorsize, yp + errorsize, yp + errorsize]) else: yneg = ypos = ypts # plot error bar painter.setPen(s.ErrorBarLine.makeQPenWHide(painter)) for function in _errorBarFunctionMap[style]: function(style, xneg, xpos, yneg, ypos, xpts, ypts, s, painter, cliprect) # draw line if not s.PlotLine.hide: painter.setPen(s.PlotLine.makeQPen(painter)) painter.drawLine(qt4.QPointF(x, yp), qt4.QPointF(x + width, yp)) # draw marker if not s.MarkerLine.hide or not s.MarkerFill.hide: if not s.MarkerFill.hide: painter.setBrush(s.MarkerFill.makeQBrush()) if not s.MarkerLine.hide: painter.setPen(s.MarkerLine.makeQPen(painter)) else: painter.setPen(qt4.QPen(qt4.Qt.NoPen)) utils.plotMarker(painter, x + width / 2, yp, s.marker, size) painter.restore()
def setClip(self, painter, bounds): '''Set clipping for graph.''' p = qt4.QPainterPath() p.addEllipse( qt4.QRectF(qt4.QPointF(bounds[0], bounds[1]), qt4.QPointF(bounds[2], bounds[3]))) painter.setClipPath(p)
def draw(self, parentposn, painthelper, outerbounds=None): '''Update the margins before drawing.''' s = self.settings margins = (s.get('leftMargin').convert(painthelper), s.get('topMargin').convert(painthelper), s.get('rightMargin').convert(painthelper), s.get('bottomMargin').convert(painthelper)) bounds = self.computeBounds(parentposn, painthelper, margins=margins) maxbounds = self.computeBounds(parentposn, painthelper) # controls for adjusting graph margins painter = painthelper.painter(self, bounds) painthelper.setControlGraph(self, [ controlgraph.ControlMarginBox(self, bounds, maxbounds, painthelper) ]) # do no painting if hidden if s.hide: return bounds # set graph rectangle attributes path = qt4.QPainterPath() path.addRect( qt4.QRectF(qt4.QPointF(bounds[0], bounds[1]), qt4.QPointF(bounds[2], bounds[3]))) utils.brushExtFillPath(painter, s.Background, path, stroke=s.Border.makeQPenWHide(painter)) # do normal drawing of children # iterate over children in reverse order for c in reversed(self.children): c.draw(bounds, painthelper, outerbounds=outerbounds) # now need to find axes which aren't children, and draw those again axestodraw = set() childrennames = set() for c in self.children: childrennames.add(c.name) try: for axis in c.getAxesNames(): axestodraw.add(axis) except AttributeError: pass axestodraw = axestodraw - childrennames if axestodraw: # now redraw all these axes if they aren't children of us axeswidgets = self.getAxes(axestodraw) for w in axeswidgets: if w is not None: w.draw(bounds, painthelper, outerbounds=outerbounds) return bounds
def renderPage(self, size, dpi, painter): """Render page using paint helper to painter. This first renders to the helper, then to the painter """ helper = painthelper.PaintHelper(size, dpi=dpi, directpaint=painter) painter.setClipRect(qt4.QRectF(qt4.QPointF(0, 0), qt4.QPointF(*size))) self.doc.paintTo(helper, self.pagenumber) painter.restore() painter.end()
def draw(self, parentposn, painthelper, outerbounds=None): """Draw the function.""" posn = GenericPlotter.draw(self, parentposn, painthelper, outerbounds=outerbounds) x1, y1, x2, y2 = posn s = self.settings # exit if hidden or function blank if s.hide or s.function.strip() == '': return # get axes widgets axes = self.parent.getAxes((s.xAxis, s.yAxis)) # return if there's no proper axes if (None in axes or axes[0].settings.direction != 'horizontal' or axes[1].settings.direction != 'vertical'): return # clip data within bounds of plotter cliprect = self.clipAxesBounds(axes, posn) painter = painthelper.painter(self, posn, clip=cliprect) # get the points to plot by evaluating the function (xpts, ypts), (pxpts, pypts) = self.calcFunctionPoints(axes, posn) # draw the function line if pxpts is None or pypts is None: # not sure how to deal with errors here painter.setPen(setting.settingdb.color('error')) f = qt4.QFont() f.setPointSize(20) painter.setFont(f) painter.drawText(qt4.QRectF(x1, y1, x2 - x1, y2 - y1), qt4.Qt.AlignCenter, "Cannot evaluate '%s'" % s.function) else: if not s.FillBelow.hide: self._fillRegion(painter, pxpts, pypts, posn, True, cliprect, s.FillBelow) if not s.FillAbove.hide: self._fillRegion(painter, pxpts, pypts, posn, False, cliprect, s.FillAbove) if not s.Line.hide: painter.setBrush(qt4.QBrush()) painter.setPen(s.Line.makeQPen(painter)) self._plotLine(painter, pxpts, pypts, posn, cliprect)
def draw(self, posn, phelper, outerbounds=None): """Draw the text label.""" s = self.settings d = self.document # exit if hidden if s.hide or s.Text.hide: return text = s.get('label').getData(d) xp, yp = self._getPlotterCoords(posn) if xp is None or yp is None: # we can't calculate coordinates return clip = None if s.clip: clip = qt4.QRectF(qt4.QPointF(posn[0], posn[1]), qt4.QPointF(posn[2], posn[3])) painter = phelper.painter(self, posn, clip=clip) textpen = s.get('Text').makeQPen() painter.setPen(textpen) font = s.get('Text').makeQFont(painter) # we should only be able to move non-dataset labels isnotdataset = (not s.get('xPos').isDataset(d) and not s.get('yPos').isDataset(d)) controlgraphitems = [] for index, (x, y, t) in enumerate( itertools.izip(xp, yp, itertools.cycle(text))): # render the text tbounds = utils.Renderer(painter, font, x, y, t, TextLabel.cnvtalignhorz[s.alignHorz], TextLabel.cnvtalignvert[s.alignVert], s.angle).render() # add cgi for adjustable positions if isnotdataset: cgi = controlgraph.ControlMovableBox(self, tbounds, phelper, crosspos=(x, y)) cgi.labelpt = (x, y) cgi.widgetposn = posn cgi.index = index controlgraphitems.append(cgi) phelper.setControlGraph(self, controlgraphitems)
def checkHighlight(self): """Check to see whether box is over hightlight area. Returns (x, y) name or None if not.""" rect = self.rect() rect.translate(self.pos()) highlight = None highlightrect = qt4.QRectF(rect.left()-10, rect.top()-10, 20, 20) for name, point in self.highlightpoints.iteritems(): if highlightrect.contains(point): highlight = name break return highlight
def draw(self, posn, phelper, outerbounds=None): """Plot the data on a plotter.""" s = self.settings # exit if hidden if s.hide: return # get points in plotter coordinates xp, yp = self._getPlotterCoords(posn) if xp is None or yp is None: # we can't calculate coordinates return x1, y1, x2, y2 = posn cliprect = qt4.QRectF(qt4.QPointF(x1, y1), qt4.QPointF(x2, y2)) painter = phelper.painter(self, posn, clip=cliprect) pen = s.Line.makeQPenWHide(painter) pw = pen.widthF() * 2 lineclip = qt4.QRectF(qt4.QPointF(x1 - pw, y1 - pw), qt4.QPointF(x2 + pw, y2 + pw)) # this is a hack as we generate temporary fake datasets path = qt4.QPainterPath() for xvals, yvals in document.generateValidDatasetParts( document.Dataset(xp), document.Dataset(yp)): poly = qt4.QPolygonF() utils.addNumpyToPolygonF(poly, xvals.data, yvals.data) clippedpoly = qt4.QPolygonF() utils.polygonClip(poly, lineclip, clippedpoly) path.addPolygon(clippedpoly) path.closeSubpath() utils.brushExtFillPath(painter, s.Fill, path, stroke=pen)
def _errorBarsDiamond(style, xmin, xmax, ymin, ymax, xplotter, yplotter, s, painter, clip): """Draw diamond around error region.""" if None not in (xmin, xmax, ymin, ymax): # expand clip by pen width (urgh) pw = painter.pen().widthF() * 2 clip = qt4.QRectF(qt4.QPointF(clip.left() - pw, clip.top() - pw), qt4.QPointF(clip.right() + pw, clip.bottom() + pw)) path = qt4.QPainterPath() utils.addNumpyPolygonToPath(path, clip, xmin, yplotter, xplotter, ymax, xmax, yplotter, xplotter, ymin) painter.setBrush(qt4.QBrush()) painter.drawPath(path)
def clipAxesBounds(self, axes, bounds): """Returns clipping rectange for start and stop values of axis.""" # update cached coordinates of axes axes[0].plotterToDataCoords(bounds, N.array([])) axes[1].plotterToDataCoords(bounds, N.array([])) # get range x1, x2 = axes[0].coordParr1, axes[0].coordParr2 if x1 > x2: x1, x2 = x2, x1 y1, y2 = axes[1].coordParr2, axes[1].coordParr1 if y1 > y2: y1, y2 = y2, y1 # actually clip the data cliprect = qt4.QRectF(qt4.QPointF(x1, y1), qt4.QPointF(x2, y2)) return cliprect
def plotBars(self, painter, s, dsnum, clip, corners): """Plot a set of boxes.""" # get style brush = s.BarFill.get('fills').returnBrushExtended(dsnum) pen = s.BarLine.get('lines').makePen(painter, dsnum) lw = pen.widthF() * 2 # make clip box bigger to avoid lines showing extclip = qt4.QRectF( qt4.QPointF(clip.left() - lw, clip.top() - lw), qt4.QPointF(clip.right() + lw, clip.bottom() + lw)) # plot bars path = qt4.QPainterPath() utils.addNumpyPolygonToPath(path, extclip, corners[0], corners[1], corners[2], corners[1], corners[2], corners[3], corners[0], corners[3]) utils.brushExtFillPath(painter, brush, path, stroke=pen)
def render(self, state): initx = state.x # draw material under bar Part.render(self, state) # draw circle over text with 1pt radius painter = state.painter height = state.fontMetrics().ascent() painter.save() circsize = state.getPixelsPerPt() painter.setBrush(qt4.QBrush(painter.pen().color())) painter.setPen(qt4.QPen(qt4.Qt.NoPen)) x = 0.5 * (initx + state.x) y = state.y - height + circsize painter.drawEllipse( qt4.QRectF(qt4.QPointF(x - circsize, y - circsize), qt4.QPointF(x + circsize, y + circsize))) painter.restore()
def drawGraph(self, painter, bounds, datarange, outerbounds=None): '''Plot graph area and axes.''' s = self.settings if s.maxradius == 'Auto': self._maxradius = datarange[1] else: self._maxradius = s.maxradius self._xscale = (bounds[2] - bounds[0]) * 0.5 self._yscale = (bounds[3] - bounds[1]) * 0.5 self._xc = 0.5 * (bounds[0] + bounds[2]) self._yc = 0.5 * (bounds[3] + bounds[1]) path = qt4.QPainterPath() path.addEllipse( qt4.QRectF(qt4.QPointF(bounds[0], bounds[1]), qt4.QPointF(bounds[2], bounds[3]))) utils.brushExtFillPath(painter, s.Background, path, stroke=s.Border.makeQPenWHide(painter))
def draw(self, parentposn, painthelper, outerbounds=None): """Draw the plotter. Clip graph inside bounds.""" # document should pass us the page bounds x1, y1, x2, y2 = parentposn # find ranges of axes axisdependhelper = _AxisDependHelper(self) axisdependhelper.findPlotters() axisdependhelper.findAxisRanges() # store axis->plotter mappings in painter too (is this nasty?) painthelper.axisplottermap.update(axisdependhelper.axis_plotter_map) if self.settings.hide: bounds = self.computeBounds(parentposn, painthelper) return bounds clip = qt4.QRectF(qt4.QPointF(parentposn[0], parentposn[1]), qt4.QPointF(parentposn[2], parentposn[3])) painter = painthelper.painter(self, parentposn, clip=clip) # clip to page bounds = widget.Widget.draw(self, parentposn, painthelper, parentposn) # w and h are non integer w = self.settings.get('width').convert(painter) h = self.settings.get('height').convert(painter) painthelper.setControlGraph(self, [ controlgraph.ControlMarginBox(self, [0, 0, w, h], [-10000, -10000, 10000, 10000], painthelper, ismovable=False) ]) return bounds
def boundingRect(self): return qt4.QRectF(0, 0, 0, 0)
def boundingRectChar(self, c): return qt4.QRectF(0, 0, self.height() * 0.5, self.height())
def draw(self, posn, phelper, outerbounds=None): """Plot the key on a plotter.""" s = self.settings d = self.document if s.hide: return # get positions of shapes width = s.get('width').getFloatArray(d) height = s.get('height').getFloatArray(d) rotate = s.get('rotate').getFloatArray(d) if width is None or height is None or rotate is None: return # translate coordinates from axes or relative values xpos, ypos = self._getPlotterCoords(posn) if xpos is None or ypos is None: # we can't calculate coordinates return # if a dataset is used, we can't use control items isnotdataset = (not s.get('xPos').isDataset(d) and not s.get('yPos').isDataset(d) and not s.get('width').isDataset(d) and not s.get('height').isDataset(d) and not s.get('rotate').isDataset(d)) controlgraphitems = [] clip = None if s.clip: clip = qt4.QRectF(qt4.QPointF(posn[0], posn[1]), qt4.QPointF(posn[2], posn[3])) painter = phelper.painter(self, posn, clip=clip) # drawing settings for shape if not s.Border.hide: painter.setPen(s.get('Border').makeQPen(painter)) else: painter.setPen(qt4.QPen(qt4.Qt.NoPen)) # iterate over positions index = 0 dx, dy = posn[2] - posn[0], posn[3] - posn[1] for x, y, w, h, r in itertools.izip(xpos, ypos, itertools.cycle(width), itertools.cycle(height), itertools.cycle(rotate)): wp, hp = dx * w, dy * h painter.save() painter.translate(x, y) if r != 0: painter.rotate(r) self.drawShape(painter, qt4.QRectF(-wp * 0.5, -hp * 0.5, wp, hp)) painter.restore() if isnotdataset: cgi = controlgraph.ControlResizableBox(self, [x, y], [wp, hp], r, allowrotate=True) cgi.index = index cgi.widgetposn = posn index += 1 controlgraphitems.append(cgi) phelper.setControlGraph(self, controlgraphitems)
def boundingRect(self): """Intentionally zero bounding rect.""" return qt4.QRectF(0, 0, 0, 0)
def draw(self, parentposn, phelper, outerbounds=None, useexistingpainter=None): """Plot the axis on the painter. useexistingpainter is a hack so that a colorbar can reuse the drawing code here. If set to a painter, it will use this rather than opening a new one. """ s = self.settings # recompute if document modified if self.docchangeset != self.document.changeset: self._computePlottedRange() posn = widget.Widget.draw(self, parentposn, phelper, outerbounds) self._updatePlotRange(posn) # get ready to draw if useexistingpainter is not None: painter = useexistingpainter else: painter = phelper.painter(self, posn) # make control item for axis phelper.setControlGraph(self, [ controlgraph.ControlAxisLine( self, s.direction, self.coordParr1, self.coordParr2, self.coordPerp, posn) ]) # get tick vals coordticks = self._graphToPlotter(self.majortickscalc) coordminorticks = self._graphToPlotter(self.minortickscalc) # exit if axis is hidden if s.hide: return texttorender = [] # multiplication factor if reflection on the axis is requested sign = 1 if s.direction == 'vertical': sign *= -1 if self.coordReflected: sign *= -1 # plot gridlines if not s.MinorGridLines.hide: self._drawGridLines('MinorGridLines', painter, coordminorticks, parentposn) if not s.GridLines.hide: self._drawGridLines('GridLines', painter, coordticks, parentposn) # plot the line along the axis if not s.Line.hide: self._drawAxisLine(painter) # plot minor ticks if not s.MinorTicks.hide: self._drawMinorTicks(painter, coordminorticks) # keep track of distance from axis self._delta_axis = 0 # plot major ticks if not s.MajorTicks.hide: self._drawMajorTicks(painter, coordticks) # plot tick labels suppresstext = self._suppressText(painter, parentposn, outerbounds) if not s.TickLabels.hide and not suppresstext: self._drawTickLabels(phelper, painter, coordticks, sign, outerbounds, texttorender) # draw an axis label if not s.Label.hide and not suppresstext: self._drawAxisLabel(painter, sign, outerbounds, texttorender) # mirror axis at other side of plot if s.autoMirror: self._autoMirrorDraw(posn, painter, coordticks, coordminorticks) # all the text is drawn at the end so that # we can check it doesn't overlap drawntext = qt4.QPainterPath() for r, pen in texttorender: bounds = r.getBounds() rect = qt4.QRectF(bounds[0], bounds[1], bounds[2]-bounds[0], bounds[3]-bounds[1]) if not drawntext.intersects(rect): painter.setPen(pen) r.render() drawntext.addRect(rect)
def draw(self, parentposn, phelper, outerbounds = None): '''Update the margins before drawing.''' s = self.settings # exit if hidden if s.hide: return # get height of label font bounds = self.computeBounds(parentposn, phelper) painter = phelper.painter(self, parentposn) font = s.get('Label').makeQFont(phelper) painter.setFont(font) fontheight = utils.FontMetrics(font, painter.device()).height() horz = s.direction == 'horizontal' # use above to estimate width and height if necessary w = s.get('width') if w.isAuto(): if horz: totalwidth = bounds[2] - bounds[0] - 2*fontheight else: totalwidth = fontheight else: totalwidth = w.convert(painter) h = s.get('height') if h.isAuto(): if horz: totalheight = fontheight else: totalheight = bounds[3] - bounds[1] - 2*fontheight else: totalheight = h.convert(painter) # work out horizontal position h = s.horzPosn if h == 'left': bounds[0] += fontheight bounds[2] = bounds[0] + totalwidth elif h == 'right': bounds[2] -= fontheight bounds[0] = bounds[2] - totalwidth elif h == 'centre': delta = (bounds[2]-bounds[0]-totalwidth)/2. bounds[0] += delta bounds[2] -= delta elif h == 'manual': bounds[0] += (bounds[2]-bounds[0])*s.horzManual bounds[2] = bounds[0] + totalwidth # work out vertical position v = s.vertPosn if v == 'top': bounds[1] += fontheight bounds[3] = bounds[1] + totalheight elif v == 'bottom': bounds[3] -= fontheight bounds[1] = bounds[3] - totalheight elif v == 'centre': delta = (bounds[3]-bounds[1]-totalheight)/2. bounds[1] += delta bounds[3] -= delta elif v == 'manual': bounds[1] += (bounds[3]-bounds[1])*s.vertManual bounds[3] = bounds[1] + totalheight # this is ugly - update bounds in helper state phelper.states[self].bounds = bounds # do no painting if hidden or no image imgwidget = s.get('widgetName').findWidget() if s.hide: return bounds # update image if necessary with new settings if imgwidget is not None: # could find widget (minval, maxval, axisscale, img) = imgwidget.makeColorbarImage(s.direction) else: # couldn't find widget minval, maxval, axisscale = 0., 1., 'linear' img = None self.setAutoRange([minval, maxval]) s.get('log').setSilent(axisscale == 'log') # now draw image on axis... minpix, maxpix = self.graphToPlotterCoords( bounds, N.array([minval, maxval]) ) if s.direction == 'horizontal': c = [ minpix, bounds[1], maxpix, bounds[3] ] else: c = [ bounds[0], maxpix, bounds[2], minpix ] r = qt4.QRectF(c[0], c[1], c[2]-c[0], c[3]-c[1]) # really draw the img if img is not None: painter.drawImage(r, img) # if there's a border if not s.Border.hide: painter.setPen( s.get('Border').makeQPen(painter) ) painter.setBrush( qt4.QBrush() ) painter.drawRect( qt4.QRectF(bounds[0], bounds[1], bounds[2]-bounds[0], bounds[3]-bounds[1]) ) # actually draw axis # we have to force position to full, as otherwise computeBounds # will mess up range if called twice savedposition = self.position self.position = (0., 0., 1., 1.) axis.Axis.draw(self, bounds, phelper, outerbounds=outerbounds, useexistingpainter=painter) self.position = savedposition
s = self.settings # exit if hidden if s.hide: return # ignore if function isn't sensible try: self.checker.check(s.function, s.variable) except RuntimeError, e: self.logEvalError(e) return x1, y1, x2, y2 = posn cliprect = qt4.QRectF( qt4.QPointF(x1, y1), qt4.QPointF(x2, y2) ) painter = phelper.painter(self, posn) self.parent.setClip(painter, posn) apts, bpts = self.getFunctionPoints() px, py = self.parent.graphToPlotCoords(apts, bpts) # plot line painter.setBrush(qt4.QBrush()) painter.setPen( s.PlotLine.makeQPenWHide(painter) ) for x, y in utils.validLinePoints(px, py): if not s.Fill1.hide: self.parent.drawFillPts(painter, s.Fill1, cliprect, x, y) if not s.Fill2.hide: self.parent.drawFillPts(painter, s.Fill2, cliprect, x, y) if not s.PlotLine.hide:
def drawAxes(self, painter, bounds, datarange, outerbounds=None): '''Plot axes.''' s = self.settings t = s.Tick if self._maxradius <= 0.: self._maxradius = 1. atick = AxisTicks(0, self._maxradius, t.number, t.number * 4, extendmin=False, extendmax=False) atick.getTicks() majtick = atick.tickvals # draw ticks as circles if not t.hideannuli: painter.setPen(s.Tick.makeQPenWHide(painter)) painter.setBrush(qt4.QBrush()) for tick in majtick[1:]: radius = tick / self._maxradius painter.drawEllipse( qt4.QRectF( qt4.QPointF(self._xc - radius * self._xscale, self._yc - radius * self._yscale), qt4.QPointF(self._xc + radius * self._xscale, self._yc + radius * self._yscale))) # setup axes plot tl = s.TickLabels scale, format = tl.scale, tl.format if format == 'Auto': format = atick.autoformat painter.setPen(tl.makeQPen()) font = tl.makeQFont(painter) # draw radial axis if not s.TickLabels.hideradial: for tick in majtick[1:]: num = utils.formatNumber(tick * scale, format, locale=self.document.locale) x = tick / self._maxradius * self._xscale + self._xc r = utils.Renderer(painter, font, x, self._yc, num, alignhorz=-1, alignvert=-1, usefullheight=True) r.render() if s.units == 'degrees': angles = [ u'0°', u'30°', u'60°', u'90°', u'120°', u'150°', u'180°', u'210°', u'240°', u'270°', u'300°', u'330°' ] else: angles = [ '0', u'π/6', u'π/3', u'π/2', u'2π/3', u'5π/6', u'π', u'7π/6', u'4π/3', u'3π/2', u'5π/3', u'11π/6' ] align = [(-1, 1), (-1, 1), (-1, 1), (0, 1), (1, 1), (1, 1), (1, 0), (1, -1), (1, -1), (0, -1), (-1, -1), (-1, -1)] if s.direction == 'anticlockwise': angles = angles[0:1] + angles[1:][::-1] # rotate labels if zero not at right if s.position0 == 'top': angles = angles[3:] + angles[:4] elif s.position0 == 'left': angles = angles[6:] + angles[:7] elif s.position0 == 'bottom': angles = angles[9:] + angles[:10] # draw labels around plot if not s.TickLabels.hidetangential: for i in xrange(12): angle = 2 * N.pi / 12 x = self._xc + N.cos(angle * i) * self._xscale y = self._yc + N.sin(angle * i) * self._yscale r = utils.Renderer(painter, font, x, y, angles[i], alignhorz=align[i][0], alignvert=align[i][1], usefullheight=True) r.render() # draw spokes if not t.hidespokes: painter.setPen(s.Tick.makeQPenWHide(painter)) painter.setBrush(qt4.QBrush()) angle = 2 * N.pi / 12 lines = [] for i in xrange(12): x = self._xc + N.cos(angle * i) * self._xscale y = self._yc + N.sin(angle * i) * self._yscale lines.append( qt4.QLineF(qt4.QPointF(self._xc, self._yc), qt4.QPointF(x, y))) painter.drawLines(lines)
def draw(self, parentposn, phelper, outerbounds = None): """Plot the key on a plotter.""" s = self.settings if s.hide: return painter = phelper.painter(self, parentposn) font = s.get('Text').makeQFont(painter) painter.setFont(font) height = utils.FontMetrics(font, painter.device()).height() margin = s.marginSize * height showtext = not s.Text.hide # maximum width of text required maxwidth = 1 # total number of layout lines required totallines = 0 # reserve space for the title titlewidth, titleheight = 0, 0 if s.title != '': titlefont = qt4.QFont(font) titlefont.setPointSize(max(font.pointSize() * 1.2, font.pointSize() + 2)) titlewidth, titleheight = utils.Renderer(painter, titlefont, 0, 0, s.title).getDimensions() titleheight += 0.5*margin maxwidth = titlewidth entries = [] # iterate over children and find widgets which are suitable for c in self.parent.children: try: num = c.getNumberKeys() except AttributeError: continue if not c.settings.hide: # add an entry for each key entry for each widget for i in xrange(num): lines = 1 if showtext: w, h = utils.Renderer(painter, font, 0, 0, c.getKeyText(i)).getDimensions() maxwidth = max(maxwidth, w) lines = max(1, math.ceil(float(h)/float(height))) totallines += lines entries.append( (c, i, lines) ) # layout the box layout, (numrows, numcols) = self._layout(entries, totallines) # total size of box symbolwidth = s.get('keyLength').convert(painter) totalwidth = ( (maxwidth + height + symbolwidth)*numcols + height*(numcols-1) ) totalheight = numrows * height + titleheight if not s.Border.hide: totalwidth += 2*margin totalheight += margin # work out horizontal position h = s.horzPosn if h == 'left': x = parentposn[0] + height elif h == 'right': x = parentposn[2] - height - totalwidth elif h == 'centre': x = ( parentposn[0] + 0.5*(parentposn[2] - parentposn[0] - totalwidth) ) elif h == 'manual': x = parentposn[0] + (parentposn[2]-parentposn[0])*s.horzManual # work out vertical position v = s.vertPosn if v == 'top': y = parentposn[1] + height elif v == 'bottom': y = parentposn[3] - totalheight - height elif v == 'centre': y = ( parentposn[1] + 0.5*(parentposn[3] - parentposn[1] - totalheight) ) elif v == 'manual': y = ( parentposn[3] - (parentposn[3]-parentposn[1])*s.vertManual - totalheight ) # for controlgraph boxposn = (x, y) boxdims = (totalwidth, totalheight) # draw surrounding box boxpath = qt4.QPainterPath() boxpath.addRect(qt4.QRectF(x, y, totalwidth, totalheight)) if not s.Background.hide: utils.brushExtFillPath(painter, s.Background, boxpath) if not s.Border.hide: painter.strokePath(boxpath, s.get('Border').makeQPen(painter) ) x += margin y += margin*0.5 # center and draw the title if s.title: xpos = x + 0.5*(totalwidth - (0 if s.Border.hide else 2*margin) - titlewidth) utils.Renderer(painter, titlefont, xpos, y, s.title, alignvert=1).render() y += titleheight textpen = s.get('Text').makeQPen() # plot dataset entries for (plotter, num, xp, yp, lines) in layout: xpos = x + xp*(maxwidth+2*height+symbolwidth) ypos = y + yp*height # plot key symbol painter.save() keyoffset = 0 if s.keyAlign == 'centre': keyoffset = (lines-1)*height/2.0 elif s.keyAlign == 'bottom': keyoffset = (lines-1)*height plotter.drawKeySymbol(num, painter, xpos, ypos+keyoffset, symbolwidth, height) painter.restore() # write key text if showtext: painter.setPen(textpen) utils.Renderer(painter, font, xpos + height + symbolwidth, ypos, plotter.getKeyText(num), -1, 1).render() phelper.setControlGraph( self, [ControlKey(self, parentposn, boxposn, boxdims, height)] )
def swapbox(painter, x1, y1, x2, y2, swap): """Return box, swapping x and y coordinates if swap is True.""" if swap: return qt4.QRectF(qt4.QPointF(y1, x1), qt4.QPointF(y2, x2)) else: return qt4.QRectF(qt4.QPointF(x1, y1), qt4.QPointF(x2, y2))
def draw(self, parentposn, phelper, outerbounds=None): """Draw the image.""" posn = plotters.GenericPlotter.draw(self, parentposn, phelper, outerbounds=outerbounds) x1, y1, x2, y2 = posn s = self.settings # get axes widgets axes = self.parent.getAxes((s.xAxis, s.yAxis)) # return if there's no proper axes if (None in axes or axes[0].settings.direction != 'horizontal' or axes[1].settings.direction != 'vertical'): return # get data and update internal computations data = self.recomputeInternals() if not data or s.hide: return # find coordinates of image coordinate bounds rangex, rangey = data.getDataRanges() # translate coordinates to plotter coordinates coordsx = axes[0].dataToPlotterCoords(posn, N.array(rangex)) coordsy = axes[1].dataToPlotterCoords(posn, N.array(rangey)) # truncate image down if necessary # This assumes linear pixels! if (coordsx[0] < x1 or coordsx[1] > x2 or coordsy[0] < y1 or coordsy[1] > y2): coordsx, coordsy, image = self.cutImageToFit( coordsx, coordsy, posn) else: image = self.image # clip data within bounds of plotter clip = self.clipAxesBounds(axes, posn) painter = phelper.painter(self, posn, clip=clip) # optionally smooth images before displaying if s.smooth: image = image.scaled(coordsx[1] - coordsx[0], coordsy[0] - coordsy[1], qt4.Qt.IgnoreAspectRatio, qt4.Qt.SmoothTransformation) # get position and size of output image xp, yp = coordsx[0], coordsy[1] xw = coordsx[1] - coordsx[0] yw = coordsy[0] - coordsy[1] # invert output drawing if axes go from positive->negative # we only translate the coordinate system if this is the case xscale = yscale = 1 if xw < 0: xscale = -1 if yw < 0: yscale = -1 if xscale != 1 or yscale != 1: painter.save() painter.translate(xp, yp) xp = yp = 0 painter.scale(xscale, yscale) # draw image painter.drawImage(qt4.QRectF(xp, yp, abs(xw), abs(yw)), image) # restore painter if image was inverted if xscale != 1 or yscale != 1: painter.restore()
def draw(self, posn, phelper, outerbounds = None): """Plot the key on a plotter.""" s = self.settings d = self.document if s.hide: return # if a dataset is used, we can't use control items isnotdataset = ( not s.get('xPos').isDataset(d) and not s.get('yPos').isDataset(d) ) if s.mode == 'length-angle': isnotdataset = ( isnotdataset and not s.get('length').isDataset(d) and not s.get('angle').isDataset(d) ) else: isnotdataset = ( isnotdataset and not s.get('xPos2').isDataset(d) and not s.get('yPos2').isDataset(d) ) # now do the drawing clip = None if s.clip: clip = qt4.QRectF( qt4.QPointF(posn[0], posn[1]), qt4.QPointF(posn[2], posn[3]) ) painter = phelper.painter(self, posn, clip=clip) # adjustable positions for the lines arrowsize = s.get('arrowSize').convert(painter) # drawing settings for line if not s.Line.hide: painter.setPen( s.get('Line').makeQPen(painter) ) else: painter.setPen( qt4.QPen(qt4.Qt.NoPen) ) # settings for fill if not s.Fill.hide: painter.setBrush( s.get('Fill').makeQBrush() ) else: painter.setBrush( qt4.QBrush() ) # iterate over positions scaling = posn[2]-posn[0] if s.mode == 'length-angle': lines = self._computeLinesLengthAngle(posn, scaling) else: lines = self._computeLinesPointToPoint(posn) if lines is None: return controlgraphitems = [] for index, (x, y, l, a) in enumerate(lines): utils.plotLineArrow(painter, x, y, l, a, arrowsize=arrowsize, arrowleft=s.arrowleft, arrowright=s.arrowright) if isnotdataset: cgi = controlgraph.ControlLine( self, x, y, x + l*math.cos(a/180.*math.pi), y + l*math.sin(a/180.*math.pi)) cgi.index = index cgi.widgetposn = posn controlgraphitems.append(cgi) phelper.setControlGraph(self, controlgraphitems)
def drawKeySymbol(self, number, painter, x, y, width, height): """Draw a fill rectangle for key entry.""" self.plotBars( painter, self.settings, number, qt4.QRectF(0, 0, 32767, 32767), ([x], [y + height * 0.1], [x + width], [y + height * 0.8]))