From 3109ce9914ad3669e362f857d76b840db10e51b8 Mon Sep 17 00:00:00 2001 From: Joseph Fox-Rabinovitz Date: Mon, 30 Jan 2017 12:08:34 -0500 Subject: [PATCH] MAINT: Updated tick and category test formatting --- lib/matplotlib/tests/test_category.py | 34 +- lib/matplotlib/tests/test_ticker.py | 820 ++++++++++++++------------ lib/matplotlib/ticker.py | 45 +- 3 files changed, 470 insertions(+), 429 deletions(-) diff --git a/lib/matplotlib/tests/test_category.py b/lib/matplotlib/tests/test_category.py index 63aa3ff1c750..6e5c43d76fb9 100644 --- a/lib/matplotlib/tests/test_category.py +++ b/lib/matplotlib/tests/test_category.py @@ -121,6 +121,25 @@ def lt(tl): class TestPlot(object): + bytes_data = [ + ['a', 'b', 'c'], + [b'a', b'b', b'c'], + np.array([b'a', b'b', b'c']) + ] + + bytes_ids = ['string list', 'bytes list', 'bytes ndarray'] + + numlike_data = [ + ['1', '11', '3'], + np.array(['1', '11', '3']), + [b'1', b'11', b'3'], + np.array([b'1', b'11', b'3']), + ] + + numlike_ids = [ + 'string list', 'string ndarray', 'bytes list', 'bytes ndarray' + ] + @pytest.fixture def data(self): self.d = ['a', 'b', 'c', 'a'] @@ -171,12 +190,7 @@ def test_plot_1d_missing(self): self.axis_test(ax.yaxis, self.dmticks, self.dmlabels, self.dmunit_data) @pytest.mark.usefixtures("data") - @pytest.mark.parametrize("bars", - [['a', 'b', 'c'], - [b'a', b'b', b'c'], - np.array([b'a', b'b', b'c'])], - ids=['string list', 'bytes list', - 'bytes ndarray']) + @pytest.mark.parametrize("bars", bytes_data, ids=bytes_ids) def test_plot_bytes(self, bars): counts = np.array([4, 6, 5]) @@ -186,13 +200,7 @@ def test_plot_bytes(self, bars): self.axis_test(ax.xaxis, self.dticks, self.dlabels, self.dunit_data) - @pytest.mark.parametrize("bars", - [['1', '11', '3'], - np.array(['1', '11', '3']), - [b'1', b'11', b'3'], - np.array([b'1', b'11', b'3'])], - ids=['string list', 'string ndarray', - 'bytes list', 'bytes ndarray']) + @pytest.mark.parametrize("bars", numlike_data, ids=numlike_ids) def test_plot_numlike(self, bars): counts = np.array([4, 6, 5]) diff --git a/lib/matplotlib/tests/test_ticker.py b/lib/matplotlib/tests/test_ticker.py index e6afa3f63aa5..443fa05d8dcf 100644 --- a/lib/matplotlib/tests/test_ticker.py +++ b/lib/matplotlib/tests/test_ticker.py @@ -12,267 +12,281 @@ import warnings -@pytest.mark.style('classic') -def test_MaxNLocator(): - loc = mticker.MaxNLocator(nbins=5) - test_value = np.array([20., 40., 60., 80., 100.]) - assert_almost_equal(loc.tick_values(20, 100), test_value) - - test_value = np.array([0., 0.0002, 0.0004, 0.0006, 0.0008, 0.001]) - assert_almost_equal(loc.tick_values(0.001, 0.0001), test_value) - - test_value = np.array([-1.0e+15, -5.0e+14, 0e+00, 5e+14, 1.0e+15]) - assert_almost_equal(loc.tick_values(-1e15, 1e15), test_value) - - -def test_MaxNLocator_integer(): - loc = mticker.MaxNLocator(nbins=5, integer=True) - test_value = np.array([-1, 0, 1, 2]) - assert_almost_equal(loc.tick_values(-0.1, 1.1), test_value) - - test_value = np.array([-0.25, 0, 0.25, 0.5, 0.75, 1.0]) - assert_almost_equal(loc.tick_values(-0.1, 0.95), test_value) - - loc = mticker.MaxNLocator(nbins=5, integer=True, steps=[1, 1.5, 5, 6, 10]) - test_value = np.array([0, 15, 30, 45, 60]) - assert_almost_equal(loc.tick_values(1, 55), test_value) - - -def test_LinearLocator(): - loc = mticker.LinearLocator(numticks=3) - test_value = np.array([-0.8, -0.3, 0.2]) - assert_almost_equal(loc.tick_values(-0.8, 0.2), test_value) - - -def test_MultipleLocator(): - loc = mticker.MultipleLocator(base=3.147) - test_value = np.array([-9.441, -6.294, -3.147, 0., 3.147, 6.294, - 9.441, 12.588]) - assert_almost_equal(loc.tick_values(-7, 10), test_value) - - -def test_AutoMinorLocator(): - fig, ax = plt.subplots() - ax.set_xlim(0, 1.39) - ax.minorticks_on() - test_value = np.array([0.05, 0.1, 0.15, 0.25, 0.3, 0.35, 0.45, - 0.5, 0.55, 0.65, 0.7, 0.75, 0.85, 0.9, - 0.95, 1, 1.05, 1.1, 1.15, 1.25, 1.3, 1.35]) - assert_almost_equal(ax.xaxis.get_ticklocs(minor=True), test_value) - - -def test_LogLocator(): - loc = mticker.LogLocator(numticks=5) - with pytest.raises(ValueError): - loc.tick_values(0, 1000) - - test_value = np.array([1.00000000e-05, 1.00000000e-03, 1.00000000e-01, - 1.00000000e+01, 1.00000000e+03, 1.00000000e+05, - 1.00000000e+07, 1.000000000e+09]) - assert_almost_equal(loc.tick_values(0.001, 1.1e5), test_value) - - loc = mticker.LogLocator(base=2) - test_value = np.array([0.5, 1., 2., 4., 8., 16., 32., 64., 128., 256.]) - assert_almost_equal(loc.tick_values(1, 100), test_value) - - -def test_LinearLocator_set_params(): - """ - Create linear locator with presets={}, numticks=2 and change it to - something else. See if change was successful. Should not exception. - """ - loc = mticker.LinearLocator(numticks=2) - loc.set_params(numticks=8, presets={(0, 1): []}) - assert loc.numticks == 8 - assert loc.presets == {(0, 1): []} - - -def test_LogLocator_set_params(): - """ - Create log locator with default value, base=10.0, subs=[1.0], numdecs=4, - numticks=15 and change it to something else. - See if change was successful. - Should not exception. - """ - loc = mticker.LogLocator() - loc.set_params(numticks=7, numdecs=8, subs=[2.0], base=4) - assert loc.numticks == 7 - assert loc.numdecs == 8 - assert loc._base == 4 - assert list(loc._subs) == [2.0] - - -def test_NullLocator_set_params(): - """ - Create null locator, and attempt to call set_params() on it. - Should not exception, and should raise a warning. - """ - loc = mticker.NullLocator() - with warnings.catch_warnings(record=True) as w: - warnings.simplefilter("always") - loc.set_params() - assert len(w) == 1 - - -def test_MultipleLocator_set_params(): - """ - Create multiple locator with 0.7 base, and change it to something else. - See if change was successful. - Should not exception. - """ - mult = mticker.MultipleLocator(base=0.7) - mult.set_params(base=1.7) - assert mult._base == 1.7 - - -def test_LogitLocator_set_params(): - """ - Create logit locator with default minor=False, and change it to something - else. See if change was successful. Should not exception. - """ - loc = mticker.LogitLocator() # Defaults to false. - loc.set_params(minor=True) - assert loc.minor - - -def test_FixedLocator_set_params(): - """ - Create fixed locator with 5 nbins, and change it to something else. - See if change was successful. - Should not exception. - """ - fixed = mticker.FixedLocator(range(0, 24), nbins=5) - fixed.set_params(nbins=7) - assert fixed.nbins == 7 - - -def test_IndexLocator_set_params(): - """ - Create index locator with 3 base, 4 offset. and change it to something - else. See if change was successful. - Should not exception. - """ - index = mticker.IndexLocator(base=3, offset=4) - index.set_params(base=7, offset=7) - assert index._base == 7 - assert index.offset == 7 - - -def test_SymmetricalLogLocator_set_params(): - """ - Create symmetrical log locator with default subs =[1.0] numticks = 15, - and change it to something else. - See if change was successful. - Should not exception. - """ - sym = mticker.SymmetricalLogLocator(base=10, linthresh=1) - sym.set_params(subs=[2.0], numticks=8) - assert sym._subs == [2.0] - assert sym.numticks == 8 - - -@pytest.mark.style('classic') -@pytest.mark.parametrize('left, right, offset', - [(123, 189, 0), - (-189, -123, 0), - (12341, 12349, 12340), - (-12349, -12341, -12340), - (99999.5, 100010.5, 100000), - (-100010.5, -99999.5, -100000), - (99990.5, 100000.5, 100000), - (-100000.5, -99990.5, -100000), - (1233999, 1234001, 1234000), - (-1234001, -1233999, -1234000), - (1, 1, 1), - (123, 123, 120), - # Test cases courtesy of @WeatherGod - (.4538, .4578, .45), - (3789.12, 3783.1, 3780), - (45124.3, 45831.75, 45000), - (0.000721, 0.0007243, 0.00072), - (12592.82, 12591.43, 12590), - (9., 12., 0), - (900., 1200., 0), - (1900., 1200., 0), - (0.99, 1.01, 1), - (9.99, 10.01, 10), - (99.99, 100.01, 100), - (5.99, 6.01, 6), - (15.99, 16.01, 16), - (-0.452, 0.492, 0), - (-0.492, 0.492, 0), - (12331.4, 12350.5, 12300), - (-12335.3, 12335.3, 0)]) -def test_ScalarFormatter_offset_value(left, right, offset): - fig, ax = plt.subplots() - formatter = ax.get_xaxis().get_major_formatter() - - with warnings.catch_warnings(record=True) as w: - warnings.filterwarnings('always', 'Attempting to set identical', - UserWarning) - ax.set_xlim(left, right) - assert len(w) == (1 if left == right else 0) - # Update ticks. - next(ax.get_xaxis().iter_ticks()) - assert formatter.offset == offset - - with warnings.catch_warnings(record=True) as w: - warnings.filterwarnings('always', 'Attempting to set identical', - UserWarning) - ax.set_xlim(right, left) - assert len(w) == (1 if left == right else 0) - # Update ticks. - next(ax.get_xaxis().iter_ticks()) - assert formatter.offset == offset - - -def _sub_labels(axis, subs=()): - "Test whether locator marks subs to be labeled" - fmt = axis.get_minor_formatter() - minor_tlocs = axis.get_minorticklocs() - fmt.set_locs(minor_tlocs) - coefs = minor_tlocs / 10**(np.floor(np.log10(minor_tlocs))) - label_expected = [np.round(c) in subs for c in coefs] - label_test = [fmt(x) != '' for x in minor_tlocs] - assert label_test == label_expected - - -@pytest.mark.style('default') -def test_LogFormatter_sublabel(): - # test label locator - fig, ax = plt.subplots() - ax.set_xscale('log') - ax.xaxis.set_major_locator(mticker.LogLocator(base=10, subs=[])) - ax.xaxis.set_minor_locator(mticker.LogLocator(base=10, - subs=np.arange(2, 10))) - ax.xaxis.set_major_formatter(mticker.LogFormatter(labelOnlyBase=True)) - ax.xaxis.set_minor_formatter(mticker.LogFormatter(labelOnlyBase=False)) - # axis range above 3 decades, only bases are labeled - ax.set_xlim(1, 1e4) - fmt = ax.xaxis.get_major_formatter() - fmt.set_locs(ax.xaxis.get_majorticklocs()) - show_major_labels = [fmt(x) != '' for x in ax.xaxis.get_majorticklocs()] - assert np.all(show_major_labels) - _sub_labels(ax.xaxis, subs=[]) - - # For the next two, if the numdec threshold in LogFormatter.set_locs - # were 3, then the label sub would be 3 for 2-3 decades and (2,5) - # for 1-2 decades. With a threshold of 1, subs are not labeled. - # axis range at 2 to 3 decades - ax.set_xlim(1, 800) - _sub_labels(ax.xaxis, subs=[]) - - # axis range at 1 to 2 decades - ax.set_xlim(1, 80) - _sub_labels(ax.xaxis, subs=[]) - - # axis range at 0.4 to 1 decades, label subs 2, 3, 4, 6 - ax.set_xlim(1, 8) - _sub_labels(ax.xaxis, subs=[2, 3, 4, 6]) - - # axis range at 0 to 0.4 decades, label all - ax.set_xlim(0.5, 0.9) - _sub_labels(ax.xaxis, subs=np.arange(2, 10, dtype=int)) +class TestMaxNLocator(object): + basic_data = [ + (20, 100, np.array([20., 40., 60., 80., 100.])), + (0.001, 0.0001, np.array([0., 0.0002, 0.0004, 0.0006, 0.0008, 0.001])), + (-1e15, 1e15, np.array([-1.0e+15, -5.0e+14, 0e+00, 5e+14, 1.0e+15])), + ] + + integer_data = [ + (-0.1, 1.1, None, np.array([-1, 0, 1, 2])), + (-0.1, 0.95, None, np.array([-0.25, 0, 0.25, 0.5, 0.75, 1.0])), + (1, 55, [1, 1.5, 5, 6, 10], np.array([0, 15, 30, 45, 60])), + ] + + @pytest.mark.parametrize('vmin, vmax, expected', basic_data) + def test_basic(self, vmin, vmax, expected): + loc = mticker.MaxNLocator(nbins=5) + assert_almost_equal(loc.tick_values(vmin, vmax), expected) + + @pytest.mark.parametrize('vmin, vmax, steps, expected', integer_data) + def test_integer(self, vmin, vmax, steps, expected): + loc = mticker.MaxNLocator(nbins=5, integer=True, steps=steps) + assert_almost_equal(loc.tick_values(vmin, vmax), expected) + + +class TestLinearLocator(object): + def test_basic(self): + loc = mticker.LinearLocator(numticks=3) + test_value = np.array([-0.8, -0.3, 0.2]) + assert_almost_equal(loc.tick_values(-0.8, 0.2), test_value) + + def test_set_params(self): + """ + Create linear locator with presets={}, numticks=2 and change it to + something else. See if change was successful. Should not exception. + """ + loc = mticker.LinearLocator(numticks=2) + loc.set_params(numticks=8, presets={(0, 1): []}) + assert loc.numticks == 8 + assert loc.presets == {(0, 1): []} + + +class TestMultipleLocator(object): + def test_basic(self): + loc = mticker.MultipleLocator(base=3.147) + test_value = np.array([-9.441, -6.294, -3.147, 0., 3.147, 6.294, + 9.441, 12.588]) + assert_almost_equal(loc.tick_values(-7, 10), test_value) + + def test_set_params(self): + """ + Create multiple locator with 0.7 base, and change it to something else. + See if change was successful. + """ + mult = mticker.MultipleLocator(base=0.7) + mult.set_params(base=1.7) + assert mult._base == 1.7 + + +class TestAutoMinorLocator(object): + def test_basic(self): + fig, ax = plt.subplots() + ax.set_xlim(0, 1.39) + ax.minorticks_on() + test_value = np.array([0.05, 0.1, 0.15, 0.25, 0.3, 0.35, 0.45, + 0.5, 0.55, 0.65, 0.7, 0.75, 0.85, 0.9, + 0.95, 1, 1.05, 1.1, 1.15, 1.25, 1.3, 1.35]) + assert_almost_equal(ax.xaxis.get_ticklocs(minor=True), test_value) + + +class TestLogLocator(object): + def test_basic(self): + loc = mticker.LogLocator(numticks=5) + with pytest.raises(ValueError): + loc.tick_values(0, 1000) + + test_value = np.array([1.00000000e-05, 1.00000000e-03, 1.00000000e-01, + 1.00000000e+01, 1.00000000e+03, 1.00000000e+05, + 1.00000000e+07, 1.000000000e+09]) + assert_almost_equal(loc.tick_values(0.001, 1.1e5), test_value) + + loc = mticker.LogLocator(base=2) + test_value = np.array([0.5, 1., 2., 4., 8., 16., 32., 64., 128., 256.]) + assert_almost_equal(loc.tick_values(1, 100), test_value) + + def test_set_params(self): + """ + Create log locator with default value, base=10.0, subs=[1.0], + numdecs=4, numticks=15 and change it to something else. + See if change was successful. Should not raise exception. + """ + loc = mticker.LogLocator() + loc.set_params(numticks=7, numdecs=8, subs=[2.0], base=4) + assert loc.numticks == 7 + assert loc.numdecs == 8 + assert loc._base == 4 + assert list(loc._subs) == [2.0] + + +class TestNullLocator(object): + def test_set_params(self): + """ + Create null locator, and attempt to call set_params() on it. + Should not exception, and should raise a warning. + """ + loc = mticker.NullLocator() + with warnings.catch_warnings(record=True) as w: + warnings.simplefilter("always") + loc.set_params() + assert len(w) == 1 + + +class TestLogitLocator(object): + def test_set_params(self): + """ + Create logit locator with default minor=False, and change it to + something else. See if change was successful. Should not exception. + """ + loc = mticker.LogitLocator() # Defaults to false. + loc.set_params(minor=True) + assert loc.minor + + +class TestFixedLocator(object): + def test_set_params(self): + """ + Create fixed locator with 5 nbins, and change it to something else. + See if change was successful. + Should not exception. + """ + fixed = mticker.FixedLocator(range(0, 24), nbins=5) + fixed.set_params(nbins=7) + assert fixed.nbins == 7 + + +class TestIndexLocator(object): + def test_set_params(self): + """ + Create index locator with 3 base, 4 offset. and change it to something + else. See if change was successful. + Should not exception. + """ + index = mticker.IndexLocator(base=3, offset=4) + index.set_params(base=7, offset=7) + assert index._base == 7 + assert index.offset == 7 + + +class TestSymmetricalLogLocator(object): + def test_set_params(self): + """ + Create symmetrical log locator with default subs =[1.0] numticks = 15, + and change it to something else. + See if change was successful. + Should not exception. + """ + sym = mticker.SymmetricalLogLocator(base=10, linthresh=1) + sym.set_params(subs=[2.0], numticks=8) + assert sym._subs == [2.0] + assert sym.numticks == 8 + + +class TestScalarFormatter(object): + offset_data = [ + (123, 189, 0), + (-189, -123, 0), + (12341, 12349, 12340), + (-12349, -12341, -12340), + (99999.5, 100010.5, 100000), + (-100010.5, -99999.5, -100000), + (99990.5, 100000.5, 100000), + (-100000.5, -99990.5, -100000), + (1233999, 1234001, 1234000), + (-1234001, -1233999, -1234000), + (1, 1, 1), + (123, 123, 120), + # Test cases courtesy of @WeatherGod + (.4538, .4578, .45), + (3789.12, 3783.1, 3780), + (45124.3, 45831.75, 45000), + (0.000721, 0.0007243, 0.00072), + (12592.82, 12591.43, 12590), + (9., 12., 0), + (900., 1200., 0), + (1900., 1200., 0), + (0.99, 1.01, 1), + (9.99, 10.01, 10), + (99.99, 100.01, 100), + (5.99, 6.01, 6), + (15.99, 16.01, 16), + (-0.452, 0.492, 0), + (-0.492, 0.492, 0), + (12331.4, 12350.5, 12300), + (-12335.3, 12335.3, 0), + ] + + use_offset_data = [True, False] + + @pytest.mark.parametrize('left, right, offset', offset_data) + def test_offset_value(self, left, right, offset): + fig, ax = plt.subplots() + formatter = ax.get_xaxis().get_major_formatter() + + with warnings.catch_warnings(record=True) as w: + warnings.filterwarnings('always', 'Attempting to set identical', + UserWarning) + ax.set_xlim(left, right) + assert len(w) == (1 if left == right else 0) + # Update ticks. + next(ax.get_xaxis().iter_ticks()) + assert formatter.offset == offset + + with warnings.catch_warnings(record=True) as w: + warnings.filterwarnings('always', 'Attempting to set identical', + UserWarning) + ax.set_xlim(right, left) + assert len(w) == (1 if left == right else 0) + # Update ticks. + next(ax.get_xaxis().iter_ticks()) + assert formatter.offset == offset + + @pytest.mark.parametrize('use_offset', use_offset_data) + def test_use_offset(self, use_offset): + with matplotlib.rc_context({'axes.formatter.useoffset': use_offset}): + tmp_form = mticker.ScalarFormatter() + assert use_offset == tmp_form.get_useOffset() + + +class TestLogFormatter(object): + def _sub_labels(self, axis, subs=()): + "Test whether locator marks subs to be labeled" + fmt = axis.get_minor_formatter() + minor_tlocs = axis.get_minorticklocs() + fmt.set_locs(minor_tlocs) + coefs = minor_tlocs / 10**(np.floor(np.log10(minor_tlocs))) + label_expected = [np.round(c) in subs for c in coefs] + label_test = [fmt(x) != '' for x in minor_tlocs] + assert label_test == label_expected + + @pytest.mark.style('default') + def test_sublabel(self): + # test label locator + fig, ax = plt.subplots() + ax.set_xscale('log') + ax.xaxis.set_major_locator(mticker.LogLocator(base=10, subs=[])) + ax.xaxis.set_minor_locator(mticker.LogLocator(base=10, + subs=np.arange(2, 10))) + ax.xaxis.set_major_formatter(mticker.LogFormatter(labelOnlyBase=True)) + ax.xaxis.set_minor_formatter(mticker.LogFormatter(labelOnlyBase=False)) + # axis range above 3 decades, only bases are labeled + ax.set_xlim(1, 1e4) + fmt = ax.xaxis.get_major_formatter() + fmt.set_locs(ax.xaxis.get_majorticklocs()) + show_major_labels = [fmt(x) != '' + for x in ax.xaxis.get_majorticklocs()] + assert np.all(show_major_labels) + self._sub_labels(ax.xaxis, subs=[]) + + # For the next two, if the numdec threshold in LogFormatter.set_locs + # were 3, then the label sub would be 3 for 2-3 decades and (2,5) + # for 1-2 decades. With a threshold of 1, subs are not labeled. + # axis range at 2 to 3 decades + ax.set_xlim(1, 800) + self._sub_labels(ax.xaxis, subs=[]) + + # axis range at 1 to 2 decades + ax.set_xlim(1, 80) + self._sub_labels(ax.xaxis, subs=[]) + + # axis range at 0.4 to 1 decades, label subs 2, 3, 4, 6 + ax.set_xlim(1, 8) + self._sub_labels(ax.xaxis, subs=[2, 3, 4, 6]) + + # axis range at 0 to 0.4 decades, label all + ax.set_xlim(0.5, 0.9) + self._sub_labels(ax.xaxis, subs=np.arange(2, 10, dtype=int)) class FakeAxis(object): @@ -285,9 +299,8 @@ def get_view_interval(self): return self.vmin, self.vmax -@pytest.mark.parametrize( - 'labelOnlyBase, exponent, locs, positions, expected', - [ +class TestLogFormatterExponent(object): + param_data = [ (True, 4, np.arange(-3, 4.0), np.arange(-3, 4.0), ['-3', '-2', '-1', '0', '1', '2', '3']), # With labelOnlyBase=False, non-integer powers should be nicely @@ -296,59 +309,60 @@ def get_view_interval(self): range(6), ['0.1', '1e-05', '3.14', '0.2', '-0.2', '-1e-05']), (False, 50, np.array([3, 5, 12, 42], dtype='float'), range(6), ['3', '5', '12', '42']), - ]) -@pytest.mark.parametrize('base', [2.0, 5.0, 10.0, np.pi, np.e]) -def test_LogFormatterExponent(labelOnlyBase, base, exponent, - locs, positions, expected): - formatter = mticker.LogFormatterExponent(base=base, - labelOnlyBase=labelOnlyBase) - formatter.axis = FakeAxis(1, base**exponent) - vals = base**locs - labels = [formatter(x, pos) for (x, pos) in zip(vals, positions)] - assert labels == expected - - -def test_LogFormatterExponent_blank(): - # Should be a blank string for non-integer powers if labelOnlyBase=True - formatter = mticker.LogFormatterExponent(base=10, labelOnlyBase=True) - formatter.axis = FakeAxis() - assert formatter(10**0.1) == '' - - -@pytest.mark.style('default') -def test_LogFormatterSciNotation(): - test_cases = { - 10: ( - (-1, '${-10^{0}}$'), - (1e-05, '${10^{-5}}$'), - (1, '${10^{0}}$'), - (100000, '${10^{5}}$'), - (2e-05, '${2\\times10^{-5}}$'), - (2, '${2\\times10^{0}}$'), - (200000, '${2\\times10^{5}}$'), - (5e-05, '${5\\times10^{-5}}$'), - (5, '${5\\times10^{0}}$'), - (500000, '${5\\times10^{5}}$'), - ), - 2: ( - (0.03125, '${2^{-5}}$'), - (1, '${2^{0}}$'), - (32, '${2^{5}}$'), - (0.0375, '${1.2\\times2^{-5}}$'), - (1.2, '${1.2\\times2^{0}}$'), - (38.4, '${1.2\\times2^{5}}$'), - ) - } - - for base in test_cases: + ] + + base_data = [2.0, 5.0, 10.0, np.pi, np.e] + + @pytest.mark.parametrize( + 'labelOnlyBase, exponent, locs, positions, expected', param_data) + @pytest.mark.parametrize('base', base_data) + def test_basic(self, labelOnlyBase, base, exponent, locs, positions, + expected): + formatter = mticker.LogFormatterExponent(base=base, + labelOnlyBase=labelOnlyBase) + formatter.axis = FakeAxis(1, base**exponent) + vals = base**locs + labels = [formatter(x, pos) for (x, pos) in zip(vals, positions)] + assert labels == expected + + def test_blank(self): + # Should be a blank string for non-integer powers if labelOnlyBase=True + formatter = mticker.LogFormatterExponent(base=10, labelOnlyBase=True) + formatter.axis = FakeAxis() + assert formatter(10**0.1) == '' + + +class TestLogFormatterSciNotation(object): + test_data = [ + (2, 0.03125, '${2^{-5}}$'), + (2, 1, '${2^{0}}$'), + (2, 32, '${2^{5}}$'), + (2, 0.0375, '${1.2\\times2^{-5}}$'), + (2, 1.2, '${1.2\\times2^{0}}$'), + (2, 38.4, '${1.2\\times2^{5}}$'), + (10, -1, '${-10^{0}}$'), + (10, 1e-05, '${10^{-5}}$'), + (10, 1, '${10^{0}}$'), + (10, 100000, '${10^{5}}$'), + (10, 2e-05, '${2\\times10^{-5}}$'), + (10, 2, '${2\\times10^{0}}$'), + (10, 200000, '${2\\times10^{5}}$'), + (10, 5e-05, '${5\\times10^{-5}}$'), + (10, 5, '${5\\times10^{0}}$'), + (10, 500000, '${5\\times10^{5}}$'), + ] + + @pytest.mark.style('default') + @pytest.mark.parametrize('base, value, expected', test_data) + def test_basic(self, base, value, expected): formatter = mticker.LogFormatterSciNotation(base=base) formatter.sublabel = {1, 2, 5, 1.2} - for value, expected in test_cases[base]: - with matplotlib.rc_context({'text.usetex': False}): - assert formatter(value) == expected + with matplotlib.rc_context({'text.usetex': False}): + assert formatter(value) == expected -@pytest.mark.parametrize('value, domain, expected', [ +class TestLogFormatter(object): + pprint_data = [ (3.141592654e-05, 0.001, '3.142e-5'), (0.0003141592654, 0.001, '3.142e-4'), (0.003141592654, 0.001, '3.142e-3'), @@ -480,82 +494,104 @@ def test_LogFormatterSciNotation(): (100, 1000000.0, '100'), (1000, 1000000.0, '1000'), (10000, 1000000.0, '1e4'), - (100000, 1000000.0, '1e5') -]) -def test_logformatter_pprint(value, domain, expected): - fmt = mticker.LogFormatter() - label = fmt.pprint_val(value, domain) - assert label == expected - - -def test_use_offset(): - for use_offset in [True, False]: - with matplotlib.rc_context({'axes.formatter.useoffset': use_offset}): - tmp_form = mticker.ScalarFormatter() - assert use_offset == tmp_form.get_useOffset() - - -def test_formatstrformatter(): - # test % style formatter - tmp_form = mticker.FormatStrFormatter('%05d') - assert '00002' == tmp_form(2) - - # test str.format() style formatter - tmp_form = mticker.StrMethodFormatter('{x:05d}') - assert '00002' == tmp_form(2) - - # test str.format() style formatter with `pos` - tmp_form = mticker.StrMethodFormatter('{x:03d}-{pos:02d}') - assert '002-01' == tmp_form(2, 1) - - -percentformatter_test_cases = ( - # Check explicitly set decimals over different intervals and values - (100, 0, '%', 120, 100, '120%'), - (100, 0, '%', 100, 90, '100%'), - (100, 0, '%', 90, 50, '90%'), - (100, 0, '%', 1.7, 40, '2%'), - (100, 1, '%', 90.0, 100, '90.0%'), - (100, 1, '%', 80.1, 90, '80.1%'), - (100, 1, '%', 70.23, 50, '70.2%'), - # 60.554 instead of 60.55: see https://bugs.python.org/issue5118 - (100, 1, '%', 60.554, 40, '60.6%'), - # Check auto decimals over different intervals and values - (100, None, '%', 95, 1, '95.00%'), - (1.0, None, '%', 3, 6, '300%'), - (17.0, None, '%', 1, 8.5, '6%'), - (17.0, None, '%', 1, 8.4, '5.9%'), - (5, None, '%', -100, 0.000001, '-2000.00000%'), - # Check percent symbol - (1.0, 2, None, 1.2, 100, '120.00'), - (75, 3, '', 50, 100, '66.667'), - (42, None, '^^Foobar$$', 21, 12, '50.0^^Foobar$$'), -) - - -@pytest.mark.parametrize('xmax, decimals, symbol, x, display_range, expected', - percentformatter_test_cases) -def test_percentformatter(xmax, decimals, symbol, x, display_range, expected): - formatter = mticker.PercentFormatter(xmax, decimals, symbol) - assert formatter.format_pct(x, display_range) == expected - - -def test_EngFormatter_formatting(): - """ - Create two instances of EngFormatter with default parameters, with and - without a unit string ('s' for seconds). Test the formatting in some cases, - especially the case when no SI prefix is present, for values in [1, 1000). - - Should not raise exceptions. - """ - unitless = mticker.EngFormatter() - assert unitless(0.1) == u'100 m' - assert unitless(1) == u'1' - assert unitless(999.9) == u'999.9' - assert unitless(1001) == u'1.001 k' - - with_unit = mticker.EngFormatter(unit=u's') - assert with_unit(0.1) == u'100 ms' - assert with_unit(1) == u'1 s' - assert with_unit(999.9) == u'999.9 s' - assert with_unit(1001) == u'1.001 ks' + (100000, 1000000.0, '1e5'), + ] + + @pytest.mark.parametrize('value, domain, expected', pprint_data) + def test_pprint(self, value, domain, expected): + fmt = mticker.LogFormatter() + label = fmt.pprint_val(value, domain) + assert label == expected + + +class TestFormatStrFormatter(object): + def test_basic(self): + # test % style formatter + tmp_form = mticker.FormatStrFormatter('%05d') + assert '00002' == tmp_form(2) + + # test str.format() style formatter + tmp_form = mticker.StrMethodFormatter('{x:05d}') + assert '00002' == tmp_form(2) + + # test str.format() style formatter with `pos` + tmp_form = mticker.StrMethodFormatter('{x:03d}-{pos:02d}') + assert '002-01' == tmp_form(2, 1) + + +class TestPercentFormatter(object): + percent_data = [ + # Check explicitly set decimals over different intervals and values + (100, 0, '%', 120, 100, '120%'), + (100, 0, '%', 100, 90, '100%'), + (100, 0, '%', 90, 50, '90%'), + (100, 0, '%', 1.7, 40, '2%'), + (100, 1, '%', 90.0, 100, '90.0%'), + (100, 1, '%', 80.1, 90, '80.1%'), + (100, 1, '%', 70.23, 50, '70.2%'), + # 60.554 instead of 60.55: see https://bugs.python.org/issue5118 + (100, 1, '%', 60.554, 40, '60.6%'), + # Check auto decimals over different intervals and values + (100, None, '%', 95, 1, '95.00%'), + (1.0, None, '%', 3, 6, '300%'), + (17.0, None, '%', 1, 8.5, '6%'), + (17.0, None, '%', 1, 8.4, '5.9%'), + (5, None, '%', -100, 0.000001, '-2000.00000%'), + # Check percent symbol + (1.0, 2, None, 1.2, 100, '120.00'), + (75, 3, '', 50, 100, '66.667'), + (42, None, '^^Foobar$$', 21, 12, '50.0^^Foobar$$'), + ] + + percent_ids = [ + # Check explicitly set decimals over different intervals and values + 'decimals=0, x>100%', + 'decimals=0, x=100%', + 'decimals=0, x<100%', + 'decimals=0, x<0%', + 'decimals=1, x>100%', + 'decimals=1, x=100%', + 'decimals=1, x<100%', + 'decimals=1, x<0%', + # Check auto decimals over different intervals and values + 'autodecimal, x<100%, display_range=1', + 'autodecimal, x>100%, display_range=6 (custom xmax test)', + 'autodecimal, x<100%, display_range=8.5 (autodecimal test 1)', + 'autodecimal, x<100%, display_range=8.4 (autodecimal test 2)', + 'autodecimal, x<-100%, display_range=1e-6 (tiny display range)', + # Check percent symbol + 'None as percent symbol', + 'Empty percent symbol', + 'Custom percent symbol', + ] + + @pytest.mark.parametrize( + 'xmax, decimals, symbol, x, display_range, expected', + percent_data, ids=percent_ids) + def test_percentformatter(self, xmax, decimals, symbol, + x, display_range, expected): + formatter = mticker.PercentFormatter(xmax, decimals, symbol) + assert formatter.format_pct(x, display_range) == expected + + +class TestEngFormatter(object): + format_data = [ + ('', 0.1, u'100 m'), + ('', 1, u'1'), + ('', 999.9, u'999.9'), + ('', 1001, u'1.001 k'), + (u's', 0.1, u'100 ms'), + (u's', 1, u'1 s'), + (u's', 999.9, u'999.9 s'), + (u's', 1001, u'1.001 ks'), + ] + + @pytest.mark.parametrize('unit, input, expected', format_data) + def test_formatting(self, unit, input, expected): + """ + Test the formatting of EngFormatter with some inputs, against + instances with and without units. Cases focus on when no SI + prefix is present, for values in [1, 1000). + """ + fmt = mticker.EngFormatter(unit) + assert fmt(input) == expected diff --git a/lib/matplotlib/ticker.py b/lib/matplotlib/ticker.py index 34120bad6716..5b5f0de93974 100644 --- a/lib/matplotlib/ticker.py +++ b/lib/matplotlib/ticker.py @@ -3,26 +3,23 @@ ============================ This module contains classes to support completely configurable tick -locating and formatting. Although the locators know nothing about major +locating and formatting. Although the locators know nothing about major or minor ticks, they are used by the Axis class to support major and -minor tick locating and formatting. Generic tick locators and +minor tick locating and formatting. Generic tick locators and formatters are provided, as well as domain specific custom ones. - Default Formatter ----------------- -The default formatter identifies when the x-data being -plotted is a small range on top of a large off set. To -reduce the chances that the ticklabels overlap the ticks -are labeled as deltas from a fixed offset. For example:: +The default formatter identifies when the x-data being plotted is a +small range on top of a large off set. To reduce the chances that the +ticklabels overlap the ticks are labeled as deltas from a fixed offset. +For example:: ax.plot(np.arange(2000, 2010), range(10)) -will have tick of 0-9 with an offset of +2e3. If this -is not desired turn off the use of the offset on the default -formatter:: - +will have tick of 0-9 with an offset of +2e3. If this is not desired +turn off the use of the offset on the default formatter:: ax.get_xaxis().get_major_formatter().set_useOffset(False) @@ -32,11 +29,11 @@ Tick locating ------------- -The Locator class is the base class for all tick locators. The locators +The Locator class is the base class for all tick locators. The locators handle autoscaling of the view limits based on the data limits, and the -choosing of tick locations. A useful semi-automatic tick locator is -MultipleLocator. You initialize this with a base, e.g., 10, and it -picks axis limits and ticks that are multiples of your base. +choosing of tick locations. A useful semi-automatic tick locator is +`MultipleLocator`. It is initialized with a base, e.g., 10, and it picks +axis limits and ticks that are multiples of that base. The Locator subclasses defined here are @@ -61,8 +58,8 @@ inside the limits :class:`MultipleLocator` - ticks and range are a multiple of base; - either integer or float + ticks and range are a multiple of base; either integer or float + :class:`OldAutoLocator` choose a MultipleLocator and dyamically reassign it for intelligent ticking during navigation @@ -76,7 +73,7 @@ :class:`AutoMinorLocator` locator for minor ticks when the axis is linear and the - major ticks are uniformly spaced. It subdivides the major + major ticks are uniformly spaced. It subdivides the major tick interval into a specified number of minor intervals, defaulting to 4 or 5 depending on the major interval. @@ -87,13 +84,13 @@ There are a number of locators specialized for date locations - see the dates module -You can define your own locator by deriving from Locator. You must -override the __call__ method, which returns a sequence of locations, +You can define your own locator by deriving from Locator. You must +override the ``__call__`` method, which returns a sequence of locations, and you will probably want to override the autoscale method to set the view limits from the data limits. If you want to override the default locator, use one of the above or a -custom locator and pass it to the x or y axis instance. The relevant +custom locator and pass it to the x or y axis instance. The relevant methods are:: ax.xaxis.set_major_locator( xmajorLocator ) @@ -107,7 +104,7 @@ Tick formatting --------------- -Tick formatting is controlled by classes derived from Formatter. The +Tick formatting is controlled by classes derived from Formatter. The formatter operates on a single tick value and returns a string to the axis. @@ -155,7 +152,7 @@ Format labels as a percentage You can derive your own formatter from the Formatter base class by -simply overriding the ``__call__`` method. The formatter class has +simply overriding the ``__call__`` method. The formatter class has access to the axis view and data limits. To control the major and minor tick label formats, use one of the @@ -167,7 +164,7 @@ ax.yaxis.set_minor_formatter( yminorFormatter ) See :ref:`pylab_examples-major_minor_demo1` for an example of setting -major and minor ticks. See the :mod:`matplotlib.dates` module for +major and minor ticks. See the :mod:`matplotlib.dates` module for more information and examples of using date locators and formatters. """ pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy