def get_dimension(text): """Return the bounding box of the <text>, assuming that the left-bottom corner of the first letter of the text is at (0, 0). This procedure ignores /h, /v, and /a directives when calculating the boundingbox; it just returns the alignment specifiers as a part of the return value. The return value is a tuple (width, height, halign, valign, angle).""" (xmax, ymax, halign, valign, angle) = unaligned_get_dimension(text) xmin = ymin = 0 if halign == 'C': xmin = -xmax / 2.0 xmax = xmax / 2.0 elif halign == 'R': xmin = -xmax xmax = 0 if valign == 'M': ymin = -ymax / 2.0 ymax = ymax / 2.0 elif valign == 'T': ymin = -ymax ymax = 0 if angle != 0: (x0, y0) = pychart_util.rotate(xmin, ymin, angle) (x1, y1) = pychart_util.rotate(xmax, ymin, angle) (x2, y2) = pychart_util.rotate(xmin, ymax, angle) (x3, y3) = pychart_util.rotate(xmax, ymax, angle) xmax = max(x0, x1, x2, x3) xmin = min(x0, x1, x2, x3) ymax = max(y0, y1, y2, y3) ymin = min(y0, y1, y2, y3) return (xmin, xmax, ymin, ymax) return (xmin, xmax, ymin, ymax)
def draw(self, ar, can): center = self.center if not center: center = (ar.loc[0] + ar.size[0] / 2.0, ar.loc[1] + ar.size[1] / 2.0) radius = self.radius if not radius: radius = min(ar.size[0] / 2.0, ar.size[1] / 2.0) * 0.5 label_offset = radius + (self.label_offset or radius * 0.1) total = self._total() i = 0 cur_angle = self.start_angle for val in self.data: fill = self.fill_styles[i] degree = 360 * float(val[self.data_col]) / float(total) off = (0, 0) if len(self.arc_offsets) > i: off = pychart_util.rotate(self.arc_offsets[i], 0, cur_angle - degree / 2.0) x_center = center[0] + off[0] y_center = center[1] + off[1] can.ellipsis(self.line_style, fill, x_center, y_center, radius, 1, cur_angle - degree, cur_angle, self.shadow) label = pychart_util.apply_format(self.label_format, val, self.label_col) if label != None: (x_label, y_label) = pychart_util.rotate(label_offset, 0, cur_angle - degree / 2.0) (x_arrowtip, y_arrowtip) = pychart_util.rotate(radius, 0, cur_angle - degree / 2.0) # Labels on left side of pie need # their text to avoid obscuring the pie if x_label < 0: x_label = x_label - font.text_width(label) t = text_box.T(loc=(x_label + x_center, y_label + y_center), text=label, line_style=self.label_line_style, fill_style=self.label_fill_style) if self.arrow_style: t.add_arrow((x_arrowtip + x_center, y_arrowtip + y_center), None, self.arrow_style) t.draw(can) cur_angle = (cur_angle - degree) % 360 i = (i + 1) % len(self.fill_styles)
def __arcsub(self, x, y, radius, start, theta): xcos = math.cos(basecanvas.to_radian(theta)) xsin = math.sin(basecanvas.to_radian(theta)) x0 = radius * xcos y0 = radius * xsin x1 = radius * (4-xcos)/3.0 y1 = radius * (1-xcos)*(xcos-3)/(3*xsin) xx0, xy0 = pychart_util.rotate(x0, y0, start+theta) xx1, xy1 = pychart_util.rotate(x1, -y1, start+theta) xx2, xy2 = pychart_util.rotate(x1, y1, start+theta) self.__write("%f %f %f %f %f %f c\n" % (x+xx1, y+xy1, x+xx2, y+xy2, x+xx0, y+xy0))
def draw(self, ar, can): center = self.center if not center: center = (ar.loc[0] + ar.size[0]/2.0, ar.loc[1] + ar.size[1]/2.0) radius = self.radius if not radius: radius = min(ar.size[0]/2.0, ar.size[1]/2.0) * 0.5 label_offset = radius + (self.label_offset or radius * 0.1) total = self._total() i = 0 cur_angle = self.start_angle for val in self.data: fill = self.fill_styles[i] degree = 360 * float(val[self.data_col]) / float(total) off = (0, 0) if len(self.arc_offsets) > i: off = pychart_util.rotate(self.arc_offsets[i], 0, cur_angle - degree/2.0) x_center = center[0]+ off[0] y_center = center[1]+ off[1] can.ellipsis(self.line_style, fill, x_center, y_center, radius, 1, cur_angle - degree, cur_angle, self.shadow) label = pychart_util.apply_format(self.label_format, val, self.label_col) if label != None: (x_label, y_label) = pychart_util.rotate(label_offset, 0, cur_angle - degree/2.0) (x_arrowtip, y_arrowtip) = pychart_util.rotate(radius, 0, cur_angle - degree/2.0) # Labels on left side of pie need # their text to avoid obscuring the pie if x_label < 0: x_label = x_label - font.text_width(label) t = text_box.T(loc = (x_label + x_center, y_label + y_center), text = label, line_style = self.label_line_style, fill_style = self.label_fill_style) if self.arrow_style: t.add_arrow((x_arrowtip + x_center, y_arrowtip + y_center), None, self.arrow_style) t.draw(can) cur_angle = (cur_angle - degree) % 360 i = (i + 1) % len(self.fill_styles)
def draw(self, ar, can): center = self.center if not center: center = (ar.loc[0] + ar.size[0]/2.0, ar.loc[1] + ar.size[1]/2.0) base_radius = self.base_radius # the maximum radius of a wedge if not base_radius: base_radius = min(ar.size[0]/2.0, ar.size[1]/2.0) #* 0.8 sector_decrement = 1./(len(self.data)*2) * self.sector_width # each following sector diagram will have its sector width decremented by half this amount (in degrees) i = 0 for dataset in self.data: cur_angle = self.start_angle if self.sector_centred: cur_angle -= self.sector_width/2. fill = self.fill_styles[i] x_center = center[0] y_center = center[1] if not i: # draw directions around sector diagram once off dir_offset = base_radius + (self.dir_offset or base_radius * 0.04) directions = ['N', 'E', 'S', 'W'] angle = self.start_angle can.ellipsis(line_style.T(color=color.black, width=0.3, dash=line_style.dash1), None, x_center, y_center, base_radius, 1, 0, 360) # for d in directions: x_label, y_label = pychart_util.rotate(dir_offset, 0, angle) # coords for bottom left corner of box tw = font.text_width(d) half = 1/3. # normal arithmetic does not seem to apply to these text_box objects... if (angle == 0): # east y_label -= font.text_height(d)[0]*half # move down half elif (angle == -180): # west y_label -= font.text_height(d)[0]*half # move down half x_label -= font.text_width(d) # move left full elif (angle == 90): # north x_label -= font.text_height(d)[0]*half # move left half elif (angle == -90): # south y_label -= font.text_height(d)[0]*.8 # move down (couldn't figure out how to set this dynamically so I fudged...) x_label -= font.text_height(d)[0]*half # move left half canvas.show(x_label + x_center, y_label + y_center, d) angle -= 360/len(directions) for val in dataset[self.data_col]: # now draw the sectors radius = base_radius*val # scale the radius start = cur_angle-self.sector_width+i*sector_decrement stop = cur_angle-i*sector_decrement # these may seem confusing, but remember that we need to go counterclockwise can.ellipsis(self.line_style, fill, x_center, y_center, radius, 1, start, stop, self.shadow) cur_angle = (cur_angle - self.sector_width) % 360 # we want to go in anticlockwise direction (North, West, South, etc. as in meteorology) i = (i + 1) % len(self.fill_styles)
def show(self, x, y, str): global out y_org = y org_str = str if invisible_p(x, y): return (xmin, xmax, ymin, ymax) = font.get_dimension(str) # rectangle(line_style.default, None, x+xmin, y+ymin, x+xmax, y+ymax) # ellipsis(line_style.default, None, x, y, 1) self.setbb(x + xmin, y + ymin) self.setbb(x + xmax, y + ymax) (halign, valign, angle) = font.get_align(str) base_x = x base_y = y # Handle vertical alignment if valign == "B": y = font.unaligned_text_height(str) elif valign == "T": y = 0 elif valign == "M": y = font.unaligned_text_height(str) / 2.0 (xmin, xmax, ymin, ymax) = font.get_dimension(org_str) self.setbb(x + xmin, y_org + y + ymin) self.setbb(x + xmax, y_org + y + ymax) itr = font.text_iterator(None) max_width = 0 lines = [] for line in str.split('\n'): cur_width = 0 cur_height = 0 itr.reset(line) strs = [] while 1: elem = itr.next() if not elem: break (font_name, size, line_height, color, _h, _v, _a, str) = elem cur_width += font.line_width(font_name, size, str) max_width = max(cur_width, max_width) cur_height = max(cur_height, line_height) # replace '(' -> '\(', ')' -> '\)' to make # Postscript string parser happy. str = str.replace("(", "\\(") str = str.replace(")", "\\)") strs.append((font_name, size, color, str)) lines.append((cur_width, cur_height, strs)) for line in lines: cur_width, cur_height, strs = line cur_y = y - cur_height y = y - cur_height self.comment("cury: %d hei %d str %s\n" % (cur_y, cur_height, strs)) if halign == 'C': cur_x = -cur_width / 2.0 elif halign == 'R': cur_x = -cur_width else: cur_x = 0 rel_x, rel_y = pychart_util.rotate(cur_x, cur_y, angle) self.text_begin() self.text_moveto(xscale(base_x + rel_x), yscale(base_y + rel_y), angle) for segment in strs: font_name, size, color, str = segment self.text_show(font_name, nscale(size), color, str) self.text_end()
def show(x, y, str): global out y_org = y org_str = str if invisible_p(x, y): return (xmin, xmax, ymin, ymax) = font.get_dimension(str) # rectangle(line_style.default, None, x+xmin, y+ymin, x+xmax, y+ymax) # ellipsis(line_style.default, None, x, y, 1) setbb(x+xmin, y+ymin) setbb(x+xmax, y+ymax) (halign, valign, angle) = font.get_align(str) base_x = x base_y = y # Handle vertical alignment if valign == "B": y = font.unaligned_text_height(str) elif valign == "T": y = 0 elif valign == "M": y = font.unaligned_text_height(str) / 2.0 (xmin, xmax, ymin, ymax) = font.get_dimension(org_str) # print org_str, xmin, xmax, ymin, ymax, x, y_org, y setbb(x+xmin, y_org+y+ymin) setbb(x+xmax, y_org+y+ymax) itr = font.text_iterator(None) max_width = 0 lines = [] for line in string.split(str, '\n'): cur_width = 0 cur_height = 0 itr.reset(line) strs = [] while 1: elem = itr.next() if not elem: break (font_name, size, line_height, color, _h, _v, _a, str) = elem cur_width = cur_width + font.line_width(font_name, size, str) max_width = max(cur_width, max_width) cur_height = max(cur_height, line_height) # replace '(' -> '\(', ')' -> '\)' to make # Postscript string parser happy. str = string.replace(str, "(", "\\(") str = string.replace(str, ")", "\\)") strs.append((font_name, size, color, str)) lines.append((cur_width, cur_height, strs)) for line in lines: cur_width, cur_height, strs = line cur_y = y - cur_height y = y - cur_height out.comment("cury: %d hei %d str %s\n" % (cur_y, cur_height, strs)) if halign == 'C': cur_x = -cur_width/2.0 elif halign == 'R': cur_x = -cur_width else: cur_x = 0 rel_x, rel_y = pychart_util.rotate(cur_x, cur_y, angle) out.text_begin() out.text_moveto(xscale(base_x + rel_x), yscale(base_y + rel_y), angle) for segment in strs: font_name, size, color, str = segment out.text_show(font_name, nscale(size), color, str) out.text_end()