Beispiel #1
0
    def bar(self, serie, rescale=False):
        """Draw a bar graph for a serie"""
        serie_node = self.svg.serie(serie)
        bars = self.svg.node(serie_node['plot'], class_="histbars")
        points = serie.points

        for i, (y, x0, x1) in enumerate(points):
            if None in (x0, x1, y) or (self.logarithmic and y <= 0):
                continue
            metadata = serie.metadata.get(i)

            bar = decorate(self.svg, self.svg.node(bars, class_='histbar'),
                           metadata)
            val = self._format(serie, i)

            bounds = self._bar(serie,
                               bar,
                               x0,
                               x1,
                               y,
                               i,
                               self.zero,
                               secondary=rescale)
            self._tooltip_and_print_values(serie_node, serie, bar, i, val,
                                           metadata, *bounds)
Beispiel #2
0
    def funnel(self, serie):
        """Draw a funnel slice"""
        serie_node = self.svg.serie(serie)
        fmt = lambda x: '%f %f' % x
        for i, poly in enumerate(serie.points):
            metadata = serie.metadata.get(i)
            val = self._format(serie, i)

            funnels = decorate(
                self.svg, self.svg.node(serie_node['plot'], class_="funnels"),
                metadata)

            alter(
                self.svg.node(funnels,
                              'polygon',
                              points=' '.join(map(fmt, map(self.view, poly))),
                              class_='funnel reactive tooltip-trigger'),
                metadata)

            # Poly center from label
            x, y = self.view((self._center(self._x_pos[serie.index]),
                              sum([point[1] for point in poly]) / len(poly)))
            self._tooltip_data(funnels, val, x, y, 'centered',
                               self._get_x_label(serie.index))
            self._static_value(serie_node, val, x, y, metadata)
Beispiel #3
0
    def bar(self, serie, rescale=False):
        """Draw a bar graph for a serie"""
        serie_node = self.svg.serie(serie)
        bars = self.svg.node(serie_node['plot'], class_="bars")
        if rescale and self.secondary_series:
            points = self._rescale(serie.points)
        else:
            points = serie.points

        for i, (x, y) in enumerate(points):
            if None in (x, y) or (self.logarithmic and y <= 0):
                continue
            metadata = serie.metadata.get(i)
            val = self._format(serie, i)

            bar = decorate(self.svg, self.svg.node(bars, class_='bar'),
                           metadata)

            x_, y_, width, height = self._bar(serie,
                                              bar,
                                              x,
                                              y,
                                              i,
                                              self.zero,
                                              secondary=rescale)

            self._confidence_interval(serie_node['overlay'], x_ + width / 2,
                                      y_, serie.values[i], metadata)

            self._tooltip_and_print_values(serie_node, serie, bar, i, val,
                                           metadata, x_, y_, width, height)
Beispiel #4
0
    def line(self, serie_node, serie):
        """Draw the line serie"""
        view_values = map(self.view, serie.points)
        if self.show_dots:
            for i, (x, y) in enumerate(view_values):
                if None in (x, y):
                    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)

                dots = decorate(self.svg, self.svg.node(serie_node["overlay"], class_="dots"), metadata)
                val = self._get_value(serie.points, i)
                self.svg.node(dots, "circle", cx=x, cy=y, r=2.5, class_="dot reactive tooltip-trigger")
                self._tooltip_data(dots, val, x, y)
                self._static_value(serie_node, val, x + self.value_font_size, y + self.value_font_size)

        if self.stroke:
            if self.interpolate:
                view_values = map(self.view, serie.interpolated)
            if self.fill:
                view_values = self._fill(view_values)
            self.svg.line(
                serie_node["plot"],
                view_values,
                close=self._self_close,
                class_="line reactive" + (" nofill" if not self.fill else ""),
            )
Beispiel #5
0
    def bar(self, serie_node, serie, index, rescale=False):
        """Draw a bar graph for a serie"""
        bars = self.svg.node(serie_node['plot'], class_="bars")
        if rescale and self.secondary_series:
            points = [
                (x, self._scale_diff + (y - self._scale_min_2nd) * self._scale)
                for x, y in serie.points
            ]
        else:
            points = serie.points

        for i, (x, y) in enumerate(points):
            if None in (x, y) or (self.logarithmic and y <= 0):
                continue
            metadata = serie.metadata.get(i)

            bar = decorate(self.svg, self.svg.node(bars, class_='bar'),
                           metadata)
            val = self._format(serie.values[i])

            x_center, y_center = self._bar(bar,
                                           x,
                                           y,
                                           index,
                                           i,
                                           self.zero,
                                           secondary=rescale)
            self._tooltip_data(bar,
                               val,
                               x_center,
                               y_center,
                               classes="centered")
            self._static_value(serie_node, val, x_center, y_center)
Beispiel #6
0
    def bar(self, serie, rescale=False):
        """Draw a bar graph for a serie"""
        serie_node = self.svg.serie(serie)
        bars = self.svg.node(serie_node['plot'], class_="bars")
        if rescale and self.secondary_series:
            points = self._rescale(serie.points)
        else:
            points = serie.points

        for i, (x, y) in enumerate(points):
            if None in (x, y) or (self.logarithmic and y <= 0):
                continue
            metadata = serie.metadata.get(i)

            bar = decorate(self.svg, self.svg.node(bars, class_='bar'),
                           metadata)
            val = self._format(serie.values[i])

            x_center, y_center = self._bar(serie,
                                           bar,
                                           x,
                                           y,
                                           i,
                                           self.zero,
                                           secondary=rescale)
            self._tooltip_data(bar, val, x_center, y_center, "centered",
                               self._get_x_label(i))
            self._static_value(serie_node, val, x_center, y_center, metadata)
Beispiel #7
0
    def _rect(self, serie, serie_node, rects, val, x, y, w, h, i):
        rx, ry = self.view((x, y))
        rw, rh = self.view((x + w, y + h))
        rw -= rx
        rh -= ry

        metadata = serie.metadata.get(i)
        value = self._format(val)

        rect = decorate(
            self.svg,
            self.svg.node(rects, class_="rect"),
            metadata)

        self.svg.node(rect, 'rect',
                      x=rx,
                      y=ry,
                      width=rw,
                      height=rh,
                      class_='rect reactive tooltip-trigger')

        self._tooltip_data(rect, value,
                           rx + rw / 2,
                           ry + rh / 2,
                           classes='centered')
        self._static_value(serie_node, value,
                           rx + rw / 2,
                           ry + rh / 2)
Beispiel #8
0
    def funnel(self, serie):
        """Draw a funnel slice"""
        serie_node = self.svg.serie(serie)
        fmt = lambda x: '%f %f' % x
        for i, poly in enumerate(serie.points):
            metadata = serie.metadata.get(i)
            val = self._format(serie, i)

            funnels = decorate(
                self.svg,
                self.svg.node(serie_node['plot'], class_="funnels"),
                metadata)

            alter(self.svg.node(
                funnels, 'polygon',
                points=' '.join(map(fmt, map(self.view, poly))),
                class_='funnel reactive tooltip-trigger'), metadata)

            # Poly center from label
            x, y = self.view((
                self._center(self._x_pos[serie.index]),
                sum([point[1] for point in poly]) / len(poly)))
            self._tooltip_data(
                funnels, val, x, y, 'centered',
                self._get_x_label(serie.index))
            self._static_value(serie_node, val, x, y, metadata)
Beispiel #9
0
    def _rect(self, serie, serie_node, rects, val, x, y, w, h, i):
        rx, ry = self.view((x, y))
        rw, rh = self.view((x + w, y + h))
        rw -= rx
        rh -= ry

        metadata = serie.metadata.get(i)
        value = self._format(val)

        rect = decorate(self.svg, self.svg.node(rects, class_="rect"),
                        metadata)

        alter(
            self.svg.node(rect,
                          'rect',
                          x=rx,
                          y=ry,
                          width=rw,
                          height=rh,
                          class_='rect reactive tooltip-trigger'), metadata)

        self._tooltip_data(rect, value, rx + rw / 2, ry + rh / 2, 'centered',
                           self._get_x_label(i))
        self._static_value(serie_node, value, rx + rw / 2, ry + rh / 2,
                           metadata)
