Example #1
0
        def drawBar(bar):
            stroke_width = self.options.stroke.width
            ux, uy = cx.device_to_user_distance(stroke_width, stroke_width)
            if ux < uy:
                ux = uy
            cx.set_line_width(ux)

            # gather bar proportions
            x = self.layout.chart.x + self.layout.chart.w * bar.x
            y = self.layout.chart.y + self.layout.chart.h * bar.y
            w = self.layout.chart.w * bar.w
            h = self.layout.chart.h * bar.h

            if (w < 1 or h < 1) and self.options.yvals.skipSmallValues:
                return  # don't draw when the bar is too small

            if self.options.stroke.shadow:
                cx.set_source_rgba(0, 0, 0, 0.15)
                rectangle = self._getShadowRectangle(x, y, w, h)
                cx.rectangle(*rectangle)
                cx.fill()

            if self.options.shouldFill or (not self.options.stroke.hide):

                if self.options.shouldFill:
                    cx.set_source_rgb(*self.colorScheme[bar.name])
                    cx.rectangle(x, y, w, h)
                    cx.fill()

                if not self.options.stroke.hide:
                    cx.set_source_rgb(*hex2rgb(self.options.stroke.color))
                    cx.rectangle(x, y, w, h)
                    cx.stroke()

            if bar.yerr:
                self._renderError(cx, x, y, w, h, bar.yval, bar.yerr)

            # render yvals above/beside bars
            if self.options.yvals.show:
                cx.save()
                cx.set_font_size(self.options.yvals.fontSize)
                cx.set_source_rgb(*hex2rgb(self.options.yvals.fontColor))

                if callable(self.options.yvals.renderer):
                    label = safe_unicode(self.options.yvals.renderer(bar),
                                         self.options.encoding)
                else:
                    label = safe_unicode(bar.yval, self.options.encoding)
                extents = cx.text_extents(label)
                labelW = extents[2]
                labelH = extents[3]

                self._renderYVal(cx, label, labelW, labelH, x, y, w, h)

                cx.restore()
Example #2
0
        def drawBar(bar):
            stroke_width = self.options.stroke.width
            ux, uy = cx.device_to_user_distance(stroke_width, stroke_width)
            if ux < uy:
                ux = uy
            cx.set_line_width(ux)

            # gather bar proportions
            x = self.layout.chart.x + self.layout.chart.w * bar.x
            y = self.layout.chart.y + self.layout.chart.h * bar.y
            w = self.layout.chart.w * bar.w
            h = self.layout.chart.h * bar.h

            if (w < 1 or h < 1) and self.options.yvals.skipSmallValues:
                return # don't draw when the bar is too small

            if self.options.stroke.shadow:
                cx.set_source_rgba(0, 0, 0, 0.15)
                rectangle = self._getShadowRectangle(x, y, w, h)
                cx.rectangle(*rectangle)
                cx.fill()

            if self.options.shouldFill or (not self.options.stroke.hide):

                if self.options.shouldFill:
                    cx.set_source_rgb(*self.colorScheme[bar.name])
                    cx.rectangle(x, y, w, h)
                    cx.fill()

                if not self.options.stroke.hide:
                    cx.set_source_rgb(*hex2rgb(self.options.stroke.color))
                    cx.rectangle(x, y, w, h)
                    cx.stroke()

            if bar.yerr:
                self._renderError(cx, x, y, w, h, bar.yval, bar.yerr)

            # render yvals above/beside bars
            if self.options.yvals.show:
                cx.save()
                cx.set_font_size(self.options.yvals.fontSize)
                cx.set_source_rgb(*hex2rgb(self.options.yvals.fontColor))

                if isinstance(self.options.yvals.renderer, collections.Callable):
                    label = safe_unicode(self.options.yvals.renderer(bar),
                                         self.options.encoding)
                else:
                    label = safe_unicode(bar.yval, self.options.encoding)
                extents = cx.text_extents(label)
                labelW = extents[2]
                labelH = extents[3]

                self._renderYVal(cx, label, labelW, labelH, x, y, w, h)

                cx.restore()
