示例#1
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
示例#2
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
示例#3
0
文件: graph.py 项目: doofinder/pygal
    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
示例#4
0
    def _legend(self):
        """Make the legend box"""
        if not self.show_legend:
            return
        truncation = self.truncate_legend
        if self.legend_at_top:
            x = self.margin_box.left
            y = self.spacing

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

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

            _sub_title = split_title(self.sub_title, self.width,
                                     self.style.sub_title_font_size)

            if self.sub_title:
                h, _ = get_text_box(_sub_title[0],
                                    self.style.sub_title_font_size)
                y += len(self._sub_title) * (self.spacing + h) + 20

            cols = self.legend_at_top_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)
        elif 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 + 60
            y = self.margin_box.top + self.spacing
            cols = 1
            if not truncation:
                truncation = 15

        if not self.legend_at_top:
            legends = self.svg.node(self.nodes['graph'],
                                    class_='legends',
                                    transform='translate(%d, %d)' % (x, y))
        else:
            legends = self.nodes['legends']
            legends.attrib['transform'] = 'translate(%d, %d)' % (x, y)

        h = max(self.legend_box_size, self.style.legend_font_size)
        x_step = 20
        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

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

                if col == 0:
                    x = 0

                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=x,
                    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,
                    rx=3,
                    ry=3,
                    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)
                legend_text = self.svg.node(node,
                                            'text',
                                            x=x + self.legend_box_size + 5,
                                            y=1.5 * row * h + .5 * h +
                                            .3 * self.style.legend_font_size)
                legend_text.text = truncated
                legend_text.attrib['font-weight'] = 'bold'

                x = x + x_step + text_len(len(title),
                                          self.style.legend_font_size)

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

                i += 1