diff --git a/features/column-formatters.feature b/features/column-formatters.feature
index 4567ed48..7b8b8659 100644
--- a/features/column-formatters.feature
+++ b/features/column-formatters.feature
@@ -16,3 +16,22 @@ Feature: Column formatters
| input |
| floats |
| integers |
+
+ Scenario Outline: Unit formatter
+ Given an instance of toyplot.format.UnitFormatter
+ Then formatting with the toyplot.format.UnitFormatter should produce valid output
+
+ Examples:
+ | input |
+ | inch units |
+ | point units |
+
+ Scenario Outline: Currency formatter
+ Given an instance of toyplot.format.CurrencyFormatter
+ Then formatting with the toyplot.format.CurrencyFormatter should produce valid output
+
+ Examples:
+ | input |
+ | Canadian currency |
+ | European currency |
+ | British currency |
diff --git a/features/steps/format.py b/features/steps/format.py
index 61f0b62a..1cd9fbb7 100644
--- a/features/steps/format.py
+++ b/features/steps/format.py
@@ -54,3 +54,68 @@ def step_impl(context):
nose.tools.assert_equal(prefix, "1")
nose.tools.assert_equal(separator, "")
nose.tools.assert_equal(suffix, "")
+
+
+@given(u'an instance of toyplot.format.UnitFormatter')
+def step_impl(context):
+ context.formatter = toyplot.format.UnitFormatter()
+
+
+@then(
+ u'formatting inch units with the toyplot.format.UnitFormatter should produce valid output')
+def step_impl(context):
+ val = context.formatter.format(12.2, "inches")
+ prefix, separator, suffix, units = val
+ nose.tools.assert_equal(prefix, "12")
+ nose.tools.assert_equal(separator, ".")
+ nose.tools.assert_equal(suffix, "2")
+ nose.tools.assert_equal(units, "in")
+
+
+@then(
+ u'formatting point units with the toyplot.format.UnitFormatter should produce valid output')
+def step_impl(context):
+ val = context.formatter.format(5.1, "points")
+ prefix, separator, suffix, units = val
+ nose.tools.assert_equal(prefix, "5")
+ nose.tools.assert_equal(separator, ".")
+ nose.tools.assert_equal(suffix, "1")
+ nose.tools.assert_equal(units, "pt")
+
+
+@given(u'an instance of toyplot.format.CurrencyFormatter')
+def step_impl(context):
+ context.formatter = toyplot.format.CurrencyFormatter(curr="cad")
+
+
+@then(
+ u'formatting Canadian currency with the toyplot.format.CurrencyFormatter should produce valid output')
+def step_impl(context):
+ codes, prefix, dp, suffix = context.formatter.format(100.00)
+ nose.tools.assert_equal(codes, "$")
+ nose.tools.assert_equal(prefix, "100")
+ nose.tools.assert_equal(dp, ".")
+ nose.tools.assert_equal(suffix, "00")
+
+
+@then(
+ u'formatting European currency with the toyplot.format.CurrencyFormatter should produce valid output')
+def step_impl(context):
+ context.formatter = toyplot.format.CurrencyFormatter(curr="eur")
+ val = context.formatter.format(9000.56)
+ codes, prefix, dp, suffix = val
+ nose.tools.assert_equal(codes, "€")
+ nose.tools.assert_equal(prefix, "9,000")
+ nose.tools.assert_equal(dp, ".")
+ nose.tools.assert_equal(suffix, "56")
+
+@then(
+ u'formatting British currency with the toyplot.format.CurrencyFormatter should produce valid output')
+def step_impl(context):
+ context.formatter = toyplot.format.CurrencyFormatter(curr="gbp")
+ val = context.formatter.format(23423410.5)
+ codes, prefix, dp, suffix = val
+ nose.tools.assert_equal(codes, "£")
+ nose.tools.assert_equal(prefix, "23,423,410")
+ nose.tools.assert_equal(dp, ".")
+ nose.tools.assert_equal(suffix, "50")
diff --git a/tests/__init__.py b/tests/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/format_tests.py b/tests/format_tests.py
new file mode 100644
index 00000000..97623c99
--- /dev/null
+++ b/tests/format_tests.py
@@ -0,0 +1,12 @@
+import toyplot
+import nose.tools
+
+def test_float_formatter():
+ formatter = toyplot.format.UnitFormatter()
+ val = formatter.format(12.2, "inches")
+ nose.tools.assert_equal(1, val)
+
+def test_currency_formatter():
+ formatter = toyplot.format.CurrencyFormatter(curr="gbp")
+ val = formatter.format(23423410.5)
+ nose.tools.assert_equal(1, val)
diff --git a/toyplot/format.py b/toyplot/format.py
index ad08e918..83f9f031 100644
--- a/toyplot/format.py
+++ b/toyplot/format.py
@@ -71,3 +71,92 @@ def format(self, value):
if len(formatted) == 1:
return formatted[0], "", ""
return formatted[0], ".", formatted[1]
+
+
+class UnitFormatter(Formatter):
+ """Formats values with corresponding units
+ """
+
+ def __init__(self, format="{:.6}", nanshow=True):
+ self._format = format
+ self._nanshow = nanshow
+
+ def format(self, value, units):
+
+ if units not in UnitFormatter._units:
+ raise Exception("Incorrect type of units provided")
+
+ if isinstance(value, six.string_types):
+ return value, "", ""
+
+ if numpy.isnan(value) and not self._nanshow:
+ return "", "", ""
+
+ formatted = self._format.format(value).split(".")
+ if len(formatted) == 1:
+ return formatted[0], "", ""
+ return formatted[0], ".", formatted[1], UnitFormatter._units[units]
+
+
+UnitFormatter._units = {
+ "centimeter": "cm",
+ "centimeters": "cm",
+ "cm": "cm",
+ "decimeter": "dm",
+ "decimeters": "dm",
+ "dm": "dm",
+ "in": "in",
+ "inch": "in",
+ "inches": "in",
+ "m": "m",
+ "meter": "m",
+ "meters": "m",
+ "millimeter": "mm",
+ "millimeters": "mm",
+ "mm": "mm",
+ "pc": "pc",
+ "pica": "pc",
+ "picas": "pc",
+ "pixel": "px",
+ "pixels": "px",
+ "point": "pt",
+ "points": "pt",
+ "pt": "pt",
+ "px": "px",
+}
+
+
+
+class CurrencyFormatter(Formatter):
+ """Formats currency value with corresponding codes
+ places: required number of places after the decimal point
+ curr: optional currency symbol before the sign (may be blank)
+ sep: optional grouping separator (comma, period, space, or blank)
+ dp: decimal point indicator (comma or period)
+ only specify as blank when places is zero
+ """
+ def __init__(self, format="{:,.2f}", nanshow=True, curr='$',
+ sep=',', dp='.',):
+ self._format = format
+ self._nanshow = nanshow
+ self._curr = curr
+ self._sep = sep
+ self._dp = dp
+
+ if self._curr not in CurrencyFormatter._codes:
+ raise Exception("Incorrect currency provided")
+
+ def format(self, value):
+ formatted = self._format.format(value).split(".")
+
+ return CurrencyFormatter._codes[self._curr], formatted[0], self._dp, formatted[1]
+
+
+CurrencyFormatter._codes = {
+ "aud": "$",
+ "cad": "$",
+ "eur": "€",
+ "gbp": "£",
+ "hkd": "HK$",
+ "usd": "$",
+}