Example #3
0
    def _getAxisTickLabelsSize(self, cx, options, axis, ticks):
        cx.save()
        cx.select_font_face(options.axis.tickFont,
                            cairo.FONT_SLANT_NORMAL,
                            cairo.FONT_WEIGHT_NORMAL)
        cx.set_font_size(options.axis.tickFontSize)

        max_width = max_height = 0.0
        if not axis.hide:
            extents = [cx.text_extents(safe_unicode(
                        tick[1], options.encoding,
                        ))[2:4] # get width and height as a tuple
                       for tick in ticks]
            if extents:
                widths, heights = zip(*extents)
                max_width, max_height = max(widths), max(heights)
                if axis.rotate:
                    radians = math.radians(axis.rotate)
                    sin = math.sin(radians)
                    cos = math.cos(radians)
                    max_width, max_height = (
                        max_width * cos + max_height * sin,
                        max_width * sin + max_height * cos,
                        )
        cx.restore()
        return max_width, max_height
Example #4
0
    def _getAxisTickLabelsSize(self, cx, options, axis, ticks):
        cx.save()
        cx.select_font_face(options.axis.tickFont,
                            cairo.FONT_SLANT_NORMAL,
                            cairo.FONT_WEIGHT_NORMAL)
        cx.set_font_size(options.axis.tickFontSize)

        max_width = max_height = 0.0
        if not axis.hide:
            extents = [cx.text_extents(safe_unicode(
                        tick[1], options.encoding,
                        ))[2:4] # get width and height as a tuple
                       for tick in ticks]
            if extents:
                widths, heights = zip(*extents)
                max_width, max_height = max(widths), max(heights)
                if axis.rotate:
                    radians = math.radians(axis.rotate)
                    sin = math.sin(radians)
                    cos = math.cos(radians)
                    max_width, max_height = (
                        max_width * cos + max_height * sin,
                        max_width * sin + max_height * cos,
                        )
        cx.restore()
        return max_width, max_height
Example #5
0
        def preparePath(storeName):
            cx.new_path()
            firstPoint = True
            lastX = None
            if self.options.shouldFill:
                # Go to the (0,0) coordinate to start drawing the area
                # cx.move_to(self.layout.chart.x,
                #           self.layout.chart.y + self.layout.chart.h)
                offset = (1.0 - self.origin) * self.layout.chart.h
                cx.move_to(self.layout.chart.x, self.layout.chart.y + offset)

            for point in self.points:
                if point.name == storeName:
                    if not self.options.shouldFill and firstPoint:
                        # starts the first point of the line
                        cx.move_to(
                            point.x * self.layout.chart.w + self.layout.chart.x,
                            point.y * self.layout.chart.h + self.layout.chart.y,
                        )
                        firstPoint = False
                        continue
                    cx.line_to(
                        point.x * self.layout.chart.w + self.layout.chart.x,
                        point.y * self.layout.chart.h + self.layout.chart.y,
                    )
                    # # cx.show_text(str(point.yval))
                    # we remember the last X coordinate to close the area
                    # properly. See bug #4
                    lastX = point.x

            if self.options.shouldFill:
                # Close the path to the start point
                y = (1.0 - self.origin) * self.layout.chart.h + self.layout.chart.y
                cx.line_to(lastX * self.layout.chart.w + self.layout.chart.x, y)
                cx.line_to(self.layout.chart.x, y)
                cx.close_path()
            else:
                cx.set_source_rgb(*self.colorScheme[storeName])
                cx.stroke()

            # Draw yvals text, add by Zhang Kun
            if self.options.yvals and self.options.yvals.show:
                cx.save()
                cx.set_font_size(self.options.yvals.fontSize)
                cx.set_source_rgb(*hex2rgb(self.options.yvals.fontColor))

                for point in self.points:
                    if point.name == storeName:
                        val_str = safe_unicode(str(point.yval), self.options.encoding)
                        extents = cx.text_extents(val_str)

                        cx.move_to(
                            point.x * self.layout.chart.w + self.layout.chart.x,
                            point.y * self.layout.chart.h + self.layout.chart.y + extents[1] / 2,
                        )
                        cx.show_text(str(point.yval))
                cx.restore()
