Exemplo n.º 1
0
    def _compute_margin(self):
        """Compute graph margins from set texts"""
        for series_group in (self.series, self.secondary_series):
            if self.show_legend and series_group:
                h, w = get_texts_box(
                    map(lambda x: truncate(x, self.truncate_legend or 15),
                        cut(series_group, 'title')),
                    self.legend_font_size)
                if self.legend_at_bottom:
                    h_max = max(h, self.legend_box_size)
                    self.margin.bottom += 10 + h_max * round(
                        sqrt(self._order) - 1) * 1.5 + h_max
                else:
                    if series_group is self.series:
                        self.margin.left += 10 + w + self.legend_box_size
                    else:
                        self.margin.right += 10 + w + self.legend_box_size

        if self.title:
            h, _ = get_text_box(self.title[0], self.title_font_size)
            self.margin.top += len(self.title) * (10 + h)

        for xlabels in (self._x_labels, self._x_2nd_labels):
            if xlabels:
                h, w = get_texts_box(
                    map(lambda x: truncate(x, self.truncate_label or 25),
                        cut(xlabels)),
                    self.label_font_size)
                self._x_labels_height = 10 + max(
                    w * sin(rad(self.x_label_rotation)), h)
                if xlabels is self._x_labels:
                    self.margin.bottom += self._x_labels_height
                else:
                    self.margin.top += self._x_labels_height
                if self.x_label_rotation:
                    self.margin.right = max(
                        w * cos(rad(self.x_label_rotation)),
                        self.margin.right)
        if not self._x_labels:
            self._x_labels_height = 0

        for ylabels in (self._y_labels, self._y_2nd_labels):
            if ylabels:
                h, w = get_texts_box(
                    cut(ylabels), self.label_font_size)
                if ylabels is self._y_labels:
                    self.margin.left += 10 + max(
                        w * cos(rad(self.y_label_rotation)), h)
                else:
                    self.margin.right += 10 + max(
                        w * cos(rad(self.y_label_rotation)), h)
Exemplo n.º 2
0
    def _compute_margin(self):
        """Compute graph margins from set texts"""
        if self.show_legend:
            h, w = get_texts_box(
                map(lambda x: truncate(x, self.truncate_legend or 15),
                  cut(self.series, 'title')),
                self.legend_font_size)
            if self.legend_at_bottom:
                h_max = max(h, self.legend_box_size)
                self.margin.bottom += 10 + h_max * round(
                        sqrt(len(self.series)) - 1) * 1.5 + h_max
            else:
                self.margin.right += 10 + w + self.legend_box_size

        if self.title:
            h, w = get_text_box(self.title, self.title_font_size)
            self.margin.top += 10 + h

        if self._x_labels:
            h, w = get_texts_box(
                cut(self._x_labels), self.label_font_size)
            self._x_labels_height = 10 + max(
                w * sin(rad(self.x_label_rotation)), h)
            self.margin.bottom += self._x_labels_height
            if self.x_label_rotation:
                self.margin.right = max(
                    w * cos(rad(self.x_label_rotation)),
                    self.margin.right)
        else:
            self._x_labels_height = 0
        if self._y_labels:
            h, w = get_texts_box(
                cut(self._y_labels), self.label_font_size)
            self.margin.left += 10 + max(
                w * cos(rad(self.y_label_rotation)), h)
Exemplo n.º 3
0
    def _x_axis(self, draw_axes=True):
        """Make the x axis: labels and guides"""
        if not self._x_labels:
            return

        axis = self.svg.node(self.nodes["plot"], class_="axis x")
        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])
                last_label_position = self.view.x(self._x_labels[-1][1])
                available_space = (last_label_position - first_label_position) / (len(self._x_labels) - 1)
                truncation = int(reverse_text_len(available_space, self.label_font_size))

        if 0 not in [label[1] for label in self._x_labels] and draw_axes:
            self.svg.node(axis, "path", d="M%f %f v%f" % (0, 0, self.view.height), class_="line")
        for label, position in self._x_labels:
            guides = self.svg.node(axis, class_="guides")
            x = self.view.x(position)
            y = self.view.height + 5
            if draw_axes:
                self.svg.node(
                    guides,
                    "path",
                    d="M%f %f v%f" % (x, 0, self.view.height),
                    class_="%sline" % ("guide " if position != 0 else ""),
                )
            text = self.svg.node(guides, "text", x=x, y=y + 0.5 * self.label_font_size + 5)
            text.text = truncate(label, truncation)
            if text.text != label:
                self.svg.node(guides, "title").text = label
            if self.x_label_rotation:
                text.attrib["transform"] = "rotate(%d %f %f)" % (self.x_label_rotation, x, y)
Exemplo n.º 4
0
    def _compute_margin(self):
        """Compute graph margins from set texts"""
        if self.show_legend and self.series:
            h, w = get_texts_box(
                map(lambda x: truncate(x, self.truncate_legend or 15),
                    cut(self.series, 'title')), self.legend_font_size)
            if self.legend_at_bottom:
                h_max = max(h, self.legend_box_size)
                self.margin.bottom += 10 + h_max * round(
                    sqrt(self._order) - 1) * 1.5 + h_max
            else:
                self.margin.right += 10 + w + self.legend_box_size

        if self.title:
            h, _ = get_text_box(self.title[0], self.title_font_size)
            self.margin.top += len(self.title) * (10 + h)

        if self._x_labels:
            h, w = get_texts_box(cut(self._x_labels), self.label_font_size)
            self._x_labels_height = 10 + max(
                w * sin(rad(self.x_label_rotation)), h)
            self.margin.bottom += self._x_labels_height
            if self.x_label_rotation:
                self.margin.right = max(w * cos(rad(self.x_label_rotation)),
                                        self.margin.right)
        else:
            self._x_labels_height = 0
        if self._y_labels:
            h, w = get_texts_box(cut(self._y_labels), self.label_font_size)
            self.margin.left += 10 + max(w * cos(rad(self.y_label_rotation)),
                                         h)
