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

# -*- 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'}