Example #6
0
def get_text_extents(cx, text, font, font_size, encoding):
    if text:
        cx.save()
        cx.select_font_face(font,
                            cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_BOLD)
        cx.set_font_size(font_size)
        safe_text = safe_unicode(text, encoding)
        extents = cx.text_extents(safe_text)
        cx.restore()
        return extents[2:4]
    return (0.0, 0.0)
Example #7
0
def get_text_extents(cx, text, font, font_size, encoding):
    if text:
        cx.save()
        cx.select_font_face(font,
                            cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_BOLD)
        cx.set_font_size(font_size)
        safe_text = safe_unicode(text, encoding)
        extents = cx.text_extents(safe_text)
        cx.restore()
        return extents[2:4]
    return (0.0, 0.0)
Example #8
0
    def _renderXTick(self, cx, i, fontAscent, center):
        tick = self.xticks[i]
        if callable(tick):
            return

        count = len(self.xticks)
        cx.select_font_face(self.options.axis.tickFont,
                            cairo.FONT_SLANT_NORMAL,
                            cairo.FONT_WEIGHT_NORMAL)
        cx.set_font_size(self.options.axis.tickFontSize)

        label = safe_unicode(tick[1], self.options.encoding)
        extents = cx.text_extents(label)
        labelWidth = extents[2]
        labelHeight = extents[3]

        x, y = center
        cx.move_to(x, y)

        if self.options.axis.x.rotate:
            radians = math.radians(self.options.axis.x.rotate)
            cx.move_to(x - (labelHeight * math.cos(radians)),
                       y + self.options.axis.tickSize
                       + (labelHeight * math.cos(radians))
                       + 4.0)
            cx.rotate(radians)
            cx.show_text(label)
            cx.rotate(-radians)
        else:
            offset1 = i * 2 * math.pi / count
            offset = math.pi / 2 - offset1

            rad = self.layout.chart.h / 2 + 10

            x = center[0] - math.cos(offset) * rad
            y = center[1] - math.sin(offset) * rad

            cx.move_to(x, y)
            cx.rotate(offset - math.pi / 2)

            if math.sin(offset) < 0.0:
                cx.rotate(math.pi)
                cx.rel_move_to(0.0, 5.0)

            cx.rel_move_to(-labelWidth / 2.0, 0)
            cx.show_text(label)
            if math.sin(offset) < 0.0:
                cx.rotate(-math.pi)

            cx.rotate(-(offset - math.pi / 2))
        return label
Example #9
0
    def _renderXTick(self, cx, i, fontAscent, center):
        tick = self.xticks[i]
        if callable(tick):
            return

        count = len(self.xticks)
        cx.select_font_face(self.options.axis.tickFont,
                            cairo.FONT_SLANT_NORMAL,
                            cairo.FONT_WEIGHT_NORMAL)
        cx.set_font_size(self.options.axis.tickFontSize)

        label = safe_unicode(tick[1], self.options.encoding)
        extents = cx.text_extents(label)
        labelWidth = extents[2]
        labelHeight = extents[3]

        x, y = center
        cx.move_to(x, y)

        if self.options.axis.x.rotate:
            radians = math.radians(self.options.axis.x.rotate)
            cx.move_to(x - (labelHeight * math.cos(radians)),
                       y + self.options.axis.tickSize
                       + (labelHeight * math.cos(radians))
                       + 4.0)
            cx.rotate(radians)
            cx.show_text(label)
            cx.rotate(-radians)
        else:
            offset1 = i * 2 * math.pi / count
            offset = math.pi / 2 - offset1

            rad = self.layout.chart.h / 2 + 10

            x = center[0] - math.cos(offset) * rad
            y = center[1] - math.sin(offset) * rad

            cx.move_to(x, y)
            cx.rotate(offset - math.pi / 2)

            if math.sin(offset) < 0.0:
                cx.rotate(math.pi)
                cx.rel_move_to(0.0, 5.0)

            cx.rel_move_to(-labelWidth / 2.0, 0)
            cx.show_text(label)
            if math.sin(offset) < 0.0:
                cx.rotate(-math.pi)

            cx.rotate(-(offset - math.pi / 2))
        return label
