Browse Source

Update documentation

pull/307/head
Florian Mounier 9 years ago
parent
commit
9d70ff3bf9
  1. 14
      demo/moulinrouge/tests.py
  2. 7
      docs/api/pygal.formatters.rst
  3. 1
      docs/api/pygal.graph.rst
  4. 7
      docs/api/pygal.graph.solidgauge.rst
  5. 1
      docs/api/pygal.rst
  6. 1
      docs/api/pygal.test.rst
  7. 7
      docs/api/pygal.test.test_formatters.rst
  8. 1
      docs/documentation/types/index.rst
  9. 52
      docs/documentation/types/solidgauge.rst
  10. 10
      pygal/css/style.css
  11. 10
      pygal/graph/solidgauge.py
  12. 111
      pygal/svg.py
  13. 4
      pygal/table.py
  14. 12
      pygal/test/test_config.py
  15. 2
      pygal/test/test_graph.py

14
demo/moulinrouge/tests.py

@ -206,24 +206,24 @@ def get_test_routes(app):
def test_solidgauge(): def test_solidgauge():
gauge = SolidGauge(half_pie=True, gauge = SolidGauge(half_pie=True,
inner_radius=0.70, inner_radius=0.70,
print_values=True, print_values=not True,
human_readable=True) human_readable=True)
gauge.title = 'Hello World!' gauge.title = 'Hello World!'
percent_formatter = lambda x: '{:.10g}%'.format(x) percent_formatter = lambda x: '{:.10g}%'.format(x)
dollar_formatter = lambda x: '{:.10g}$'.format(x) dollar_formatter = lambda x: '{:.10g}$'.format(x)
gauge.value_formatter = percent_formatter gauge.value_formatter = percent_formatter
gauge.add('Series 1', [{'value': 225000, 'maxvalue': 1275000}], gauge.add('Series 1', [{'value': 225000, 'max_value': 1275000}],
formatter=dollar_formatter) formatter=dollar_formatter)
gauge.add('Series 2', [{'value': 110, 'maxvalue': 100}]) gauge.add('Series 2', [{'value': 110, 'max_value': 100}])
gauge.add('Series 3', [{'value': 3}]) gauge.add('Series 3', [{'value': 3}])
gauge.add( gauge.add(
'Series 4', [ 'Series 4', [
{'value': 51, 'maxvalue': 100}, {'value': 51, 'max_value': 100},
{'value': 12, 'maxvalue': 100}]) {'value': 12, 'max_value': 100}])
gauge.add('Series 5', [{'value': 79, 'maxvalue': 100}]) gauge.add('Series 5', [{'value': 79, 'max_value': 100}])
gauge.add('Series 6', 99) gauge.add('Series 6', 99)
gauge.add('Series 7', [{'value': 100, 'maxvalue': 100}]) gauge.add('Series 7', [{'value': 100, 'max_value': 100}])
return gauge.render_response() return gauge.render_response()
@app.route('/test/gauge/log') @app.route('/test/gauge/log')

7
docs/api/pygal.formatters.rst

@ -0,0 +1,7 @@
pygal.formatters module
=======================
.. automodule:: pygal.formatters
:members:
:undoc-members:
:show-inheritance:

1
docs/api/pygal.graph.rst

@ -31,6 +31,7 @@ Submodules
pygal.graph.public pygal.graph.public
pygal.graph.pyramid pygal.graph.pyramid
pygal.graph.radar pygal.graph.radar
pygal.graph.solidgauge
pygal.graph.stackedbar pygal.graph.stackedbar
pygal.graph.stackedline pygal.graph.stackedline
pygal.graph.time pygal.graph.time

7
docs/api/pygal.graph.solidgauge.rst

@ -0,0 +1,7 @@
pygal.graph.solidgauge module
=============================
.. automodule:: pygal.graph.solidgauge
:members:
:undoc-members:
:show-inheritance:

1
docs/api/pygal.rst

@ -24,6 +24,7 @@ Submodules
pygal.colors pygal.colors
pygal.config pygal.config
pygal.etree pygal.etree
pygal.formatters
pygal.interpolate pygal.interpolate
pygal.serie pygal.serie
pygal.state pygal.state

1
docs/api/pygal.test.rst

@ -17,6 +17,7 @@ Submodules
pygal.test.test_colors pygal.test.test_colors
pygal.test.test_config pygal.test.test_config
pygal.test.test_date pygal.test.test_date
pygal.test.test_formatters
pygal.test.test_graph pygal.test.test_graph
pygal.test.test_histogram pygal.test.test_histogram
pygal.test.test_interpolate pygal.test.test_interpolate

