Browse Source

Bar print value positioning with `print_values_position`. Can be `top`, `center` or `bottom` (thanks @chartique) Fix #291

pull/293/head
Florian Mounier 9 years ago
parent
commit
d1eba64bdf
  1. 11
      demo/moulinrouge/tests.py
  2. 2
      docs/changelog.rst
  3. 24
      pygal/graph/bar.py
  4. 24
      pygal/graph/graph.py

11
demo/moulinrouge/tests.py

@ -3,7 +3,7 @@
from pygal import ( from pygal import (
Bar, Gauge, Pyramid, Funnel, Dot, StackedBar, StackedLine, XY, Bar, Gauge, Pyramid, Funnel, Dot, StackedBar, StackedLine, XY,
CHARTS_BY_NAME, Config, Line, Histogram, Box, CHARTS_BY_NAME, Config, Line, Histogram, Box,
Pie, Treemap, TimeLine, DateLine, Radar, Pie, Treemap, TimeLine, DateLine, Radar, HorizontalBar,
DateTimeLine) DateTimeLine)
try: try:
@ -353,9 +353,12 @@ def get_test_routes(app):
@app.route('/test/bar/position') @app.route('/test/bar/position')
def test_bar_print_values_position(): def test_bar_print_values_position():
bar = Bar(print_values=True, print_values_position='top') bar = HorizontalBar(print_values=True, print_values_position='top',
bar.add('1', [1, 2, 3]) style=styles['default'](
bar.add('2', [4, 5, 6]) value_font_family='googlefont:Raleway',
value_font_size=46))
bar.add('1', [-1, 2, 3])
bar.add('2', [4, -5, 6])
bar.x_labels = [2, 4, 6] bar.x_labels = [2, 4, 6]
bar.x_labels_major = [4] bar.x_labels_major = [4]
return bar.render_response() return bar.render_response()

2
docs/changelog.rst

@ -5,7 +5,7 @@ Changelog
2.0.13 UNRELEASED 2.0.13 UNRELEASED
====== ======
* Bar label positioning * Bar print value positioning with `print_values_position`. Can be `top`, `center` or `bottom` (thanks @chartique #291)
2.0.12 2.0.12
====== ======

24
pygal/graph/bar.py

@ -65,11 +65,32 @@ class Bar(Graph):
x, y, width, height): x, y, width, height):
transpose = swap if self.horizontal else ident transpose = swap if self.horizontal else ident
x_center, y_center = transpose((x + width / 2, y + height / 2)) x_center, y_center = transpose((x + width / 2, y + height / 2))
x_top, y_top = transpose((x + width, y + height))
x_bottom, y_bottom = transpose((x, y))
sign = -1 if height < self.zero else 1
self._tooltip_data( self._tooltip_data(
parent, val, x_center, y_center, "centered", parent, val, x_center, y_center, "centered",
self._get_x_label(i)) self._get_x_label(i))
if self.print_values_position == 'top':
if self.horizontal:
x = x_bottom - sign * self.style.value_font_size / 2
y = y_center
else:
x = x_center
y = y_bottom - sign * self.style.value_font_size / 2
elif self.print_values_position == 'bottom':
if self.horizontal:
x = x_top - sign * self.style.value_font_size / 2
y = y_center
else:
x = x_center
y = y_top - sign * self.style.value_font_size / 2
else:
x = x_center
y = y_center
self._static_value( self._static_value(
serie_node, val, x_center, y_center, metadata) serie_node, val, x, y, metadata, "centered")
def bar(self, serie, rescale=False): def bar(self, serie, rescale=False):
"""Draw a bar graph for a serie""" """Draw a bar graph for a serie"""
@ -103,7 +124,6 @@ class Bar(Graph):
self._box.ymin = min(self._min, self.zero) self._box.ymin = min(self._min, self.zero)
if self._max: if self._max:
self._box.ymax = max(self._max, self.zero) self._box.ymax = max(self._max, self.zero)
self._x_pos = [ self._x_pos = [
x / self._len for x in range(self._len + 1) x / self._len for x in range(self._len + 1)
] if self._len > 1 else [0, 1] # Center if only one value ] if self._len > 1 else [0, 1] # Center if only one value

24
pygal/graph/graph.py

@ -491,25 +491,31 @@ class Graph(PublicApi):
self.svg.node(node, 'desc', self.svg.node(node, 'desc',
class_="x_label").text = to_str(xlabel) class_="x_label").text = to_str(xlabel)
def _static_value(self, serie_node, value, x, y, metadata): def _static_value(self, serie_node, value, x, y, metadata, classes=None):
"""Write the print value""" """Write the print value"""
label = metadata and metadata.get('label') label = metadata and metadata.get('label')
classes = classes and [classes] or []
if self.print_labels and label: if self.print_labels and label:
label_cls = classes + ['label']
if self.print_values: if self.print_values:
y -= self.style.value_font_size / 2 y -= self.style.value_font_size / 2
self.svg.node( self.svg.node(
serie_node['text_overlay'], 'text', serie_node['text_overlay'], 'text',
class_='centered label', class_=' '.join(label_cls),
x=x, x=x,
y=y + self.style.value_font_size / 3 y=y + self.style.value_font_size / 3
).text = label ).text = label
y += self.style.value_font_size y += self.style.value_font_size
if self.print_values or self.dynamic_print_values: if self.print_values or self.dynamic_print_values:
val_cls = classes + ['value']
if self.dynamic_print_values:
val_cls.append('showable')
self.svg.node( self.svg.node(
serie_node['text_overlay'], 'text', serie_node['text_overlay'], 'text',
class_='centered value%s' % ( class_=' '.join(val_cls),
' showable' if self.dynamic_print_values else ''),
x=x, x=x,
y=y + self.style.value_font_size / 3 y=y + self.style.value_font_size / 3
).text = value if self.print_zeroes or value != '0' else '' ).text = value if self.print_zeroes or value != '0' else ''
@ -676,6 +682,16 @@ class Graph(PublicApi):
self.margin_box.left += height self.margin_box.left += height
self._y_title_height = height + self.spacing self._y_title_height = height + self.spacing
# Inner margin
if self.print_values_position == 'top':
gw = self.width - self.margin_box.x
gh = self.height - self.margin_box.y
alpha = 1.1 * (self.style.value_font_size / gh) * self._box.height
if self._max > 0:
self._box.ymax += alpha
if self._min < 0:
self._box.ymin -= alpha
@cached_property @cached_property
def _legends(self): def _legends(self):
"""Getter for series title""" """Getter for series title"""

Loading…
Cancel
Save