Example #10
0
    def _renderYTick(self, cx, tick, center):
        """Aux method for _renderAxis"""

        i = tick
        tick = self.yticks[i]

        count = len(self.yticks)

        if callable(tick):
            return

        x = center[0]
        y = center[1] - i * (self.layout.chart.h / 2) / count

        cx.new_path()
        cx.move_to(x, y)
        cx.line_to(x - self.options.axis.tickSize, y)
        cx.close_path()
        cx.stroke()

        cx.select_font_face(self.options.axis.tickFont,
                            cairo.FONT_SLANT_NORMAL,
                            cairo.FONT_WEIGHT_NORMAL)
        cx.set_font_size(self.options.axis.tickFontSize)

        label = safe_unicode(tick[1], self.options.encoding)
        extents = cx.text_extents(label)
        labelWidth = extents[2]
        labelHeight = extents[3]

        if self.options.axis.y.rotate:
            radians = math.radians(self.options.axis.y.rotate)
            cx.move_to(x - self.options.axis.tickSize
                       - (labelWidth * math.cos(radians))
                       - 4,
                       y + (labelWidth * math.sin(radians))
                       + labelHeight / (2.0 / math.cos(radians)))
            cx.rotate(-radians)
            cx.show_text(label)
            cx.rotate(radians)  # this is probably faster than a save/restore
        else:
            cx.move_to(x - self.options.axis.tickSize - labelWidth - 4,
                       y + labelHeight / 2.0)
            cx.rel_move_to(0.0, -labelHeight / 2.0)
            cx.show_text(label)

        return label
Example #11
0
    def _renderYTick(self, cx, tick, center):
        """Aux method for _renderAxis"""

        i = tick
        tick = self.yticks[i]

        count = len(self.yticks)

        if callable(tick):
            return

        x = center[0]
        y = center[1] - i * (self.layout.chart.h / 2) / count

        cx.new_path()
        cx.move_to(x, y)
        cx.line_to(x - self.options.axis.tickSize, y)
        cx.close_path()
        cx.stroke()

        cx.select_font_face(self.options.axis.tickFont,
                            cairo.FONT_SLANT_NORMAL,
                            cairo.FONT_WEIGHT_NORMAL)
        cx.set_font_size(self.options.axis.tickFontSize)

        label = safe_unicode(tick[1], self.options.encoding)
        extents = cx.text_extents(label)
        labelWidth = extents[2]
        labelHeight = extents[3]

        if self.options.axis.y.rotate:
            radians = math.radians(self.options.axis.y.rotate)
            cx.move_to(x - self.options.axis.tickSize
                       - (labelWidth * math.cos(radians))
                       - 4,
                       y + (labelWidth * math.sin(radians))
                       + labelHeight / (2.0 / math.cos(radians)))
            cx.rotate(-radians)
            cx.show_text(label)
            cx.rotate(radians)  # this is probably faster than a save/restore
        else:
            cx.move_to(x - self.options.axis.tickSize - labelWidth - 4,
                       y + labelHeight / 2.0)
            cx.rel_move_to(0.0, -labelHeight / 2.0)
            cx.show_text(label)

        return label