Exemplo n.º 5
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_ = lambda x: '%f %f' % x
        center = self.view((0, 0))
        r = self._rmax
        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)

        for label, theta in self._x_labels:
            major = label in self._x_major_labels
            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(%f %s)' % (
                self.x_label_rotation or deg(angle), format_(pos_text))
Exemplo n.º 6
0
 def _title(self):
     """Make the title"""
     if self.title:
         self.svg.node(self.nodes['graph'], 'text', class_='title',
                       x=self.margin.left + self.view.width / 2,
                       y=self.title_font_size + 10
                   ).text = truncate(self.title, int(reverse_text_len(
                       self.width, self.title_font_size)))
Exemplo n.º 7
0
    def _legend(self):
        """Make the legend box"""
        if not self.show_legend:
            return
        truncation = self.truncate_legend
        if self.legend_at_bottom:
            x = self.margin.left + 10
            y = (self.margin.top + self.view.height +
                 self._x_labels_height + 10)
            cols = ceil(sqrt(self._order))

            if not truncation:
                available_space = self.view.width / cols - (
                    self.legend_box_size + 5)
                truncation = int(reverse_text_len(
                    available_space, self.legend_font_size))
        else:
            x = self.margin.left + self.view.width + 10
            y = self.margin.top + 10
            cols = 1
            if not truncation:
                truncation = 15

        legends = self.svg.node(
            self.nodes['graph'], class_='legends',
            transform='translate(%d, %d)' % (x, y))

        h = max(self.legend_box_size, self.legend_font_size)
        x_step = self.view.width / cols
        for i, title in enumerate(self._legends):
            col = i % cols
            row = i // cols

            legend = self.svg.node(
                legends, class_='legend reactive activate-serie',
                id="activate-serie-%d" % i)
            self.svg.node(
                legend, 'rect',
                x=col * x_step,
                y=1.5 * row * h + (
                    self.legend_font_size - self.legend_box_size
                    if self.legend_font_size > self.legend_box_size else 0
                ) / 2,
                width=self.legend_box_size,
                height=self.legend_box_size,
                class_="color-%d reactive" % (i % 16)
            )
            truncated = truncate(title, truncation)
            # Serious magical numbers here
            self.svg.node(
                legend, 'text',
                x=col * x_step + self.legend_box_size + 5,
                y=1.5 * row * h
                + .5 * h
                + .3 * self.legend_font_size
            ).text = truncated
            if truncated != title:
                self.svg.node(legend, 'title').text = title
Exemplo n.º 8
0
    def _legend(self):
        """Make the legend box"""
        if not self.show_legend:
            return
        truncation = self.truncate_legend
        if self.legend_at_bottom:
            x = self.margin.left + 10
            y = (self.margin.top + self.view.height +
                 self._x_labels_height + 10)
            cols = ceil(sqrt(self._order))

            if not truncation:
                available_space = self.view.width / cols - (
                    self.legend_box_size + 5)
                truncation = reverse_text_len(
                    available_space, self.legend_font_size)
        else:
            x = self.margin.left + self.view.width + 10
            y = self.margin.top + 10
            cols = 1
            if not truncation:
                truncation = 15

        legends = self.svg.node(
            self.nodes['graph'], class_='legends',
            transform='translate(%d, %d)' % (x, y))

        h = max(self.legend_box_size, self.legend_font_size)
        x_step = self.view.width / cols
        for i, title in enumerate(self._legends):
            col = i % cols
            row = i // cols

            legend = self.svg.node(
                legends, class_='legend reactive activate-serie',
                id="activate-serie-%d" % i)
            self.svg.node(
                legend, 'rect',
                x=col * x_step,
                y=1.5 * row * h + (
                    self.legend_font_size - self.legend_box_size
                    if self.legend_font_size > self.legend_box_size else 0
                ) / 2,
                width=self.legend_box_size,
                height=self.legend_box_size,
                class_="color-%d reactive" % (i % 16)
            )
            truncated = truncate(title, truncation)
            # Serious magical numbers here
            self.svg.node(
                legend, 'text',
                x=col * x_step + self.legend_box_size + 5,
                y=1.5 * row * h
                + .5 * h
                + .3 * self.legend_font_size
            ).text = truncated
            if truncated != title:
                self.svg.node(legend, 'title').text = title
Exemplo n.º 9
0
def test_truncate():
    assert truncate('1234567890', 50) == '1234567890'
    assert truncate('1234567890', 5) == u('1234…')
    assert truncate('1234567890', 1) == u('…')
    assert truncate('1234567890', 9) == u('12345678…')
    assert truncate('1234567890', 10) == '1234567890'
    assert truncate('1234567890', 0) == '1234567890'
    assert truncate('1234567890', -1) == '1234567890'
Exemplo n.º 10
0
def test_truncate():
    assert truncate('1234567890', 50) == '1234567890'
    assert truncate('1234567890', 5) == u'1234…'
    assert truncate('1234567890', 1) == u'…'
    assert truncate('1234567890', 9) == u'12345678…'
    assert truncate('1234567890', 10) == '1234567890'
    assert truncate('1234567890', 0) == '1234567890'
    assert truncate('1234567890', -1) == '1234567890'
Exemplo n.º 11
0
Arquivo: radar.py Projeto: Kozea/pygal
    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_ = lambda x: '%f %f' % 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(%f %s)' % (
                self.x_label_rotation or deg(angle), format_(pos_text)
            )
Exemplo n.º 12
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_ = lambda x: '%f %f' % 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(%f %s)' % (
                self.x_label_rotation or deg(angle), format_(pos_text)
            )
Exemplo n.º 13
0
 def _title(self):
     """Make the title"""
     if self.title:
         self.svg.node(
             self.nodes["graph"],
             "text",
             class_="title",
             x=self.margin.left + self.view.width / 2,
             y=self.title_font_size + 10,
         ).text = truncate(self.title, int(reverse_text_len(self.width, self.title_font_size)))
