示例#1
0
    def drawLabels(self, painter, xplotter, yplotter, textvals, markersize):
        """Draw labels for the points."""

        s = self.settings
        lab = s.get('Label')

        # work out offset an alignment
        deltax = markersize * 1.5 * {
            'left': -1,
            'centre': 0,
            'right': 1
        }[lab.posnHorz]
        deltay = markersize * 1.5 * {
            'top': -1,
            'centre': 0,
            'bottom': 1
        }[lab.posnVert]
        alignhorz = {'left': 1, 'centre': 0, 'right': -1}[lab.posnHorz]
        alignvert = {'top': -1, 'centre': 0, 'bottom': 1}[lab.posnVert]

        # make font and len
        textpen = lab.makeQPen()
        painter.setPen(textpen)
        font = lab.makeQFont(painter)
        angle = lab.angle

        # iterate over each point and plot each label
        for x, y, t in itertools.izip(xplotter + deltax, yplotter + deltay,
                                      textvals):
            utils.Renderer(painter, font, x, y, t, alignhorz, alignvert,
                           angle).render()
示例#2
0
    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)
示例#3
0
    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)] )
示例#4
0
    def _drawAxisLabel(self, painter, sign, outerbounds, texttorender):
        """Draw an axis label on the plot.

        texttorender is a list which contains text for the axis to render
        after checking for collisions
        """

        s = self.settings
        sl = s.Label
        label = s.get('Label')
        font = label.makeQFont(painter)
        painter.setFont(font)
        fm = utils.FontMetrics(font, painter.device())
        al_spacing = fm.leading() + fm.descent()

        # an extra offset if required
        self._delta_axis += label.get('offset').convert(painter)

        text = s.label
        # avoid adding blank text to plot
        if not text:
            return

        horz = s.direction == 'horizontal'

        align1 = 1
        align2 = {'centre': 0,
                  'at-minimum': -1,
                  'at-maximum': 1}[sl.position]

        if horz:
            ax, ay = align2, align1
        else:
            ax, ay = align1, align2

        reflected = self.coordReflected
        if reflected:
            if horz:
                ay = -ay
            else:
                ax = -ax

        # angle of text (logic is slightly complex)
        angle = int(sl.rotate)
        if horz:
            if not reflected:
                angle = 360-angle
        else:
            angle = angle+270
            if reflected:
                angle = 360-angle
        angle = angle % 360

        if sl.position == 'centre':
            x = 0.5*(self.coordParr1 + self.coordParr2)
        elif sl.position == 'at-minimum':
            x = self.coordParr1
        else:
            x = self.coordParr2

        y = self.coordPerp + sign*(self._delta_axis+al_spacing)
        if not horz:
            x, y = y, x

        # make axis label flush with edge of plot if
        # it's appropriate
        if outerbounds is not None and sl.atEdge:
            if abs(s.otherPosition) < 1e-4 and not reflected:
                if horz:
                    y = outerbounds[3]
                    ay = -ay
                else:
                    x = outerbounds[0]
                    ax = -ax
            elif abs(s.otherPosition-1.) < 1e-4 and reflected:
                if horz:
                    y = outerbounds[1]
                    ay = -ay
                else:
                    x = outerbounds[2]
                    ax = -ax

        r = utils.Renderer(painter, font, x, y, text,
                           ax, ay, angle,
                           usefullheight = True)

        # make sure text is in plot rectangle
        if outerbounds is not None:
            r.ensureInBox( minx=outerbounds[0], maxx=outerbounds[2],
                           miny=outerbounds[1], maxy=outerbounds[3] )

        texttorender.insert(0, (r, s.get('Label').makeQPen()) )
示例#5
0
    def _drawTickLabels(self, phelper, painter, coordticks, sign, outerbounds,
                        texttorender):
        """Draw tick labels on the plot.

        texttorender is a list which contains text for the axis to render
        after checking for collisions
        """

        s = self.settings
        vertical = s.direction == 'vertical'
        font = s.get('TickLabels').makeQFont(painter)
        painter.setFont(font)
        fm = utils.FontMetrics(font, painter.device())
        tl_spacing = fm.leading() + fm.descent()

        # work out font alignment
        angle = int(s.TickLabels.rotate)
        if not self.coordReflected and angle != 0:
            angle = 360-angle
        
        if vertical:
            # limit tick labels to be directly below/besides axis
            ax, ay = 1, 0
        else:
            ax, ay = 0, 1

        if self.coordReflected:
            ax, ay = -ax, -ay

        # get information about text scales
        tl = s.get('TickLabels')
        scale = tl.scale
        pen = tl.makeQPen()

        # an extra offset if required
        self._delta_axis += tl.get('offset').convert(painter)

        def generateTickLabels():
            """Return plotter position of labels and label text."""
            # get format for labels
            format = s.TickLabels.format
            if format.lower() == 'auto':
                format = self.autoformat

            # generate positions and labels
            for posn, tickval in izip(coordticks, self.majortickscalc):
                text = utils.formatNumber(tickval*scale, format,
                                          locale=self.document.locale)
                yield posn, text

        # position of label perpendicular to axis
        perpposn = self.coordPerp + sign*(self._delta_axis+tl_spacing)

        # use generator function to get labels and positions
        if s.mode == 'labels':
            ticklabels = self.generateLabelLabels(phelper)
        else:
            ticklabels = generateTickLabels()

        # iterate over each label
        maxdim = 0
        for parlposn, text in ticklabels:

            # x and y round other way if vertical
            if vertical:
                x, y = perpposn, parlposn
            else:
                x, y = parlposn, perpposn

            r = utils.Renderer(painter, font, x, y, text, alignhorz=ax,
                               alignvert=ay, angle=angle)
            if outerbounds is not None:
                # make sure ticks are within plot
                if vertical:
                    r.ensureInBox(miny=outerbounds[1], maxy=outerbounds[3],
                                  extraspace=True)
                else:
                    r.ensureInBox(minx=outerbounds[0], maxx=outerbounds[2],
                                  extraspace=True)

            bnd = r.getBounds()
            texttorender.append( (r, pen) )

            # keep track of maximum extent of label perpendicular to axis
            if vertical:
                maxdim = max(maxdim, bnd[2] - bnd[0])
            else:
                maxdim = max(maxdim, bnd[3] - bnd[1])

        # keep track of where we are
        self._delta_axis += 2*tl_spacing + maxdim
示例#6
0
    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)