7
docs/api/pygal.test.test_formatters.rst

@ -0,0 +1,7 @@
pygal.test.test_formatters module
=================================
.. automodule:: pygal.test.test_formatters
:members:
:undoc-members:
:show-inheritance:

1
docs/documentation/types/index.rst

@ -15,6 +15,7 @@ pygal provides various kinds of charts:
box box
dot dot
funnel funnel
solidgauge
gauge gauge
pyramid pyramid
treemap treemap

52
docs/documentation/types/solidgauge.rst

@ -0,0 +1,52 @@
SolidGauge
----------
SolidGauge charts
Normal
~~~~~~
.. pygal-code::
gauge = pygal.SolidGauge(inner_radius=0.70)
percent_formatter = lambda x: '{:.10g}%'.format(x)
dollar_formatter = lambda x: '{:.10g}$'.format(x)
gauge.value_formatter = percent_formatter
gauge.add('Series 1', [{'value': 225000, 'max_value': 1275000}],
formatter=dollar_formatter)
gauge.add('Series 2', [{'value': 110, 'max_value': 100}])
gauge.add('Series 3', [{'value': 3}])
gauge.add(
'Series 4', [
{'value': 51, 'max_value': 100},
{'value': 12, 'max_value': 100}])
gauge.add('Series 5', [{'value': 79, 'max_value': 100}])
gauge.add('Series 6', 99)
gauge.add('Series 7', [{'value': 100, 'max_value': 100}])
Half
~~~~
.. pygal-code::
gauge = pygal.SolidGauge(
half_pie=True, inner_radius=0.70,
style=pygal.style.styles['default'](value_font_size=10))
percent_formatter = lambda x: '{:.10g}%'.format(x)
dollar_formatter = lambda x: '{:.10g}$'.format(x)
gauge.value_formatter = percent_formatter
gauge.add('Series 1', [{'value': 225000, 'max_value': 1275000}],
formatter=dollar_formatter)
gauge.add('Series 2', [{'value': 110, 'max_value': 100}])
gauge.add('Series 3', [{'value': 3}])
gauge.add(
'Series 4', [
{'value': 51, 'max_value': 100},
{'value': 12, 'max_value': 100}])
gauge.add('Series 5', [{'value': 79, 'max_value': 100}])
gauge.add('Series 6', 99)
gauge.add('Series 7', [{'value': 100, 'max_value': 100}])

10
pygal/css/style.css