Exemplo n.º 14
0
def test_truncate():
    """Test truncate function"""
    assert truncate('1234567890', 50) == '1234567890'
    assert truncate('1234567890', 5) == u('1234…')
    assert truncate('1234567890', 1) == u('…')
    assert truncate('1234567890', 9) == u('12345678…')
    assert truncate('1234567890', 10) == '1234567890'
    assert truncate('1234567890', 0) == '1234567890'
    assert truncate('1234567890', -1) == '1234567890'
Exemplo n.º 15
0
def test_truncate():
    """Test truncate function"""
    assert truncate('1234567890', 50) == '1234567890'
    assert truncate('1234567890', 5) == u('1234…')
    assert truncate('1234567890', 1) == u('…')
    assert truncate('1234567890', 9) == u('12345678…')
    assert truncate('1234567890', 10) == '1234567890'
    assert truncate('1234567890', 0) == '1234567890'
    assert truncate('1234567890', -1) == '1234567890'
Exemplo n.º 16
0
    def _x_axis(self, draw_axes=True):
        """Make the x axis: labels and guides"""
        if not self._x_labels:
            return
        axis = self.svg.node(self.nodes['plot'], class_="axis x")
        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])
                last_label_position = self.view.x(self._x_labels[-1][1])
                available_space = (
                    last_label_position - first_label_position) / (
                        len(self._x_labels) - 1)
                truncation = reverse_text_len(
                    available_space, self.label_font_size)

        if 0 not in [label[1] for label in self._x_labels] and draw_axes:
            self.svg.node(axis, 'path',
                          d='M%f %f v%f' % (0, 0, self.view.height),
                          class_='line')
        for label, position in self._x_labels:
            major = is_major(position)
            guides = self.svg.node(axis, class_='guides')
            x = self.view.x(position)
            y = self.view.height + 5
            if draw_axes:
                self.svg.node(
                    guides, 'path',
                    d='M%f %f v%f' % (x, 0, self.view.height),
                    class_='%s%sline' % (
                        'major ' if major else '',
                        'guide ' if position != 0 else ''))
            y += .5 * self.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
            if self.x_label_rotation:
                text.attrib['transform'] = "rotate(%d %f %f)" % (
                    self.x_label_rotation, x, y)
Exemplo n.º 17
0
    def _x_axis(self, draw_axes=True):
        """Make the x axis: labels and guides"""
        if not self._x_labels:
            return
        axis = self.svg.node(self.nodes['plot'], class_="axis x")
        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])
                last_label_position = self.view.x(self._x_labels[-1][1])
                available_space = (last_label_position - first_label_position
                                   ) / (len(self._x_labels) - 1)
                truncation = reverse_text_len(available_space,
                                              self.label_font_size)

        if 0 not in [label[1] for label in self._x_labels] and draw_axes:
            self.svg.node(axis,
                          'path',
                          d='M%f %f v%f' % (0, 0, self.view.height),
                          class_='line')
        for label, position in self._x_labels:
            major = is_major(position)
            guides = self.svg.node(axis, class_='guides')
            x = self.view.x(position)
            y = self.view.height + 5
            if draw_axes:
                self.svg.node(guides,
                              'path',
                              d='M%f %f v%f' % (x, 0, self.view.height),
                              class_='%s%sline' %
                              ('major ' if major else '',
                               'guide ' if position != 0 else ''))
            y += .5 * self.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
            if self.x_label_rotation:
                text.attrib['transform'] = "rotate(%d %f %f)" % (
                    self.x_label_rotation, x, y)
Exemplo n.º 18
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_ = lambda x: "%f %f" % 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(%f %s)" % (self.x_label_rotation or deg(angle), format_(pos_text))
Exemplo n.º 19
0
    def _compute_margin(self):
        """Compute graph margins from set texts"""
        self._legend_at_left_width = 0
        for series_group in (self.series, self.secondary_series):
            if self.show_legend and series_group:
                h, w = get_texts_box(
                    map(lambda x: truncate(x, self.truncate_legend or 15),
                        cut(series_group, 'title')),
                    self.legend_font_size)
                if self.legend_at_bottom:
                    h_max = max(h, self.legend_box_size)
                    cols = (self._order // self.legend_at_bottom_columns
                            if self.legend_at_bottom_columns
                            else ceil(sqrt(self._order)) or 1)
                    self.margin.bottom += self.spacing + h_max * round(
                        cols - 1) * 1.5 + h_max
                else:
                    if series_group is self.series:
                        legend_width = self.spacing + w + self.legend_box_size
                        self.margin.left += legend_width
                        self._legend_at_left_width += legend_width
                    else:
                        self.margin.right += (
                            self.spacing + w + self.legend_box_size)

        self._x_labels_height = 0
        if (self._x_labels or self._x_2nd_labels) and self.show_x_labels:
            for xlabels in (self._x_labels, self._x_2nd_labels):
                if xlabels:
                    h, w = get_texts_box(
                        map(lambda x: truncate(x, self.truncate_label or 25),
                            cut(xlabels)),
                        self.label_font_size)
                    self._x_labels_height = self.spacing + max(
                        w * sin(rad(self.x_label_rotation)), h)
                    if xlabels is self._x_labels:
                        self.margin.bottom += self._x_labels_height
                    else:
                        self.margin.top += self._x_labels_height
                    if self.x_label_rotation:
                        self.margin.right = max(
                            w * cos(rad(self.x_label_rotation)),
                            self.margin.right)

        if self.show_y_labels:
            for ylabels in (self._y_labels, self._y_2nd_labels):
                if ylabels:
                    h, w = get_texts_box(
                        cut(ylabels), self.label_font_size)
                    if ylabels is self._y_labels:
                        self.margin.left += self.spacing + max(
                            w * cos(rad(self.y_label_rotation)), h)
                    else:
                        self.margin.right += self.spacing + max(
                            w * cos(rad(self.y_label_rotation)), h)

        self.title = split_title(
            self.title, self.width, self.title_font_size)

        if self.title:
            h, _ = get_text_box(self.title[0], self.title_font_size)
            self.margin.top += len(self.title) * (self.spacing + h)

        self.x_title = split_title(
            self.x_title, self.width - self.margin.x, self.title_font_size)

        self._x_title_height = 0
        if self.x_title:
            h, _ = get_text_box(self.x_title[0], self.title_font_size)
            height = len(self.x_title) * (self.spacing + h)
            self.margin.bottom += height
            self._x_title_height = height + self.spacing

        self.y_title = split_title(
            self.y_title, self.height - self.margin.y, self.title_font_size)

        self._y_title_height = 0
        if self.y_title:
            h, _ = get_text_box(self.y_title[0], self.title_font_size)
            height = len(self.y_title) * (self.spacing + h)
            self.margin.left += height
            self._y_title_height = height + self.spacing
