def _drawPlotLine(self, painter, xvals, yvals, posn, xdata, ydata, cliprect): """Draw the line connecting the points.""" pts = self._getLinePoints(xvals, yvals, posn, xdata, ydata) if len(pts) < 2: return s = self.settings if not s.FillBelow.hide: # construct polygon to draw filled region polypts = qt4.QPolygonF([qt4.QPointF(pts[0].x(), posn[3])]) polypts += pts polypts.append(qt4.QPointF(pts[len(pts) - 1].x(), posn[3])) utils.brushExtFillPolygon(painter, s.FillBelow, cliprect, polypts) if not s.FillAbove.hide: polypts = qt4.QPolygonF([qt4.QPointF(pts[0].x(), posn[1])]) polypts += pts polypts.append(qt4.QPointF(pts[len(pts) - 1].x(), posn[1])) utils.brushExtFillPolygon(painter, s.FillAbove, cliprect, polypts) # draw line between points if not s.PlotLine.hide: painter.setPen(s.PlotLine.makeQPen(painter)) utils.plotClippedPolyline(painter, cliprect, pts)
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 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 _plotLine(self, painter, xpts, ypts, bounds, clip): """ Plot the points in xpts, ypts.""" x1, y1, x2, y2 = bounds maxdeltax = (x2 - x1) * 3 / 4 maxdeltay = (y2 - y1) * 3 / 4 # idea is to collect points until we go out of the bounds # or reach the end, then plot them pts = qt4.QPolygonF() lastx = lasty = -65536 for x, y in itertools.izip(xpts, ypts): # ignore point if it outside sensible bounds if x < -32767 or y < -32767 or x > 32767 or y > 32767: if len(pts) >= 2: utils.plotClippedPolyline(painter, clip, pts) pts.clear() else: # if the jump wasn't too large, add the point to the points if abs(x - lastx) < maxdeltax and abs(y - lasty) < maxdeltay: pts.append(qt4.QPointF(x, y)) else: # draw what we have until now, and start a new line if len(pts) >= 2: utils.plotClippedPolyline(painter, clip, pts) pts.clear() pts.append(qt4.QPointF(x, y)) lastx = x lasty = y # draw remaining points if len(pts) >= 2: utils.plotClippedPolyline(painter, clip, pts)
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 drawKeySymbol(self, number, painter, x, y, width, height): """Draw the plot symbol and/or line.""" s = self.settings yp = y + height / 2 # draw line if not s.Line.hide: painter.setBrush(qt4.QBrush()) painter.setPen(s.Line.makeQPen(painter)) painter.drawLine(qt4.QPointF(x, yp), qt4.QPointF(x + width, yp))
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 drawGraph(self, painter, bounds, datarange, outerbounds=None): '''Plot graph area and axes.''' s = self.settings xw, yw = bounds[2]-bounds[0], bounds[3]-bounds[1] d60 = 60./180.*math.pi ang = math.atan2(yw, xw/2.) if ang > d60: # taller than wider widthh = xw/2 height = math.tan(d60) * widthh else: # wider than taller height = yw widthh = height / math.tan(d60) # box for equilateral triangle self._box = ( (bounds[2]+bounds[0])/2 - widthh, (bounds[1]+bounds[3])/2 - height/2, (bounds[2]+bounds[0])/2 + widthh, (bounds[1]+bounds[3])/2 + height/2 ) self._width = widthh*2 self._height = height # triangle shaped polygon for graph self._tripoly = p = qt4.QPolygonF() p.append( qt4.QPointF(self._box[0], self._box[3]) ) p.append( qt4.QPointF(self._box[0]+widthh, self._box[1]) ) p.append( qt4.QPointF(self._box[2], self._box[3]) ) path = qt4.QPainterPath() path.addPolygon(p) path.closeSubpath() utils.brushExtFillPath(painter, s.Background, path, stroke=s.Border.makeQPenWHide(painter)) # work out origins and size self._size = max(min(s.fracsize, 1.), 0.) # make sure we don't go past the ends of the allowed range # value of origin of left axis at top self._orgleft = min(s.originleft, 1.-self._size) # value of origin of bottom axis at left self._orgbot = min(s.originbottom, 1.-self._size) # origin of right axis at bottom self._orgright = 1. - self._orgleft - (self._orgbot + self._size)
def render(self, state): initx = state.x # draw material under bar Part.render(self, state) # draw line over text with 0.5pt thickness painter = state.painter height = state.fontMetrics().ascent() painter.save() penw = state.getPixelsPerPt() * 0.5 painter.setPen(qt4.QPen(painter.pen().brush(), penw)) painter.drawLine(qt4.QPointF(initx, state.y - height + penw), qt4.QPointF(state.x, state.y - height + penw)) painter.restore()
def __init__(self, params): qt4.QGraphicsRectItem.__init__(self, params.posn[0], params.posn[1], params.dims[0], params.dims[1]) self.params = params self.setCursor(qt4.Qt.SizeAllCursor) self.setZValue(1.) self.setFlag(qt4.QGraphicsItem.ItemIsMovable) self.highlightpen = qt4.QPen(qt4.Qt.red, 2, qt4.Qt.DotLine) pposn, dims = params.parentposn, params.dims th = params.textheight # special places on the plot xposn = { 'left': pposn[0] + th, 'centre': pposn[0] + 0.5*(pposn[2]-pposn[0]-dims[0]), 'right': pposn[2] - th - dims[0] } yposn = { 'top': pposn[1] + th, 'centre': pposn[1] + 0.5*(pposn[3]-pposn[1]-dims[1]), 'bottom': pposn[3] - th - dims[1] } # these are special places where the key is aligned self.highlightpoints = {} for xname, xval in xposn.iteritems(): for yname, yval in yposn.iteritems(): self.highlightpoints[(xname, yname)] = qt4.QPointF(xval, yval) self.updatePen()
def updateCornerPosns(self): """Update all corners from updated box.""" par = self.params pos = par.posn # update cursors self.corners[0].setCursor(qt4.Qt.SizeFDiagCursor) self.corners[1].setCursor(qt4.Qt.SizeBDiagCursor) self.corners[2].setCursor(qt4.Qt.SizeBDiagCursor) self.corners[3].setCursor(qt4.Qt.SizeFDiagCursor) # trim box to maximum size pos[0] = max(pos[0], par.maxposn[0]) pos[1] = max(pos[1], par.maxposn[1]) pos[2] = min(pos[2], par.maxposn[2]) pos[3] = min(pos[3], par.maxposn[3]) # move corners for corner, (xindex, yindex) in itertools.izip(self.corners, self.mapcornertoposn): corner.setPos(qt4.QPointF(pos[xindex], pos[yindex])) # move lines w, h = pos[2] - pos[0], pos[3] - pos[1] self.lines[0].setPos(pos[0], pos[1]) self.lines[0].setLine(0, 0, w, 0) self.lines[1].setPos(pos[2], pos[1]) self.lines[1].setLine(0, 0, 0, h) self.lines[2].setPos(pos[2], pos[3]) self.lines[2].setLine(0, 0, -w, 0) self.lines[3].setPos(pos[0], pos[3]) self.lines[3].setLine(0, 0, 0, -h)
def render(self): """Render the text.""" if self.calcbounds is None: self.getBounds() state = RenderState(self.font, self.painter, self.xi, self.yi, self.alignhorz) # if the text is rotated, change the coordinate frame if self.angle != 0: self.painter.save() self.painter.translate(qt4.QPointF(state.x, state.y)) self.painter.rotate(self.angle) state.x = 0 state.y = 0 # actually paint the string self.painter.setFont(self.font) self.parttree.render(state) # restore coordinate frame if text was rotated if self.angle != 0: self.painter.restore() # caller might want this information return self.calcbounds
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): """Render some text.""" width = state.fontMetrics().width(self.text) # actually write the text if requested if state.actually_render: state.painter.drawText(qt4.QPointF(state.x, state.y), self.text) # move along, nothing to see state.x += width
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 drawFillPts(self, painter, brushext, cliprect, ptsx, ptsy): '''Draw points for plotting a fill.''' pts = qt4.QPolygonF() utils.addNumpyToPolygonF(pts, ptsx, ptsy) filltype = brushext.filltype # this is broken: FIXME if filltype == 'left': dyend = ptsy[-1]-self._box[1] pts.append( qt4.QPointF(ptsx[-1]-dyend*tan30, self._box[1]) ) dystart = ptsy[0]-self._box[1] pts.append( qt4.QPointF(ptsx[0]-dystart*tan30, self._box[1]) ) elif filltype == 'right': pts.append( qt4.QPointF(self._box[2], ptsy[-1]) ) pts.append( qt4.QPointF(self._box[2], ptsy[0]) ) elif filltype == 'bottom': dyend = self._box[3]-ptsy[-1] pts.append( qt4.QPointF(ptsx[-1]-dyend*tan30, self._box[3]) ) dystart = self._box[3]-ptsy[0] pts.append( qt4.QPointF(ptsx[0]-dystart*tan30, self._box[3]) ) elif filltype == 'polygon': pass else: pts = None if pts is not None: utils.brushExtFillPolygon(painter, brushext, cliprect, pts)
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 _getBezierLine(self, poly): """Try to draw a bezier line connecting the points.""" npts = qtloops.bezier_fit_cubic_multi(poly, 0.1, len(poly) + 1) i = 0 path = qt4.QPainterPath() lastpt = qt4.QPointF(-999999, -999999) while i < len(npts): if lastpt != npts[i]: path.moveTo(npts[i]) path.cubicTo(npts[i + 1], npts[i + 2], npts[i + 3]) lastpt = npts[i + 3] i += 4 return path
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 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 drawFillPts(self, painter, extfill, cliprect, ptsx, ptsy): '''Draw points for plotting a fill.''' pts = qt4.QPolygonF() utils.addNumpyToPolygonF(pts, ptsx, ptsy) filltype = extfill.filltype if filltype == 'center': pts.append(qt4.QPointF(self._xc, self._yc)) utils.brushExtFillPolygon(painter, extfill, cliprect, pts) elif filltype == 'outside': pp = qt4.QPainterPath() pp.moveTo(self._xc, self._yc) pp.arcTo(cliprect, 0, 360) pp.addPolygon(pts) utils.brushExtFillPath(painter, extfill, pp) elif filltype == 'polygon': utils.brushExtFillPolygon(painter, extfill, cliprect, pts)
def _fillRegion(self, painter, pxpts, pypts, bounds, belowleft, clip, brush): """Fill the region above/below or left/right of the points. belowleft fills below if the variable is 'x', or left if 'y' otherwise it fills above/right.""" # find starting and ending points for the filled region x1, y1, x2, y2 = bounds pts = qt4.QPolygonF() if self.settings.variable == 'x': if belowleft: pts.append(qt4.QPointF(pxpts[0], y2)) endpt = qt4.QPointF(pxpts[-1], y2) else: pts.append(qt4.QPointF(pxpts[0], y1)) endpt = qt4.QPointF(pxpts[-1], y1) else: if belowleft: pts.append(qt4.QPointF(x1, pypts[0])) endpt = qt4.QPointF(x1, pypts[-1]) else: pts.append(qt4.QPointF(x2, pypts[0])) endpt = qt4.QPointF(x2, pypts[-1]) # add the points between utils.addNumpyToPolygonF(pts, pxpts, pypts) # stick on the ending point pts.append(endpt) # draw the clipped polygon clipped = qt4.QPolygonF() utils.polygonClip(pts, clip, clipped) path = qt4.QPainterPath() path.addPolygon(clipped) utils.brushExtFillPath(painter, brush, path)
def render(self, state): if len(self.children) != 2: return font = state.font painter = state.painter # make font half size size = font.pointSizeF() font.setPointSizeF(size * 0.5) painter.setFont(font) # keep track of width above and below line if not state.actually_render: self.widths = [] initx = state.x inity = state.y # render bottom of fraction if state.actually_render and len(self.widths) == 2: # centre line state.x = initx + (max(self.widths) - self.widths[0]) * 0.5 self.children[1].render(state) if not state.actually_render: # get width if not rendering self.widths.append(state.x - initx) # render top of fraction m = state.fontMetrics() state.y -= (m.ascent() + m.descent()) if state.actually_render and len(self.widths) == 2: # centre line state.x = initx + (max(self.widths) - self.widths[1]) * 0.5 else: state.x = initx self.children[0].render(state) if not state.actually_render: self.widths.append(state.x - initx) state.x = initx + max(self.widths) state.y = inity # restore font font.setPointSizeF(size) painter.setFont(font) height = state.fontMetrics().ascent() # draw line between lines with 0.5pt thickness painter.save() pen = painter.pen() painter.setPen( qt4.QPen(painter.pen().brush(), state.getPixelsPerPt() * 0.5)) painter.setPen(pen) painter.drawLine( qt4.QPointF(initx, inity - height / 2.), qt4.QPointF(initx + max(self.widths), inity - height / 2)) painter.restore()
def _getLinePoints(self, xvals, yvals, posn, xdata, ydata): """Get the points corresponding to the line connecting the points.""" pts = qt4.QPolygonF() s = self.settings steps = s.PlotLine.steps # simple continuous line if steps == 'off': utils.addNumpyToPolygonF(pts, xvals, yvals) # stepped line, with points on left elif steps[:4] == 'left': x1 = xvals[:-1] x2 = xvals[1:] y1 = yvals[:-1] y2 = yvals[1:] utils.addNumpyToPolygonF(pts, x1, y1, x2, y1, x2, y2) # stepped line, with points on right elif steps[:5] == 'right': x1 = xvals[:-1] x2 = xvals[1:] y1 = yvals[:-1] y2 = yvals[1:] utils.addNumpyToPolygonF(pts, x1, y1, x1, y2, x2, y2) # stepped line, with points in centre # this is complex as we can't use the mean of the plotter coords, # as the axis could be log elif steps[:6] == 'centre': axes = self.parent.getAxes((s.xAxis, s.yAxis)) if xdata.hasErrors(): # Special case if error bars on x points: # here we use the error bars to define the steps xmin, xmax = xdata.getPointRanges() # this is duplicated from drawing error bars: bad # convert xmin and xmax to graph coordinates xmin = axes[0].dataToPlotterCoords(posn, xmin) xmax = axes[0].dataToPlotterCoords(posn, xmax) utils.addNumpyToPolygonF(pts, xmin, yvals, xmax, yvals) else: # we put the bin edges half way between the points # we assume this is the correct thing to do even in log space x1 = xvals[:-1] x2 = xvals[1:] y1 = yvals[:-1] y2 = yvals[1:] xc = 0.5 * (x1 + x2) utils.addNumpyToPolygonF(pts, x1, y1, xc, y1, xc, y2) if len(xvals) > 0: pts.append(qt4.QPointF(xvals[-1], yvals[-1])) else: assert False return pts
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 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 swapline(self, painter, a1, b1, a2, b2): """Draw line, but swap x & y coordinates if vertical axis.""" if self.settings.direction == 'horizontal': painter.drawLine(qt4.QPointF(a1, b1), qt4.QPointF(a2, b2)) else: painter.drawLine(qt4.QPointF(b1, a1), qt4.QPointF(b2, a2))