@ -90,6 +90,7 @@
fill: {{ style.foreground_strong }}; fill: {{ style.foreground_strong }};
} }
{{ id }}.reactive { {{ id }}.reactive {
fill-opacity: {{ style.opacity }}; fill-opacity: {{ style.opacity }};
} }
@ -147,6 +148,15 @@
font-size: 1.5em; font-size: 1.5em;
} }
{{ id }}.bound {
font-size: .5em;
}
{{ id }}.max-value {
font-size: .75em;
fill: {{ style.foreground_subtle }};
}
{{ id }}.map-element { {{ id }}.map-element {
fill: {{ style.plot_background }}; fill: {{ style.plot_background }};
stroke: {{ style.foreground_subtle }} !important; stroke: {{ style.foreground_subtle }} !important;

10
pygal/graph/solidgauge.py

@ -48,19 +48,19 @@ class SolidGauge(Graph):
(current_square[0]*sq_dimensions[1]) - (sq_dimensions[1] / 2.)) (current_square[0]*sq_dimensions[1]) - (sq_dimensions[1] / 2.))
end_angle = 2 * pi end_angle = 2 * pi
maxvalue = serie.metadata.get(0, {}).get('maxvalue', 100) max_value = serie.metadata.get(0, {}).get('max_value', 100)
radius = min([sq_dimensions[0]/2, sq_dimensions[1]/2]) * .9 radius = min([sq_dimensions[0]/2, sq_dimensions[1]/2]) * .9
small_radius = radius * serie.inner_radius small_radius = radius * serie.inner_radius
self.svg.gauge_background( self.svg.gauge_background(
serie_node, start_angle, center, radius, small_radius, end_angle, serie_node, start_angle, center, radius, small_radius, end_angle,
self.half_pie) self.half_pie, self._serie_format(serie, max_value))
sum_ = 0 sum_ = 0
for i, value in enumerate(serie.values): for i, value in enumerate(serie.values):
if value is None: if value is None:
continue continue
ratio = min(value, maxvalue) / maxvalue ratio = min(value, max_value) / max_value
if self.half_pie: if self.half_pie:
angle = 2 * pi * ratio / 2 angle = 2 * pi * ratio / 2
else: else:
@ -79,7 +79,7 @@ class SolidGauge(Graph):
serie_node, gauge_, radius, small_radius, serie_node, gauge_, radius, small_radius,
angle, start_angle, center, val, i, metadata, angle, start_angle, center, val, i, metadata,
self.half_pie, end_angle, self.half_pie, end_angle,
self._serie_format(serie, maxvalue)), self._serie_format(serie, max_value)),
metadata) metadata)
start_angle += angle start_angle += angle
sum_ += value sum_ += value
@ -87,7 +87,7 @@ class SolidGauge(Graph):
x, y = center x, y = center
self.svg.node( self.svg.node(
serie_node['text_overlay'], 'text', serie_node['text_overlay'], 'text',
class_='value solidgauge-sum', class_='value gauge-sum',
x=x, x=x,
y=y + self.style.value_font_size / 3, y=y + self.style.value_font_size / 3,
attrib={'text-anchor': 'middle'} attrib={'text-anchor': 'middle'}

111
pygal/svg.py

@ -32,6 +32,8 @@ from pygal.util import (
coord_project, coord_diff, coord_format, coord_dual, coord_abs_project) coord_project, coord_diff, coord_format, coord_dual, coord_abs_project)
from pygal import __version__ from pygal import __version__
nearly_2pi = 2 * pi - .00001
class Svg(object): class Svg(object):
@ -258,17 +260,13 @@ class Svg(object):
angle, start_angle, center, val, i, metadata): angle, start_angle, center, val, i, metadata):
"""Draw a pie slice""" """Draw a pie slice"""
if angle == 2 * pi: if angle == 2 * pi:
rv = self.node( angle = nearly_2pi
node, 'circle',
cx=center[0], if angle > 0:
cy=center[1], to = [coord_abs_project(center, radius, start_angle),
r=radius, coord_abs_project(center, radius, start_angle + angle),
class_='slice reactive tooltip-trigger') coord_abs_project(center, small_radius, start_angle + angle),
elif angle > 0: coord_abs_project(center, small_radius, start_angle)]
to = [coord_abs_project(center,radius, start_angle),
coord_abs_project(center,radius, start_angle + angle),
coord_abs_project(center,small_radius, start_angle + angle),
coord_abs_project(center,small_radius, start_angle)]
rv = self.node( rv = self.node(
node, 'path', node, 'path',
d='M%s A%s 0 %d 1 %s L%s A%s 0 %d 0 %s z' % ( d='M%s A%s 0 %d 1 %s L%s A%s 0 %d 0 %s z' % (
@ -291,7 +289,11 @@ class Svg(object):
def gauge_background( def gauge_background(
self, serie_node, start_angle, center, radius, small_radius, self, serie_node, start_angle, center, radius, small_radius,
end_angle, half_pie): end_angle, half_pie, max_value):
if end_angle == 2 * pi:
end_angle = nearly_2pi
to_shade = [ to_shade = [
coord_abs_project(center, radius, start_angle), coord_abs_project(center, radius, start_angle),
coord_abs_project(center, radius, end_angle), coord_abs_project(center, radius, end_angle),
@ -309,36 +311,6 @@ class Svg(object):
to_shade[3]), to_shade[3]),
class_='gauge-background reactive') class_='gauge-background reactive')
def solid_gauge(
self, serie_node, node, radius, small_radius,
angle, start_angle, center, val, i, metadata, half_pie, end_angle,
maxvalue):
"""Draw a solid gauge slice and background slice"""
if angle == 2 * pi:
to = [coord_abs_project(center, radius, start_angle),
coord_abs_project(
center, radius, start_angle + angle - 0.0001),
coord_abs_project(
center, small_radius, start_angle + angle - 0.0001),
coord_abs_project(center, small_radius, start_angle)]
self.node(
node, 'path',
d='M%s A%s 0 %d 1 %s L%s A%s 0 %d 0 %s z' % (
to[0],
coord_dual(radius),
int(angle > pi),
to[1],
to[2],
coord_dual(small_radius),
int(angle > pi),
to[3]),
class_='slice reactive tooltip-trigger')
elif angle > 0:
to = [coord_abs_project(center, radius, start_angle),
coord_abs_project(center, radius, start_angle + angle),
coord_abs_project(center, small_radius, start_angle + angle),
coord_abs_project(center, small_radius, start_angle)]
if half_pie: if half_pie:
begin_end = [ begin_end = [
coord_diff( coord_diff(
@ -352,39 +324,54 @@ class Svg(object):
pos = 0 pos = 0
for i in begin_end: for i in begin_end:
self.node( self.node(
node, 'text', serie_node['plot'], 'text',
class_='y-{} reactive'.format(pos), class_='y-{} bound reactive'.format(pos),
x=i[0], x=i[0],
y=i[1]+10, y=i[1]+10,
attrib={'text-anchor': 'middle', attrib={'text-anchor': 'middle'}
'font-size': 10} ).text = '{}'.format(0 if pos == 0 else max_value)
).text = '{}'.format(0 if pos == 0 else maxvalue)
pos += 1 pos += 1
else: else:
middle_radius = .5 * (radius + small_radius)
# Correct text vertical alignment
middle_radius -= .1 * (radius - small_radius)
to_labels = [ to_labels = [
coord_abs_project( coord_abs_project(
center, radius-(radius-small_radius)/2, 0), center, middle_radius, 0),
coord_abs_project( coord_abs_project(
center, radius-(radius-small_radius)/2, 2*359.5/360*pi) center, middle_radius, nearly_2pi)
] ]
self.node( self.node(
self.defs, 'path', id='valuePath-%s%s' % center, self.defs, 'path', id='valuePath-%s%s' % center,
d='M%s A%s 0 1 1 %s' % ( d='M%s A%s 0 1 1 %s' % (
to_labels[0], to_labels[0],
coord_dual(radius-(radius-small_radius)/2), coord_dual(middle_radius),
to_labels[1] to_labels[1]
), stroke='#000000', width='3px') ))
text_ = self.node(node, 'text', x=10, y=100, stroke='black') text_ = self.node(
serie_node['text_overlay'], 'text')
self.node( self.node(
text_, 'textPath', class_='maxvalue reactive', text_, 'textPath', class_='max-value reactive',
attrib={ attrib={
'href': '#valuePath-%s%s' % center, 'href': '#valuePath-%s%s' % center,
'startOffset': '%s' % ( 'startOffset': '99%',
97-1.2*len(str(maxvalue))) + '%', 'text-anchor': 'end'
'text-anchor': 'start', }
'font-size': (radius-small_radius)/2, ).text = max_value
'fill': '#999999'}
).text = maxvalue def solid_gauge(
self, serie_node, node, radius, small_radius,
angle, start_angle, center, val, i, metadata, half_pie, end_angle,
max_value):
"""Draw a solid gauge slice and background slice"""
if angle == 2 * pi:
angle = nearly_2pi
if angle > 0:
to = [coord_abs_project(center, radius, start_angle),
coord_abs_project(center, radius, start_angle + angle),
coord_abs_project(center, small_radius, start_angle + angle),
coord_abs_project(center, small_radius, start_angle)]
self.node( self.node(
node, 'path', node, 'path',
@ -410,9 +397,9 @@ class Svg(object):
def confidence_interval(self, node, x, low, high, width=7): def confidence_interval(self, node, x, low, high, width=7):
if self.graph.horizontal: if self.graph.horizontal:
coord_format = lambda xy: '%f %f' % (xy[1], xy[0]) fmt = lambda xy: '%f %f' % (xy[1], xy[0])
else: else:
coord_format = lambda xy: '%f %f' % xy fmt = coord_format
shr = lambda xy: (xy[0] + width, xy[1]) shr = lambda xy: (xy[0] + width, xy[1])
shl = lambda xy: (xy[0] - width, xy[1]) shl = lambda xy: (xy[0] - width, xy[1])
@ -424,7 +411,7 @@ class Svg(object):
self.node( self.node(
ci, 'path', d="M%s L%s M%s L%s M%s L%s L%s M%s L%s" % tuple( ci, 'path', d="M%s L%s M%s L%s M%s L%s L%s M%s L%s" % tuple(
map(coord_format, ( map(fmt, (
top, shr(top), top, shl(top), top, top, shr(top), top, shl(top), top,
bottom, shr(bottom), bottom, shl(bottom) bottom, shr(bottom), bottom, shl(bottom)
)) ))

4
pygal/table.py

@ -94,7 +94,7 @@ class Table(object):
row.append(self.chart._format(serie, j)) row.append(self.chart._format(serie, j))
if total: if total:
acc[-1] += sum_ acc[-1] += sum_
row.append(self.chart._value_format(serie, sum_)) row.append(self.chart._serie_format(serie, sum_))
table.append(row) table.append(row)
width = ln + 1 width = ln + 1
@ -102,7 +102,7 @@ class Table(object):
width += 1 width += 1
table.append(['Total']) table.append(['Total'])
for val in acc: for val in acc:
table[-1].append(self.chart._value_format(serie, val)) table[-1].append(self.chart._serie_format(serie, val))
# Align values # Align values
len_ = max([len(r) for r in table] or [0]) len_ = max([len(r) for r in table] or [0])

12
pygal/test/test_config.py

@ -24,7 +24,9 @@ from pygal import (
Histogram, Gauge, Box, XY, Histogram, Gauge, Box, XY,
Pyramid, HorizontalBar, HorizontalStackedBar, Pyramid, HorizontalBar, HorizontalStackedBar,
HorizontalStackedLine, HorizontalLine, HorizontalStackedLine, HorizontalLine,
DateTimeLine, TimeLine, DateLine, TimeDeltaLine) DateTimeLine, TimeLine, DateLine, TimeDeltaLine,
SolidGauge
)
from pygal.graph.map import BaseMap from pygal.graph.map import BaseMap
from pygal.graph.horizontal import HorizontalGraph from pygal.graph.horizontal import HorizontalGraph
from pygal.graph.dual import Dual from pygal.graph.dual import Dual
@ -299,7 +301,7 @@ def test_include_x_axis(Chart):
"""Test x axis inclusion option""" """Test x axis inclusion option"""
chart = Chart() chart = Chart()
if Chart in ( if Chart in (
Pie, Treemap, Radar, Funnel, Dot, Gauge, Histogram, Box Pie, Treemap, Radar, Funnel, Dot, Gauge, Histogram, Box, SolidGauge
) or issubclass(Chart, BaseMap): ) or issubclass(Chart, BaseMap):
return return
if not chart._dual: if not chart._dual:
@ -391,7 +393,7 @@ def test_x_y_title(Chart):
def test_x_label_major(Chart): def test_x_label_major(Chart):
"""Test x label major option""" """Test x label major option"""
if Chart in ( if Chart in (
Pie, Treemap, Funnel, Dot, Gauge, Histogram, Box, Pie, Treemap, Funnel, Dot, Gauge, Histogram, Box, SolidGauge,
Pyramid, DateTimeLine, TimeLine, DateLine, Pyramid, DateTimeLine, TimeLine, DateLine,
TimeDeltaLine TimeDeltaLine
) or issubclass(Chart, (BaseMap, Dual, HorizontalGraph)): ) or issubclass(Chart, (BaseMap, Dual, HorizontalGraph)):
@ -436,7 +438,7 @@ def test_x_label_major(Chart):
def test_y_label_major(Chart): def test_y_label_major(Chart):
"""Test y label major option""" """Test y label major option"""
if Chart in ( if Chart in (
Pie, Treemap, Funnel, Dot, Gauge, Histogram, Box, Pie, Treemap, Funnel, Dot, Gauge, Histogram, Box, SolidGauge,
HorizontalBar, HorizontalStackedBar, HorizontalBar, HorizontalStackedBar,
HorizontalStackedLine, HorizontalLine, HorizontalStackedLine, HorizontalLine,
Pyramid, DateTimeLine, TimeLine, DateLine, Pyramid, DateTimeLine, TimeLine, DateLine,
@ -522,4 +524,4 @@ def test_formatters(Chart):
q = chart.render_pyquery() q = chart.render_pyquery()
assert set([v.text for v in q(".value")]) == set(( assert set([v.text for v in q(".value")]) == set((
u('4€'), u('5€'), u('6€'), '1_a$', '2_a$', u('')) + ( u('4€'), u('5€'), u('6€'), '1_a$', '2_a$', u('')) + (
('6_a$', u('15€')) if Chart == Pie else ())) ('6_a$', u('15€')) if Chart in (Pie, SolidGauge) else ()))

2
pygal/test/test_graph.py

@ -107,7 +107,7 @@ def test_metadata(Chart):
for md in ('http://7.example.com/', 'http://4.example.com/'): for md in ('http://7.example.com/', 'http://4.example.com/'):
assert md in [e.attrib.get('xlink:href') for e in q('a')] assert md in [e.attrib.get('xlink:href') for e in q('a')]
if Chart in (pygal.Pie, pygal.Treemap): if Chart in (pygal.Pie, pygal.Treemap, pygal.SolidGauge):
# Slices with value 0 are not rendered # Slices with value 0 are not rendered
assert len(v) - 1 == len(q('.tooltip-trigger').siblings('.value')) assert len(v) - 1 == len(q('.tooltip-trigger').siblings('.value'))
elif not issubclass(Chart, BaseMap): elif not issubclass(Chart, BaseMap):

Loading…
Cancel
Save