Exemplo n.º 20
0
    def _x_axis(self):
        """Make the x axis: labels and guides"""
        if not self._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.label_font_size)
                truncation = max(truncation, 1)

        if 0 not in [label[1] for label in self._x_labels]:
            self.svg.node(axis, 'path',
                          d='M%f %f v%f' % (0, 0, self.view.height),
                          class_='line')
        lastlabel = self._x_labels[-1][0]

        for label, position in self._x_labels:
            major = label in self._x_major_labels
            if not (self.show_minor_x_labels or major):
                continue
            guides = self.svg.node(axis, class_='guides')
            x = self.view.x(position)
            y = self.view.height + 5
            last_guide = (self._y_2nd_labels and label == lastlabel)
            self.svg.node(
                guides, 'path',
                d='M%f %f v%f' % (x or 0, 0, self.view.height),
                class_='%s%sline' % (
                    'major ' if major else '',
                    'guide ' if position != 0 and not last_guide else ''))
            y += .5 * self.label_font_size + 5
            text = self.svg.node(
                guides, 'text',
                x=x,
                y=y,
                class_='major' if major else ''
            )

            if isinstance(label, dict):
                label = label['title']

            text.text = truncate(label, truncation)
            if text.text != label:
                self.svg.node(guides, 'title').text = label
            if self.x_label_rotation:
                text.attrib['transform'] = "rotate(%d %f %f)" % (
                    self.x_label_rotation, x, y)

        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_major_labels
                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 %f %f)" % (
                        -self.x_label_rotation, x, y)
Exemplo n.º 21
0
    def _legend(self):
        """Make the legend box"""
        if not self.show_legend:
            return
        truncation = self.truncate_legend
        if self.legend_at_bottom:
            x = self.margin.left + self.spacing
            y = (self.margin.top + self.view.height +
                 self._x_title_height +
                 self._x_labels_height + self.spacing)
            cols = ceil(sqrt(self._order)) or 1

            if not truncation:
                available_space = self.view.width / cols - (
                    self.legend_box_size + 5)
                truncation = reverse_text_len(
                    available_space, self.legend_font_size)
        else:
            x = self.spacing
            y = self.margin.top + self.spacing
            cols = 1
            if not truncation:
                truncation = 15

        legends = self.svg.node(
            self.nodes['graph'], class_='legends',
            transform='translate(%d, %d)' % (x, y))

        h = max(self.legend_box_size, self.legend_font_size)
        x_step = self.view.width / cols
        if self.legend_at_bottom:
            # if legends at the bottom, we dont split the windows
            # gen structure - (i, (j, (l, tf)))
            # i - global serie number - used for coloring and identification
            # j - position within current legend box
            # l - label
            # tf - whether it is secondary label
            gen = enumerate(enumerate(chain(
                zip(self._legends, repeat(False)),
                zip(self._secondary_legends, repeat(True)))))
            secondary_legends = legends  # svg node is the same
        else:
            gen = enumerate(chain(
                enumerate(zip(self._legends, repeat(False))),
                enumerate(zip(self._secondary_legends, repeat(True)))))

            # draw secondary axis on right
            x = self.margin.left + self.view.width + self.spacing
            if self._y_2nd_labels:
                h, w = get_texts_box(
                    cut(self._y_2nd_labels), self.label_font_size)
                x += self.spacing + max(w * cos(rad(self.y_label_rotation)), h)

            y = self.margin.top + self.spacing

            secondary_legends = self.svg.node(
                self.nodes['graph'], class_='legends',
                transform='translate(%d, %d)' % (x, y))

        for (global_serie_number, (i, (title, is_secondary))) in gen:

            col = i % cols
            row = i // cols

            legend = self.svg.node(
                secondary_legends if is_secondary else legends,
                class_='legend reactive activate-serie',
                id="activate-serie-%d" % global_serie_number)
            self.svg.node(
                legend, 'rect',
                x=col * x_step,
                y=1.5 * row * h + (
                    self.legend_font_size - self.legend_box_size
                    if self.legend_font_size > self.legend_box_size else 0
                ) / 2,
                width=self.legend_box_size,
                height=self.legend_box_size,
                class_="color-%d reactive" % (
                    global_serie_number % len(self.style['colors']))
            )

            if isinstance(title, dict):
                node = decorate(self.svg, legend, title)
                title = title['title']
            else:
                node = legend

            truncated = truncate(title, truncation)
            self.svg.node(
                node, 'text',
                x=col * x_step + self.legend_box_size + 5,
                y=1.5 * row * h + .5 * h + .3 * self.legend_font_size
            ).text = truncated

            if truncated != title:
                self.svg.node(legend, 'title').text = title