Beispiel #10
0
    def needle(self, serie_node, serie,):
        thickness = .05
        for i, value in enumerate(serie.values):
            if not value:
                continue
            theta = self.arc_pos(value)
            fmt = lambda x: '%f %f' % x
            value = self._format(serie.values[i])
            metadata = serie.metadata.get(i)
            gauges = decorate(
                self.svg,
                self.svg.node(serie_node['plot'], class_="dots"),
                metadata)

            self.svg.node(
                gauges, 'polygon', points=' '.join([
                    fmt(self.view((0, 0))),
                    fmt(self.view((.75, theta + thickness))),
                    fmt(self.view((.8, theta))),
                    fmt(self.view((.75, theta - thickness)))]),
                class_='line reactive tooltip-trigger')

            x, y = self.view((.75, theta))
            self._tooltip_data(gauges, value, x, y)
            self._static_value(serie_node, value, x, y)
Beispiel #11
0
    def dot(self, serie, r_max):
        """Draw a dot line"""
        serie_node = self.svg.serie(serie)
        view_values = list(map(self.view, serie.points))
        for i, value in safe_enumerate(serie.values):
            x, y = view_values[i]

            if self.logarithmic:
                log10min = log10(self._min) - 1
                log10max = log10(self._max or 1)

                if value != 0:
                    size = r_max * (
                        (log10(abs(value)) - log10min) /
                        (log10max - log10min)
                    )
                else:
                    size = 0
            else:
                size = r_max * (abs(value) / (self._max or 1))

            metadata = serie.metadata.get(i)
            dots = decorate(
                self.svg,
                self.svg.node(serie_node['plot'], class_="dots"),
                metadata)
            alter(self.svg.node(
                dots, 'circle',
                cx=x, cy=y, r=size,
                class_='dot reactive tooltip-trigger' + (
                    ' negative' if value < 0 else '')), metadata)

            value = self._format(value)
            self._tooltip_data(dots, value, x, y, classes='centered')
            self._static_value(serie_node, value, x, y)
Beispiel #12
0
    def bar(self, serie_node, serie, index, rescale=False):
        """Draw a bar graph for a serie"""
        bars = self.svg.node(serie_node["plot"], class_="bars")
        if rescale and self.secondary_series:
            points = [
                (x, self._scale_diff + (y - self._scale_min_2nd) * self._scale)
                for x, y in serie.points
                if y is not None
            ]
        else:
            points = serie.points

        for i, (x, y) in enumerate(points):
            if None in (x, y) or (self.logarithmic and y <= 0):
                continue
            metadata = serie.metadata.get(i)

            bar = decorate(self.svg, self.svg.node(bars, class_="bar"), metadata)
            val = self._format(serie.values[i])

            x_center, y_center = self._bar(
                bar, x, y, index, i, self.zero, secondary=rescale, rounded=serie.rounded_bars
            )
            self._tooltip_data(bar, val, x_center, y_center, classes="centered")
            self._static_value(serie_node, val, x_center, y_center)
Beispiel #13
0
    def bar(self, serie, rescale=False):
        """Draw a bar graph for a serie"""
        serie_node = self.svg.serie(serie)
        bars = self.svg.node(serie_node['plot'], class_="bars")
        if rescale and self.secondary_series:
            points = self._rescale(serie.points)
        else:
            points = serie.points

        for i, (x, y) in enumerate(points):
            if None in (x, y) or (self.logarithmic and y <= 0):
                continue
            metadata = serie.metadata.get(i)
            val = self._format(serie.values[i])

            bar = decorate(
                self.svg,
                self.svg.node(bars, class_='bar'),
                metadata)

            bounds = self._bar(
                serie, bar, x, y, i, self.zero, secondary=rescale)

            self._tooltip_and_print_values(
                serie_node, serie, bar, i, val, metadata, *bounds)
Beispiel #14
0
    def bar(self, serie, rescale=False):
        """Draw a bar graph for a serie"""
        serie_node = self.svg.serie(serie)
        bars = self.svg.node(serie_node['plot'], class_="bars")
        if rescale and self.secondary_series:
            points = self._rescale(serie.points)
        else:
            points = serie.points
        total = sum(list(filter(None, serie.values)))
        for i, (x, y) in enumerate(points):
            if None in (x, y) or (self.logarithmic and y <= 0):
                continue
            metadata = serie.metadata.get(i)
            val = self._format(serie, i)

            bar = decorate(
                self.svg,
                self.svg.node(bars, class_='bar'),
                metadata)

            x_, y_, width, height = self._bar(
                serie, bar, x, y, i, self.zero, secondary=rescale)

            self._confidence_interval(
                serie_node['overlay'], x_ + width / 2, y_, serie.values[i],
                metadata)

            self._tooltip_and_print_values(
                serie_node, serie, bar, i, val, metadata,
                x_, y_, width, height, total)
Beispiel #15
0
    def gaugify(self, serie, squares, sq_dimensions, current_square):
        serie_node = self.svg.serie(serie)
        if self.half_pie:
            start_angle = 3 * pi / 2
            center = ((current_square[1] * sq_dimensions[0]) -
                      (sq_dimensions[0] / 2.),
                      (current_square[0] * sq_dimensions[1]) -
                      (sq_dimensions[1] / 4))
            end_angle = pi / 2
        else:
            start_angle = 0
            center = ((current_square[1] * sq_dimensions[0]) -
                      (sq_dimensions[0] / 2.),
                      (current_square[0] * sq_dimensions[1]) -
                      (sq_dimensions[1] / 2.))
            end_angle = 2 * pi

        max_value = serie.metadata.get(0, {}).get('max_value', 100)
        radius = min([sq_dimensions[0] / 2, sq_dimensions[1] / 2]) * .9
        small_radius = radius * serie.inner_radius

        self.svg.gauge_background(serie_node, start_angle, center, radius,
                                  small_radius, end_angle, self.half_pie,
                                  self._serie_format(serie, max_value))

        sum_ = 0
        for i, value in enumerate(serie.values):
            if value is None:
                continue
            ratio = min(value, max_value) / max_value
            if self.half_pie:
                angle = 2 * pi * ratio / 2
            else:
                angle = 2 * pi * ratio

            val = self._format(serie, i)
            metadata = serie.metadata.get(i)

            gauge_ = decorate(
                self.svg, self.svg.node(serie_node['plot'], class_="gauge"),
                metadata)

            alter(
                self.svg.solid_gauge(serie_node, gauge_, radius, small_radius,
                                     angle, start_angle, center, val, i,
                                     metadata, self.half_pie, end_angle,
                                     self._serie_format(serie, max_value)),
                metadata)
            start_angle += angle
            sum_ += value

        x, y = center
        self.svg.node(serie_node['text_overlay'],
                      'text',
                      class_='value gauge-sum',
                      x=x,
                      y=y + self.style.value_font_size / 3,
                      attrib={
                          'text-anchor': 'middle'
                      }).text = self._serie_format(serie, sum_)
Beispiel #16
0
    def needle(
        self,
        serie_node,
        serie,
    ):
        thickness = .05
        for i, value in enumerate(serie.values):
            if not value:
                continue
            theta = self.arc_pos(value)
            fmt = lambda x: '%f %f' % x
            value = self._format(serie.values[i])
            metadata = serie.metadata.get(i)
            gauges = decorate(self.svg,
                              self.svg.node(serie_node['plot'], class_="dots"),
                              metadata)

            self.svg.node(gauges,
                          'polygon',
                          points=' '.join([
                              fmt(self.view((0, 0))),
                              fmt(self.view((.75, theta + thickness))),
                              fmt(self.view((.8, theta))),
                              fmt(self.view((.75, theta - thickness)))
                          ]),
                          class_='line reactive tooltip-trigger')

            x, y = self.view((.75, theta))
            self._tooltip_data(gauges, value, x, y)
            self._static_value(serie_node, value, x, y)
Beispiel #17
0
    def bar(self, serie, rescale=False):
        """Draw a bar graph for a serie"""
        serie_node = self.svg.serie(serie)
        bars = self.svg.node(serie_node['plot'], class_="bars")
        if rescale and self.secondary_series:
            points = self._rescale(serie.points)
        else:
            points = serie.points

        for i, (x, y) in enumerate(points):
            if None in (x, y) or (self.logarithmic and y <= 0):
                continue
            metadata = serie.metadata.get(i)

            bar = decorate(
                self.svg,
                self.svg.node(bars, class_='bar'),
                metadata)
            val = self._format(serie.values[i])

            x_center, y_center = self._bar(
                serie, bar, x, y, self.zero, secondary=rescale)
            self._tooltip_data(
                bar, val, x_center, y_center, classes="centered")
            self._static_value(serie_node, val, x_center, y_center)
Beispiel #18
0
    def needle(self, serie):
        serie_node = self.svg.serie(serie)
        for i, theta in enumerate(serie.values):
            if theta is None:
                continue
            fmt = lambda x: '%f %f' % x
            value = self._format(serie.values[i])
            metadata = serie.metadata.get(i)
            gauges = decorate(
                self.svg,
                self.svg.node(serie_node['plot'], class_="dots"),
                metadata)

            alter(self.svg.node(
                gauges, 'polygon', points=' '.join([
                    fmt(self.view((0, 0))),
                    fmt(self.view((.75, theta))),
                    fmt(self.view((.8, theta))),
                    fmt(self.view((.75, theta)))]),
                class_='line reactive tooltip-trigger'),
                  metadata)

            x, y = self.view((.75, theta))
            self._tooltip_data(gauges, value, x, y)
            self._static_value(serie_node, value, x, y)
Beispiel #19
0
    def needle(self, serie):
        serie_node = self.svg.serie(serie)
        for i, theta in enumerate(serie.values):
            if theta is None:
                continue
            fmt = lambda x: '%f %f' % x
            value = self._format(serie.values[i])
            metadata = serie.metadata.get(i)
            gauges = decorate(self.svg,
                              self.svg.node(serie_node['plot'], class_="dots"),
                              metadata)

            self.svg.node(gauges,
                          'polygon',
                          points=' '.join([
                              fmt(self.view((0, 0))),
                              fmt(self.view((.75, theta))),
                              fmt(self.view((.8, theta))),
                              fmt(self.view((.75, theta)))
                          ]),
                          class_='line reactive tooltip-trigger')

            x, y = self.view((.75, theta))
            self._tooltip_data(gauges, value, x, y)
            self._static_value(serie_node, value, x, y)
Beispiel #20
0
    def bar(self, serie_node, serie, index, rescale=False):
        """Draw a bar graph for a serie"""
        bars = self.svg.node(serie_node['plot'], class_="histbars")
        points = serie.points

        for i, (y, x0, x1) in enumerate(points):
            if None in (x0, x1, y) or (self.logarithmic and y <= 0):
                continue
            metadata = serie.metadata.get(i)

            bar = decorate(self.svg, self.svg.node(bars, class_='histbar'),
                           metadata)
            val = self._format(serie.values[i][0])

            x_center, y_center = self._bar(bar,
                                           x0,
                                           x1,
                                           y,
                                           index,
                                           i,
                                           self.zero,
                                           secondary=rescale,
                                           rounded=serie.rounded_bars)
            self._tooltip_data(bar,
                               val,
                               x_center,
                               y_center,
                               classes="centered")
            self._static_value(serie_node, val, x_center, y_center)
Beispiel #21
0
    def _plot(self):
        map = etree.fromstring(MAP)
        map.set('width', str(self.view.width))
        map.set('height', str(self.view.height))

        for i, serie in enumerate(self.series):
            safe_vals = list(filter(
                lambda x: x is not None, cut(serie.values, 1)))
            if not safe_vals:
                continue
            min_ = min(safe_vals)
            max_ = max(safe_vals)
            for j, (country_code, value) in enumerate(serie.values):
                if value is None:
                    continue
                if max_ == min_:
                    ratio = 1
                else:
                    ratio = .3 + .7 * (value - min_) / (max_ - min_)

                try:
                    country = map.find('.//*[@id="%s"]' % country_code)
                except SyntaxError:
                    # Python 2.6 (you'd better install lxml)
                    country = None
                    for e in map:
                        if e.attrib.get('id', '') == country_code:
                            country = e

                if country is None:
                    continue
                cls = country.get('class', '').split(' ')
                cls.append('color-%d' % i)
                country.set('class', ' '.join(cls))
                country.set(
                    'style', 'fill-opacity: %f' % (
                        ratio))

                metadata = serie.metadata.get(j)
                if metadata:
                    node = decorate(self.svg, country, metadata)
                    if node != country:
                        country.remove(node)
                        index = list(map).index(country)
                        map.remove(country)
                        node.append(country)
                        map.insert(index, node)

                last_node = len(country) > 0 and country[-1]
                if last_node is not None and last_node.tag == 'title':
                    title_node = last_node
                    text = title_node.text + '\n'
                else:
                    title_node = self.svg.node(country, 'title')
                    text = ''
                title_node.text = text + '[%s] %s: %s' % (
                    serie.title,
                    self.country_names[country_code], self._format(value))

        self.nodes['plot'].append(map)
Beispiel #22
0
    def gaugify(self, serie, squares, sq_dimensions, current_square):
        serie_node = self.svg.serie(serie)
        if self.half_pie:
            start_angle = 3*pi/2
            center = (
                (current_square[1]*sq_dimensions[0]) - (sq_dimensions[0] / 2.),
                (current_square[0]*sq_dimensions[1]) - (sq_dimensions[1] / 4))
            end_angle = pi / 2
        else:
            start_angle = 0
            center = (
                (current_square[1]*sq_dimensions[0]) - (sq_dimensions[0] / 2.),
                (current_square[0]*sq_dimensions[1]) - (sq_dimensions[1] / 2.))
            end_angle = 2 * pi

        max_value = serie.metadata.get(0, {}).get('max_value', 100)
        radius = min([sq_dimensions[0]/2, sq_dimensions[1]/2]) * .9
        small_radius = radius * serie.inner_radius

        self.svg.gauge_background(
            serie_node, start_angle, center, radius, small_radius, end_angle,
            self.half_pie, self._serie_format(serie, max_value))

        sum_ = 0
        for i, value in enumerate(serie.values):
            if value is None:
                continue
            ratio = min(value, max_value) / max_value
            if self.half_pie:
                angle = 2 * pi * ratio / 2
            else:
                angle = 2 * pi * ratio

            val = self._format(serie, i)
            metadata = serie.metadata.get(i)

            gauge_ = decorate(
                self.svg,
                self.svg.node(serie_node['plot'], class_="gauge"),
                metadata)

            alter(
                self.svg.solid_gauge(
                    serie_node, gauge_, radius, small_radius,
                    angle, start_angle, center, val, i, metadata,
                    self.half_pie, end_angle,
                    self._serie_format(serie, max_value)),
                metadata)
            start_angle += angle
            sum_ += value

        x, y = center
        self.svg.node(
            serie_node['text_overlay'], 'text',
            class_='value gauge-sum',
            x=x,
            y=y + self.style.value_font_size / 3,
            attrib={'text-anchor': 'middle'}
        ).text = self._serie_format(serie, sum_)
Beispiel #23
0
    def _plot(self):
        map = etree.fromstring(self.svg_map)
        map.set('width', str(self.view.width))
        map.set('height', str(self.view.height))

        for i, serie in enumerate(self.series):
            safe_vals = list(filter(
                lambda x: x is not None, cut(serie.values, 1)))
            if not safe_vals:
                continue
            min_ = min(safe_vals)
            max_ = max(safe_vals)
            for j, (area_code, value) in enumerate(serie.values):
                if isinstance(area_code, Number):
                    area_code = '%2d' % area_code
                if value is None:
                    continue
                if max_ == min_:
                    ratio = 1
                else:
                    ratio = .3 + .7 * (value - min_) / (max_ - min_)
                areae = map.findall(
                    ".//*[@class='%s%s %s map-element']" % (
                        self.area_prefix, area_code,
                        self.kind))

                if not areae:
                    continue
                for area in areae:
                    cls = area.get('class', '').split(' ')
                    cls.append('color-%d' % i)
                    area.set('class', ' '.join(cls))
                    area.set('style', 'fill-opacity: %f' % (ratio))

                    metadata = serie.metadata.get(j)
                    if metadata:
                        node = decorate(self.svg, area, metadata)
                        if node != area:
                            area.remove(node)
                            for g in map:
                                if area not in g:
                                    continue
                                index = list(g).index(area)
                                g.remove(area)
                                node.append(area)
                                g.insert(index, node)

                    last_node = len(area) > 0 and area[-1]
                    if last_node is not None and last_node.tag == 'title':
                        title_node = last_node
                        text = title_node.text + '\n'
                    else:
                        title_node = self.svg.node(area, 'title')
                        text = ''
                    title_node.text = text + '[%s] %s: %s' % (
                        serie.title,
                        self.area_names[area_code], self._format(value))

        self.nodes['plot'].append(map)
Beispiel #24
0
    def line(self, serie, rescale=False):
        """Draw the line serie"""
        serie_node = self.svg.serie(serie)
        if rescale and self.secondary_series:
            points = [
                (x, self._scale_diff + (y - self._scale_min_2nd) * self._scale)
                for x, y in serie.points if y is not None]
        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 (serie.show_only_major_dots and
                        self.x_labels and i < len(self.x_labels) and
                        self.x_labels[i] not in self._x_major_labels):
                    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)
                dots = decorate(
                    self.svg,
                    self.svg.node(serie_node['overlay'], class_="dots"),
                    metadata)
                val = self._get_value(serie.points, i)
                self.svg.node(dots, 'circle', cx=x, cy=y, r=serie.dots_size,
                              class_='dot reactive tooltip-trigger')
                self._tooltip_data(
                    dots, val, x, y)
                self._static_value(
                    serie_node, val,
                    x + self.value_font_size,
                    y + self.value_font_size)

        line_view_values = [[]]
        for view_value in view_values:
            if None in view_value:
                line_view_values.append([])
            else:
                line_view_values[-1].append(view_value)

        if serie.stroke:
            if self.interpolate:
                view_values = list(map(self.view, serie.interpolated))
            if serie.fill:
                view_values = self._fill(view_values)
            for row in line_view_values:
                if not row:
                    continue
                self.svg.line(
                    serie_node['plot'], row, close=self._self_close,
                    class_='line reactive' + (
                        ' nofill' if not serie.fill else ''))
Beispiel #25
0
    def _plot(self):
        map = etree.fromstring(MAP)
        map.set('width', str(self.view.width))
        map.set('height', str(self.view.height))

        for i, serie in enumerate(self.series):
            safe_vals = list(
                filter(lambda x: x is not None, cut(serie.values, 1)))
            if not safe_vals:
                continue
            min_ = min(safe_vals)
            max_ = max(safe_vals)
            for j, (country_code, value) in enumerate(serie.values):
                if value is None:
                    continue
                if max_ == min_:
                    ratio = 1
                else:
                    ratio = .3 + .7 * (value - min_) / (max_ - min_)

                try:
                    country = map.find('.//*[@id="%s"]' % country_code)
                except SyntaxError:
                    # Python 2.6 (you'd better install lxml)
                    country = None
                    for e in map:
                        if e.attrib.get('id', '') == country_code:
                            country = e

                if country is None:
                    continue
                cls = country.get('class', '').split(' ')
                cls.append('color-%d' % i)
                country.set('class', ' '.join(cls))
                country.set('style', 'fill-opacity: %f' % (ratio))

                metadata = serie.metadata.get(j)
                if metadata:
                    node = decorate(self.svg, country, metadata)
                    if node != country:
                        country.remove(node)
                        index = list(map).index(country)
                        map.remove(country)
                        node.append(country)
                        map.insert(index, node)

                last_node = len(country) > 0 and country[-1]
                if last_node is not None and last_node.tag == 'title':
                    title_node = last_node
                    text = title_node.text + '\n'
                else:
                    title_node = self.svg.node(country, 'title')
                    text = ''
                title_node.text = text + '[%s] %s: %s' % (
                    serie.title, self.country_names[country_code],
                    self._format(value))

        self.nodes['plot'].append(map)
