Pygal: изменить тип точки / символ - PullRequest
0 голосов
/ 28 сентября 2018

Я хочу изменить точки в моей диаграмме Pygal с окружностей по умолчанию на прямоугольники (звучит странно, но имеет смысл в моем случае) и иметь возможность определять размер прямоугольников.Я не мог найти решение в документах.С помощью модуля конфигурации я могу показать / скрыть точки и изменить размер точек, но насколько я вижу, я не могу изменить значок точки.Я также не могу найти решение в модуле стиля.

Есть ли простой способ сделать это?

Большое спасибо

1 Ответ

0 голосов
/ 08 ноября 2018

Нет способа достичь этого, используя стили или конфигурацию: круглые точки жестко запрограммированы в функции, которая отображает линейные диаграммы.Но вы можете легко расширить класс линейной диаграммы и переопределить эту функцию, чтобы создать диаграмму с любой формой точки.

Если вы просматриваете исходный код класса Line , вы получитесм. следующий код в функции line:

alter(
    self.svg.transposable_node(
        dots,
        'circle',
        cx=x,
        cy=y,
        r=serie.dots_size,
        class_='dot reactive tooltip-trigger'
    ), metadata
)

Это создает круг для каждой точки и добавляет его к данным SVG, которые будут использоваться для создания диаграммы.

Копироватьвсю функцию в ваш новый класс и замените эти строки следующим кодом.Это добавит квадраты вместо кругов, используя конфигурацию dots_size для определения ширины и высоты:

alter(
    self.svg.transposable_node(
        dots,
        'rect',
        x=x - serie.dots_size / 2,
        y=y - serie.dots_size / 2,
        width=serie.dots_size,
        height=serie.dots_size,
        class_='dot reactive tooltip-trigger'
    ), metadata
)

Полный класс будет выглядеть примерно так (выглядит как много кода, но большинствоон вставлен в копию):

from pygal.util import alter, decorate

class SquareDots(pygal.Line):

    def __init__(self, *args, **kwargs):
        super(SquareDots, self).__init__(*args, **kwargs)

    def line(self, serie, rescale=False):
        serie_node = self.svg.serie(serie)
        if rescale and self.secondary_series:
            points = self._rescale(serie.points)
        else:
            points = serie.points
        view_values = list(map(self.view, points))
        if serie.show_dots:
            for i, (x, y) in enumerate(view_values):
                if None in (x, y):
                    continue
                if self.logarithmic:
                    if points[i][1] is None or points[i][1] <= 0:
                        continue
                if (serie.show_only_major_dots and self.x_labels
                        and i < len(self.x_labels)
                        and self.x_labels[i] not in self._x_labels_major):
                    continue
                metadata = serie.metadata.get(i)
                classes = []
                if x > self.view.width / 2:
                    classes.append('left')
                if y > self.view.height / 2:
                    classes.append('top')
                classes = ' '.join(classes)
                self._confidence_interval(
                    serie_node['overlay'], x, y, serie.values[i], metadata
                )
                dots = decorate(
                    self.svg,
                    self.svg.node(serie_node['overlay'], class_="dots"),
                    metadata
                )
                val = self._format(serie, i)

                # This is the part that needs to be changed.
                alter(self.svg.transposable_node(
                        dots,
                        'rect',
                        x=x - serie.dots_size / 2,
                        y=y - serie.dots_size / 2,
                        width=serie.dots_size,
                        height=serie.dots_size,
                        class_='dot reactive tooltip-trigger'
                    ), metadata
                )

                self._tooltip_data(
                    dots, val, x, y, xlabel=self._get_x_label(i)
                )
                self._static_value(
                    serie_node, val, x + self.style.value_font_size,
                    y + self.style.value_font_size, metadata
                )
        if serie.stroke:
            if self.interpolate:
                points = serie.interpolated
                if rescale and self.secondary_series:
                    points = self._rescale(points)
                view_values = list(map(self.view, points))
            if serie.fill:
                view_values = self._fill(view_values)
            if serie.allow_interruptions:
                sequences = []
                cur_sequence = []
                for x, y in view_values:
                    if y is None and len(cur_sequence) > 0:
                        sequences.append(cur_sequence)
                        cur_sequence = []
                    elif y is None:
                        continue
                    else:
                        cur_sequence.append((x, y))
                if len(cur_sequence) > 0:
                    sequences.append(cur_sequence)
            else:
                sequences = [view_values]
            if self.logarithmic:
                for seq in sequences:
                    for ele in seq[::-1]:
                        y = points[seq.index(ele)][1]
                        if y is None or y <= 0:
                            del seq[seq.index(ele)]
            for seq in sequences:
                self.svg.line(
                    serie_node['plot'],
                    seq,
                    close=self._self_close,
                    class_='line reactive' +
                    (' nofill' if not serie.fill else '')
                )

Ваш новый класс может быть использован как любая другая диаграмма Pygal.

chart = SquareDots(dots_size=50)
chart.add("line", [1, 2, 3, 4, 3, 2])
chart.render_to_png("chart.png")

Example chart with square dots

...