示例#7
0
    def _drawTickSet(self, painter, tickSetn, gridSetn,
                     tickbot, tickleft, tickright,
                     tickLabelSetn=None, labelSetn=None):
        '''Draw a set of ticks (major or minor).

        tickSetn: tick setting to get line details
        gridSetn: setting for grid line (if any)
        tickXXX: tick arrays for each axis
        tickLabelSetn: setting used to label ticks, or None if minor ticks
        labelSetn: setting for labels, if any
        '''

        # this is mostly a lot of annoying trigonometry
        # compute line ends for ticks and grid lines

        tl = tickSetn.get('length').convert(painter)
        mv = self._maxVal()

        # bottom ticks
        x1 = (tickbot - self._orgbot)/self._size*self._width + self._box[0]
        x2 = x1 - tl * sin30
        y1 = self._box[3] + N.zeros(x1.shape)
        y2 = y1 + tl * cos30
        tickbotline = (x1, y1, x2, y2)

        # bottom grid (removing lines at edge of plot)
        scaletick = 1 - (tickbot-self._orgbot)/self._size
        gx = x1 + scaletick*self._width*sin30
        gy = y1 - scaletick*self._width*cos30
        ne = (scaletick > 1e-6) & (scaletick < (1-1e-6))
        gridbotline = (x1[ne], y1[ne], gx[ne], gy[ne])

        # left ticks
        x1 = -(tickleft - self._orgleft)/self._size*self._width*sin30 + (
            self._box[0] + self._box[2])*0.5
        x2 = x1 - tl * sin30
        y1 = (tickleft - self._orgleft)/self._size*self._width*cos30 + self._box[1]
        y2 = y1 - tl * cos30
        tickleftline = (x1, y1, x2, y2)

        # left grid
        scaletick = 1 - (tickleft-self._orgleft)/self._size
        gx = x1 + scaletick*self._width*sin30
        gy = self._box[3] + N.zeros(y1.shape)
        ne = (scaletick > 1e-6) & (scaletick < (1-1e-6))
        gridleftline = (x1[ne], y1[ne], gx[ne], gy[ne])

        # right ticks
        x1 = -(tickright - self._orgright)/self._size*self._width*sin30+self._box[2]
        x2 = x1 + tl
        y1 = -(tickright - self._orgright)/self._size*self._width*cos30+self._box[3]
        y2 = y1
        tickrightline = (x1, y1, x2, y2)

        # right grid
        scaletick = 1 - (tickright-self._orgright)/self._size
        gx = x1 - scaletick*self._width
        gy = y1
        gridrightline = (x1[ne], y1[ne], gx[ne], gy[ne])

        if not gridSetn.hide:
            # draw the grid
            pen = gridSetn.makeQPen(painter)
            painter.setPen(pen)
            utils.plotLinesToPainter(painter, *gridbotline)
            utils.plotLinesToPainter(painter, *gridleftline)
            utils.plotLinesToPainter(painter, *gridrightline)

        # calculate deltas for ticks
        bdelta = ldelta = rdelta = 0

        if not tickSetn.hide:
            # draw ticks themselves
            pen = tickSetn.makeQPen(painter)
            pen.setCapStyle(qt4.Qt.FlatCap)
            painter.setPen(pen)
            utils.plotLinesToPainter(painter, *tickbotline)
            utils.plotLinesToPainter(painter, *tickleftline)
            utils.plotLinesToPainter(painter, *tickrightline)

            ldelta += tl*sin30
            bdelta += tl*cos30
            rdelta += tl

        if tickLabelSetn is not None and not tickLabelSetn.hide:
            # compute the labels for the ticks
            tleftlabels = self._getLabels(tickleft*mv, '%Vg')
            trightlabels = self._getLabels(tickright*mv, '%Vg')
            tbotlabels = self._getLabels(tickbot*mv, '%Vg')

            painter.setPen( tickLabelSetn.makeQPen() )
            font = tickLabelSetn.makeQFont(painter)
            painter.setFont(font)

            fm = utils.FontMetrics(font, painter.device())
            sp = fm.leading() + fm.descent()
            off = tickLabelSetn.get('offset').convert(painter)

            # draw tick labels in each direction
            hlabbot = wlableft = wlabright = 0
            for l, x, y in izip(tbotlabels, tickbotline[2], tickbotline[3]+off):
                r = utils.Renderer(painter, font, x, y, l, 0, 1, 0)
                bounds = r.render()
                hlabbot = max(hlabbot, bounds[3]-bounds[1])
            for l, x, y in izip(tleftlabels, tickleftline[2]-off-sp, tickleftline[3]):
                r = utils.Renderer(painter, font, x, y, l, 1, 0, 0)
                bounds = r.render()
                wlableft = max(wlableft, bounds[2]-bounds[0])
            for l, x, y in izip(trightlabels,tickrightline[2]+off+sp, tickrightline[3]):
                r = utils.Renderer(painter, font, x, y, l, -1, 0, 0)
                bounds = r.render()
                wlabright = max(wlabright, bounds[2]-bounds[0])

            bdelta += hlabbot+off+sp
            ldelta += wlableft+off+sp
            rdelta += wlabright+off+sp

        if labelSetn is not None and not labelSetn.hide:
            # draw label on edges (if requested)
            painter.setPen( labelSetn.makeQPen() )
            font = labelSetn.makeQFont(painter)
            painter.setFont(font)

            fm = utils.FontMetrics(font, painter.device())
            sp = fm.leading() + fm.descent()
            off = labelSetn.get('offset').convert(painter)

            # bottom label
            r = utils.Renderer(painter, font,
                               self._box[0]+self._width/2,
                               self._box[3] + bdelta + off,
                               self.settings.labelbottom,
                               0, 1)
            r.render()

            # left label - rotate frame before drawing so we can get
            # the bounds correct
            r = utils.Renderer(painter, font, 0, -sp,
                               self.settings.labelleft,
                               0, -1)
            painter.save()
            painter.translate(self._box[0]+self._width*0.25 - ldelta - off,
                              0.5*(self._box[1]+self._box[3]))
            painter.rotate(-60)
            r.render()
            painter.restore()

            # right label
            r = utils.Renderer(painter, font, 0, -sp,
                               self.settings.labelright,
                               0, -1)
            painter.save()
            painter.translate(self._box[0]+self._width*0.75 + ldelta + off,
                              0.5*(self._box[1]+self._box[3]))
            painter.rotate(60)
            r.render()
            painter.restore()