Skip to content

Commit

Permalink
Add tick formatter option. Closes #13.
Browse files Browse the repository at this point in the history
  • Loading branch information
onyxfish committed May 19, 2016
1 parent 45af283 commit 3f09e97
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 19 deletions.
36 changes: 28 additions & 8 deletions leather/axis.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,26 @@
class Axis(Renderable):
"""
A horizontal or vertical chart axis.
:param ticks:
The number of ticks to display for this axis.
:param tick_formatter:
An optional function to call on every tick. The function must take
three arguments: :code:`(value, index, count)` where :code:`value` is
the tick, :code:`index` is the index of the tick, and :code:`count`
is the total number of ticks. The return value of the function will
be used for display instead of the original tick value.
"""
def __init__(self, ticks=5):
self.ticks = ticks
def __init__(self, ticks=5, tick_formatter=None):
self._ticks = ticks
self._tick_formatter = tick_formatter

def estimate_label_margin(self, scale, orient):
"""
Estimate the space needed for the tick labels.
"""
if orient == 'left':
max_len = max(len(six.text_type(t)) for t in scale.ticks(self.ticks))
max_len = max(len(six.text_type(t)) for t in scale.ticks(self._ticks))
return max_len * theme.tick_font_char_width
elif orient == 'bottom':
return theme.tick_font_char_height
Expand All @@ -45,10 +55,16 @@ def to_svg(self, width, height, scale, orient):
range_min = 0
range_max = width

for value in scale.ticks(self.ticks):
tick_values = scale.ticks(self._ticks)
tick_count = len(tick_values)

for i, value in enumerate(tick_values):
# Tick group
tick_group = ET.Element('g')
tick_group.set('class', 'tick')
group.append(tick_group)

# Tick line
projected_value = scale.project(value, range_min, range_max)

if value == 0:
Expand All @@ -73,6 +89,9 @@ def to_svg(self, width, height, scale, orient):
)
tick.set('stroke-width', six.text_type(theme.tick_width))

tick_group.append(tick)

# Tick label
if orient == 'left':
x = label_x
y = projected_value
Expand All @@ -91,12 +110,13 @@ def to_svg(self, width, height, scale, orient):
fill=theme.label_color
)
label.set('text-anchor', text_anchor)
label.set('font-family', theme.tick_font_family)
label.set('font-family', theme.tick_font_family)

if self._tick_formatter:
value = self._tick_formatter(value, i, tick_count)

label.text = six.text_type(value)

tick_group.append(tick)
tick_group.append(label)

group.append(tick_group)

return group
13 changes: 5 additions & 8 deletions leather/chart.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,16 +121,13 @@ def _validate_dimension(self, dimension):
scale = self._scales[dimension]
axis = self._axes[dimension]

if not axis:
if not scale:
scale = Scale.infer(self._layers, dimension, self._types[dimension])
else:
scale = scale
if not scale:
scale = Scale.infer(self._layers, dimension, self._types[dimension])
else:
scale = scale

if not axis:
axis = Axis()
# Verify data are within bounds
else:
pass

return (scale, axis)

Expand Down
2 changes: 0 additions & 2 deletions leather/shapes/dots.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,6 @@ def to_svg(self, width, height, x_scale, y_scale, series):
proj_x = x_scale.project(x, 0, width)
proj_y = y_scale.project(y, height, 0)

print(x, proj_x)

group.append(ET.Element('circle',
cx=six.text_type(proj_x),
cy=six.text_type(proj_y),
Expand Down
33 changes: 33 additions & 0 deletions tests/test_axis.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#!/usr/bin/env python

try:
import unittest2 as unittest
except ImportError:
import unittest

import leather
from tests.utils import XMLTest


class TestChart(XMLTest):
def setUp(self):
self.data = [
(0, 3),
(4, 5),
(7, 9),
(10, 4)
]

def test_tick_formatter(self):
chart = leather.Chart()
chart.add_dots(self.data)

def test_formatter(value, i, count):
return '%i+' % (value * 10)

axis = leather.Axis(tick_formatter=test_formatter)
chart.set_x_axis(axis)

svg = self.render_chart(chart)

self.assertTickLabels(svg, 'bottom', ['0+', '25+', '50+', '75+', '100+'])
1 change: 0 additions & 1 deletion tests/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
import unittest

from lxml import etree
import six


class XMLTest(unittest.TestCase):
Expand Down

0 comments on commit 3f09e97

Please sign in to comment.