Exemplo n.º 22
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'])
Exemplo n.º 23
0
    def _x_axis(self):
        """Make the x axis: labels and guides"""
        if not self._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])
                last_label_position = self.view.x(self._x_labels[-1][1])
                available_space = (last_label_position - first_label_position) / (len(self._x_labels) - 1)
                truncation = reverse_text_len(available_space, self.label_font_size)

        if 0 not in [label[1] for label in self._x_labels]:
            self.svg.node(axis, "path", d="M%f %f v%f" % (0, 0, self.view.height), class_="line")
        lastlabel = self._x_labels[-1][0]
        if self.x_labels_major:
            x_labels_major = self.x_labels_major
        elif self.x_labels_major_every:
            x_labels_major = [self._x_labels[i][0] for i in range(0, len(self._x_labels), self.x_labels_major_every)]
        elif self.x_labels_major_count:
            label_count = len(self._x_labels)
            major_count = self.x_labels_major_count
            if major_count >= label_count:
                x_labels_major = [label[0] for label in self._x_labels]
            else:
                x_labels_major = [
                    self._x_labels[int(i * (label_count - 1) / (major_count - 1))][0] for i in range(major_count)
                ]
        else:
            x_labels_major = []
        for label, position in self._x_labels:
            major = label in 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)
            y = self.view.height + 5
            last_guide = self._y_2nd_labels and label == lastlabel
            self.svg.node(
                guides,
                "path",
                d="M%f %f v%f" % (x, 0, self.view.height),
                class_="%s%sline" % ("major " if major else "", "guide " if position != 0 and not last_guide else ""),
            )
            y += 0.5 * self.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
            if self.x_label_rotation:
                text.attrib["transform"] = "rotate(%d %f %f)" % (self.x_label_rotation, x, y)

        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 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 %f %f)" % (-self.x_label_rotation, x, y)
Exemplo n.º 24
0
    def _legend(self):
        """Make the legend box"""
        if not self.show_legend:
            return
        truncation = self.truncate_legend
        if self.legend_at_bottom:
            x = self.margin.left + self.spacing
            y = (self.margin.top + self.view.height + self._x_title_height +
                 self._x_labels_height + self.spacing)
            cols = self.legend_at_bottom_columns or ceil(sqrt(
                self._order)) or 1

            if not truncation:
                available_space = self.view.width / cols - (
                    self.legend_box_size + 5)
                truncation = reverse_text_len(available_space,
                                              self.legend_font_size)
        else:
            x = self.spacing
            y = self.margin.top + self.spacing
            cols = 1
            if not truncation:
                truncation = 15

        legends = self.svg.node(self.nodes['graph'],
                                class_='legends',
                                transform='translate(%d, %d)' % (x, y))

        h = max(self.legend_box_size, self.legend_font_size)
        x_step = self.view.width / cols
        if self.legend_at_bottom:
            # if legends at the bottom, we dont split the windows
            # gen structure - (i, (j, (l, tf)))
            # i - global serie number - used for coloring and identification
            # j - position within current legend box
            # l - label
            # tf - whether it is secondary label
            gen = enumerate(
                enumerate(
                    chain(zip(self._legends, repeat(False)),
                          zip(self._secondary_legends, repeat(True)))))
            secondary_legends = legends  # svg node is the same
        else:
            gen = enumerate(
                chain(enumerate(zip(self._legends, repeat(False))),
                      enumerate(zip(self._secondary_legends, repeat(True)))))

            # draw secondary axis on right
            x = self.margin.left + self.view.width + self.spacing
            if self._y_2nd_labels:
                h, w = get_texts_box(cut(self._y_2nd_labels),
                                     self.label_font_size)
                x += self.spacing + max(w * cos(rad(self.y_label_rotation)), h)

            y = self.margin.top + self.spacing

            secondary_legends = self.svg.node(self.nodes['graph'],
                                              class_='legends',
                                              transform='translate(%d, %d)' %
                                              (x, y))

        for (global_serie_number, (i, (title, is_secondary))) in gen:

            col = i % cols
            row = i // cols

            legend = self.svg.node(
                secondary_legends if is_secondary else legends,
                class_='legend reactive activate-serie',
                id="activate-serie-%d" % global_serie_number)
            self.svg.node(
                legend,
                'rect',
                x=col * x_step,
                y=1.5 * row * h +
                (self.legend_font_size - self.legend_box_size
                 if self.legend_font_size > self.legend_box_size else 0) / 2,
                width=self.legend_box_size,
                height=self.legend_box_size,
                class_="color-%d reactive" %
                (global_serie_number % len(self.style['colors'])))

            if isinstance(title, dict):
                node = decorate(self.svg, legend, title)
                title = title['title']
            else:
                node = legend

            truncated = truncate(title, truncation)
            self.svg.node(node,
                          'text',
                          x=col * x_step + self.legend_box_size + 5,
                          y=1.5 * row * h + .5 * h +
                          .3 * self.legend_font_size).text = truncated

            if truncated != title:
                self.svg.node(legend, 'title').text = title
Exemplo n.º 25
0
    def _x_axis(self, draw_axes=True):
        """Make the x axis: labels and guides"""
        if not self._x_labels:
            return
        axis = self.svg.node(self.nodes['plot'], class_="axis x")
        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])
                last_label_position = self.view.x(self._x_labels[-1][1])
                available_space = (last_label_position - first_label_position
                                   ) / (len(self._x_labels) - 1)
                truncation = reverse_text_len(available_space,
                                              self.label_font_size)

        if 0 not in [label[1] for label in self._x_labels] and draw_axes:
            self.svg.node(axis,
                          'path',
                          d='M%f %f v%f' % (0, 0, self.view.height),
                          class_='line')
        lastlabel = self._x_labels[-1][0]
        if self.x_labels_major:
            x_labels_major = self.x_labels_major
        elif self.x_labels_major_every:
            x_labels_major = [
                self._x_labels[i][0] for i in xrange(0, len(self._x_labels),
                                                     self.x_labels_major_every)
            ]
        elif self.x_labels_major_count:
            label_count = len(self._x_labels)
            major_count = self.x_labels_major_count
            if (major_count >= label_count):
                x_labels_major = [label[0] for label in self._x_labels]
            else:
                x_labels_major = [
                    self._x_labels[int(i * (label_count - 1) /
                                       (major_count - 1))][0]
                    for i in xrange(major_count)
                ]
        else:
            x_labels_major = []
        for label, position in self._x_labels:
            major = label in 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)
            y = self.view.height + 5
            if draw_axes:
                last_guide = (self._y_2nd_labels and label == lastlabel)
                self.svg.node(
                    guides,
                    'path',
                    d='M%f %f v%f' % (x, 0, self.view.height),
                    class_='%s%sline' %
                    ('major ' if major else '',
                     'guide ' if position != 0 and not last_guide else ''))
            y += .5 * self.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
            if self.x_label_rotation:
                text.attrib['transform'] = "rotate(%d %f %f)" % (
                    self.x_label_rotation, x, y)

        if self._x_2nd_labels:
            secondary_ax = self.svg.node(self.nodes['plot'],
                                         class_="axis x x2")
            for label, position in self._x_2nd_labels:
                major = label in 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 %f %f)" % (
                        -self.x_label_rotation, x, y)