Beispiel #26
0
    def line(self, serie, rescale=False):
        """Draw the line serie"""
        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 (
                    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._get_value(serie.points, i)
                alter(
                    self.svg.transposable_node(
                        dots, "circle", cx=x, cy=y, r=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)
            self.svg.line(
                serie_node["plot"],
                view_values,
                close=self._self_close,
                class_="line reactive" + (" nofill" if not serie.fill else ""),
            )
Beispiel #27
0
    def _plot(self):
        map = etree.fromstring(self.svg_map)
        map.set("width", str(self.view.width))
        map.set("height", str(self.view.height))

        for i, serie in enumerate(self.series):
            safe_vals = list(filter(lambda x: x is not None, cut(serie.values, 1)))
            if not safe_vals:
                continue
            min_ = min(safe_vals)
            max_ = max(safe_vals)
            for j, (area_code, value) in enumerate(serie.values):
                if isinstance(area_code, Number):
                    area_code = "%2d" % area_code
                if value is None:
                    continue
                if max_ == min_:
                    ratio = 1
                else:
                    ratio = 0.3 + 0.7 * (value - min_) / (max_ - min_)
                areae = map.xpath(
                    "//*[contains(concat(' ', normalize-space(@class), ' '),"
                    " ' %s%s ')]" % (self.area_prefix, area_code)
                )

                if not areae:
                    continue
                for area in areae:
                    cls = area.get("class", "").split(" ")
                    cls.append("color-%d" % i)
                    area.set("class", " ".join(cls))
                    area.set("style", "fill-opacity: %f" % (ratio))

                    metadata = serie.metadata.get(j)
                    if metadata:
                        parent = area.getparent()
                        node = decorate(self.svg, area, metadata)
                        if node != area:
                            area.remove(node)
                            index = parent.index(area)
                            parent.remove(area)
                            node.append(area)
                            parent.insert(index, node)

                    last_node = len(area) > 0 and area[-1]
                    if last_node is not None and last_node.tag == "title":
                        title_node = last_node
                        text = title_node.text + "\n"
                    else:
                        title_node = self.svg.node(area, "title")
                        text = ""
                    title_node.text = text + "[%s] %s: %s" % (
                        serie.title,
                        self.area_names[area_code],
                        self._format(value),
                    )

        self.nodes["plot"].append(map)
Beispiel #28
0
    def _plot(self):
        map = etree.fromstring(self.svg_map)
        map.set('width', str(self.view.width))
        map.set('height', str(self.view.height))

        for i, serie in enumerate(self.series):
            safe_vals = list(
                filter(lambda x: x is not None, cut(serie.values, 1)))
            if not safe_vals:
                continue
            min_ = min(safe_vals)
            max_ = max(safe_vals)
            for j, (area_code, value) in enumerate(serie.values):
                if isinstance(area_code, Number):
                    area_code = '%2d' % area_code
                if value is None:
                    continue
                if max_ == min_:
                    ratio = 1
                else:
                    ratio = .3 + .7 * (value - min_) / (max_ - min_)
                areae = map.findall(".//*[@class='%s%s %s map-element']" %
                                    (self.area_prefix, area_code, self.kind))

                if not areae:
                    continue
                for area in areae:
                    cls = area.get('class', '').split(' ')
                    cls.append('color-%d' % i)
                    area.set('class', ' '.join(cls))
                    area.set('style', 'fill-opacity: %f' % (ratio))

                    metadata = serie.metadata.get(j)
                    if metadata:
                        node = decorate(self.svg, area, metadata)
                        if node != area:
                            area.remove(node)
                            for g in map:
                                if area not in g:
                                    continue
                                index = list(g).index(area)
                                g.remove(area)
                                node.append(area)
                                g.insert(index, node)

                    last_node = len(area) > 0 and area[-1]
                    if last_node is not None and last_node.tag == 'title':
                        title_node = last_node
                        text = title_node.text + '\n'
                    else:
                        title_node = self.svg.node(area, 'title')
                        text = ''
                    title_node.text = text + '[%s] %s: %s' % (
                        serie.title, self.area_names[area_code],
                        self._format(value))

        self.nodes['plot'].append(map)
Beispiel #29
0
    def line(self, serie, rescale=False):
        """Draw the line serie"""
        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 (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._get_value(serie.points, i)
                alter(self.svg.transposable_node(
                    dots, 'circle', cx=x, cy=y, r=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)
            self.svg.line(
                serie_node['plot'], view_values, close=self._self_close,
                class_='line reactive' + (' nofill' if not serie.fill else ''))
Beispiel #30
0
    def needle(self, serie):
        """Draw a needle for each value"""
        serie_node = self.svg.serie(serie)
        for i, theta in enumerate(serie.values):
            if theta is None:
                continue

            def point(x, y):
                if self.clockwise:
                    transform = compose(self.clockwiser, self.view)
                else:
                    transform = self.view
                return '%f %f' % transform((x, y))

            val = self._format(serie, i)
            metadata = serie.metadata.get(i)
            gauges = decorate(
                self.svg,
                self.svg.node(serie_node['plot'], class_="dots"),
                metadata)

            tolerance = 1.15

            if theta < self._min:
                theta = self._min * tolerance

            if theta > self._max:
                theta = self._max * tolerance

            w = (self._box._tmax - self._box._tmin + self.view.aperture) / 4

            if self.logarithmic:
                w = min(w, self._min - self._min * 10 ** -10)

            sweep_flag = '0' if self.clockwise else '1'

            alter(
                self.svg.node(
                    gauges, 'path', d='M %s L %s A %s 1 0 %s %s Z' % (
                        point(.85, theta),
                        point(self.needle_width, theta - w),
                        '%f %f' % (self.needle_width, self.needle_width),
                        sweep_flag,
                        point(self.needle_width, theta + w),
                    ),
                    class_='line reactive tooltip-trigger'),
                metadata)

            x, y = self.view((.75, theta))
            if self.clockwise:
                x, y = self.clockwiser((x, y))
            self._tooltip_data(
                gauges, val, x, y,
                xlabel=self._get_x_label(i))
            self._static_value(serie_node, val, x, y, metadata)
Beispiel #31
0
    def _plot(self):
        map = etree.fromstring(MAP)
        map.set('width', str(self.view.width))
        map.set('height', str(self.view.height))

        for i, serie in enumerate(self.series):
            safe_vals = list(filter(
                lambda x: x is not None, cut(serie.values, 1)))
            if not safe_vals:
                continue
            min_ = min(safe_vals)
            max_ = max(safe_vals)
            serie.values = self.replace_supranationals(serie.values)
            for j, (country_code, value) in enumerate(serie.values):
                if value is None:
                    continue
                if max_ == min_:
                    ratio = 1
                else:
                    ratio = .3 + .7 * (value - min_) / (max_ - min_)
                country = map.find('.//*[@id="%s"]' % country_code)
                if country is None:
                    continue
                cls = country.get('class', '').split(' ')
                cls.append('color-%d' % i)
                country.set('class', ' '.join(cls))
                country.set(
                    'style', 'fill-opacity: %f' % (
                        ratio))

                metadata = serie.metadata.get(j)
                if metadata:
                    parent = country.getparent()
                    node = decorate(self.svg, country, metadata)
                    if node != country:
                        country.remove(node)
                        index = parent.index(country)
                        parent.remove(country)
                        node.append(country)
                        parent.insert(index, node)

                last_node = len(country) > 0 and country[-1]
                if last_node is not None and last_node.tag == 'title':
                    title_node = last_node
                    text = title_node.text + '\n'
                else:
                    title_node = self.svg.node(country, 'title')
                    text = ''
                title_node.text = text + '[%s] %s: %d' % (
                    serie.title,
                    self.country_names[country_code], value)

        self.nodes['plot'].append(map)
Beispiel #32
0
    def slice(self, serie, start_angle, total):
        """Make a serie slice"""
        #serie_angle = totallist[2]
        #total=totallist[0]
        #start_angle=totallist[1]

        print(serie, total, start_angle, serie_angle)
        serie_node = self.svg.serie(serie)
        dual = self._len > 1 and not self._order == 1

        slices = self.svg.node(serie_node['plot'], class_="slices")

        original_start_angle = start_angle
        if self.half_pie:
            center = ((self.width - self.margin_box.x) / 2.,
                      (self.height - self.margin_box.y) / 1.25)
        else:
            center = ((self.width - self.margin_box.x) / 2.,
                      (self.height - self.margin_box.y) / 2.)

        radius = min(center)
        for i, val in enumerate(serie.values):
            perc = val / total
            if self.half_pie:
                angle = 2 * pi * perc / 2
            else:
                angle = 2 * pi * perc
            serie_angle += angle
            val = self._format(serie, i)
            metadata = serie.metadata.get(i)
            slice_ = decorate(self.svg, self.svg.node(slices, class_="slice"),
                              metadata)
            if dual:
                small_radius = radius * .9
                big_radius = radius
            else:
                big_radius = radius * .9
                small_radius = radius * serie.inner_radius

            alter(
                self.svg.slice(serie_node, slice_, big_radius, small_radius,
                               angle, start_angle, center, val, i, metadata),
                metadata)
            start_angle += angle

        if dual:
            val = self._serie_format(serie, sum(serie.values))
            self.svg.slice(serie_node, self.svg.node(slices,
                                                     class_="big_slice"),
                           radius * .9, 0, serie_angle, original_start_angle,
                           center, val, i, metadata)
        return serie_angle
Beispiel #33
0
    def dot(self, serie_node, serie, r_max):
        """Draw a dot line"""
        view_values = list(map(self.view, serie.points))
        for i, value in safe_enumerate(serie.values):
            x, y = view_values[i]
            size = r_max * value
            value = self._format(value)
            metadata = serie.metadata.get(i)
            dots = decorate(self.svg, self.svg.node(serie_node["plot"], class_="dots"), metadata)
            self.svg.node(dots, "circle", cx=x, cy=y, r=size, class_="dot reactive tooltip-trigger")

            self._tooltip_data(dots, value, x, y)
            self._static_value(serie_node, value, x, y)
Beispiel #34
0
    def slice(self, serie, start_angle, total):
        """Make a serie slice"""
        serie_node = self.svg.serie(serie)
        dual = self._len > 1 and not self._order == 1

        slices = self.svg.node(serie_node['plot'], class_="slices")
        serie_angle = 0
        original_start_angle = start_angle
        if self.half_pie:
            center = ((self.width - self.margin_box.x) / 2.,
                      (self.height - self.margin_box.y) / 1.25)
        else:
            center = ((self.width - self.margin_box.x) / 2.,
                      (self.height - self.margin_box.y) / 2.)

        radius = min(center)
        for i, val in enumerate(serie.values):
            perc = val / total
            if self.half_pie:
                angle = 2 * pi * perc / 2
            else:
                angle = 2 * pi * perc
            serie_angle += angle
            val = self._format(serie, i)
            metadata = serie.metadata.get(i)
            slice_ = decorate(
                self.svg, self.svg.node(slices, class_="slice"), metadata
            )
            if dual:
                small_radius = radius * .9
                big_radius = radius
            else:
                big_radius = radius * .9
                small_radius = radius * serie.inner_radius

            alter(
                self.svg.slice(
                    serie_node, slice_, big_radius, small_radius, angle,
                    start_angle, center, val, i, metadata
                ), metadata
            )
            start_angle += angle

        if dual:
            val = self._serie_format(serie, sum(serie.values))
            self.svg.slice(
                serie_node, self.svg.node(slices,
                                          class_="big_slice"), radius * .9, 0,
                serie_angle, original_start_angle, center, val, i, metadata
            )
        return serie_angle
Beispiel #35
0
    def line(self, serie, rescale=False):
        """Draw the line serie"""
        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 (serie.show_only_major_dots and
                        self.x_labels and i < len(self.x_labels) and
                        self.x_labels[i] not in self._x_major_labels):
                    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)
                dots = decorate(
                    self.svg,
                    self.svg.node(serie_node['overlay'], class_="dots"),
                    metadata)
                val = self._get_value(serie.points, i)
                alter(self.svg.transposable_node(
                    dots, 'circle', cx=x, cy=y, r=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)

        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)
            self.svg.line(
                serie_node['plot'], view_values, close=self._self_close,
                class_='line reactive' + (' nofill' if not serie.fill else ''))
Beispiel #36
0
    def line(self, serie_node, serie, rescale=False):
        """Draw the line serie"""
        if rescale and self.secondary_series:
            points = [
                (x, self._scale_diff + (y - self._scale_min_2nd) * self._scale)
                for x, y in serie.points if y is not None
            ]
        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 (serie.show_only_major_dots and self.x_labels
                        and i < len(self.x_labels)
                        and self.x_labels[i] not in self._x_major_labels):
                    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)
                dots = decorate(
                    self.svg,
                    self.svg.node(serie_node['overlay'], class_="dots"),
                    metadata)
                val = self._get_value(serie.points, i)
                self.svg.node(dots,
                              'circle',
                              cx=x,
                              cy=y,
                              r=serie.dots_size,
                              class_='dot reactive tooltip-trigger')
                self._tooltip_data(dots, val, x, y)
                self._static_value(serie_node, val, x + self.value_font_size,
                                   y + self.value_font_size)

        if serie.stroke:
            if self.interpolate:
                view_values = list(map(self.view, serie.interpolated))
            if serie.fill:
                view_values = self._fill(view_values)
            self.svg.line(serie_node['plot'],
                          view_values,
                          close=self._self_close,
                          class_='line reactive' +
                          (' nofill' if not serie.fill else ''))
Beispiel #37
0
    def _plot(self):
        map = etree.fromstring(MAP)
        map.set('width', str(self.view.width))
        map.set('height', str(self.view.height))

        for i, serie in enumerate(self.series):
            safe_vals = list(
                filter(lambda x: x is not None, cut(serie.values, 1)))
            if not safe_vals:
                continue
            min_ = min(safe_vals)
            max_ = max(safe_vals)
            serie.values = self.replace_supranationals(serie.values)
            for j, (country_code, value) in enumerate(serie.values):
                if value is None:
                    continue
                if max_ == min_:
                    ratio = 1
                else:
                    ratio = .3 + .7 * (value - min_) / (max_ - min_)
                country = map.find('.//*[@id="%s"]' % country_code)
                if country is None:
                    continue
                cls = country.get('class', '').split(' ')
                cls.append('color-%d' % i)
                country.set('class', ' '.join(cls))
                country.set('style', 'fill-opacity: %f' % (ratio))

                metadata = serie.metadata.get(j)
                if metadata:
                    parent = country.getparent()
                    node = decorate(self.svg, country, metadata)
                    if node != country:
                        country.remove(node)
                        index = parent.index(country)
                        parent.remove(country)
                        node.append(country)
                        parent.insert(index, node)

                last_node = len(country) > 0 and country[-1]
                if last_node is not None and last_node.tag == 'title':
                    title_node = last_node
                    text = title_node.text + '\n'
                else:
                    title_node = self.svg.node(country, 'title')
                    text = ''
                title_node.text = text + '[%s] %s: %d' % (
                    serie.title, self.country_names[country_code], value)

        self.nodes['plot'].append(map)
Beispiel #38
0
    def slice(self, serie, start_angle, total):
        """Make a serie slice"""
        serie_node = self.svg.serie(serie)
        dual = self._len > 1 and not self._order == 1

        slices = self.svg.node(serie_node['plot'], class_="slices")
        serie_angle = 0
        total_perc = 0
        original_start_angle = start_angle
        if self.half_pie:
            center = ((self.width - self.margin.x) / 2.,
                      (self.height - self.margin.y) / 1.25)
        else:
            center = ((self.width - self.margin.x) / 2.,
                      (self.height - self.margin.y) / 2.)

        radius = min(center)
        for i, val in enumerate(serie.values):
            perc = val / total
            if self.half_pie:
                angle = 2 * pi * perc / 2
            else:
                angle = 2 * pi * perc
            serie_angle += angle
            val = '{0:.2%}'.format(perc)
            metadata = serie.metadata.get(i)
            slice_ = decorate(
                self.svg,
                self.svg.node(slices, class_="slice"),
                metadata)
            if dual:
                small_radius = radius * .9
                big_radius = radius
            else:
                big_radius = radius * .9
                small_radius = radius * serie.inner_radius

            self.svg.slice(
                serie_node, slice_, big_radius, small_radius,
                angle, start_angle, center, val)
            start_angle += angle
            total_perc += perc

        if dual:
            val = '{0:.2%}'.format(total_perc)
            self.svg.slice(serie_node,
                           self.svg.node(slices, class_="big_slice"),
                           radius * .9, 0, serie_angle,
                           original_start_angle, center, val)
        return serie_angle
Beispiel #39
0
    def needle(self, serie):
        """Draw a needle for each value"""
        serie_node = self.svg.serie(serie)
        for i, theta in enumerate(serie.values):
            if theta is None:
                continue

            def point(x, y):
                return '%f %f' % self.view((x, y))

            value = self._format(serie.values[i])
            metadata = serie.metadata.get(i)
            gauges = decorate(self.svg,
                              self.svg.node(serie_node['plot'], class_="dots"),
                              metadata)

            tolerance = 1.15

            if theta < self._min:
                theta = self._min * tolerance

            if theta > self._max:
                theta = self._max * tolerance

            w = (self._box._tmax - self._box._tmin + self.view.aperture) / 4

            if self.logarithmic:
                w = min(w, self._min - self._min * 10**-10)

            alter(
                self.svg.node(
                    gauges,
                    'path',
                    d='M %s L %s A %s 1 0 1 %s Z' % (
                        point(.85, theta),
                        point(self.needle_width, theta - w),
                        '%f %f' % (self.needle_width, self.needle_width),
                        point(self.needle_width, theta + w),
                    ),
                    class_='line reactive tooltip-trigger'), metadata)

            x, y = self.view((.75, theta))
            self._tooltip_data(gauges,
                               value,
                               x,
                               y,
                               xlabel=self._get_x_label(i))
            self._static_value(serie_node, value, x, y, metadata)
Beispiel #40
0
    def bar(self, serie_node, serie, index, rescale=False):
        """Draw a bar graph for a serie"""
        bars = self.svg.node(serie_node["plot"], class_="histbars")
        points = serie.points

        for i, (y, x0, x1) in enumerate(points):
            if None in (x0, x1, y) or (self.logarithmic and y <= 0):
                continue
            metadata = serie.metadata.get(i)

            bar = decorate(self.svg, self.svg.node(bars, class_="histbar"), metadata)
            val = self._format(serie.values[i][0])

            x_center, y_center = self._bar(bar, x0, x1, y, index, i, self.zero, secondary=rescale)
            self._tooltip_data(bar, val, x_center, y_center, classes="centered")
            self._static_value(serie_node, val, x_center, y_center)
Beispiel #41
0
    def _plot(self):
        map = etree.fromstring(MAP)
        map.set("width", str(self.view.width))
        map.set("height", str(self.view.height))

        for i, serie in enumerate(self.series):
            safe_vals = list(filter(lambda x: x is not None, cut(serie.values, 1)))
            if not safe_vals:
                continue
            min_ = min(safe_vals)
            max_ = max(safe_vals)
            for j, (country_code, value) in enumerate(serie.values):
                if value is None:
                    continue
                if max_ == min_:
                    ratio = 1
                else:
                    ratio = 0.3 + 0.7 * (value - min_) / (max_ - min_)
                country = map.find('.//*[@id="%s"]' % country_code)
                if country is None:
                    continue
                cls = country.get("class", "").split(" ")
                cls.append("color-%d" % i)
                country.set("class", " ".join(cls))
                country.set("style", "fill-opacity: %f" % (ratio))

                metadata = serie.metadata.get(j)
                if metadata:
                    parent = country.getparent()
                    node = decorate(self.svg, country, metadata)
                    if node != country:
                        country.remove(node)
                        index = parent.index(country)
                        parent.remove(country)
                        node.append(country)
                        parent.insert(index, node)

                last_node = len(country) > 0 and country[-1]
                if last_node is not None and last_node.tag == "title":
                    title_node = last_node
                    text = title_node.text + "\n"
                else:
                    title_node = self.svg.node(country, "title")
                    text = ""
                title_node.text = text + "[%s] %s: %d" % (serie.title, self.country_names[country_code], value)

        self.nodes["plot"].append(map)
Beispiel #42
0
    def line(self, serie_node, serie, rescale=False):
        """Draw the line serie"""
        if rescale and self.secondary_series:
            points = [
                (x, self._scale_diff + (y - self._scale_min_2nd) * self._scale)
                for x, y in serie.points
                if y is not None
            ]
        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 (
                    serie.show_only_major_dots
                    and self.x_labels
                    and i < len(self.x_labels)
                    and self.x_labels[i] not in self._x_major_labels
                ):
                    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)
                dots = decorate(self.svg, self.svg.node(serie_node["overlay"], class_="dots"), metadata)
                val = self._get_value(serie.points, i)
                self.svg.node(dots, "circle", cx=x, cy=y, r=serie.dots_size, class_="dot reactive tooltip-trigger")
                self._tooltip_data(dots, val, x, y)
                self._static_value(serie_node, val, x + self.value_font_size, y + self.value_font_size)

        if serie.stroke:
            if self.interpolate:
                view_values = list(map(self.view, serie.interpolated))
            if serie.fill:
                view_values = self._fill(view_values)
            self.svg.line(
                serie_node["plot"],
                view_values,
                close=self._self_close,
                class_="line reactive" + (" nofill" if not serie.fill else ""),
            )
Beispiel #43
0
    def dot(self, serie_node, serie, r_max):
        """Draw a dot line"""
        view_values = map(self.view, serie.points)
        for i, value in safe_enumerate(serie.values):
            x, y = view_values[i]
            size = r_max * value
            value = self._format(value)
            metadata = serie.metadata.get(i)
            dots = decorate(
                self.svg,
                self.svg.node(serie_node['plot'], class_="dots"),
                metadata)
            self.svg.node(dots, 'circle', cx=x, cy=y, r=size,
                          class_='dot reactive tooltip-trigger')

            self._tooltip_data(dots, value, x, y)
            self._static_value(serie_node, value, x, y)
Beispiel #44
0
    def _boxf(self, serie_node, serie, index):
        """
        For a specific series, draw the box plot.
        """
        # Note: q0 and q4 do not literally mean the zero-th quartile
        # and the fourth quartile, but rather the distance from 1.5 times
        # the inter-quartile range to Q1 and Q3, respectively.
        boxes = self.svg.node(serie_node['plot'], class_="boxes")

        metadata = serie.metadata.get(0)

        box = decorate(self.svg, self.svg.node(boxes, class_='box'), metadata)
        val = self._format(serie.values)

        x_center, y_center = self._draw_box(box, serie.values, index)
        self._tooltip_data(box, val, x_center, y_center, classes="centered")
        self._static_value(serie_node, val, x_center, y_center)
Beispiel #45
0
    def dot(self, serie_node, serie, r_max):
        """Draw a dot line"""
        view_values = map(self.view, serie.points)
        for i, (x, y) in enumerate(view_values):
            value = serie.values[i]
            size = r_max * value
            value = self._format(value)
            metadata = serie.metadata[i]
            dots = decorate(
                    self.svg,
                    self.svg.node(serie_node['plot'], class_="dots"),
                    metadata)
            self.svg.node(dots, 'circle', cx=x, cy=y, r=size,
                          class_='dot reactive tooltip-trigger')

            self._tooltip_data(dots, value, x, y)
            self._static_value(serie_node, value, x, y)
Beispiel #46
0
    def _boxf(self, serie):
        """
        For a specific series, draw the box plot.
        """
        serie_node = self.svg.serie(serie)
        # Note: q0 and q4 do not literally mean the zero-th quartile
        # and the fourth quartile, but rather the distance from 1.5 times
        # the inter-quartile range to Q1 and Q3, respectively.
        boxes = self.svg.node(serie_node["plot"], class_="boxes")

        metadata = serie.metadata.get(0)

        box = decorate(self.svg, self.svg.node(boxes, class_="box"), metadata)
        val = self._format(serie.values)

        x_center, y_center = self._draw_box(box, serie.values, serie.index)
        self._tooltip_data(box, val, x_center, y_center, classes="centered")
        self._static_value(serie_node, val, x_center, y_center)
Beispiel #47
0
    def line(self, serie_node, serie, rescale=False):
        """Draw the line serie"""
        if rescale and self.secondary_series:
            points = [
                (x, self._scale_diff + (y - self._scale_min_2nd) * self._scale)
                for x, y in serie.points]
        else:
            points = serie.points
        view_values = map(self.view, points)
        if self.show_dots:
            for i, (x, y) in enumerate(view_values):
                if None in (x, y):
                    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)

                dots = decorate(
                    self.svg,
                    self.svg.node(serie_node['overlay'], class_="dots"),
                    metadata)
                val = self._get_value(serie.points, i)
                self.svg.node(dots, 'circle', cx=x, cy=y, r=self.dots_size,
                              class_='dot reactive tooltip-trigger')
                self._tooltip_data(
                    dots, val, x, y)
                self._static_value(
                    serie_node, val,
                    x + self.value_font_size,
                    y + self.value_font_size)

        if self.stroke:
            if self.interpolate:
                view_values = map(self.view, serie.interpolated)
            if self.fill:
                view_values = self._fill(view_values)
            self.svg.line(
                serie_node['plot'], view_values, close=self._self_close,
                class_='line reactive' + (' nofill' if not self.fill else ''))
