| 77 | | def drawBar(bar): |
| 78 | | stroke_width = self.options.stroke.width |
| 79 | | ux, uy = cx.device_to_user_distance(stroke_width, stroke_width) |
| 80 | | if ux < uy: |
| 81 | | ux = uy |
| 82 | | cx.set_line_width(ux) |
| 83 | | |
| 84 | | # gather bar proportions |
| 85 | | x = self.area.x + self.area.w * bar.x |
| 86 | | y = self.area.y + self.area.h * bar.y |
| 87 | | w = self.area.w * bar.w |
| 88 | | h = self.area.h * bar.h |
| 89 | | |
| 90 | | if w < 1 or h < 1: |
| 91 | | return # don't draw when the bar is too small |
| 92 | | |
| 93 | | if self.options.stroke.shadow: |
| 94 | | cx.set_source_rgba(0, 0, 0, 0.15) |
| 95 | | rectangle = self._getShadowRectangle(x, y, w, h) |
| 96 | | cx.rectangle(*rectangle) |
| 97 | | cx.fill() |
| 98 | | |
| 99 | | if self.options.shouldFill or (not self.options.stroke.hide): |
| 100 | | cx.rectangle(x, y, w, h) |
| 101 | | |
| 102 | | if self.options.shouldFill: |
| 103 | | cx.set_source_rgb(*self.options.colorScheme[bar.name]) |
| 104 | | cx.fill_preserve() |
| 105 | | |
| 106 | | if not self.options.stroke.hide: |
| 107 | | cx.set_source_rgb(*hex2rgb(self.options.stroke.color)) |
| 108 | | cx.stroke() |
| 109 | | |
| 110 | | # render yvals above/beside bars |
| 111 | | if self.options.yvals.show: |
| 112 | | cx.save() |
| 113 | | cx.set_font_size(self.options.yvals.fontSize) |
| 114 | | cx.set_source_rgb(*hex2rgb(self.options.yvals.fontColor)) |
| 115 | | |
| 116 | | label = unicode(bar.yval) |
| 117 | | extents = cx.text_extents(label) |
| 118 | | labelW = extents[2] |
| 119 | | labelH = extents[3] |
| 120 | | |
| 121 | | self._renderYVal(cx, label, labelW, labelH, x, y, w, h) |
| 122 | | |
| 123 | | cx.restore() |
| 124 | | |
| 125 | | cx.save() |
| 126 | | for bar in self.bars: |
| 127 | | drawBar(bar) |
| 128 | | cx.restore() |
| 129 | | |
| 130 | | def _renderYVal(self, cx, label, width, height, x, y, w, h): |
| 131 | | raise NotImplementedError |
| 132 | | |
| 133 | | |
| 134 | | class StackedVerticalBarChart(StackedBarChart): |
| | 73 | class StackedVerticalBarChart(StackedBarChart, VerticalBarChart): |
| 160 | | |
| 161 | | def _updateTicks(self): |
| 162 | | """Evaluates bar ticks""" |
| 163 | | super(StackedBarChart, self)._updateTicks() |
| 164 | | offset = (self.minxdelta * self.xscale) / 2 |
| 165 | | self.xticks = [(tick[0] + offset, tick[1]) for tick in self.xticks] |
| 166 | | |
| 167 | | def _getShadowRectangle(self, x, y, w, h): |
| 168 | | return (x-2, y-2, w+4, h+2) |
| 169 | | |
| 170 | | def _renderYVal(self, cx, label, labelW, labelH, barX, barY, barW, barH): |
| 171 | | x = barX + (barW / 2.0) - (labelW / 2.0) |
| 172 | | if self.options.yvals.inside: |
| 173 | | y = barY + (1.5 * labelH) |
| 174 | | else: |
| 175 | | y = barY - 0.5 * labelH |
| 176 | | |
| 177 | | # if the label doesn't fit below the bar, put it above the bar |
| 178 | | if y > (barY + barH): |
| 179 | | y = barY - 0.5 * labelH |
| 180 | | |
| 181 | | cx.move_to(x, y) |
| 182 | | cx.show_text(label) |