Example #12
0
    def _renderTick(self, cx, tick, x, y, x2, y2, rotate, text_position):
        """Aux method for _renderXTick and _renderYTick"""
        if callable(tick):
            return

        cx.new_path()
        cx.move_to(x, y)
        cx.line_to(x2, y2)
        cx.close_path()
        cx.stroke()

        cx.select_font_face(self.options.axis.tickFont,
                            cairo.FONT_SLANT_NORMAL,
                            cairo.FONT_WEIGHT_NORMAL)
        cx.set_font_size(self.options.axis.tickFontSize)

        label = safe_unicode(tick[1], self.options.encoding)
        xb, yb, width, height, xa, ya = cx.text_extents(label)

        x, y = text_position

        if rotate:
            cx.save()
            cx.translate(x, y)
            cx.rotate(math.radians(rotate))
            x = -width / 2.0
            y = -height / 2.0
            cx.move_to(x - xb, y - yb)
            cx.show_text(label)
            if self.debug:
                cx.rectangle(x, y, width, height)
                cx.stroke()
            cx.restore()
        else:
            x -= width / 2.0
            y -= height / 2.0
            cx.move_to(x - xb, y - yb)
            cx.show_text(label)
            if self.debug:
                cx.rectangle(x, y, width, height)
                cx.stroke()

        return label
Example #13
0
    def _renderTick(self, cx, tick, x, y, x2, y2, rotate, text_position):
        """Aux method for _renderXTick and _renderYTick"""
        if callable(tick):
            return

        cx.new_path()
        cx.move_to(x, y)
        cx.line_to(x2, y2)
        cx.close_path()
        cx.stroke()

        cx.select_font_face(self.options.axis.tickFont,
                            cairo.FONT_SLANT_NORMAL,
                            cairo.FONT_WEIGHT_NORMAL)
        cx.set_font_size(self.options.axis.tickFontSize)

        label = safe_unicode(tick[1], self.options.encoding)
        xb, yb, width, height, xa, ya = cx.text_extents(label)

        x, y = text_position

        if rotate:
            cx.save()
            cx.translate(x, y)
            cx.rotate(math.radians(rotate))
            x = -width / 2.0
            y = -height / 2.0
            cx.move_to(x - xb, y - yb)
            cx.show_text(label)
            if self.debug:
                cx.rectangle(x, y, width, height)
                cx.stroke()
            cx.restore()
        else:
            x -= width / 2.0
            y -= height / 2.0
            cx.move_to(x - xb, y - yb)
            cx.show_text(label)
            if self.debug:
                cx.rectangle(x, y, width, height)
                cx.stroke()

        return label
Example #14
0
    def _renderTitle(self, cx):
        if self.options.title:
            cx.save()
            cx.select_font_face(self.options.titleFont,
                                cairo.FONT_SLANT_NORMAL,
                                cairo.FONT_WEIGHT_BOLD)
            cx.set_font_size(self.options.titleFontSize)
            cx.set_source_rgb(*hex2rgb(self.options.titleColor))

            title = safe_unicode(self.options.title, self.options.encoding)
            extents = cx.text_extents(title)
            title_width = extents[2]

            x = (self.layout.title.x + self.layout.title.w / 2.0 - title_width / 2.0)
            y = self.layout.title.y - extents[1]

            cx.move_to(x, y)
            cx.show_text(title)

            cx.restore()
Example #15
0
    def _renderTitle(self, cx):
        if self.options.title:
            cx.save()
            cx.select_font_face(self.options.titleFont,
                                cairo.FONT_SLANT_NORMAL,
                                cairo.FONT_WEIGHT_BOLD)
            cx.set_font_size(self.options.titleFontSize)
            cx.set_source_rgb(*hex2rgb(self.options.titleColor))

            title = safe_unicode(self.options.title, self.options.encoding)
            extents = cx.text_extents(title)
            title_width = extents[2]

            x = (self.layout.title.x
                 + self.layout.title.w / 2.0
                 - title_width / 2.0)
            y = self.layout.title.y - extents[1]

            cx.move_to(x, y)
            cx.show_text(title)

            cx.restore()