Beispiel #48
0
    def needle(self, serie):
        serie_node = self.svg.serie(serie)
        for i, theta in enumerate(serie.values):
            if theta is None:
                continue

            def point(x, y):
                return '%f %f' % self.view((x, y))

            value = self._format(serie.values[i])
            metadata = serie.metadata.get(i)
            gauges = decorate(
                self.svg,
                self.svg.node(serie_node['plot'], class_="dots"),
                metadata)

            tolerance = 1.15

            if theta < self._min:
                theta = self._min * tolerance

            if theta > self._max:
                theta = self._max * tolerance

            w = (self._box._tmax - self._box._tmin + self.view.aperture) / 4

            if self.logarithmic:
                w = min(w, self._min - self._min * 10 ** -10)

            alter(
                self.svg.node(
                    gauges, 'path', d='M %s L %s A %s 1 0 1 %s Z' % (
                        point(.85, theta),
                        point(self.needle_width, theta - w),
                        '%f %f' % (self.needle_width, self.needle_width),
                        point(self.needle_width, theta + w),
                    ),
                    class_='line reactive tooltip-trigger'),
                metadata)

            x, y = self.view((.75, theta))
            self._tooltip_data(gauges, value, x, y)
            self._static_value(serie_node, value, x, y)
Beispiel #49
0
    def bar(self, serie_node, serie, index):
        """Draw a bar graph for a serie"""
        bars = self.svg.node(serie_node['plot'], class_="bars")
        for i, (x, y) in enumerate(serie.points):
            if None in (x, y) or (self.logarithmic and y <= 0):
                continue
            metadata = serie.metadata.get(i)

            bar = decorate(
                self.svg,
                self.svg.node(bars, class_='bar'),
                metadata)
            val = self._format(serie.values[i])

            x_center, y_center = self._bar(
                bar, x, y, index, i, self.zero)
            self._tooltip_data(
                bar, val, x_center, y_center, classes="centered")
            self._static_value(serie_node, val, x_center, y_center)
