def _renderChart(self, cx): """Renders a pie chart""" cx.set_line_join(cairo.LINE_JOIN_ROUND) if self.options.stroke.shadow: cx.save() cx.set_source_rgba(0, 0, 0, 0.15) cx.new_path() cx.move_to(self.centerx, self.centery) cx.arc(self.centerx + 1, self.centery + 2, self.radius + 1, 0, math.pi * 2) cx.line_to(self.centerx, self.centery) cx.close_path() cx.fill() cx.restore() cx.save() for slice in self.slices: if slice.isBigEnough(): cx.set_source_rgb(*self.colorScheme[slice.name]) if self.options.shouldFill: slice.draw(cx, self.centerx, self.centery, self.radius) cx.fill() if not self.options.stroke.hide: slice.draw(cx, self.centerx, self.centery, self.radius) cx.set_line_width(self.options.stroke.width) cx.set_source_rgb(*hex2rgb(self.options.stroke.color)) cx.stroke() cx.restore()
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() for key in keys: 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.stroke.width) 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()
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.area.x + self.area.w * bar.x y = self.area.y + self.area.h * bar.y w = self.area.w * bar.w h = self.area.h * bar.h if w < 1 or h < 1: 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() # 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)) label = unicode(bar.yval) extents = cx.text_extents(label) labelW = extents[2] labelH = extents[3] self._renderYVal(cx, label, labelW, labelH, x, y, w, h) cx.restore()
def _renderBackground(self, cx): """Renders the background area of the chart""" if self.options.background.hide: return cx.save() if self.options.background.baseColor: cx.set_source_rgb(*hex2rgb(self.options.background.baseColor)) cx.paint() if self.options.background.chartColor: cx.set_source_rgb(*hex2rgb(self.options.background.chartColor)) cx.rectangle(self.area.x, self.area.y, self.area.w, self.area.h) cx.fill() if self.options.background.lineColor: cx.set_source_rgb(*hex2rgb(self.options.background.lineColor)) cx.set_line_width(self.options.axis.lineWidth) self._renderLines(cx) cx.restore()
def _renderAxis(self, cx): """Renders axis""" if self.options.axis.x.hide and self.options.axis.y.hide: return cx.save() cx.set_source_rgb(*hex2rgb(self.options.axis.lineColor)) cx.set_line_width(self.options.axis.lineWidth) if not self.options.axis.y.hide: if self.yticks: for tick in self.yticks: self._renderYTick(cx, tick) if self.options.axis.y.label: cx.save() rotate = self.options.axis.y.rotate tickWidth, tickHeight = self._getTickSize( cx, self.yticks, rotate) label = unicode(self.options.axis.y.label) x = self.area.x - tickWidth - 4.0 y = self.area.y + 0.5 * self.area.h self._renderAxisLabel(cx, tickWidth, tickHeight, label, x, y, True) cx.restore() self._renderYAxis(cx) if not self.options.axis.x.hide: fontAscent = cx.font_extents()[0] if self.xticks: for tick in self.xticks: self._renderXTick(cx, tick, fontAscent) if self.options.axis.x.label: cx.save() rotate = self.options.axis.x.rotate tickWidth, tickHeight = self._getTickSize( cx, self.xticks, rotate) label = unicode(self.options.axis.x.label) x = self.area.x + self.area.w / 2.0 y = self.area.y + self.area.h + tickHeight + 4.0 self._renderAxisLabel(cx, tickWidth, tickHeight, label, x, y, False) cx.restore() self._renderXAxis(cx) cx.restore()
def _renderAxis(self, cx): """Renders axis""" if self.options.axis.x.hide and self.options.axis.y.hide: return cx.save() cx.set_source_rgb(*hex2rgb(self.options.axis.lineColor)) cx.set_line_width(self.options.axis.lineWidth) if not self.options.axis.y.hide: if self.yticks: for tick in self.yticks: self._renderYTick(cx, tick) if self.options.axis.y.label: cx.save() rotate = self.options.axis.y.rotate tickWidth, tickHeight = self._getTickSize(cx, self.yticks, rotate) label = unicode(self.options.axis.y.label) x = self.area.x - tickWidth - 4.0 y = self.area.y + 0.5 * self.area.h self._renderAxisLabel(cx, tickWidth, tickHeight, label, x, y, True) cx.restore() self._renderYAxis(cx) if not self.options.axis.x.hide: fontAscent = cx.font_extents()[0] if self.xticks: for tick in self.xticks: self._renderXTick(cx, tick, fontAscent) if self.options.axis.x.label: cx.save() rotate = self.options.axis.x.rotate tickWidth, tickHeight = self._getTickSize(cx, self.xticks, rotate) label = unicode(self.options.axis.x.label) x = self.area.x + self.area.w / 2.0 y = self.area.y + self.area.h + tickHeight + 4.0 self._renderAxisLabel(cx, tickWidth, tickHeight, label, x, y, False) cx.restore() self._renderXAxis(cx) cx.restore()
def _renderBackground(self, cx): """Renders the background of the chart""" if self.options.background.hide: return cx.save() if self.options.background.baseColor: cx.set_source_rgb(*hex2rgb(self.options.background.baseColor)) x, y, w, h = 0, 0, self.area.w, self.area.h w += self.options.padding.left + self.options.padding.right h += self.options.padding.top + self.options.padding.bottom cx.rectangle(x, y, w, h) cx.fill() cx.restore()
def _renderAxis(self, cx): """Renders the axis for pie charts""" if self.options.axis.x.hide or not self.xticks: return self.xlabels = [] lookup = dict([(slice.xval, slice) for slice in self.slices]) cx.select_font_face(self.options.axis.tickFont, cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL) cx.set_font_size(self.options.axis.tickFontSize) cx.set_source_rgb(*hex2rgb(self.options.axis.labelColor)) for tick in self.xticks: slice = lookup[tick[0]] normalisedAngle = slice.getNormalisedAngle() big_radius = self.radius + 10 labelx = self.centerx + math.sin(normalisedAngle) * big_radius labely = self.centery - math.cos(normalisedAngle) * big_radius label = tick[1] extents = cx.text_extents(label) labelWidth = extents[2] labelHeight = extents[3] x = y = 0 if normalisedAngle <= math.pi * 0.5: x = labelx y = labely - labelHeight elif math.pi * 0.5 < normalisedAngle <= math.pi: x = labelx y = labely elif math.pi < normalisedAngle <= math.pi * 1.5: x = labelx - labelWidth y = labely else: x = labelx - labelWidth y = labely - labelHeight # draw label with text tick[1] cx.move_to(x, y) cx.show_text(label) self.xlabels.append(label)
def drawLine(storeName): if self.options.stroke.shadow: # draw shadow cx.save() cx.set_source_rgba(0, 0, 0, 0.15) cx.translate(2, -2) preparePath(storeName) cx.fill() cx.restore() # fill the line cx.set_source_rgb(*self.colorScheme[storeName]) preparePath(storeName) cx.fill() if not self.options.stroke.hide: # draw stroke cx.set_source_rgb(*hex2rgb(self.options.stroke.color)) preparePath(storeName) cx.stroke()