Exemplo n.º 26
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%f %f v%f' % (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%f %f v%f' % (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 %f %f)" % (
                    self.x_label_rotation, x, 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 %f %f)" % (
                        -self.x_label_rotation, x, y)
                    if self.x_label_rotation >= 180:
                        text.attrib['class'] = ' '.join((
                            text.attrib['class'] and
                            text.attrib['class'].split(
                                ' ') or []) + ['backwards'])
Exemplo n.º 27
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.label_font_size)
                truncation = max(truncation, 1)

        if 0 not in [label[1] for label in self._x_labels]:
            self.svg.node(axis,
                          'path',
                          d='M%f %f v%f' % (0, 0, self.view.height),
                          class_='line')
        lastlabel = self._x_labels[-1][0]

        for label, position in self._x_labels:
            major = label in self._x_major_labels
            if not (self.show_minor_x_labels or major):
                continue
            guides = self.svg.node(axis, class_='guides')
            x = self.view.x(position)
            y = self.view.height + 5
            last_guide = (self._y_2nd_labels and label == lastlabel)
            self.svg.node(
                guides,
                'path',
                d='M%f %f v%f' % (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.label_font_size + 5
            text = self.svg.node(guides,
                                 'text',
                                 x=x,
                                 y=y,
                                 class_='major' if major else '')

            if isinstance(label, dict):
                label = label['title']

            text.text = truncate(label, truncation)
            if text.text != label:
                self.svg.node(guides, 'title').text = label
            if self.x_label_rotation:
                text.attrib['transform'] = "rotate(%d %f %f)" % (
                    self.x_label_rotation, x, y)

        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_major_labels
                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 %f %f)" % (
                        -self.x_label_rotation, x, y)
Exemplo n.º 28
0
    def _legend(self):
        """Make the legend box"""
        if not self.show_legend:
            return
        truncation = self.truncate_legend
        if self.legend_at_bottom:
            x = self.margin_box.left + self.spacing
            y = (self.margin_box.top + self.view.height +
                 self._x_title_height +
                 self._x_labels_height + self.spacing)
            cols = self.legend_at_bottom_columns or ceil(
                sqrt(self._order)) or 1

            if not truncation:
                available_space = self.view.width / cols - (
                    self.legend_box_size + 5)
                truncation = reverse_text_len(
                    available_space, self.style.legend_font_size)
        else:
            x = self.spacing
            y = self.margin_box.top + self.spacing
            cols = 1
            if not truncation:
                truncation = 15

        legends = self.svg.node(
            self.nodes['graph'], class_='legends',
            transform='translate(%d, %d)' % (x, y))

        h = max(self.legend_box_size, self.style.legend_font_size)
        x_step = self.view.width / cols
        if self.legend_at_bottom:
            secondary_legends = legends  # svg node is the same
        else:

            # draw secondary axis on right
            x = self.margin_box.left + self.view.width + self.spacing
            if self._y_2nd_labels:
                h, w = get_texts_box(
                    cut(self._y_2nd_labels), self.style.label_font_size)
                x += self.spacing + max(w * abs(cos(rad(
                    self.y_label_rotation))), h)

            y = self.margin_box.top + self.spacing

            secondary_legends = self.svg.node(
                self.nodes['graph'], class_='legends',
                transform='translate(%d, %d)' % (x, y))

        serie_number = -1
        i = 0

        for titles, is_secondary in (
                (self._legends, False),
                (self._secondary_legends, True)):
            if not self.legend_at_bottom and is_secondary:
                i = 0

            for title in titles:
                serie_number += 1
                if title is None:
                    continue
                col = i % cols
                row = i // cols

                legend = self.svg.node(
                    secondary_legends if is_secondary else legends,
                    class_='legend reactive activate-serie',
                    id="activate-serie-%d" % serie_number)
                self.svg.node(
                    legend, 'rect',
                    x=col * x_step,
                    y=1.5 * row * h + (
                        self.style.legend_font_size - self.legend_box_size
                        if self.style.legend_font_size > self.legend_box_size
                        else 0
                    ) / 2,
                    width=self.legend_box_size,
                    height=self.legend_box_size,
                    class_="color-%d reactive" % (
                        serie_number % len(self.style.colors))
                )

                if isinstance(title, dict):
                    node = decorate(self.svg, legend, title)
                    title = title['title']
                else:
                    node = legend

                truncated = truncate(title, truncation)
                self.svg.node(
                    node, 'text',
                    x=col * x_step + self.legend_box_size + 5,
                    y=1.5 * row * h + .5 * h + .3 * self.style.legend_font_size
                ).text = truncated

                if truncated != title:
                    self.svg.node(legend, 'title').text = title

                i += 1
