From 241270d1a84610a4d547a55076d43b38dfd1faa2 Mon Sep 17 00:00:00 2001 From: Florian Mounier Date: Thu, 9 Jul 2015 15:11:38 +0200 Subject: [PATCH] Add output doc and table doc --- docs/changelog.rst | 1 + docs/documentation/configuration/serie.rst | 2 +- docs/documentation/index.rst | 2 + docs/documentation/output.rst | 197 +++++++++++++++++++++ docs/documentation/table.rst | 81 +++++++++ docs/ext/pygal_sphinx_directives.py | 48 ++++- pygal/config.py | 3 +- pygal/svg.py | 3 +- pygal/table.py | 8 +- 9 files changed, 337 insertions(+), 8 deletions(-) create mode 100644 docs/documentation/output.rst create mode 100644 docs/documentation/table.rst diff --git a/docs/changelog.rst b/docs/changelog.rst index 6127574..bbc8b22 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -26,6 +26,7 @@ Changelog * fix stack_from_top for stacked lines * Add flake8 test to py.test in tox * Remove stroke style in style and set it as a global / serie configuration. +* Fix None values in tables 1.7.0 ===== diff --git a/docs/documentation/configuration/serie.rst b/docs/documentation/configuration/serie.rst index b89753d..9f3a3d8 100644 --- a/docs/documentation/configuration/serie.rst +++ b/docs/documentation/configuration/serie.rst @@ -93,7 +93,7 @@ dots_size stroke_style ------------- +~~~~~~~~~~~~ .. pygal-code:: diff --git a/docs/documentation/index.rst b/docs/documentation/index.rst index a3bde57..ea64839 100644 --- a/docs/documentation/index.rst +++ b/docs/documentation/index.rst @@ -11,4 +11,6 @@ Documentation configuration/serie configuration/value sparks + table + output web diff --git a/docs/documentation/output.rst b/docs/documentation/output.rst new file mode 100644 index 0000000..df8c903 --- /dev/null +++ b/docs/documentation/output.rst @@ -0,0 +1,197 @@ +Output +====== + +pygal can generate multiple output formats. + + +SVG +--- + +String +~~~~~~ + +The obvious output is the vectorial output in svg format: + +.. code-block:: python + + chart = pygal.Line() + ... + chart.render() # Return the svg as bytes + + +It can be rendered as unicode when specifying ``is_unicode=True`` or when ``disable_xml_declaration`` is used + +.. code-block:: python + + chart = pygal.Line() + ... + chart.render(is_unicode=True) # Return the svg as a unicode string + + +File +~~~~ + + +You can also write the chart to a file using ``render_to_file``: + +.. code-block:: python + + chart = pygal.Line() + ... + chart.render_to_file('/tmp/chart.svg') # Write the chart in the specified file + + +PNG +--- + +With cairosvg installed you can directly get the png file using ``render_to_png``: + +.. code-block:: python + + chart = pygal.Line() + ... + chart.render_to_png('/tmp/chart.png') # Write the chart in the specified file + + +Etree +----- + + +It is possible to get the xml etree root element of the chart (or lxml etree node if lxml is installed) by calling the ``render_tree`` method: + + +.. code-block:: python + + chart = pygal.Line() + ... + chart.render_tree() # Return the svg root etree node + + +Browser +------- + +With lxml installed you can use the ``render_in_browser`` method to magically make your chart appear in you default browser. + +.. code-block:: python + + chart = pygal.Line() + ... + chart.render_in_browser() + + +PyQuery +------- + +If pyquery is installed you can get the pyquery object wrapping the chart by calling ``render_pyquery``: + +(This is mainly used for testing) + +.. code-block:: python + + chart = pygal.Line() + ... + chart.render_pyquery() # Return pyquery object + + +Flask response +-------------- + +If you are using pygal in a flask app the ``render_response`` may come in handy: + +.. code-block:: python + + @app.route('/charts/line.svg') + def line_route(): + chart = pygal.Line() + ... + return chart.render_response() + + +Django response +--------------- + +Same thing for django with ``render_django_response``. + + + +Table +----- + +pygal also supports a html table export of given data using the ``render_table`` option: + + +.. pygal-code:: + + line_chart = pygal.Bar() + line_chart.title = 'Browser usage evolution (in %)' + line_chart.x_labels = map(str, range(2002, 2013)) + line_chart.add('Firefox', [None, None, 0, 16.6, 25, 31, 36.4, 45.5, 46.3, 42.8, 37.1]) + line_chart.add('Chrome', [None, None, None, None, None, None, 0, 3.9, 10.8, 23.8, 35.3]) + line_chart.add('IE', [85.8, 84.6, 84.7, 74.5, 66, 58.6, 54.7, 44.8, 36.2, 26.6, 20.1]) + line_chart.add('Others', [14.2, 15.4, 15.3, 8.9, 9, 10.4, 8.9, 5.8, 6.7, 6.8, 7.5]) + line_chart.value_formatter = lambda x: '%.2f%%' % x if x is not None else '∅' + + +Default +~~~~~~~ + +.. pygal-table-code:: + + line_chart = pygal.Bar() + line_chart.title = 'Browser usage evolution (in %)' + line_chart.x_labels = map(str, range(2002, 2013)) + line_chart.add('Firefox', [None, None, 0, 16.6, 25, 31, 36.4, 45.5, 46.3, 42.8, 37.1]) + line_chart.add('Chrome', [None, None, None, None, None, None, 0, 3.9, 10.8, 23.8, 35.3]) + line_chart.add('IE', [85.8, 84.6, 84.7, 74.5, 66, 58.6, 54.7, 44.8, 36.2, 26.6, 20.1]) + line_chart.add('Others', [14.2, 15.4, 15.3, 8.9, 9, 10.4, 8.9, 5.8, 6.7, 6.8, 7.5]) + line_chart.value_formatter = lambda x: '%.2f%%' % x if x is not None else '∅' + line_chart.render_table() + + +Style +~~~~~ + +.. pygal-table-code:: + + line_chart = pygal.Bar() + line_chart.title = 'Browser usage evolution (in %)' + line_chart.x_labels = map(str, range(2002, 2013)) + line_chart.add('Firefox', [None, None, 0, 16.6, 25, 31, 36.4, 45.5, 46.3, 42.8, 37.1]) + line_chart.add('Chrome', [None, None, None, None, None, None, 0, 3.9, 10.8, 23.8, 35.3]) + line_chart.add('IE', [85.8, 84.6, 84.7, 74.5, 66, 58.6, 54.7, 44.8, 36.2, 26.6, 20.1]) + line_chart.add('Others', [14.2, 15.4, 15.3, 8.9, 9, 10.4, 8.9, 5.8, 6.7, 6.8, 7.5]) + line_chart.value_formatter = lambda x: '%.2f%%' % x if x is not None else '∅' + line_chart.render_table(style=True) + + +Total +~~~~~ + +.. pygal-table-code:: + + line_chart = pygal.Bar() + line_chart.title = 'Browser usage evolution (in %)' + line_chart.x_labels = map(str, range(2002, 2013)) + line_chart.add('Firefox', [None, None, 0, 16.6, 25, 31, 36.4, 45.5, 46.3, 42.8, 37.1]) + line_chart.add('Chrome', [None, None, None, None, None, None, 0, 3.9, 10.8, 23.8, 35.3]) + line_chart.add('IE', [85.8, 84.6, 84.7, 74.5, 66, 58.6, 54.7, 44.8, 36.2, 26.6, 20.1]) + line_chart.add('Others', [14.2, 15.4, 15.3, 8.9, 9, 10.4, 8.9, 5.8, 6.7, 6.8, 7.5]) + line_chart.value_formatter = lambda x: '%.2f%%' % x if x is not None else '∅' + line_chart.render_table(style=True, total=True) + + +Transposed +~~~~~~~~~~ + +.. pygal-table-code:: + + line_chart = pygal.Bar() + line_chart.title = 'Browser usage evolution (in %)' + line_chart.x_labels = map(str, range(2002, 2013)) + line_chart.add('Firefox', [None, None, 0, 16.6, 25, 31, 36.4, 45.5, 46.3, 42.8, 37.1]) + line_chart.add('Chrome', [None, None, None, None, None, None, 0, 3.9, 10.8, 23.8, 35.3]) + line_chart.add('IE', [85.8, 84.6, 84.7, 74.5, 66, 58.6, 54.7, 44.8, 36.2, 26.6, 20.1]) + line_chart.add('Others', [14.2, 15.4, 15.3, 8.9, 9, 10.4, 8.9, 5.8, 6.7, 6.8, 7.5]) + line_chart.value_formatter = lambda x: '%.2f%%' % x if x is not None else '∅' + line_chart.render_table(style=True, total=True, transpose=True) + diff --git a/docs/documentation/table.rst b/docs/documentation/table.rst new file mode 100644 index 0000000..ac918aa --- /dev/null +++ b/docs/documentation/table.rst @@ -0,0 +1,81 @@ +Table +===== + +pygal also supports a html table export of given data using the ``render_table`` option: + + +.. pygal-code:: + + line_chart = pygal.Bar() + line_chart.title = 'Browser usage evolution (in %)' + line_chart.x_labels = map(str, range(2002, 2013)) + line_chart.add('Firefox', [None, None, 0, 16.6, 25, 31, 36.4, 45.5, 46.3, 42.8, 37.1]) + line_chart.add('Chrome', [None, None, None, None, None, None, 0, 3.9, 10.8, 23.8, 35.3]) + line_chart.add('IE', [85.8, 84.6, 84.7, 74.5, 66, 58.6, 54.7, 44.8, 36.2, 26.6, 20.1]) + line_chart.add('Others', [14.2, 15.4, 15.3, 8.9, 9, 10.4, 8.9, 5.8, 6.7, 6.8, 7.5]) + line_chart.value_formatter = lambda x: '%.2f%%' % x if x is not None else '∅' + + +Default +------- + +.. pygal-table-code:: + + line_chart = pygal.Bar() + line_chart.title = 'Browser usage evolution (in %)' + line_chart.x_labels = map(str, range(2002, 2013)) + line_chart.add('Firefox', [None, None, 0, 16.6, 25, 31, 36.4, 45.5, 46.3, 42.8, 37.1]) + line_chart.add('Chrome', [None, None, None, None, None, None, 0, 3.9, 10.8, 23.8, 35.3]) + line_chart.add('IE', [85.8, 84.6, 84.7, 74.5, 66, 58.6, 54.7, 44.8, 36.2, 26.6, 20.1]) + line_chart.add('Others', [14.2, 15.4, 15.3, 8.9, 9, 10.4, 8.9, 5.8, 6.7, 6.8, 7.5]) + line_chart.value_formatter = lambda x: '%.2f%%' % x if x is not None else '∅' + line_chart.render_table() + + +Style +----- + +.. pygal-table-code:: + + line_chart = pygal.Bar() + line_chart.title = 'Browser usage evolution (in %)' + line_chart.x_labels = map(str, range(2002, 2013)) + line_chart.add('Firefox', [None, None, 0, 16.6, 25, 31, 36.4, 45.5, 46.3, 42.8, 37.1]) + line_chart.add('Chrome', [None, None, None, None, None, None, 0, 3.9, 10.8, 23.8, 35.3]) + line_chart.add('IE', [85.8, 84.6, 84.7, 74.5, 66, 58.6, 54.7, 44.8, 36.2, 26.6, 20.1]) + line_chart.add('Others', [14.2, 15.4, 15.3, 8.9, 9, 10.4, 8.9, 5.8, 6.7, 6.8, 7.5]) + line_chart.value_formatter = lambda x: '%.2f%%' % x if x is not None else '∅' + line_chart.render_table(style=True) + + +Total +----- + +.. pygal-table-code:: + + line_chart = pygal.Bar() + line_chart.title = 'Browser usage evolution (in %)' + line_chart.x_labels = map(str, range(2002, 2013)) + line_chart.add('Firefox', [None, None, 0, 16.6, 25, 31, 36.4, 45.5, 46.3, 42.8, 37.1]) + line_chart.add('Chrome', [None, None, None, None, None, None, 0, 3.9, 10.8, 23.8, 35.3]) + line_chart.add('IE', [85.8, 84.6, 84.7, 74.5, 66, 58.6, 54.7, 44.8, 36.2, 26.6, 20.1]) + line_chart.add('Others', [14.2, 15.4, 15.3, 8.9, 9, 10.4, 8.9, 5.8, 6.7, 6.8, 7.5]) + line_chart.value_formatter = lambda x: '%.2f%%' % x if x is not None else '∅' + line_chart.render_table(style=True, total=True) + + +Transposed +---------- + +.. pygal-table-code:: + + line_chart = pygal.Bar() + line_chart.title = 'Browser usage evolution (in %)' + line_chart.x_labels = map(str, range(2002, 2013)) + line_chart.add('Firefox', [None, None, 0, 16.6, 25, 31, 36.4, 45.5, 46.3, 42.8, 37.1]) + line_chart.add('Chrome', [None, None, None, None, None, None, 0, 3.9, 10.8, 23.8, 35.3]) + line_chart.add('IE', [85.8, 84.6, 84.7, 74.5, 66, 58.6, 54.7, 44.8, 36.2, 26.6, 20.1]) + line_chart.add('Others', [14.2, 15.4, 15.3, 8.9, 9, 10.4, 8.9, 5.8, 6.7, 6.8, 7.5]) + line_chart.value_formatter = lambda x: '%.2f%%' % x if x is not None else '∅' + line_chart.render_table(style=True, total=True, transpose=True) + diff --git a/docs/ext/pygal_sphinx_directives.py b/docs/ext/pygal_sphinx_directives.py index a971363..ab8e8ac 100644 --- a/docs/ext/pygal_sphinx_directives.py +++ b/docs/ext/pygal_sphinx_directives.py @@ -102,7 +102,6 @@ class PygalDirective(Directive): class PygalWithCode(PygalDirective): - width_code = True def run(self): node_list = super(PygalWithCode, self).run() @@ -120,8 +119,55 @@ class PygalWithCode(PygalDirective): return [docutils.nodes.compound('', *node_list)] +class PygalTable(Directive): + """Execute the given python file and puts its result in the document.""" + required_arguments = 0 + optional_arguments = 0 + final_argument_whitespace = True + has_content = True + + def run(self): + + self.content = list(self.content) + content = list(self.content) + content[-1] = 'rv = ' + content[-1] + code = '\n'.join(content) + scope = {'pygal': pygal} + try: + exec(code, scope) + except Exception: + print_exc() + return [docutils.nodes.system_message( + 'An exception as occured during code parsing:' + ' \n %s' % format_exc(), type='ERROR', source='/', + level=3)] + rv = scope['rv'] + + return [docutils.nodes.raw('', rv, format='html')] + + +class PygalTableWithCode(PygalTable): + + def run(self): + node_list = super(PygalTableWithCode, self).run() + node_list.extend(CodeBlock( + self.name, + ['python'], + self.options, + self.content, + self.lineno, + self.content_offset, + self.block_text, + self.state, + self.state_machine).run()) + + return [docutils.nodes.compound('', *node_list)] + + def setup(app): app.add_directive('pygal', PygalDirective) app.add_directive('pygal-code', PygalWithCode) + app.add_directive('pygal-table', PygalTable) + app.add_directive('pygal-table-code', PygalTableWithCode) return {'version': '1.0.1'} diff --git a/pygal/config.py b/pygal/config.py index 6384d0c..b071122 100644 --- a/pygal/config.py +++ b/pygal/config.py @@ -157,7 +157,8 @@ class CommonConfig(BaseConfig): stroke_style = Key(None, dict, "Look", "Stroke style of serie element.", "This is a dict which can contain a " - "'width', 'linejoin', 'linecap' and 'dasharray'") + "'width', 'linejoin', 'linecap', 'dasharray' " + "and 'dashoffset'") rounded_bars = Key( None, int, "Look", diff --git a/pygal/svg.py b/pygal/svg.py index e701b27..b65443b 100644 --- a/pygal/svg.py +++ b/pygal/svg.py @@ -317,7 +317,8 @@ class Svg(object): def stroke_dict_to_css(stroke, i=None): css = ['%s.series%s {\n' % ( self.id, '.serie-%d' % i if i is not None else '')] - for key in ('width', 'linejoin', 'linecap', 'dasharray'): + for key in ('width', 'linejoin', 'linecap', + 'dasharray', 'dashoffset'): if stroke.get(key): css.append(' stroke-%s: %s;\n' % ( key, stroke[key])) diff --git a/pygal/table.py b/pygal/table.py index 174608b..ed9a05e 100644 --- a/pygal/table.py +++ b/pygal/table.py @@ -73,8 +73,9 @@ class Table(object): sum_ = 0 for j, value in enumerate(serie.values): if total: - acc[j] += value - sum_ += value + v = value or 0 + acc[j] += v + sum_ += v row.append(fmt(value)) if total: acc[-1] += sum_ @@ -183,7 +184,6 @@ class Table(object): table = tostring(html.style( template(css, **attrs), scoped='scoped')) + table - if self.chart.disable_xml_declaration: - table = table.decode('utf-8') + table = table.decode('utf-8') self.chart.teardown() return table