Browse Source

Implemented methods that were stubbed with NotImplementedError(s).

Copied flatten method from my internal development and add it to util.py.
Removed reference to itools from Line.py.
Cleaned up docstring tests that weren't actually executable.
pull/8/head
jaraco 17 years ago
parent
commit
2a10be37cc
  1. 2
      lib/SVG/Line.py
  2. 8
      lib/SVG/Pie.py
  3. 52
      lib/SVG/__init__.py
  4. 50
      lib/SVG/util.py

2
lib/SVG/Line.py

@ -3,7 +3,7 @@
# $Id$
from operator import itemgetter, add
from itools import flatten
from util import flatten
import SVG
from Plot import float_range

8
lib/SVG/Pie.py

@ -103,19 +103,19 @@ class Pie(SVG.Graph):
"""
Add a data set to the graph
>>> graph.add_data({data:[1,2,3,4]})
>>> graph.add_data({data:[1,2,3,4]}) # doctest: +SKIP
Note that a 'title' key is ignored.
Multiple calls to add_data will sum the elements, and the pie will
display the aggregated data. e.g.
>>> graph.add_data({data:[1,2,3,4]})
>>> graph.add_data({data:[2,3,5,7]})
>>> graph.add_data({data:[1,2,3,4]}) # doctest: +SKIP
>>> graph.add_data({data:[2,3,5,7]}) # doctest: +SKIP
is the same as:
graph.add_data({data:[3,5,8,11]})
graph.add_data({data:[3,5,8,11]}) # doctest: +SKIP
"""
self.data = map(robust_add, self.data, data_descriptor['data'])

52
lib/SVG/__init__.py

@ -126,11 +126,11 @@ Copyright © 2008 Jason R. Coombs
"""This method allows you do add data to the graph object.
It can be called several times to add more data sets in.
>>> data_sales_02 = [12, 45, 21]
>>> graph.add_data({
>>> data_sales_02 = [12, 45, 21] # doctest: +SKIP
>>> graph.add_data({ # doctest: +SKIP
... 'data': data_sales_02,
... 'title': 'Sales 2002'
...})
... }) # doctest: +SKIP
"""
self.validate_data(conf)
self.process_data(conf)
@ -151,7 +151,8 @@ Copyright © 2008 Jason R. Coombs
"""This method removes all data from the object so that you can
reuse it to create a new graph but with the same config options.
>>> graph.clear_data()"""
>>> graph.clear_data() # doctest: +SKIP
"""
self.data = []
def burn(self):
@ -476,10 +477,31 @@ Copyright © 2008 Jason R. Coombs
self.root.appendChild(text)
def draw_graph_subtitle(self):
raise NotImplementedError
y_subtitle_options = [subtitle_font_size, title_font_size+10]
y_subtitle = y_subtitle_options[self.show_graph_title]
text = self._create_element('text', {
'x': str(self.width/2),
'y': str(y_subtitle),
'class': 'subTitle',
})
text.appendChild(self._doc.createTextNode(self.graph_title))
self.root.appendChild(text)
def draw_x_title(self):
raise NotImplementedError
y = self.graph_height + self.border_top + self.x_title_font_size
if self.show_x_labels:
y_size = self.x_label_font_size+5
if self.stagger_x_labels: y_size*=2
y += y_size
x = self.width / 2
text = self._create_element('text', {
'x': str(x),
'y': str(y),
'class': 'xAxisTitle',
})
text.appendChild(self._doc.createTextNode(self.x_title))
self.root.appendChild(text)
def draw_y_title(self):
x = self.y_title_font_size
@ -528,9 +550,25 @@ Copyright © 2008 Jason R. Coombs
x_offset = self.graph_width + self.border_left + 10
y_offset = self.border_top + 20
if self.key_position == 'bottom':
raise NotImplementedError
x_offset, y_offset = self.calculate_offsets_bottom()
group.setAttribute('transform', 'translate(%(x_offset)d %(y_offset)d)' % vars())
def calculate_offsets_bottom(self):
x_offset = self.border_left + 20
y_offset = self.border_top + self.graph_height + 5
if self.show_x_labels:
max_x_label_height_px = x_label_font_size
if self.rotate_x_labels:
longest_label_length = max(map(len, self.get_x_labels()))
# note: I think 0.6 is the ratio of width to height of characters
max_x_label_height_px *= longest_label_length * 0.6
y_offset += max_x_label_height_px
if self.stagger_x_labels:
y_offset += max_x_label_height_px + 5
if self.show_x_title:
y_offset += x_title_font_size + 5
return x_offset, y_offset
def style(self):
"hard code the styles into the xml if style sheets are not used."
if self.no_css:

50
lib/SVG/util.py

@ -110,3 +110,53 @@ class TimeScale(object):
def __mul__(self, delta):
scale = divide_timedelta(delta, self.range)
return scale*self.width
# the following three functions were copied from jaraco.util.iter_
# todo, factor out caching capability
class iterable_test(dict):
"Test objects for iterability, caching the result by type"
def __init__(self, ignore_classes=(basestring,)):
"""ignore_classes must include basestring, because if a string
is iterable, so is a single character, and the routine runs
into an infinite recursion"""
assert basestring in ignore_classes, 'basestring must be in ignore_classes'
self.ignore_classes = ignore_classes
def __getitem__(self, candidate):
return dict.get(self, type(candidate)) or self._test(candidate)
def _test(self, candidate):
try:
if isinstance(candidate, self.ignore_classes):
raise TypeError
iter(candidate)
result = True
except TypeError:
result = False
self[type(candidate)] = result
return result
def iflatten(subject, test=None):
if test is None:
test = iterable_test()
if not test[subject]:
yield subject
else:
for elem in subject:
for subelem in iflatten(elem, test):
yield subelem
def flatten(subject, test=None):
"""flatten an iterable with possible nested iterables.
Adapted from
http://mail.python.org/pipermail/python-list/2003-November/233971.html
>>> flatten(['a','b',['c','d',['e','f'],'g'],'h']) == ['a','b','c','d','e','f','g','h']
True
Note this will normally ignore string types as iterables.
>>> flatten(['ab', 'c'])
['ab', 'c']
"""
return list(iflatten(subject, test))

Loading…
Cancel
Save