Example #16
0
 def _renderXAxisLabel(self, cx, label_text):
     label = safe_unicode(label_text, self.options.encoding)
     x = self.layout.x_label.x + self.layout.x_label.w / 2.0
     y = self.layout.x_label.y
     self._renderAxisLabel(cx, label, x, y, False)
Example #17
0
    def _renderLegend(self, cx):
        """This function adds a legend to the chart"""
        if self.options.legend.hide:
            return

        surface_width, surface_height = self.getSurfaceSize()

        # Compute legend dimensions
        padding = 4
        bullet = 15
        width = 0
        height = padding
        keys = self._getDatasetsKeys()
        cx.select_font_face(self.options.legend.legendFont,
                            cairo.FONT_SLANT_NORMAL,
                            cairo.FONT_WEIGHT_NORMAL)
        cx.set_font_size(self.options.legend.legendFontSize)
        for key in keys:
            key = safe_unicode(key, self.options.encoding)
            extents = cx.text_extents(key)
            width = max(extents[2], width)
            height += max(extents[3], bullet) + padding
        width = padding + bullet + padding + width + padding

        # Compute legend position
        legend = self.options.legend
        if legend.position.right is not None:
            legend.position.left = (surface_width
                                    - legend.position.right
                                    - width)
        if legend.position.bottom is not None:
            legend.position.top = (surface_height
                                   - legend.position.bottom
                                   - height)

        # Draw the legend
        cx.save()
        cx.rectangle(self.options.legend.position.left,
                     self.options.legend.position.top,
                     width, height)
        cx.set_source_rgba(1, 1, 1, self.options.legend.opacity)
        cx.fill_preserve()
        cx.set_line_width(self.options.legend.borderWidth)
        cx.set_source_rgb(*hex2rgb(self.options.legend.borderColor))
        cx.stroke()

        def drawKey(key, x, y, text_height):
            cx.rectangle(x, y, bullet, bullet)
            cx.set_source_rgb(*self.colorScheme[key])
            cx.fill_preserve()
            cx.set_source_rgb(0, 0, 0)
            cx.stroke()
            cx.move_to(x + bullet + padding,
                       y + bullet / 2.0 + text_height / 2.0)
            cx.show_text(key)

        cx.set_line_width(1)
        x = self.options.legend.position.left + padding
        y = self.options.legend.position.top + padding
        for key in keys:
            extents = cx.text_extents(key)
            drawKey(key, x, y, extents[3])
            y += max(extents[3], bullet) + padding

        cx.restore()
Example #18
0
 def _renderXAxisLabel(self, cx, label_text):
     label = safe_unicode(label_text, self.options.encoding)
     x = self.layout.x_label.x + self.layout.x_label.w / 2.0
     y = self.layout.x_label.y
     self._renderAxisLabel(cx, label, x, y, False)
Example #19
0
 def _renderYAxisLabel(self, cx, label_text):
     label = safe_unicode(label_text, self.options.encoding)
     x = self.layout.y_label.x
     y = self.layout.y_label.y + self.layout.y_label.h / 2.0
     self._renderAxisLabel(cx, label, x, y, True)