Exemplo n.º 29
0
    def _compute_margin(self):
        """Compute graph margins from set texts"""
        self._legend_at_left_width = 0
        for series_group in (self.series, self.secondary_series):
            if self.show_legend and series_group:
                h, w = get_texts_box(
                    map(
                        lambda x: truncate(x, self.truncate_legend or 15), [
                            serie.title['title']
                            if isinstance(serie.title, dict) else serie.title
                            or '' for serie in series_group
                        ]
                    ), self.style.legend_font_size
                )
                if self.legend_at_bottom:
                    h_max = max(h, self.legend_box_size)
                    cols = (
                        self._order // self.legend_at_bottom_columns
                        if self.legend_at_bottom_columns else
                        ceil(sqrt(self._order)) or 1
                    )
                    self.margin_box.bottom += self.spacing + h_max * round(
                        cols - 1
                    ) * 1.5 + h_max
                else:
                    if series_group is self.series:
                        legend_width = self.spacing + w + self.legend_box_size
                        self.margin_box.left += legend_width
                        self._legend_at_left_width += legend_width
                    else:
                        self.margin_box.right += (
                            self.spacing + w + self.legend_box_size
                        )

        self._x_labels_height = 0
        if (self._x_labels or self._x_2nd_labels) and self.show_x_labels:
            for xlabels in (self._x_labels, self._x_2nd_labels):
                if xlabels:
                    h, w = get_texts_box(
                        map(
                            lambda x: truncate(x, self.truncate_label or 25),
                            cut(xlabels)
                        ), self.style.label_font_size
                    )
                    self._x_labels_height = self.spacing + max(
                        w * abs(sin(rad(self.x_label_rotation))), h
                    )
                    if xlabels is self._x_labels:
                        self.margin_box.bottom += self._x_labels_height
                    else:
                        self.margin_box.top += self._x_labels_height
                    if self.x_label_rotation:
                        if self.x_label_rotation % 180 < 90:
                            self.margin_box.right = max(
                                w * abs(cos(rad(self.x_label_rotation))),
                                self.margin_box.right
                            )
                        else:
                            self.margin_box.left = max(
                                w * abs(cos(rad(self.x_label_rotation))),
                                self.margin_box.left
                            )

        if self.show_y_labels:
            for ylabels in (self._y_labels, self._y_2nd_labels):
                if ylabels:
                    h, w = get_texts_box(
                        cut(ylabels), self.style.label_font_size
                    )
                    if ylabels is self._y_labels:
                        self.margin_box.left += self.spacing + max(
                            w * abs(cos(rad(self.y_label_rotation))), h
                        )
                    else:
                        self.margin_box.right += self.spacing + max(
                            w * abs(cos(rad(self.y_label_rotation))), h
                        )

        self._title = split_title(
            self.title, self.width, self.style.title_font_size
        )

        if self.title:
            h, _ = get_text_box(self._title[0], self.style.title_font_size)
            self.margin_box.top += len(self._title) * (self.spacing + h)

        self._x_title = split_title(
            self.x_title, self.width - self.margin_box.x,
            self.style.title_font_size
        )

        self._x_title_height = 0
        if self._x_title:
            h, _ = get_text_box(self._x_title[0], self.style.title_font_size)
            height = len(self._x_title) * (self.spacing + h)
            self.margin_box.bottom += height
            self._x_title_height = height + self.spacing

        self._y_title = split_title(
            self.y_title, self.height - self.margin_box.y,
            self.style.title_font_size
        )

        self._y_title_height = 0
        if self._y_title:
            h, _ = get_text_box(self._y_title[0], self.style.title_font_size)
            height = len(self._y_title) * (self.spacing + h)
            self.margin_box.left += height
            self._y_title_height = height + self.spacing

        # Inner margin
        if self.print_values_position == 'top':
            gh = self.height - self.margin_box.y
            alpha = 1.1 * (self.style.value_font_size / gh) * self._box.height
            if self._max and self._max > 0:
                self._box.ymax += alpha
            if self._min and self._min < 0:
                self._box.ymin -= alpha
Exemplo n.º 30
0
    def _legend(self):
        """Make the legend box"""
        if not self.show_legend:
            return
        truncation = self.truncate_legend
        if self.legend_at_bottom:
            x = self.margin_box.left + self.spacing
            y = (
                self.margin_box.top + self.view.height + self._x_title_height +
                self._x_labels_height + self.spacing
            )
            cols = self.legend_at_bottom_columns or ceil(sqrt(self._order)
                                                         ) or 1

            if not truncation:
                available_space = self.view.width / cols - (
                    self.legend_box_size + 5
                )
                truncation = reverse_text_len(
                    available_space, self.style.legend_font_size
                )
        else:
            x = self.spacing
            y = self.margin_box.top + self.spacing
            cols = 1
            if not truncation:
                truncation = 15

        legends = self.svg.node(
            self.nodes['graph'],
            class_='legends',
            transform='translate(%d, %d)' % (x, y)
        )

        h = max(self.legend_box_size, self.style.legend_font_size)
        x_step = self.view.width / cols
        if self.legend_at_bottom:
            secondary_legends = legends  # svg node is the same
        else:

            # draw secondary axis on right
            x = self.margin_box.left + self.view.width + self.spacing
            if self._y_2nd_labels:
                h, w = get_texts_box(
                    cut(self._y_2nd_labels), self.style.label_font_size
                )
                x += self.spacing + max(
                    w * abs(cos(rad(self.y_label_rotation))), h
                )

            y = self.margin_box.top + self.spacing

            secondary_legends = self.svg.node(
                self.nodes['graph'],
                class_='legends',
                transform='translate(%d, %d)' % (x, y)
            )

        serie_number = -1
        i = 0

        for titles, is_secondary in ((self._legends, False),
                                     (self._secondary_legends, True)):
            if not self.legend_at_bottom and is_secondary:
                i = 0

            for title in titles:
                serie_number += 1
                if title is None:
                    continue
                col = i % cols
                row = i // cols

                legend = self.svg.node(
                    secondary_legends if is_secondary else legends,
                    class_='legend reactive activate-serie',
                    id="activate-serie-%d" % serie_number
                )
                self.svg.node(
                    legend,
                    'rect',
                    x=col * x_step,
                    y=1.5 * row * h + (
                        self.style.legend_font_size - self.legend_box_size
                        if self.style.legend_font_size > self.legend_box_size
                        else 0
                    ) / 2,
                    width=self.legend_box_size,
                    height=self.legend_box_size,
                    class_="color-%d reactive" % serie_number
                )

                if isinstance(title, dict):
                    node = decorate(self.svg, legend, title)
                    title = title['title']
                else:
                    node = legend

                truncated = truncate(title, truncation)
                self.svg.node(
                    node,
                    'text',
                    x=col * x_step + self.legend_box_size + 5,
                    y=1.5 * row * h + .5 * h + .3 * self.style.legend_font_size
                ).text = truncated

                if truncated != title:
                    self.svg.node(legend, 'title').text = title

                i += 1
