Skip to content

Commit

Permalink
Add legend at bottom option
Browse files Browse the repository at this point in the history
  • Loading branch information
paradoxxxzero committed Apr 27, 2012
1 parent da0cb8a commit 4ff8fe3
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 27 deletions.
14 changes: 8 additions & 6 deletions demo/simple_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,12 +172,14 @@
xy.render_to_file('out-xy.svg')

pie = Pie(Config(style=NeonStyle))
pie.add('test', [lnk(11, 'Foo'), {'value': 8, 'label': 'Few'}, 21])
pie.add('test2', [lnk(29), None, 9])
pie.add('test3', [24, 10, 32])
pie.add('test4', [20, lnk(18), 9])
pie.add('test5', [17, 5, 10])
pie.add('test6', [None, None, 10])
# pie.add('test', [lnk(11, 'Foo'), {'value': 8, 'label': 'Few'}, 21])
# pie.add('test2', [lnk(29), None, 9])
# pie.add('test3', [24, 10, 32])
# pie.add('test4', [20, lnk(18), 9])
# pie.add('test5', [17, 5, 10])
# pie.add('test6', [None, None, 10])
for i in range(30):
pie.add(str(i) + '!' * i, [i, 30 - i])

# pie.included_js = []
# pie.external_js = [
Expand Down
6 changes: 3 additions & 3 deletions pygal/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ class Config(object):
#: Set to false to remove legend
show_legend = True
#: Set to true to position legend at bottom
legend_at_bottom = True
legend_at_bottom = False
#: Set to false to remove dots
show_dots = True
#: Size of legend boxes
Expand Down Expand Up @@ -106,8 +106,8 @@ class Config(object):
disable_xml_declaration = False
#: Write width and height attributes
explicit_size = False
#: Legend string length truncation threshold
truncate_legend = 15
#: Legend string length truncation threshold (None = auto)
truncate_legend = None
#: Label string length truncation threshold (None = auto)
truncate_label = None

Expand Down
14 changes: 10 additions & 4 deletions pygal/graph/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
from pygal.svg import Svg
from pygal.config import Config
from pygal.util import cached_property
from math import sin, cos
from math import sin, cos, sqrt


class BaseGraph(object):
Expand Down Expand Up @@ -86,10 +86,13 @@ def _compute_margin(self):
"""Compute graph margins from set texts"""
if self.show_legend:
h, w = get_texts_box(
map(lambda x: truncate(x, self.truncate_legend),
map(lambda x: truncate(x, self.truncate_legend or 15),
cut(self.series, 'title')),
self.legend_font_size)
self.margin.right += 10 + w + self.legend_box_size
if self.legend_at_bottom:
self.margin.bottom += 10 + h * int(sqrt(len(self.series)))
else:
self.margin.right += 10 + w + self.legend_box_size

if self.title:
h, w = get_text_box(self.title, self.title_font_size)
Expand All @@ -98,12 +101,15 @@ def _compute_margin(self):
if self._x_labels:
h, w = get_texts_box(
cut(self._x_labels), self.label_font_size)
self.margin.bottom += 10 + max(
self._x_labels_height = 10 + max(
w * sin(rad(self.x_label_rotation)), h)
self.margin.bottom += self._x_labels_height
if self.x_label_rotation:
self.margin.right = max(
w * cos(rad(self.x_label_rotation)),
self.margin.right)
else:
self._x_labels_height = 0
if self._y_labels:
h, w = get_texts_box(
cut(self._y_labels), self.label_font_size)
Expand Down
47 changes: 34 additions & 13 deletions pygal/graph/graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
from pygal.graph.base import BaseGraph
from pygal.view import View, LogView
from pygal.util import is_major, truncate, reverse_text_len
from math import isnan, pi
from math import isnan, pi, sqrt, floor, ceil


class Graph(BaseGraph):
Expand Down Expand Up @@ -181,29 +181,50 @@ def _legend(self):
"""Make the legend box"""
if not self.show_legend:
return
truncation = self.truncate_legend
if self.legend_at_bottom:
x = self.margin.left + 10
y = (self.margin.top + self.view.height +
self._x_labels_height + 10)
cols = ceil(sqrt(len(self.series)))
if not truncation:
available_space = self.width / cols - (
self.legend_box_size + 5)
truncation = int(reverse_text_len(
available_space, self.legend_font_size))
else:
x = self.margin.left + self.view.width + 10
y = self.margin.top + 10
cols = 1
if not truncation:
truncation = 15

legends = self.svg.node(
self.nodes['graph'], class_='legends',
transform='translate(%d, %d)' % (
self.margin.left + self.view.width + 10,
self.margin.top + 10))
transform='translate(%d, %d)' % (x, y))

x_step = self.width / cols
for i, title in enumerate(self._legends):
col = i % cols
row = i // cols

legend = self.svg.node(
legends, class_='legend reactive activate-serie',
id="activate-serie-%d" % i)
self.svg.node(
legend, 'rect',
x=0,
y=1.5 * i * self.legend_box_size,
x=col * x_step,
y=1.5 * row * self.legend_box_size,
width=self.legend_box_size,
height=self.legend_box_size,
class_="color-%d reactive" % i
class_="color-%d reactive" % (i % 16)
)
truncated = truncate(title, self.truncate_legend)
truncated = truncate(title, truncation)
# Serious magical numbers here
self.svg.node(
legend, 'text',
x=self.legend_box_size + 5,
y=1.5 * i * self.legend_box_size
x=col * x_step + self.legend_box_size + 5,
y=1.5 * row * self.legend_box_size
+ .5 * self.legend_box_size
+ .3 * self.legend_font_size
).text = truncated
Expand All @@ -224,13 +245,13 @@ def _serie(self, serie):
return dict(
plot=self.svg.node(
self.nodes['plot'],
class_='series serie-%d color-%d' % (serie, serie)),
class_='series serie-%d color-%d' % (serie, serie % 16)),
overlay=self.svg.node(
self.nodes['overlay'],
class_='series serie-%d color-%d' % (serie, serie)),
class_='series serie-%d color-%d' % (serie, serie % 16)),
text_overlay=self.svg.node(
self.nodes['text_overlay'],
class_='series serie-%d color-%d' % (serie, serie)))
class_='series serie-%d color-%d' % (serie, serie % 16)))

def _interpolate(self, ys, xs,
polar=False, xy=False, xy_xmin=None, xy_rng=None):
Expand Down
2 changes: 1 addition & 1 deletion pygal/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ def cycle_fill(short_list, max_len):
"""Fill a list to max_len using a cycle of it"""
short_list = list(short_list)
list_cycle = cycle(short_list)
while len(short_list) < 16:
while len(short_list) < max_len:
short_list.append(list_cycle.next())
return short_list

Expand Down

0 comments on commit 4ff8fe3

Please sign in to comment.