Beispiel #50
0
    def _boxf(self, serie_node, serie, index):
        """
        For a specific series, draw the box plot.
        """
        # Note: q0 and q4 do not literally mean the zero-th quartile
        # and the fourth quartile, but rather the distance from 1.5 times
        # the inter-quartile range to Q1 and Q3, respectively.
        q0, q1, q2, q3, q4 = serie.values
        boxes = self.svg.node(serie_node['plot'], class_="boxes")

        metadata = serie.metadata.get(0)

        box = decorate(
            self.svg,
            self.svg.node(boxes, class_='box'),
            metadata)
        val = self._format(q2)

        x_center, y_center = self._draw_box(box, (q0, q1, q2, q3, q4), index)
        self._tooltip_data(box, val, x_center, y_center, classes="centered")
Beispiel #51
0
    def line(self, serie_node, serie):
        """Draw the line serie"""
        view_values = map(self.view, serie.points)
        if self.show_dots:
            for i, (x, y) in enumerate(view_values):
                if None in (x, y):
                    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)

                dots = decorate(
                    self.svg,
                    self.svg.node(serie_node['overlay'], class_="dots"),
                    metadata)
                val = self._get_value(serie.points, i)
                self.svg.node(dots,
                              'circle',
                              cx=x,
                              cy=y,
                              r=2.5,
                              class_='dot reactive tooltip-trigger')
                self._tooltip_data(dots, val, x, y)
                self._static_value(serie_node, val, x + self.value_font_size,
                                   y + self.value_font_size)

        if self.stroke:
            if self.interpolate:
                view_values = map(self.view, serie.interpolated)
            if self.fill:
                view_values = self._fill(view_values)
            self.svg.line(serie_node['plot'],
                          view_values,
                          close=self._self_close,
                          class_='line reactive' +
                          (' nofill' if not self.fill else ''))