Exemplo n.º 31
0
    def _compute_margin(self):
        """Compute graph margins from set texts"""
        self._legend_at_left_width = 0
        for series_group in (self.series, self.secondary_series):
            if self.show_legend and series_group:
                h, w = get_texts_box(
                    map(lambda x: truncate(x, self.truncate_legend or 15),
                        [serie.title['title']
                         if isinstance(serie.title, dict)
                         else serie.title or '' for serie in series_group]),
                    self.style.legend_font_size)
                if self.legend_at_bottom:
                    h_max = max(h, self.legend_box_size)
                    cols = (self._order // self.legend_at_bottom_columns
                            if self.legend_at_bottom_columns
                            else ceil(sqrt(self._order)) or 1)
                    self.margin_box.bottom += self.spacing + h_max * round(
                        cols - 1) * 1.5 + h_max
                else:
                    if series_group is self.series:
                        legend_width = self.spacing + w + self.legend_box_size
                        self.margin_box.left += legend_width
                        self._legend_at_left_width += legend_width
                    else:
                        self.margin_box.right += (
                            self.spacing + w + self.legend_box_size)

        self._x_labels_height = 0
        if (self._x_labels or self._x_2nd_labels) and self.show_x_labels:
            for xlabels in (self._x_labels, self._x_2nd_labels):
                if xlabels:
                    h, w = get_texts_box(
                        map(lambda x: truncate(x, self.truncate_label or 25),
                            cut(xlabels)),
                        self.style.label_font_size)
                    self._x_labels_height = self.spacing + max(
                        w * abs(sin(rad(self.x_label_rotation))), h)
                    if xlabels is self._x_labels:
                        self.margin_box.bottom += self._x_labels_height
                    else:
                        self.margin_box.top += self._x_labels_height
                    if self.x_label_rotation:
                        if self.x_label_rotation % 180 < 90:
                            self.margin_box.right = max(
                                w * abs(cos(rad(self.x_label_rotation))),
                                self.margin_box.right)
                        else:
                            self.margin_box.left = max(
                                w * abs(cos(rad(self.x_label_rotation))),
                                self.margin_box.left)

        if self.show_y_labels:
            for ylabels in (self._y_labels, self._y_2nd_labels):
                if ylabels:
                    h, w = get_texts_box(
                        cut(ylabels), self.style.label_font_size)
                    if ylabels is self._y_labels:
                        self.margin_box.left += self.spacing + max(
                            w * abs(cos(rad(self.y_label_rotation))), h)
                    else:
                        self.margin_box.right += self.spacing + max(
                            w * abs(cos(rad(self.y_label_rotation))), h)

        self._title = split_title(
            self.title, self.width, self.style.title_font_size)

        if self.title:
            h, _ = get_text_box(self._title[0], self.style.title_font_size)
            self.margin_box.top += len(self._title) * (self.spacing + h)

        self._x_title = split_title(
            self.x_title, self.width - self.margin_box.x,
            self.style.title_font_size)

        self._x_title_height = 0
        if self._x_title:
            h, _ = get_text_box(self._x_title[0], self.style.title_font_size)
            height = len(self._x_title) * (self.spacing + h)
            self.margin_box.bottom += height
            self._x_title_height = height + self.spacing

        self._y_title = split_title(
            self.y_title, self.height - self.margin_box.y,
            self.style.title_font_size)

        self._y_title_height = 0
        if self._y_title:
            h, _ = get_text_box(self._y_title[0], self.style.title_font_size)
            height = len(self._y_title) * (self.spacing + h)
            self.margin_box.left += height
            self._y_title_height = height + self.spacing

        # Inner margin
        if self.print_values_position == 'top':
            gh = self.height - self.margin_box.y
            alpha = 1.1 * (self.style.value_font_size / gh) * self._box.height
            if self._max > 0:
                self._box.ymax += alpha
            if self._min < 0:
                self._box.ymin -= alpha
Exemplo n.º 32
0
Arquivo: graph.py Projeto: psibi/pygal
    def _x_axis(self, draw_axes=True):
        """Make the x axis: labels and guides"""
        if not self._x_labels:
            return
        axis = self.svg.node(self.nodes['plot'], class_="axis x")
        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])
                last_label_position = self.view.x(self._x_labels[-1][1])
                available_space = (
                    last_label_position - first_label_position) / (
                        len(self._x_labels) - 1)
                truncation = reverse_text_len(
                    available_space, self.label_font_size)

        if 0 not in [label[1] for label in self._x_labels] and draw_axes:
            self.svg.node(axis, 'path',
                          d='M%f %f v%f' % (0, 0, self.view.height),
                          class_='line')
        lastlabel = self._x_labels[-1][0]
        if self.x_labels_major:
            x_labels_major = self.x_labels_major
        elif self.x_labels_major_every:
            x_labels_major = [self._x_labels[i][0] for i in xrange(
                0, len(self._x_labels), self.x_labels_major_every)]
        elif self.x_labels_major_count:
            label_count = len(self._x_labels)
            major_count = self.x_labels_major_count
            if (major_count >= label_count):
                x_labels_major = [label[0] for label in self._x_labels]
            else:
                x_labels_major = [self._x_labels[
                    int(i * (label_count - 1) / (major_count - 1))][0]
                    for i in xrange(major_count)]
        else:
            x_labels_major = []
        for label, position in self._x_labels:
            major = label in 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)
            y = self.view.height + 5
            if draw_axes:
                last_guide = (self._y_2nd_labels and label == lastlabel)
                self.svg.node(
                    guides, 'path',
                    d='M%f %f v%f' % (x, 0, self.view.height),
                    class_='%s%sline' % (
                        'major ' if major else '',
                        'guide ' if position != 0 and not last_guide else ''))
            y += .5 * self.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
            if self.x_label_rotation:
                text.attrib['transform'] = "rotate(%d %f %f)" % (
                    self.x_label_rotation, x, y)

        if self._x_2nd_labels:
            secondary_ax = self.svg.node(
                self.nodes['plot'], class_="axis x x2")
            for label, position in self._x_2nd_labels:
                major = label in 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 %f %f)" % (
                        -self.x_label_rotation, x, y)