Example #20
0
        def preparePath(storeName):
            cx.new_path()
            firstPoint = True
            lastX = None
            if self.options.shouldFill:
                # Go to the (0,0) coordinate to start drawing the area
                #cx.move_to(self.layout.chart.x,
                #           self.layout.chart.y + self.layout.chart.h)
                offset = (1.0 - self.origin) * self.layout.chart.h
                cx.move_to(self.layout.chart.x, self.layout.chart.y + offset)

            for point in self.points:
                if point.name == storeName:
                    if not self.options.shouldFill and firstPoint:
                        # starts the first point of the line
                        cx.move_to(
                            point.x * self.layout.chart.w +
                            self.layout.chart.x,
                            point.y * self.layout.chart.h +
                            self.layout.chart.y)
                        firstPoint = False
                        continue
                    cx.line_to(
                        point.x * self.layout.chart.w + self.layout.chart.x,
                        point.y * self.layout.chart.h + self.layout.chart.y)
                    # # cx.show_text(str(point.yval))
                    # we remember the last X coordinate to close the area
                    # properly. See bug #4
                    lastX = point.x

            if self.options.shouldFill:
                # Close the path to the start point
                y = ((1.0 - self.origin) * self.layout.chart.h +
                     self.layout.chart.y)
                cx.line_to(lastX * self.layout.chart.w + self.layout.chart.x,
                           y)
                cx.line_to(self.layout.chart.x, y)
                cx.close_path()
            else:
                cx.set_source_rgb(*self.colorScheme[storeName])
                cx.stroke()

            # Draw yvals text, add by Zhang Kun
            if self.options.yvals and self.options.yvals.show:
                cx.save()
                cx.set_font_size(self.options.yvals.fontSize)
                cx.set_source_rgb(*hex2rgb(self.options.yvals.fontColor))

                for point in self.points:
                    if point.name == storeName:
                        val_str = safe_unicode(str(point.yval),
                                               self.options.encoding)
                        extents = cx.text_extents(val_str)

                        cx.move_to(
                            point.x * self.layout.chart.w +
                            self.layout.chart.x,
                            point.y * self.layout.chart.h +
                            self.layout.chart.y + extents[1] / 2)
                        cx.show_text(str(point.yval))
                cx.restore()
Example #21
0
    def _renderLegend(self, cx):
        """This function adds a legend to the chart"""
        if self.options.legend.hide:
            return

        surface_width, surface_height = self.getSurfaceSize()

        # Compute legend dimensions
        padding = 4
        bullet = 15
        width = 0
        height = padding
        keys = self._getDatasetsKeys()
        cx.select_font_face(self.options.legend.legendFont,
                            cairo.FONT_SLANT_NORMAL,
                            cairo.FONT_WEIGHT_NORMAL)
        cx.set_font_size(self.options.legend.legendFontSize)
        for key in keys:
            key = safe_unicode(key, self.options.encoding)
            extents = cx.text_extents(key)
            width = max(extents[2], width)
            height += max(extents[3], bullet) + padding
        width = padding + bullet + padding + width + padding

        # Compute legend position
        legend = self.options.legend
        if legend.position.right is not None:
            legend.position.left = (surface_width
                                    - legend.position.right
                                    - width)
        if legend.position.bottom is not None:
            legend.position.top = (surface_height
                                   - legend.position.bottom
                                   - height)

        # Draw the legend
        cx.save()
        cx.rectangle(self.options.legend.position.left,
                     self.options.legend.position.top,
                     width, height)
        cx.set_source_rgba(1, 1, 1, self.options.legend.opacity)
        cx.fill_preserve()
        cx.set_line_width(self.options.legend.borderWidth)
        cx.set_source_rgb(*hex2rgb(self.options.legend.borderColor))
        cx.stroke()

        def drawKey(key, x, y, text_height):
            cx.rectangle(x, y, bullet, bullet)
            cx.set_source_rgb(*self.colorScheme[key])
            cx.fill_preserve()
            cx.set_source_rgb(0, 0, 0)
            cx.stroke()
            cx.move_to(x + bullet + padding,
                       y + bullet / 2.0 + text_height / 2.0)
            cx.show_text(key)

        cx.set_line_width(1)
        x = self.options.legend.position.left + padding
        y = self.options.legend.position.top + padding
        for key in keys:
            extents = cx.text_extents(key)
            drawKey(key, x, y, extents[3])
            y += max(extents[3], bullet) + padding

        cx.restore()
Example #22
0
 def _renderYAxisLabel(self, cx, label_text):
     label = safe_unicode(label_text, self.options.encoding)
     x = self.layout.y_label.x
     y = self.layout.y_label.y + self.layout.y_label.h / 2.0
     self._renderAxisLabel(cx, label, x, y, True)