Skip to content

Commit

Permalink
Use exponent notation for log_format bases
Browse files Browse the repository at this point in the history
  • Loading branch information
has2k1 committed Sep 28, 2022
1 parent 78b6236 commit 3458383
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 32 deletions.
5 changes: 5 additions & 0 deletions doc/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ Bug Fixes
where formatting for bases 2, 8 and 16 would fail if the values were
float-integers.

Enhancements
************
- :class:`~mizani.formatters.log_format` now uses exponent notation
for bases other than base 10.

v0.8.0
------

Expand Down
42 changes: 23 additions & 19 deletions mizani/formatters.py
Original file line number Diff line number Diff line change
Expand Up @@ -489,26 +489,30 @@ def __call__(self, x):
fmt = '{:1.0e}'
else:
fmt = '{:g}'
elif self.base == 2:
fmt = '{:b}'
elif self.base == 8:
fmt = '{:o}'
elif self.base == 16:
fmt = '{:x}'
labels = [fmt.format(num) for num in x]
return self._tidyup_labels(labels)
else:
warn("Formating values as base = 10")
fmt = '{:g}'

# Base 2, 8 & 16 formatters work with integers
if self.base != 10:
x = [
int(f)
if isinstance(f, float) and float.is_integer(f)
else f
for f in x
]
labels = [fmt.format(num) for num in x]
return self._tidyup_labels(labels)
def _exp(num, base):
e = np.log(num)/np.log(base)
if float.is_integer(e):
e = int(e)
else:
e = np.round(e, 3)
return e

base_txt = f'{self.base}'
if self.base == np.e:
base_txt = 'e'

if self.mathtex:
fmt_parts = (f'${base_txt}^', '{{{e}}}$')
else:
fmt_parts = (f'{base_txt}^', '{e}')

fmt = ''.join(fmt_parts)
exps = [_exp(num, self.base) for num in x]
labels = [fmt.format(e=e) for e in exps]
return labels


class date_format:
Expand Down
21 changes: 8 additions & 13 deletions mizani/tests/test_formatters.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,23 +100,15 @@ def test_log_format():
assert formatter([1, 35, 60, 1e6]) == ['1', '4e1', '6e1', '1e6']

formatter = log_format(base=2)
assert formatter([1, 2, 4, 8]) == ['1', '10', '100', '1000']
assert formatter([0b1, 0b10, 0b11, 0b1011]) == ['1', '10', '11', '1011']
assert formatter([1, 2, 4, 8]) == ['2^0', '2^1', '2^2', '2^3']
assert formatter([0b1, 0b10, 0b11]) == ['2^0', '2^1', '2^1.585']

formatter = log_format(base=8)
assert formatter([1, 4, 8, 16, 64]) == ['1', '4', '10', '20', '100']
assert formatter([1, 4, 8, 64]) == ['8^0', '8^0.667', '8^1', '8^2']

formatter = log_format(base=16)
assert formatter([1, 8, 16, 32, 256]) == ['1', '8', '10', '20', '100']

# Floats
formatter = log_format(base=8)
assert formatter([1., 4., 8., 16.]) == ['1', '4', '10', '20']

# Fallback to base 10
formatter = log_format(base=np.e)
with pytest.warns(UserWarning, match=r"base = 10$"):
assert formatter([1, 8, 16, 32]) == ['1', '8', '16', '32']
assert formatter([1, np.pi, np.e**2, np.e**3]) == \
['e^0', 'e^1.145', 'e^2', 'e^3']

# mathtex
formatter = log_format(mathtex=True)
Expand All @@ -125,6 +117,9 @@ def test_log_format():
assert formatter([35, 60]) == ['35', '60']
assert formatter([1, 10000]) == ['$10^{0}$', '$10^{4}$']

formatter = log_format(base=8, mathtex=True)
assert formatter([1, 4, 64]) == ['$8^{0}$', '$8^{0.667}$', '$8^{2}$']


def test_date_format():
x = pd.date_range('1/1/2010', periods=4, freq='4AS')
Expand Down

0 comments on commit 3458383

Please sign in to comment.