mirror of https://github.com/Kozea/pygal.git
Python to generate nice looking SVG graph
http://pygal.org/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
181 lines
5.7 KiB
181 lines
5.7 KiB
# -*- coding: utf-8 -*- |
|
# This file is part of pygal_sphinx_directives |
|
# |
|
# Pygal sphinx integration |
|
# Copyright © 2012-2016 Florian Mounier |
|
# |
|
# 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/>. |
|
|
|
from traceback import format_exc, print_exc |
|
|
|
import docutils.core |
|
import pygal |
|
from docutils.parsers.rst import Directive |
|
from sphinx.directives.code import CodeBlock |
|
|
|
# Patch default style |
|
|
|
pygal.config.Config.style.value = pygal.style.RotateStyle( |
|
'#2980b9', |
|
background='#fcfcfc', |
|
plot_background='#ffffff', |
|
foreground='#707070', |
|
foreground_strong='#404040', |
|
foreground_subtle='#909090', |
|
opacity='.8', |
|
opacity_hover='.9', |
|
transition='400ms ease-in' |
|
) |
|
|
|
|
|
class PygalDirective(Directive): |
|
"""Execute the given python file and puts its result in the document.""" |
|
required_arguments = 0 |
|
optional_arguments = 2 |
|
final_argument_whitespace = True |
|
has_content = True |
|
|
|
def run(self): |
|
width, height = map(int, self.arguments[:2] |
|
) if len(self.arguments) >= 2 else (600, 400) |
|
if len(self.arguments) == 1: |
|
self.render_fix = bool(self.arguments[0]) |
|
elif len(self.arguments) == 3: |
|
self.render_fix = bool(self.arguments[2]) |
|
else: |
|
self.render_fix = False |
|
self.content = list(self.content) |
|
content = list(self.content) |
|
if self.render_fix: |
|
content[-1] = 'rv = ' + content[-1] |
|
code = '\n'.join(content) |
|
scope = {'pygal': pygal} |
|
try: |
|
exec(code, scope) |
|
except Exception: |
|
print(code) |
|
print_exc() |
|
return [ |
|
docutils.nodes.system_message( |
|
'An exception as occured during code parsing:' |
|
' \n %s' % format_exc(), |
|
type='ERROR', |
|
source='/', |
|
level=3 |
|
) |
|
] |
|
if self.render_fix: |
|
rv = scope['rv'] |
|
else: |
|
chart = None |
|
for key, value in scope.items(): |
|
if isinstance(value, pygal.graph.graph.Graph): |
|
chart = value |
|
self.content.append(key + '.render()') |
|
break |
|
if chart is None: |
|
return [ |
|
docutils.nodes.system_message( |
|
'No instance of graph found', |
|
level=3, |
|
type='ERROR', |
|
source='/' |
|
) |
|
] |
|
chart.config.width = width |
|
chart.config.height = height |
|
chart.explicit_size = True |
|
|
|
try: |
|
svg = '<embed src="%s" />' % chart.render_data_uri() |
|
except Exception: |
|
return [ |
|
docutils.nodes.system_message( |
|
'An exception as occured during graph generation:' |
|
' \n %s' % format_exc(), |
|
type='ERROR', |
|
source='/', |
|
level=3 |
|
) |
|
] |
|
return [docutils.nodes.raw('', svg, format='html')] |
|
|
|
|
|
class PygalWithCode(PygalDirective): |
|
def run(self): |
|
node_list = super(PygalWithCode, 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)] |
|
|
|
|
|
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'}
|
|
|