File: public.py

package info (click to toggle)
python-pygal 3.0.5-1
  • links: PTS
  • area: main
  • in suites: forky, sid, trixie
  • size: 636 kB
  • sloc: python: 7,359; makefile: 9
file content (169 lines) | stat: -rw-r--r-- 5,823 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
# -*- coding: utf-8 -*-
# This file is part of pygal
#
# A python svg graph plotting library
# Copyright © 2012-2016 Kozea
#
# This library is free software: you can redistribute it and/or modify it under
# the terms of the GNU Lesser General Public License as published by the Free
# Software Foundation, either version 3 of the License, or (at your option) any
# later version.
#
# This library is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
# details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with pygal. If not, see <http://www.gnu.org/licenses/>.
"""pygal public api functions"""

import base64
import io

from pygal._compat import is_list_like
from pygal.graph.base import BaseGraph


class PublicApi(BaseGraph):
    """Chart public functions"""

    def add(self, title, values, **kwargs):
        """Add a serie to this graph, compat api"""
        if not is_list_like(values) and not isinstance(values, dict):
            values = [values]
        kwargs['title'] = title
        self.raw_series.append((values, kwargs))
        return self

    def __call__(self, *args, **kwargs):
        """Call api: chart(1, 2, 3, title='T')"""
        self.raw_series.append((args, kwargs))
        return self

    def add_xml_filter(self, callback):
        """Add an xml filter for in tree post processing"""
        self.xml_filters.append(callback)
        return self

    def render(self, is_unicode=False, **kwargs):
        """Render the graph, and return the svg string"""
        self.setup(**kwargs)
        svg = self.svg.render(
            is_unicode=is_unicode, pretty_print=self.pretty_print
        )
        self.teardown()
        return svg

    def render_tree(self, **kwargs):
        """Render the graph, and return (l)xml etree"""
        self.setup(**kwargs)
        svg = self.svg.root
        for f in self.xml_filters:
            svg = f(svg)
        self.teardown()
        return svg

    def render_table(self, **kwargs):
        """Render the data as a html table"""
        # Import here to avoid lxml import
        try:
            from pygal.table import Table
        except ImportError:
            raise ImportError('You must install lxml to use render table')
        return Table(self).render(**kwargs)

    def render_pyquery(self, **kwargs):
        """Render the graph, and return a pyquery wrapped tree"""
        from pyquery import PyQuery as pq
        return pq(self.render(**kwargs), parser='html')

    def render_in_browser(self, **kwargs):
        """Render the graph, open it in your browser with black magic"""
        try:
            from lxml.html import open_in_browser
        except ImportError:
            raise ImportError('You must install lxml to use render in browser')
        kwargs.setdefault('force_uri_protocol', 'https')
        open_in_browser(self.render_tree(**kwargs), encoding='utf-8')

    def render_response(self, **kwargs):
        """Render the graph, and return a Flask response"""
        from flask import Response
        return Response(self.render(**kwargs), mimetype='image/svg+xml')

    def render_django_response(self, **kwargs):
        """Render the graph, and return a Django response"""
        from django.http import HttpResponse
        return HttpResponse(
            self.render(**kwargs), content_type='image/svg+xml'
        )

    def render_data_uri(self, **kwargs):
        """Output a base 64 encoded data uri"""
        # Force protocol as data uri have none
        kwargs.setdefault('force_uri_protocol', 'https')
        return "data:image/svg+xml;charset=utf-8;base64,%s" % (
            base64.b64encode(self.render(**kwargs)
                             ).decode('utf-8').replace('\n', '')
        )

    def render_to_file(self, filename, **kwargs):
        """Render the graph, and write it to filename"""
        with io.open(filename, 'w', encoding='utf-8') as f:
            f.write(self.render(is_unicode=True, **kwargs))

    def render_to_png(self, filename=None, dpi=72, **kwargs):
        """Render the graph, convert it to png and write it to filename"""
        import cairosvg
        return cairosvg.svg2png(
            bytestring=self.render(**kwargs), write_to=filename, dpi=dpi
        )

    def render_sparktext(self, relative_to=None):
        """Make a mini text sparkline from chart"""
        bars = '▁▂▃▄▅▆▇█'
        if len(self.raw_series) == 0:
            return ''
        values = list(self.raw_series[0][0])
        if len(values) == 0:
            return ''

        chart = ''
        values = list(map(lambda x: max(x, 0), values))

        vmax = max(values)
        if relative_to is None:
            relative_to = min(values)

        if (vmax - relative_to) == 0:
            chart = bars[0] * len(values)
            return chart

        divisions = len(bars) - 1
        for value in values:
            chart += bars[int(
                divisions * (value - relative_to) / (vmax - relative_to)
            )]
        return chart

    def render_sparkline(self, **kwargs):
        """Render a sparkline"""
        spark_options = dict(
            width=200,
            height=50,
            show_dots=False,
            show_legend=False,
            show_x_labels=False,
            show_y_labels=False,
            spacing=0,
            margin=5,
            min_scale=1,
            max_scale=2,
            explicit_size=True,
            no_data_text='',
            js=(),
            classes=(Ellipsis, 'pygal-sparkline'),
        )
        spark_options.update(kwargs)
        return self.render(**spark_options)