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.set_line_width(10.0) cx.arc(self.layout.chart.x + self.layout.chart.w / 2, self.layout.chart.y + self.layout.chart.h / 2, min(self.layout.chart.w / 2, self.layout.chart.h / 2), 0, 2 * math.pi) 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 _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)) 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() 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 _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)) surface_width, surface_height = self.getSurfaceSize() cx.rectangle(self.options.padding.left, self.options.padding.top, surface_width - (self.options.padding.left + self.options.padding.right), surface_height - (self.options.padding.top + self.options.padding.bottom)) 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 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()
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()
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 # do not 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 _renderAxis(self, cx): """Renders the axis for pie charts""" if self.options.axis.x.hide or not self.xticks: return self.xlabels = [] if self.debug: px = max(cx.device_to_user_distance(1, 1)) cx.set_source_rgba(0, 0, 1, 0.5) for x, y, w, h in self.layout.ticks: cx.rectangle(x, y, w, h) cx.stroke() cx.arc(x + w / 2.0, y + h / 2.0, 5 * px, 0, 2 * math.pi) cx.fill() cx.arc(x, y, 2 * px, 0, 2 * math.pi) cx.fill() 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 i, tick in enumerate(self.xticks): label = tick[1] x, y, w, h = self.layout.ticks[i] xb, yb, width, height, xa, ya = cx.text_extents(label) # draw label with text tick[1] cx.move_to(x - xb, y - yb) cx.show_text(label) self.xlabels.append(label)
def _renderAxis(self, cx): """Renders the axis for pie charts""" if self.options.axis.x.hide or not self.xticks: return self.xlabels = [] if self.debug: px = max(cx.device_to_user_distance(1, 1)) cx.set_source_rgba(0, 0, 1, 0.5) for x, y, w, h in self.layout.ticks: cx.rectangle(x, y, w, h) cx.stroke() cx.arc(x + w / 2.0, y + h / 2.0, 5 * px, 0, 2 * math.pi) cx.fill() cx.arc(x, y, 2 * px, 0, 2 * math.pi) cx.fill() 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)) radius = self.layout.radius radius_inc = radius / (self.nrings + 1) current_radius = self.centery + radius_inc + radius_inc / 2 for i, tick in enumerate(self.xticks): label = tick[1] cx.move_to(self.centerx, current_radius) cx.show_text(label) current_radius += radius_inc
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.options.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.options.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 _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 _renderAxisLabel(self, cx, label, x, y, vertical=False): cx.save() cx.select_font_face(self.options.axis.labelFont, cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_BOLD) cx.set_font_size(self.options.axis.labelFontSize) cx.set_source_rgb(*hex2rgb(self.options.axis.labelColor)) xb, yb, width, height, xa, ya = cx.text_extents(label) if vertical: y = y + width / 2.0 cx.move_to(x - xb, y - yb) cx.translate(x, y) cx.rotate(-math.radians(90)) cx.move_to(-xb, -yb) cx.show_text(label) if self.debug: cx.rectangle(0, 0, width, height) cx.stroke() else: x = x - width / 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()
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: self._renderYAxisLabel(cx, self.options.axis.y.label) self._renderYAxis(cx) if not self.options.axis.x.hide: if self.xticks: for tick in self.xticks: self._renderXTick(cx, tick) if self.options.axis.x.label: self._renderXAxisLabel(cx, self.options.axis.x.label) 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() # draws the vertical line representing the Y axis cx.new_path() cx.move_to(self.area.x, self.area.y) cx.line_to(self.area.x, self.area.y + self.area.h) cx.close_path() cx.stroke() 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() # draws the horizontal line representing the X axis cx.new_path() cx.move_to(self.area.x, self.area.y + self.area.h) cx.line_to(self.area.x + self.area.w, self.area.y + self.area.h) cx.close_path() cx.stroke() cx.restore()
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()
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 _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.set_line_width(10.0) cx.new_path() init = None count = len(self.xticks) for index, tick in enumerate(self.xticks): ang = math.pi / 2 - index * 2 * math.pi / count x = (self.layout.chart.x + self.layout.chart.w / 2 - math.cos(ang) * min(self.layout.chart.w / 2, self.layout.chart.h / 2)) y = (self.layout.chart.y + self.layout.chart.h / 2 - math.sin(ang) * min(self.layout.chart.w / 2, self.layout.chart.h / 2)) if init is None: cx.move_to(x, y) init = (x, y) else: cx.line_to(x, y) cx.line_to(init[0], init[1]) cx.close_path() 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 _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 _renderChart(self, cx): """Renders a pie chart""" self.centerx = self.layout.chart.x + self.layout.chart.w * 0.5 self.centery = self.layout.chart.y + self.layout.chart.h * 0.5 cx.set_line_join(cairo.LINE_JOIN_ROUND) if self.options.stroke.shadow and False: 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.layout.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.layout.radius) cx.fill() if not self.options.stroke.hide: slice.draw(cx, self.centerx, self.centery, self.layout.radius) cx.set_line_width(self.options.stroke.width) cx.set_source_rgb(*hex2rgb(self.options.stroke.color)) cx.stroke() cx.restore() if self.debug: cx.set_source_rgba(1, 0, 0, 0.5) px = max(cx.device_to_user_distance(1, 1)) for x, y in self.layout._lines: cx.arc(x, y, 5 * px, 0, 2 * math.pi) cx.fill() cx.new_path() cx.move_to(self.centerx, self.centery) cx.line_to(x, y) cx.stroke()
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 _renderLines(self, cx): """Aux function for _renderBackground""" centerx = self.layout.chart.x + self.layout.chart.w * 0.5 centery = self.layout.chart.y + self.layout.chart.h * 0.5 cx.set_line_width(self.options.background.lineWidth) cx.set_source_rgb(*hex2rgb(self.options.background.lineColor)) for angle in self.layout.angles: car = math.cos(angle) * self.layout.radius sar = math.sin(angle) * self.layout.radius cx.move_to(centerx, centery) cx.line_to(centerx + car, centery + sar) cx.stroke()
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 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.colors[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()
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()
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()
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) centerx = self.layout.chart.x + self.layout.chart.w / 2 centery = self.layout.chart.y + self.layout.chart.h / 2 if not self.options.axis.y.hide: if self.yticks: count = len(self.yticks) for i in range(0, count): self._renderYTick(cx, i, (centerx, centery)) if self.options.axis.y.label: self._renderYAxisLabel(cx, self.options.axis.y.label) self._renderYAxis(cx) if not self.options.axis.x.hide: fontAscent = cx.font_extents()[0] if self.xticks: count = len(self.xticks) for i in range(0, count): self._renderXTick(cx, i, fontAscent, (centerx, centery)) if self.options.axis.x.label: self._renderXAxisLabel(cx, self.options.axis.x.label) self._renderXAxis(cx) 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 = sorted(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) try: cx.set_source_rgb(*self.colorScheme[key]) #TODO: cleaner handling of alpha channel except TypeError: cx.set_source_rgba(*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 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()
def _renderAxis(self, cx): """Renders the axis for radar charts""" if self.options.axis.x.hide or not self.xticks: return self.xlabels = [] if self.debug: px = max(cx.device_to_user_distance(1, 1)) cx.set_source_rgba(0, 0, 1, 0.5) for x, y, w, h in self.layout.ticks: cx.rectangle(x, y, w, h) cx.stroke() cx.arc(x + w / 2.0, y + h / 2.0, 5 * px, 0, 2 * math.pi) cx.fill() cx.arc(x, y, 2 * px, 0, 2 * math.pi) cx.fill() cx.select_font_face(self.options.axis.labelFont, cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL) cx.set_font_size(self.options.axis.labelFontSize) cx.set_source_rgb(*hex2rgb(self.options.axis.labelColor)) for i, tick in enumerate(self.xticks): label = tick[1] x, y, w, h = self.layout.ticks[i] xb, yb, width, height, xa, ya = cx.text_extents(label) # draw label with text tick[1] cx.move_to(x - xb, y - yb) cx.show_text(label) self.xlabels.append(label) # Draw y-axis centerx = self.layout.chart.x + self.layout.chart.w * 0.5 centery = self.layout.chart.y + self.layout.chart.h * 0.5 cr = self.layout.radius / float(self.slice) cx.set_line_width(self.options.axis.lineWidth) cx.set_source_rgb(*hex2rgb(self.options.axis.lineColor)) if self.frame == 'circle': for i in xrange(self.slice): cx.move_to(centerx, centery) cx.arc(centerx, centery, (i+1) * cr, 0, 2*math.pi) else: for i in xrange(self.slice): for j, angle in enumerate(self.layout.angles): x = centerx + math.cos(angle) * (i+1) * cr y = centery + math.sin(angle) * (i+1) * cr if j: cx.line_to(x, y) else: cx.move_to(x, 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) cx.set_source_rgb(*hex2rgb(self.options.axis.labelColor)) for i in xrange(self.slice): yval = "%.1f" % (self.maxyval / self.slice * (i+1)) tw, th = get_text_extents(cx, yval, self.options.axis.tickFont, self.options.axis.tickFontSize, self.options.encoding) tx = centerx + (i+1) * cr - tw cx.move_to(tx, centery+th) cx.show_text(yval)
def _renderAxis(self, cx): """Renders the axis for radar charts""" if self.options.axis.x.hide or not self.xticks: return self.xlabels = [] if self.debug: px = max(cx.device_to_user_distance(1, 1)) cx.set_source_rgba(0, 0, 1, 0.5) for x, y, w, h in self.layout.ticks: cx.rectangle(x, y, w, h) cx.stroke() cx.arc(x + w / 2.0, y + h / 2.0, 5 * px, 0, 2 * math.pi) cx.fill() cx.arc(x, y, 2 * px, 0, 2 * math.pi) cx.fill() cx.select_font_face(self.options.axis.labelFont, cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL) cx.set_font_size(self.options.axis.labelFontSize) cx.set_source_rgb(*hex2rgb(self.options.axis.labelColor)) for i, tick in enumerate(self.xticks): label = tick[1] x, y, w, h = self.layout.ticks[i] xb, yb, width, height, xa, ya = cx.text_extents(label) # draw label with text tick[1] cx.move_to(x - xb, y - yb) cx.show_text(label) self.xlabels.append(label) # Draw y-axis centerx = self.layout.chart.x + self.layout.chart.w * 0.5 centery = self.layout.chart.y + self.layout.chart.h * 0.5 cr = self.layout.radius / float(self.slice) cx.set_line_width(self.options.axis.lineWidth) cx.set_source_rgb(*hex2rgb(self.options.axis.lineColor)) if self.frame == 'circle': for i in range(self.slice): cx.move_to(centerx, centery) cx.arc(centerx, centery, (i+1) * cr, 0, 2*math.pi) else: for i in range(self.slice): for j, angle in enumerate(self.layout.angles): x = centerx + math.cos(angle) * (i+1) * cr y = centery + math.sin(angle) * (i+1) * cr if j: cx.line_to(x, y) else: cx.move_to(x, 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) cx.set_source_rgb(*hex2rgb(self.options.axis.labelColor)) for i in range(self.slice): yval = "%.1f" % (self.maxyval / self.slice * (i+1)) tw, th = get_text_extents(cx, yval, self.options.axis.tickFont, self.options.axis.tickFontSize, self.options.encoding) tx = centerx + (i+1) * cr - tw cx.move_to(tx, centery+th) cx.show_text(yval)