Beispiel #1
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)])
Beispiel #2
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)])
Beispiel #3
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
Beispiel #4
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
Beispiel #5
0
    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)
Beispiel #6
0
    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)
Beispiel #7
0
    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))
Beispiel #8
0
    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))
Beispiel #9
0
    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'])
Beispiel #10
0
    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'])
Beispiel #11
0
    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)
Beispiel #12
0
    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'])
Beispiel #13
0
    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'])
Beispiel #14
0
    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)