def __call__(self, val): if val is None: return self.none_char order = val and int(floor(log(abs(val)) / log(1000))) orders = self.ORDERS.split(" ")[int(order > 0)] if order == 0 or order > len(orders): return float_format(val / (1000**int(order))) return (float_format(val / (1000**int(order))) + orders[int(order) - int(order > 0)])
def __call__(self, val): if val is None: return self.none_char order = val and int(floor(log(abs(val)) / log(1000))) orders = self.ORDERS.split(" ")[int(order > 0)] if order == 0 or order > len(orders): return float_format(val / (1000 ** int(order))) return ( float_format(val / (1000 ** int(order))) + orders[int(order) - int(order > 0)])
def _make_y_title(self): """Make the Y-Axis title""" if self._y_title: yc = self.margin_box.top + self.view.height / 2 for i, title_line in enumerate(self._y_title, 1): text = self.svg.node( self.nodes['title'], 'text', class_='title', x=self._legend_at_left_width, y=i * (self.style.title_font_size + self.spacing) + yc ) text.attrib['transform'] = "rotate(%d %s %s)" % ( -90, float_format(self._legend_at_left_width), float_format(yc)) text.text = title_line
def _make_y_title(self): """Make the Y-Axis title""" if self._y_title: yc = self.margin_box.top + self.view.height / 2 for i, title_line in enumerate(self._y_title, 1): text = self.svg.node( self.nodes['title'], 'text', class_='title', x=self._legend_at_left_width, y=i * (self.style.title_font_size + self.spacing) + yc) text.attrib['transform'] = "rotate(%d %s %s)" % ( -90, float_format( self._legend_at_left_width), float_format(yc)) text.text = title_line
def _tooltip_data(self, node, value, x, y, classes=None, xlabel=None): """Insert in desc tags informations for the javascript tooltip""" self.svg.node(node, 'desc', class_="value").text = value if classes is None: classes = [] if x > self.view.width / 2: classes.append('left') if y > self.view.height / 2: classes.append('top') classes = ' '.join(classes) self.svg.node(node, 'desc', class_="x " + classes).text = float_format(x) if type(x) == float else str(x) self.svg.node(node, 'desc', class_="y " + classes).text = float_format(y) if type(y) == float else str(y) if xlabel: self.svg.node(node, 'desc', class_="x_label").text = float_format(xlabel) if type(xlabel) == float else to_str(xlabel)
def _tooltip_data(self, node, value, x, y, classes=None, xlabel=None): """Insert in desc tags informations for the javascript tooltip""" self.svg.node(node, 'desc', class_="value").text = value if classes is None: classes = [] if x > self.view.width / 2: classes.append('left') if y > self.view.height / 2: classes.append('top') classes = ' '.join(classes) self.svg.node( node, 'desc', class_="x " + classes).text = float_format(x) if type(x) == float else str(x) self.svg.node( node, 'desc', class_="y " + classes).text = float_format(y) if type(y) == float else str(y) if xlabel: self.svg.node(node, 'desc', class_="x_label").text = float_format( xlabel) if type(xlabel) == float else to_str(xlabel)
def _x_axis(self, draw_axes=True): """Override x axis to make it polar""" if not self._x_labels or not self.show_x_labels: return axis = self.svg.node(self.nodes['plot'], class_="axis x web%s" % (' always_show' if self.show_x_guides else '')) format_ = coord_format(x) center = self.view((0, 0)) r = self._rmax # Can't simply determine truncation truncation = self.truncate_label or 25 for label, theta in self._x_labels: major = label in self._x_labels_major if not (self.show_minor_x_labels or major): continue guides = self.svg.node(axis, class_='guides') end = self.view((r, theta)) self.svg.node( guides, 'path', d='M%s L%s' % (format_(center), format_(end)), class_='%s%sline' % ('axis ' if label == "0" else '', 'major ' if major else '')) r_txt = (1 - self._box.__class__.margin) * self._box.ymax pos_text = self.view((r_txt, theta)) text = self.svg.node(guides, 'text', x=pos_text[0], y=pos_text[1], class_='major' if major else '') text.text = truncate(label, truncation) if text.text != label: self.svg.node(guides, 'title').text = label else: self.svg.node( guides, 'title', ).text = self._x_format(theta) angle = -theta + pi / 2 if cos(angle) < 0: angle -= pi text.attrib['transform'] = 'rotate(%s %s)' % (float_format( self.x_label_rotation or deg(angle)), format_(pos_text))
def _x_axis(self, draw_axes=True): """Override x axis to make it polar""" if not self._x_labels or not self.show_x_labels: return axis = self.svg.node(self.nodes['plot'], class_="axis x web%s" % ( ' always_show' if self.show_x_guides else '' )) format_ = coord_format(x) center = self.view((0, 0)) r = self._rmax # Can't simply determine truncation truncation = self.truncate_label or 25 for label, theta in self._x_labels: major = label in self._x_labels_major if not (self.show_minor_x_labels or major): continue guides = self.svg.node(axis, class_='guides') end = self.view((r, theta)) self.svg.node( guides, 'path', d='M%s L%s' % (format_(center), format_(end)), class_='%s%sline' % ( 'axis ' if label == "0" else '', 'major ' if major else '')) r_txt = (1 - self._box.__class__.margin) * self._box.ymax pos_text = self.view((r_txt, theta)) text = self.svg.node( guides, 'text', x=pos_text[0], y=pos_text[1], class_='major' if major else '') text.text = truncate(label, truncation) if text.text != label: self.svg.node(guides, 'title').text = label else: self.svg.node( guides, 'title', ).text = self._x_format(theta) angle = - theta + pi / 2 if cos(angle) < 0: angle -= pi text.attrib['transform'] = 'rotate(%s %s)' % ( float_format(self.x_label_rotation or deg(angle)), format_(pos_text))
def _y_axis(self): """Make the y axis: labels and guides""" if not self._y_labels or not self.show_y_labels: return axis = self.svg.node(self.nodes['plot'], class_="axis y") if (0 not in [label[1] for label in self._y_labels] and self.show_y_guides): self.svg.node( axis, 'path', d='M%s %s h%s' % float_format(0, 0 if self.inverse_y_axis else self.view.height, self.view.width), class_='line') for label, position in self._y_labels: if self.horizontal: major = label in self._y_labels_major else: major = position in self._y_labels_major if not (self.show_minor_y_labels or major): continue guides = self.svg.node( axis, class_='%sguides' % ('logarithmic ' if self.logarithmic else '')) x = -5 y = self.view.y(position) if not y: continue if self.show_y_guides: self.svg.node( guides, 'path', d='M%s %s h%s' % float_format(0, y, self.view.width), class_='%s%s%sline' % ('axis ' if label == "0" else '', 'major ' if major else '', 'guide ' if position != 0 else '')) text = self.svg.node(guides, 'text', x=x, y=y + .35 * self.style.label_font_size, class_='major' if major else '') text.text = label if self.y_label_rotation: text.attrib['transform'] = "rotate(%d %s %s)" % ( self.y_label_rotation, float_format(x), float_format(y)) if 90 < self.y_label_rotation < 270: text.attrib['class'] = ' '.join( (text.attrib['class'] and text.attrib['class'].split(' ') or []) + ['backwards']) self.svg.node( guides, 'title', ).text = self._format(position) if self._y_2nd_labels: secondary_ax = self.svg.node(self.nodes['plot'], class_="axis y2") for label, position in self._y_2nd_labels: major = position in self._y_labels_major if not (self.show_minor_y_labels or major): continue # it is needed, to have the same structure as primary axis guides = self.svg.node(secondary_ax, class_='guides') x = self.view.width + 5 y = self.view.y(position) text = self.svg.node(guides, 'text', x=x, y=y + .35 * self.style.label_font_size, class_='major' if major else '') text.text = label if self.y_label_rotation: text.attrib['transform'] = "rotate(%d %s %s)" % ( self.y_label_rotation, float_format(x), float_format(y)) if 90 < self.y_label_rotation < 270: text.attrib['class'] = ' '.join( (text.attrib['class'] and text.attrib['class'].split(' ') or []) + ['backwards'])
def _x_axis(self): """Make the x axis: labels and guides""" if not self._x_labels or not self.show_x_labels: return axis = self.svg.node(self.nodes['plot'], class_="axis x%s" % (' always_show' if self.show_x_guides else '')) truncation = self.truncate_label if not truncation: if self.x_label_rotation or len(self._x_labels) <= 1: truncation = 25 else: first_label_position = self.view.x(self._x_labels[0][1]) or 0 last_label_position = self.view.x(self._x_labels[-1][1]) or 0 available_space = (last_label_position - first_label_position ) / (len(self._x_labels) - 1) truncation = reverse_text_len(available_space, self.style.label_font_size) truncation = max(truncation, 1) lastlabel = self._x_labels[-1][0] if 0 not in [label[1] for label in self._x_labels]: self.svg.node(axis, 'path', d='M%s %s v%s' % float_format(0, 0, self.view.height), class_='line') lastlabel = None for label, position in self._x_labels: if self.horizontal: major = position in self._x_labels_major else: major = label in self._x_labels_major if not (self.show_minor_x_labels or major): continue guides = self.svg.node(axis, class_='guides') x = self.view.x(position) if x is None: continue y = self.view.height + 5 last_guide = (self._y_2nd_labels and label == lastlabel) self.svg.node( guides, 'path', d='M%s %s v%s' % float_format(x or 0, 0, self.view.height), class_='%s%s%sline' % ('axis ' if label == "0" else '', 'major ' if major else '', 'guide ' if position != 0 and not last_guide else '')) y += .5 * self.style.label_font_size + 5 text = self.svg.node(guides, 'text', x=x, y=y, class_='major' if major else '') text.text = truncate(label, truncation) if text.text != label: self.svg.node(guides, 'title').text = label elif self._dual: self.svg.node( guides, 'title', ).text = self._x_format(position) if self.x_label_rotation: text.attrib['transform'] = "rotate(%d %s %s)" % ( self.x_label_rotation, float_format(x), float_format(y)) if self.x_label_rotation >= 180: text.attrib['class'] = ' '.join( (text.attrib['class'] and text.attrib['class'].split(' ') or []) + ['backwards']) if self._y_2nd_labels and 0 not in [ label[1] for label in self._x_labels ]: self.svg.node(axis, 'path', d='M%f %f v%f' % (self.view.width, 0, self.view.height), class_='line') if self._x_2nd_labels: secondary_ax = self.svg.node( self.nodes['plot'], class_="axis x x2%s" % (' always_show' if self.show_x_guides else '')) for label, position in self._x_2nd_labels: major = label in self._x_labels_major if not (self.show_minor_x_labels or major): continue # it is needed, to have the same structure as primary axis guides = self.svg.node(secondary_ax, class_='guides') x = self.view.x(position) y = -5 text = self.svg.node(guides, 'text', x=x, y=y, class_='major' if major else '') text.text = label if self.x_label_rotation: text.attrib['transform'] = "rotate(%d %s %s)" % ( -self.x_label_rotation, float_format(x), float_format(y)) if self.x_label_rotation >= 180: text.attrib['class'] = ' '.join( (text.attrib['class'] and text.attrib['class'].split(' ') or []) + ['backwards'])
def _plot(self): """Insert a map in the chart and apply data on it""" map = etree.fromstring(self.svg_map) map.set('width', str(self.view.width)) map.set('height', str(self.view.height)) for i, serie in enumerate(self.series): safe_vals = list(filter( lambda x: x is not None, cut(serie.values, 1))) if not safe_vals: continue min_ = min(safe_vals) max_ = max(safe_vals) for j, (area_code, value) in self.enumerate_values(serie): area_code = self.adapt_code(area_code) if value is None: continue if max_ == min_: ratio = 1 else: ratio = .3 + .7 * (value - min_) / (max_ - min_) try: areae = map.findall( ".//*[@class='%s%s %s map-element']" % ( self.area_prefix, area_code, self.kind)) except SyntaxError: # Python 2.6 (you'd better install lxml) raise ImportError('lxml is required under python 2.6') if not areae: continue for area in areae: cls = area.get('class', '').split(' ') cls.append('color-%d' % i) cls.append('serie-%d' % i) cls.append('series') area.set('class', ' '.join(cls)) area.set('style', 'fill-opacity: %s' % float_format(ratio)) metadata = serie.metadata.get(j) if metadata: node = decorate(self.svg, area, metadata) if node != area: area.remove(node) for g in map: if area not in g: continue index = list(g).index(area) g.remove(area) node.append(area) g.insert(index, node) for node in area: cls = node.get('class', '').split(' ') cls.append('reactive') cls.append('tooltip-trigger') cls.append('map-area') node.set('class', ' '.join(cls)) alter(node, metadata) val = self._get_value((area_code, value)) self._tooltip_data(area, val, 0, 0, 'auto') self.nodes['plot'].append(map)
def _y_axis(self): """Make the y axis: labels and guides""" if not self._y_labels or not self.show_y_labels: return axis = self.svg.node(self.nodes['plot'], class_="axis y") if (0 not in [label[1] for label in self._y_labels] and self.show_y_guides): self.svg.node( axis, 'path', d='M%s %s h%s' % float_format( 0, 0 if self.inverse_y_axis else self.view.height, self.view.width), class_='line' ) for label, position in self._y_labels: if self.horizontal: major = label in self._y_labels_major else: major = position in self._y_labels_major if not (self.show_minor_y_labels or major): continue guides = self.svg.node(axis, class_='%sguides' % ( 'logarithmic ' if self.logarithmic else '' )) x = -5 y = self.view.y(position) if not y: continue if self.show_y_guides: self.svg.node( guides, 'path', d='M%s %s h%s' % float_format(0, y, self.view.width), class_='%s%s%sline' % ( 'axis ' if label == "0" else '', 'major ' if major else '', 'guide ' if position != 0 else '')) text = self.svg.node( guides, 'text', x=x, y=y + .35 * self.style.label_font_size, class_='major' if major else '' ) text.text = label if self.y_label_rotation: text.attrib['transform'] = "rotate(%d %s %s)" % ( self.y_label_rotation, float_format(x), float_format(y)) if 90 < self.y_label_rotation < 270: text.attrib['class'] = ' '.join( (text.attrib['class'] and text.attrib['class'].split( ' ') or []) + ['backwards']) self.svg.node( guides, 'title', ).text = self._format(position) if self._y_2nd_labels: secondary_ax = self.svg.node( self.nodes['plot'], class_="axis y2") for label, position in self._y_2nd_labels: major = position in self._y_labels_major if not (self.show_minor_y_labels or major): continue # it is needed, to have the same structure as primary axis guides = self.svg.node(secondary_ax, class_='guides') x = self.view.width + 5 y = self.view.y(position) text = self.svg.node( guides, 'text', x=x, y=y + .35 * self.style.label_font_size, class_='major' if major else '' ) text.text = label if self.y_label_rotation: text.attrib['transform'] = "rotate(%d %s %s)" % ( self.y_label_rotation, float_format(x), float_format(y)) if 90 < self.y_label_rotation < 270: text.attrib['class'] = ' '.join( (text.attrib['class'] and text.attrib['class'].split( ' ') or []) + ['backwards'])
def _x_axis(self): """Make the x axis: labels and guides""" if not self._x_labels or not self.show_x_labels: return axis = self.svg.node(self.nodes['plot'], class_="axis x%s" % ( ' always_show' if self.show_x_guides else '' )) truncation = self.truncate_label if not truncation: if self.x_label_rotation or len(self._x_labels) <= 1: truncation = 25 else: first_label_position = self.view.x(self._x_labels[0][1]) or 0 last_label_position = self.view.x(self._x_labels[-1][1]) or 0 available_space = ( last_label_position - first_label_position) / ( len(self._x_labels) - 1) truncation = reverse_text_len( available_space, self.style.label_font_size) truncation = max(truncation, 1) lastlabel = self._x_labels[-1][0] if 0 not in [label[1] for label in self._x_labels]: self.svg.node(axis, 'path', d='M%s %s v%s' % float_format(0, 0, self.view.height), class_='line') lastlabel = None for label, position in self._x_labels: if self.horizontal: major = position in self._x_labels_major else: major = label in self._x_labels_major if not (self.show_minor_x_labels or major): continue guides = self.svg.node(axis, class_='guides') x = self.view.x(position) if x is None: continue y = self.view.height + 5 last_guide = (self._y_2nd_labels and label == lastlabel) self.svg.node( guides, 'path', d='M%s %s v%s' % float_format(x or 0, 0, self.view.height), class_='%s%s%sline' % ( 'axis ' if label == "0" else '', 'major ' if major else '', 'guide ' if position != 0 and not last_guide else '')) y += .5 * self.style.label_font_size + 5 text = self.svg.node( guides, 'text', x=x, y=y, class_='major' if major else '' ) text.text = truncate(label, truncation) if text.text != label: self.svg.node(guides, 'title').text = label elif self._dual: self.svg.node( guides, 'title', ).text = self._x_format(position) if self.x_label_rotation: text.attrib['transform'] = "rotate(%d %s %s)" % ( self.x_label_rotation, float_format(x), float_format(y)) if self.x_label_rotation >= 180: text.attrib['class'] = ' '.join( (text.attrib['class'] and text.attrib['class'].split( ' ') or []) + ['backwards']) if self._y_2nd_labels and 0 not in [ label[1] for label in self._x_labels]: self.svg.node(axis, 'path', d='M%f %f v%f' % ( self.view.width, 0, self.view.height), class_='line') if self._x_2nd_labels: secondary_ax = self.svg.node( self.nodes['plot'], class_="axis x x2%s" % ( ' always_show' if self.show_x_guides else '' )) for label, position in self._x_2nd_labels: major = label in self._x_labels_major if not (self.show_minor_x_labels or major): continue # it is needed, to have the same structure as primary axis guides = self.svg.node(secondary_ax, class_='guides') x = self.view.x(position) y = -5 text = self.svg.node( guides, 'text', x=x, y=y, class_='major' if major else '' ) text.text = label if self.x_label_rotation: text.attrib['transform'] = "rotate(%d %s %s)" % ( -self.x_label_rotation, float_format(x), float_format(y)) if self.x_label_rotation >= 180: text.attrib['class'] = ' '.join(( text.attrib['class'] and text.attrib['class'].split( ' ') or []) + ['backwards'])