1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
|
import re
import numpy as np
import pytest
from mpl_toolkits.axisartist.angle_helper import (
FormatterDMS, FormatterHMS, select_step, select_step24, select_step360)
_MS_RE = (
r'''\$ # Mathtext
(
# The sign sometimes appears on a 0 when a fraction is shown.
# Check later that there's only one.
(?P<degree_sign>-)?
(?P<degree>[0-9.]+) # Degrees value
{degree} # Degree symbol (to be replaced by format.)
)?
(
(?(degree)\\,) # Separator if degrees are also visible.
(?P<minute_sign>-)?
(?P<minute>[0-9.]+) # Minutes value
{minute} # Minute symbol (to be replaced by format.)
)?
(
(?(minute)\\,) # Separator if minutes are also visible.
(?P<second_sign>-)?
(?P<second>[0-9.]+) # Seconds value
{second} # Second symbol (to be replaced by format.)
)?
\$ # Mathtext
'''
)
DMS_RE = re.compile(_MS_RE.format(degree=re.escape(FormatterDMS.deg_mark),
minute=re.escape(FormatterDMS.min_mark),
second=re.escape(FormatterDMS.sec_mark)),
re.VERBOSE)
HMS_RE = re.compile(_MS_RE.format(degree=re.escape(FormatterHMS.deg_mark),
minute=re.escape(FormatterHMS.min_mark),
second=re.escape(FormatterHMS.sec_mark)),
re.VERBOSE)
def dms2float(degrees, minutes=0, seconds=0):
return degrees + minutes / 60.0 + seconds / 3600.0
@pytest.mark.parametrize('args, kwargs, expected_levels, expected_factor', [
((-180, 180, 10), {'hour': False}, np.arange(-180, 181, 30), 1.0),
((-12, 12, 10), {'hour': True}, np.arange(-12, 13, 2), 1.0)
])
def test_select_step(args, kwargs, expected_levels, expected_factor):
levels, n, factor = select_step(*args, **kwargs)
assert n == len(levels)
np.testing.assert_array_equal(levels, expected_levels)
assert factor == expected_factor
@pytest.mark.parametrize('args, kwargs, expected_levels, expected_factor', [
((-180, 180, 10), {}, np.arange(-180, 181, 30), 1.0),
((-12, 12, 10), {}, np.arange(-750, 751, 150), 60.0)
])
def test_select_step24(args, kwargs, expected_levels, expected_factor):
levels, n, factor = select_step24(*args, **kwargs)
assert n == len(levels)
np.testing.assert_array_equal(levels, expected_levels)
assert factor == expected_factor
@pytest.mark.parametrize('args, kwargs, expected_levels, expected_factor', [
((dms2float(20, 21.2), dms2float(21, 33.3), 5), {},
np.arange(1215, 1306, 15), 60.0),
((dms2float(20.5, seconds=21.2), dms2float(20.5, seconds=33.3), 5), {},
np.arange(73820, 73835, 2), 3600.0),
((dms2float(20, 21.2), dms2float(20, 53.3), 5), {},
np.arange(1220, 1256, 5), 60.0),
((21.2, 33.3, 5), {},
np.arange(20, 35, 2), 1.0),
((dms2float(20, 21.2), dms2float(21, 33.3), 5), {},
np.arange(1215, 1306, 15), 60.0),
((dms2float(20.5, seconds=21.2), dms2float(20.5, seconds=33.3), 5), {},
np.arange(73820, 73835, 2), 3600.0),
((dms2float(20.5, seconds=21.2), dms2float(20.5, seconds=21.4), 5), {},
np.arange(7382120, 7382141, 5), 360000.0),
# test threshold factor
((dms2float(20.5, seconds=11.2), dms2float(20.5, seconds=53.3), 5),
{'threshold_factor': 60}, np.arange(12301, 12310), 600.0),
((dms2float(20.5, seconds=11.2), dms2float(20.5, seconds=53.3), 5),
{'threshold_factor': 1}, np.arange(20502, 20517, 2), 1000.0),
])
def test_select_step360(args, kwargs, expected_levels, expected_factor):
levels, n, factor = select_step360(*args, **kwargs)
assert n == len(levels)
np.testing.assert_array_equal(levels, expected_levels)
assert factor == expected_factor
@pytest.mark.parametrize('Formatter, regex',
[(FormatterDMS, DMS_RE),
(FormatterHMS, HMS_RE)],
ids=['Degree/Minute/Second', 'Hour/Minute/Second'])
@pytest.mark.parametrize('direction, factor, values', [
("left", 60, [0, -30, -60]),
("left", 600, [12301, 12302, 12303]),
("left", 3600, [0, -30, -60]),
("left", 36000, [738210, 738215, 738220]),
("left", 360000, [7382120, 7382125, 7382130]),
("left", 1., [45, 46, 47]),
("left", 10., [452, 453, 454]),
])
def test_formatters(Formatter, regex, direction, factor, values):
fmt = Formatter()
result = fmt(direction, factor, values)
prev_degree = prev_minute = prev_second = None
for tick, value in zip(result, values):
m = regex.match(tick)
assert m is not None, f'{tick!r} is not an expected tick format.'
sign = sum(m.group(sign + '_sign') is not None
for sign in ('degree', 'minute', 'second'))
assert sign <= 1, f'Only one element of tick {tick!r} may have a sign.'
sign = 1 if sign == 0 else -1
degree = float(m.group('degree') or prev_degree or 0)
minute = float(m.group('minute') or prev_minute or 0)
second = float(m.group('second') or prev_second or 0)
if Formatter == FormatterHMS:
# 360 degrees as plot range -> 24 hours as labelled range
expected_value = pytest.approx((value // 15) / factor)
else:
expected_value = pytest.approx(value / factor)
assert sign * dms2float(degree, minute, second) == expected_value, \
f'{tick!r} does not match expected tick value.'
prev_degree = degree
prev_minute = minute
prev_second = second
|