Beispiel #52
0
    def dot(self, serie, r_max):
        """Draw a dot line"""
        serie_node = self.svg.serie(serie)
        view_values = list(map(self.view, serie.points))
        for i, value in safe_enumerate(serie.values):
            x, y = view_values[i]

            if self.logarithmic:
                log10min = log10(self._min) - 1
                log10max = log10(self._max or 1)

                if value != 0:
                    size = r_max * ((log10(abs(value)) - log10min) /
                                    (log10max - log10min))
                else:
                    size = 0
            else:
                size = r_max * (abs(value) / (self._max or 1))

            metadata = serie.metadata.get(i)
            dots = decorate(
                self.svg, self.svg.node(serie_node['plot'], class_="dots"),
                metadata
            )
            alter(
                self.svg.node(
                    dots,
                    'circle',
                    cx=x,
                    cy=y,
                    r=size,
                    class_='dot reactive tooltip-trigger' +
                    (' negative' if value < 0 else '')
                ), metadata
            )

            val = self._format(serie, i)
            self._tooltip_data(
                dots, val, x, y, 'centered', self._get_x_label(i)
            )
            self._static_value(serie_node, val, x, y, metadata)
Beispiel #53
0
    def funnel(self, serie_node, serie, index):
        """Draw a dot line"""

        fmt = lambda x: '%f %f' % x
        for i, poly in enumerate(serie.points):
            metadata = serie.metadata.get(i)
            value = self._format(serie.values[i])

            funnels = decorate(
                self.svg, self.svg.node(serie_node['plot'], class_="funnels"),
                metadata)

            self.svg.node(funnels,
                          'polygon',
                          points=' '.join(map(fmt, map(self.view, poly))),
                          class_='funnel reactive tooltip-trigger')

            x, y = self.view((
                self._x_labels[index][1],  # Poly center from label
                sum([point[1] for point in poly]) / len(poly)))
            self._tooltip_data(funnels, value, x, y, classes='centered')
            self._static_value(serie_node, value, x, y)
Beispiel #54
0
    def dot(self, serie, r_max):
        """Draw a box line"""
        width = (self.view.x(1) - self.view.x(0))
        serie_node = self.svg.serie(serie)
        view_values = list(map(self.view, serie.points))

        for i, value in safe_enumerate(serie.values):
            x, y = view_values[i]

            if self.logarithmic:
                log10min = log10(self._min) - 1
                log10max = log10(self._max or 1)

                if value != 0:
                    size = r_max * ((log10(abs(value)) - log10min) /
                                    (log10max - log10min))
                else:
                    size = 0
            else:
                size = r_max * (abs(value) / (self._max or 1))

            metadata = serie.metadata.get(i)
            dots = decorate(self.svg,
                            self.svg.node(serie_node['plot'], class_="dots"),
                            metadata)

            alter(
                self.svg.node(dots,
                              'rect',
                              x=x - 0.5 * width,
                              y=(y - size) if value > 0 else y,
                              width=width,
                              height=size,
                              class_='dot reactive tooltip-trigger' +
                              (' negative' if value < 0 else '')), metadata)

            val = self._format(serie, i)
            self._tooltip_data(dots, val, x, y, '', self._get_x_label(i))
            self._static_value(serie_node, val, x, y, metadata)
Beispiel #55
0
    def line(self, serie, rescale=False):
        """Draw the line serie"""
        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 (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)
                alter(self.svg.transposable_node(
                    dots, 'circle', cx=x, cy=y, r=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:
                # view_values are in form [(x1, y1), (x2, y2)]. We
                # need to split that into multiple sequences if a
                # None is present here

                sequences = []
                cur_sequence = []
                for x, y in view_values:
                    if y is None and len(cur_sequence) > 0:
                        # emit current subsequence
                        sequences.append(cur_sequence)
                        cur_sequence = []
                    elif y is None:       # just discard
                        continue
                    else:
                        cur_sequence.append((x, y))   # append the element

                if len(cur_sequence) > 0:      # emit last possible sequence
                    sequences.append(cur_sequence)
            else:
                # plain vanilla rendering
                sequences = [view_values]

            for seq in sequences:
                self.svg.line(
                    serie_node['plot'], seq, close=self._self_close,
                    class_='line reactive' +
                           (' nofill' if not serie.fill else ''))
Beispiel #56
0
    def _plot(self):
        """Insert a map in the chart and apply data on it"""
        map = etree.fromstring(self.svg_map)
        map.set('width', str(self.view.width))
        map.set('height', str(self.view.height))

        for i, serie in enumerate(self.series):
            safe_vals = list(
                filter(lambda x: x is not None, cut(serie.values, 1)))
            if not safe_vals:
                continue
            min_ = min(safe_vals)
            max_ = max(safe_vals)
            for j, (area_code, value) in self.enumerate_values(serie):
                area_code = self.adapt_code(area_code)
                if value is None:
                    continue
                if max_ == min_:
                    ratio = 1
                else:
                    ratio = .3 + .7 * (value - min_) / (max_ - min_)

                try:
                    areae = map.findall(
                        ".//*[@class='%s%s %s map-element']" %
                        (self.area_prefix, area_code, self.kind))
                except SyntaxError:
                    # Python 2.6 (you'd better install lxml)
                    raise ImportError('lxml is required under python 2.6')

                if not areae:
                    continue

                for area in areae:
                    cls = area.get('class', '').split(' ')
                    cls.append('color-%d' % i)
                    cls.append('serie-%d' % i)
                    cls.append('series')
                    area.set('class', ' '.join(cls))
                    area.set('style', 'fill-opacity: %f' % ratio)

                    metadata = serie.metadata.get(j)

                    if metadata:
                        node = decorate(self.svg, area, metadata)
                        if node != area:
                            area.remove(node)
                            for g in map:
                                if area not in g:
                                    continue
                                index = list(g).index(area)
                                g.remove(area)
                                node.append(area)
                                g.insert(index, node)

                    for node in area:
                        cls = node.get('class', '').split(' ')
                        cls.append('reactive')
                        cls.append('tooltip-trigger')
                        cls.append('map-area')
                        node.set('class', ' '.join(cls))
                        alter(node, metadata)

                    val = self._format(serie, j)
                    self._tooltip_data(area, val, 0, 0, 'auto')

        self.nodes['plot'].append(map)
Beispiel #57
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
Beispiel #58
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
Beispiel #59
0
    def bar(self, serie_node, serie, values, index, stack_vals=None):
        """Draw a bar graph for a serie"""

        # value here is a list of tuple range of tuple coord

        def view(rng):
            """Project range"""
            t, T = rng
            fun = swap if self.horizontal else ident
            return self.view(fun(t)), self.view(fun(T))

        bars = self.svg.node(serie_node['plot'], class_="bars")
        view_values = map(view, values)
        for i, ((x, y), (X, Y)) in enumerate(view_values):
            if None in (x, y):
                continue

            #          +-------+
            #          |       |
            #          |       |
            #          |       +-------+
            #          |       |       |
            #          |       |       |
            #          |       |       |
            #          +-------+-------+
            #        (x,y)   (X,Y)
            #
            # x and y are left range coords and X, Y right ones
            metadata = serie.metadata.get(i)
            val = self._format(values[i][1][1])
            if self.horizontal:
                x, y, X, Y = Y, X, y, x
            width = X - x
            padding = .1 * width
            inner_width = width - 2 * padding
            if self.horizontal:
                height = self.view.x(self.zero) - y
            else:
                height = self.view.y(self.zero) - y
            if stack_vals is None:
                bar_width = inner_width / self._order
                bar_padding = .1 * bar_width
                bar_inner_width = bar_width - 2 * bar_padding
                offset = index * bar_width + bar_padding
                shift = 0
            else:
                offset = 0
                bar_inner_width = inner_width
                shift = stack_vals[i][int(height < 0)]
                stack_vals[i][int(height < 0)] += height
            x = x + padding + offset

            if height < 0:
                y = y + height
                height = -height
            y -= shift

            bar = decorate(self.svg, self.svg.node(bars, class_='bar'),
                           metadata)
            self.svg.transposable_node(
                bar,
                'rect',
                x=x,
                y=y,
                rx=self.rounded_bars * 1 if self.rounded_bars else 0,
                ry=self.rounded_bars * 1 if self.rounded_bars else 0,
                width=bar_inner_width,
                height=height,
                class_='rect reactive tooltip-trigger')

            x += bar_inner_width / 2
            y += height / 2

            if self.horizontal:
                x, y = y, x

            self._tooltip_data(bar, val, x, y, classes="centered")
            self._static_value(serie_node, val, x, y)

        return stack_vals