From 5a3a8827b685c49853f4bedb9484d8ef4fae9c98 Mon Sep 17 00:00:00 2001 From: Herbert Kruitbosch Date: Wed, 11 May 2016 14:23:59 +0200 Subject: [PATCH 1/8] Added an {figure,.pyplot}.encode_as feature to encode a figure as a bytestring (not writing it to file), which can be practical in combination with the base64-package. Also addded a {figure,pyplot}.subplots_iterator which returns an iterator over subplots, which can be practical in for example ipynb's, where one wants to make many graphs and likes them to be 3 (or 5 or whatever) on a line. --- lib/matplotlib/__init__.py | 8 +- lib/matplotlib/figure.py | 38 +- lib/matplotlib/pyplot.py | 30 + lib/matplotlib/testing/decorators.py | 2 +- lib/matplotlib/tests/__init__.py | 1 + .../subplots_offset_text.pdf | Bin 0 -> 9208 bytes .../subplots_offset_text.png | Bin 0 -> 35299 bytes .../subplots_offset_text.svg | 1774 +++++++++++++++++ .../tests/test_subplots_iterator.py | 149 ++ setupext.py | 1 + 10 files changed, 2000 insertions(+), 3 deletions(-) create mode 100644 lib/matplotlib/tests/baseline_images/test_subplots_iterator/subplots_offset_text.pdf create mode 100644 lib/matplotlib/tests/baseline_images/test_subplots_iterator/subplots_offset_text.png create mode 100644 lib/matplotlib/tests/baseline_images/test_subplots_iterator/subplots_offset_text.svg create mode 100644 lib/matplotlib/tests/test_subplots_iterator.py diff --git a/lib/matplotlib/__init__.py b/lib/matplotlib/__init__.py index 63698180788a..2542973f5c63 100644 --- a/lib/matplotlib/__init__.py +++ b/lib/matplotlib/__init__.py @@ -1513,6 +1513,7 @@ def _jupyter_nbextension_paths(): 'matplotlib.tests.test_streamplot', 'matplotlib.tests.test_style', 'matplotlib.tests.test_subplots', + 'matplotlib.tests.test_subplots_iterator', 'matplotlib.tests.test_table', 'matplotlib.tests.test_text', 'matplotlib.tests.test_texmanager', @@ -1553,7 +1554,12 @@ def _init_tests(): warnings.warn( "matplotlib is not built with the correct FreeType version to run " "tests. Set local_freetype=True in setup.cfg and rebuild. " - "Expect many image comparison failures below.") + "Expect many image comparison failures below. " + "Expected {0} != found {1}".format( + ft2font.__freetype_version__, + LOCAL_FREETYPE_VERSION + ) + ) try: import nose diff --git a/lib/matplotlib/figure.py b/lib/matplotlib/figure.py index 407478052e4d..0249e685482f 100644 --- a/lib/matplotlib/figure.py +++ b/lib/matplotlib/figure.py @@ -49,6 +49,8 @@ TransformedBbox) from matplotlib.backend_bases import NonGuiException +import io + docstring.interpd.update(projection_names=get_projection_names()) @@ -1082,7 +1084,7 @@ def subplots(self, nrows=1, ncols=1, sharex=False, sharey=False, -------- pyplot.subplots : pyplot API; docstring includes examples. """ - + # for backwards compatibility if isinstance(sharex, bool): sharex = "all" if sharex else "none" @@ -1144,6 +1146,29 @@ def subplots(self, nrows=1, ncols=1, sharex=False, sharey=False, # Returned axis array will be always 2-d, even if nrows=ncols=1. return axarr + + def subplots_iterator(self, nrows=1, ncols=1, show_in_between=False, + sharex=False, sharey=False, squeeze=True, + subplot_kw=None, gridspec_kw=None): + """ Iteratively yields the axis object of a rows x cols subplot and creates new subplots when needed""" + while True: + axes = self.subplots( + nrows=nrows, + ncols=ncols, + sharex=sharex, + sharey=sharey, + squeeze=False, + subplot_kw=subplot_kw, + gridspec_kw=gridspec_kw + ) + assert axes.shape == (nrows, ncols), "Matplotlib panic: the returned shape of subplots() is not what was expected: {0} != {1}".format(axes.shape, (nrows, ncols)) + for row in range(nrows): + for col in range(ncols): + yield axes[row, col] + if show_in_between: + self.show(block=False) + + def __remove_ax(self, ax): def _reset_loc_form(axis): axis.set_major_formatter(axis.get_major_formatter()) @@ -1673,6 +1698,17 @@ def savefig(self, *args, **kwargs): ax.patch.set_facecolor(cc[0]) ax.patch.set_edgecolor(cc[1]) + def encode_as(self, **kwargs): + """ Equivalent of savefig, but does not store to a file, but returns a bytestring + using io.BytesIO. All kwargs are passed to savefig.""" + assert 'format' in kwargs, "Make sure to specify the format" + assert 'fname' not in kwargs, "Do not provide a filename, this method returns a bytestring and does not write to a file" + + in_memory_file = io.BytesIO() + self.savefig(in_memory_file, **kwargs) + in_memory_file.seek(0) + return in_memory_file.getvalue() + @docstring.dedent_interpd def colorbar(self, mappable, cax=None, ax=None, use_gridspec=True, **kw): """ diff --git a/lib/matplotlib/pyplot.py b/lib/matplotlib/pyplot.py index c195804daadf..03cbe8b0144b 100644 --- a/lib/matplotlib/pyplot.py +++ b/lib/matplotlib/pyplot.py @@ -21,6 +21,7 @@ from matplotlib.externals import six import sys +import io import warnings import types @@ -688,6 +689,18 @@ def savefig(*args, **kwargs): return res + +def encode_as(**kwargs): + """ Equivalent of savefig, but does not store to a file, but returns a bytestring + using io.BytesIO. All kwargs are passed to savefig.""" + assert 'format' in kwargs, "Make sure to specify the format" + assert 'fname' not in kwargs, "Do not provide a filename, this function returns a bytestring and does not write to a file" + + in_memory_file = io.BytesIO() + savefig(in_memory_file, **kwargs) + in_memory_file.seek(0) + return in_memory_file.getvalue() + @docstring.copy_dedent(Figure.ginput) def ginput(*args, **kwargs): """ @@ -1146,6 +1159,23 @@ def subplots(nrows=1, ncols=1, sharex=False, sharey=False, squeeze=True, gridspec_kw=gridspec_kw) return fig, axs +def subplots_iterator(nrows=1, ncols=1, show_in_between=False, sharex=False, + sharey=False, squeeze=True, subplot_kw=None, + gridspec_kw=None, **fig_kw): + """ Iteratively yields the axis object of a rows x cols subplot and creates new subplots when needed""" + for axis in ( + figure(**fig_kw).subplots_iterator( + nrows=nrows, + ncols=ncols, + sharex=sharex, + sharey=sharey, + squeeze=squeeze, + subplot_kw=subplot_kw, + gridspec_kw=gridspec_kw + ) + ): + yield axis + def subplot2grid(shape, loc, rowspan=1, colspan=1, fig=None, **kwargs): """ diff --git a/lib/matplotlib/testing/decorators.py b/lib/matplotlib/testing/decorators.py index f61b13194700..4a1d0fce18d3 100644 --- a/lib/matplotlib/testing/decorators.py +++ b/lib/matplotlib/testing/decorators.py @@ -232,7 +232,7 @@ def test(self): shutil.copyfile(orig_expected_fname, expected_fname) else: will_fail = True - fail_msg = 'Do not have baseline image %s' % expected_fname + fail_msg = 'Do not have baseline image {0} because this file does not exist: {1}'.format(expected_fname, orig_expected_fname) @knownfailureif( will_fail, fail_msg, diff --git a/lib/matplotlib/tests/__init__.py b/lib/matplotlib/tests/__init__.py index 354d9e8a23b8..cd2dbd9d796e 100644 --- a/lib/matplotlib/tests/__init__.py +++ b/lib/matplotlib/tests/__init__.py @@ -10,6 +10,7 @@ _multiprocess_can_split_ = True +import pyparsing; # Check that the test directories exist if not os.path.exists(os.path.join( diff --git a/lib/matplotlib/tests/baseline_images/test_subplots_iterator/subplots_offset_text.pdf b/lib/matplotlib/tests/baseline_images/test_subplots_iterator/subplots_offset_text.pdf new file mode 100644 index 0000000000000000000000000000000000000000..5fdc39730c4f81fc248f175698d540c471faee28 GIT binary patch literal 9208 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 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/test_subplots_iterator.py b/lib/matplotlib/tests/test_subplots_iterator.py new file mode 100644 index 000000000000..26cb10c50448 --- /dev/null +++ b/lib/matplotlib/tests/test_subplots_iterator.py @@ -0,0 +1,149 @@ +from __future__ import (absolute_import, division, print_function, + unicode_literals) + +import warnings +from matplotlib.externals import six +from matplotlib.externals.six.moves import xrange + +import numpy +import matplotlib.pyplot as plt +from matplotlib.testing.decorators import image_comparison, cleanup + +from nose.tools import assert_raises + + +def check_shared(axs, x_shared, y_shared): + """ + x_shared and y_shared are n x n boolean matrices; entry (i, j) indicates + whether the x (or y) axes of subplots i and j should be shared. + """ + shared = [axs[0]._shared_x_axes, axs[0]._shared_y_axes] + for (i1, ax1), (i2, ax2), (i3, (name, shared)) in zip( + enumerate(axs), + enumerate(axs), + enumerate(zip("xy", [x_shared, y_shared]))): + if i2 <= i1: + continue + assert shared[i3].joined(ax1, ax2) == shared[i1, i2], \ + "axes %i and %i incorrectly %ssharing %s axis" % ( + i1, i2, "not " if shared[i1, i2] else "", name) + + +def check_visible(axs, x_visible, y_visible): + tostr = lambda v: "invisible" if v else "visible" + for (ax, vx, vy) in zip(axs, x_visible, y_visible): + for l in ax.get_xticklabels() + [ax.get_xaxis().offsetText]: + assert l.get_visible() == vx, \ + "X axis was incorrectly %s" % (tostr(vx)) + for l in ax.get_yticklabels() + [ax.get_yaxis().offsetText]: + assert l.get_visible() == vy, \ + "Y axis was incorrectly %s" % (tostr(vy)) + + +@cleanup +def test_shared(): + rdim = (4, 4, 2) + share = { + 'all': numpy.ones(rdim[:2], dtype=bool), + 'none': numpy.zeros(rdim[:2], dtype=bool), + 'row': numpy.array([ + [False, True, False, False], + [True, False, False, False], + [False, False, False, True], + [False, False, True, False]]), + 'col': numpy.array([ + [False, False, True, False], + [False, False, False, True], + [True, False, False, False], + [False, True, False, False]]), + } + visible = { + 'x': { + 'all': [False, False, True, True], + 'col': [False, False, True, True], + 'row': [True] * 4, + 'none': [True] * 4, + False: [True] * 4, + True: [False, False, True, True], + }, + 'y': { + 'all': [True, False, True, False], + 'col': [True] * 4, + 'row': [True, False, True, False], + 'none': [True] * 4, + False: [True] * 4, + True: [True, False, True, False], + }, + } + share[False] = share['none'] + share[True] = share['all'] + + # test default + axs = [axis for axis, _ in zip(plt.subplots_iterator(2, 2), range(4))] + check_shared(axs, share['none'], share['none']) + plt.close(axs[0].figure) + + # test all option combinations + ops = [False, True, 'all', 'none', 'row', 'col'] + for xo in ops: + for yo in ops: + axs = [axis for axis, _ in zip(plt.subplots_iterator(2, 2, sharex=xo, sharey=yo), range(4))] + check_shared(axs, share[xo], share[yo]) + check_visible(axs, visible['x'][xo], visible['y'][yo]) + plt.close(axs[0].figure) + + # test label_outer + axs = [axis for axis, _ in zip(plt.subplots_iterator(2, 2, sharex=True, sharey=True), range(4))] + for ax in axs: + ax.label_outer() + check_visible(axs, [False, False, True, True], [True, False, True, False]) + + + +def test_exceptions(): + # TODO should this test more options? + assert_raises(ValueError, lambda: next(plt.subplots_iterator(2, 2, sharex='blah')) ) + assert_raises(ValueError, lambda: next(plt.subplots_iterator(2, 2, sharey='blah')) ) + # We filter warnings in this test which are genuine since + # the point of this test is to ensure that this raises. + with warnings.catch_warnings(): + warnings.filterwarnings('ignore', + message='.*sharex\ argument\ to\ subplots', + category=UserWarning) + assert_raises(ValueError, lambda: next(plt.subplots_iterator(2, 2, sharex=-1)) ) + assert_raises(ValueError, lambda: next(plt.subplots_iterator(2, 2, sharex=0)) ) + assert_raises(ValueError, lambda: next(plt.subplots_iterator(2, 2, sharex=5)) ) + + +@image_comparison(baseline_images=['subplots_offset_text'], remove_text=False) +def test_subplots_offsettext(): + x = numpy.arange(0, 1e10, 1e9) + y = numpy.arange(0, 100, 10)+1e4 + it = plt.subplots_iterator(2, 2, sharex='col', sharey='all') + next(it).plot(x, x) + next(it).plot(y, x) + next(it).plot(x, x) + next(it).plot(y, x) + +def test_multiple_figures(): + x = numpy.arange(0, 1e10, 1e9) + y = numpy.arange(0, 100, 10)+1e4 + it = plt.subplots_iterator(2, 2, sharex='col', sharey='all') + for _ in range(12): + next(it).plot(x, y) + +@cleanup +def test_subplots(): + # things to test + # - are axes actually shared? + # - are tickmarks correctly hidden? + test_shared() + # - are exceptions thrown correctly + test_exceptions() + # - no problem to get more axes than nrows x ncols + test_multiple_figures() + + +if __name__ == "__main__": + import nose + nose.runmodule(argv=['-s', '--with-doctest'], exit=False) diff --git a/setupext.py b/setupext.py index 417748be5299..e2c6ea5f6b0d 100755 --- a/setupext.py +++ b/setupext.py @@ -15,6 +15,7 @@ import shutil import versioneer +print(123) PY3min = (sys.version_info[0] >= 3) PY32min = (PY3min and sys.version_info[1] >= 2 or sys.version_info[0] > 3) From 977be99e706bf6365c69a49f19da3b73d09a8142 Mon Sep 17 00:00:00 2001 From: Herbert Kruitbosch Date: Wed, 11 May 2016 15:26:57 +0200 Subject: [PATCH 2/8] fixed some PR comments --- lib/matplotlib/__init__.py | 7 +- lib/matplotlib/figure.py | 13 ++-- lib/matplotlib/pyplot.py | 16 +++-- lib/matplotlib/tests/__init__.py | 2 - .../tests/test_subplots_iterator.py | 72 ++++++++++--------- setupext.py | 1 - 6 files changed, 56 insertions(+), 55 deletions(-) diff --git a/lib/matplotlib/__init__.py b/lib/matplotlib/__init__.py index 2542973f5c63..6f4166bf1e2c 100644 --- a/lib/matplotlib/__init__.py +++ b/lib/matplotlib/__init__.py @@ -1554,12 +1554,7 @@ def _init_tests(): warnings.warn( "matplotlib is not built with the correct FreeType version to run " "tests. Set local_freetype=True in setup.cfg and rebuild. " - "Expect many image comparison failures below. " - "Expected {0} != found {1}".format( - ft2font.__freetype_version__, - LOCAL_FREETYPE_VERSION - ) - ) + "Expect many image comparison failures below.") try: import nose diff --git a/lib/matplotlib/figure.py b/lib/matplotlib/figure.py index 0249e685482f..a4df9021e6cd 100644 --- a/lib/matplotlib/figure.py +++ b/lib/matplotlib/figure.py @@ -1084,7 +1084,6 @@ def subplots(self, nrows=1, ncols=1, sharex=False, sharey=False, -------- pyplot.subplots : pyplot API; docstring includes examples. """ - # for backwards compatibility if isinstance(sharex, bool): sharex = "all" if sharex else "none" @@ -1146,11 +1145,11 @@ def subplots(self, nrows=1, ncols=1, sharex=False, sharey=False, # Returned axis array will be always 2-d, even if nrows=ncols=1. return axarr - def subplots_iterator(self, nrows=1, ncols=1, show_in_between=False, sharex=False, sharey=False, squeeze=True, subplot_kw=None, gridspec_kw=None): - """ Iteratively yields the axis object of a rows x cols subplot and creates new subplots when needed""" + """ Iteratively yields the axis object of a rows x cols subplot and + creates new subplots when needed""" while True: axes = self.subplots( nrows=nrows, @@ -1161,14 +1160,18 @@ def subplots_iterator(self, nrows=1, ncols=1, show_in_between=False, subplot_kw=subplot_kw, gridspec_kw=gridspec_kw ) - assert axes.shape == (nrows, ncols), "Matplotlib panic: the returned shape of subplots() is not what was expected: {0} != {1}".format(axes.shape, (nrows, ncols)) + if axes.shape != (nrows, ncols): + raise AssertionError("Matplotlib panic: the returned shape of" + "subplots() is not what was expected:" + "{0} != {1}" + .format(axes.shape, (nrows, ncols)) + ) for row in range(nrows): for col in range(ncols): yield axes[row, col] if show_in_between: self.show(block=False) - def __remove_ax(self, ax): def _reset_loc_form(axis): axis.set_major_formatter(axis.get_major_formatter()) diff --git a/lib/matplotlib/pyplot.py b/lib/matplotlib/pyplot.py index 03cbe8b0144b..23a6c7a26246 100644 --- a/lib/matplotlib/pyplot.py +++ b/lib/matplotlib/pyplot.py @@ -67,6 +67,7 @@ LinearLocator, LogLocator, AutoLocator, MultipleLocator,\ MaxNLocator from matplotlib.backends import pylab_setup +from argparse import ArgumentError ## Backend detection ## def _backend_selection(): @@ -689,18 +690,21 @@ def savefig(*args, **kwargs): return res - def encode_as(**kwargs): - """ Equivalent of savefig, but does not store to a file, but returns a bytestring - using io.BytesIO. All kwargs are passed to savefig.""" - assert 'format' in kwargs, "Make sure to specify the format" - assert 'fname' not in kwargs, "Do not provide a filename, this function returns a bytestring and does not write to a file" - + """ Equivalent of savefig, but does not store to a file, but returns a + bytestring using io.BytesIO. All kwargs are passed to savefig.""" + if 'format' not in kwargs: + raise ArgumentError("Make sure to specify the format") + if 'fname' in kwargs: + raise ArgumentError("Do not provide a filename, this function returns " + "a bytestring and does not write to a file") + in_memory_file = io.BytesIO() savefig(in_memory_file, **kwargs) in_memory_file.seek(0) return in_memory_file.getvalue() + @docstring.copy_dedent(Figure.ginput) def ginput(*args, **kwargs): """ diff --git a/lib/matplotlib/tests/__init__.py b/lib/matplotlib/tests/__init__.py index cd2dbd9d796e..55f04e53c35a 100644 --- a/lib/matplotlib/tests/__init__.py +++ b/lib/matplotlib/tests/__init__.py @@ -10,8 +10,6 @@ _multiprocess_can_split_ = True -import pyparsing; - # Check that the test directories exist if not os.path.exists(os.path.join( os.path.dirname(__file__), 'baseline_images')): diff --git a/lib/matplotlib/tests/test_subplots_iterator.py b/lib/matplotlib/tests/test_subplots_iterator.py index 26cb10c50448..4c4d0251531e 100644 --- a/lib/matplotlib/tests/test_subplots_iterator.py +++ b/lib/matplotlib/tests/test_subplots_iterator.py @@ -34,47 +34,47 @@ def check_visible(axs, x_visible, y_visible): for (ax, vx, vy) in zip(axs, x_visible, y_visible): for l in ax.get_xticklabels() + [ax.get_xaxis().offsetText]: assert l.get_visible() == vx, \ - "X axis was incorrectly %s" % (tostr(vx)) + "X axis was incorrectly %s" % (tostr(vx)) for l in ax.get_yticklabels() + [ax.get_yaxis().offsetText]: assert l.get_visible() == vy, \ - "Y axis was incorrectly %s" % (tostr(vy)) + "Y axis was incorrectly %s" % (tostr(vy)) @cleanup def test_shared(): rdim = (4, 4, 2) share = { - 'all': numpy.ones(rdim[:2], dtype=bool), - 'none': numpy.zeros(rdim[:2], dtype=bool), - 'row': numpy.array([ - [False, True, False, False], - [True, False, False, False], - [False, False, False, True], - [False, False, True, False]]), - 'col': numpy.array([ - [False, False, True, False], - [False, False, False, True], - [True, False, False, False], - [False, True, False, False]]), - } + 'all': numpy.ones(rdim[:2], dtype=bool), + 'none': numpy.zeros(rdim[:2], dtype=bool), + 'row': numpy.array([ + [False, True, False, False], + [True, False, False, False], + [False, False, False, True], + [False, False, True, False]]), + 'col': numpy.array([ + [False, False, True, False], + [False, False, False, True], + [True, False, False, False], + [False, True, False, False]]), + } visible = { - 'x': { - 'all': [False, False, True, True], - 'col': [False, False, True, True], - 'row': [True] * 4, - 'none': [True] * 4, - False: [True] * 4, - True: [False, False, True, True], - }, - 'y': { - 'all': [True, False, True, False], - 'col': [True] * 4, - 'row': [True, False, True, False], - 'none': [True] * 4, - False: [True] * 4, - True: [True, False, True, False], - }, - } + 'x': { + 'all': [False, False, True, True], + 'col': [False, False, True, True], + 'row': [True] * 4, + 'none': [True] * 4, + False: [True] * 4, + True: [False, False, True, True], + }, + 'y': { + 'all': [True, False, True, False], + 'col': [True] * 4, + 'row': [True, False, True, False], + 'none': [True] * 4, + False: [True] * 4, + True: [True, False, True, False], + }, + } share[False] = share['none'] share[True] = share['all'] @@ -99,7 +99,6 @@ def test_shared(): check_visible(axs, [False, False, True, True], [True, False, True, False]) - def test_exceptions(): # TODO should this test more options? assert_raises(ValueError, lambda: next(plt.subplots_iterator(2, 2, sharex='blah')) ) @@ -125,13 +124,16 @@ def test_subplots_offsettext(): next(it).plot(x, x) next(it).plot(y, x) + +@cleanup def test_multiple_figures(): x = numpy.arange(0, 1e10, 1e9) y = numpy.arange(0, 100, 10)+1e4 it = plt.subplots_iterator(2, 2, sharex='col', sharey='all') for _ in range(12): next(it).plot(x, y) - + + @cleanup def test_subplots(): # things to test @@ -140,7 +142,7 @@ def test_subplots(): test_shared() # - are exceptions thrown correctly test_exceptions() - # - no problem to get more axes than nrows x ncols + # - no problem to get more axes than nrows x ncols test_multiple_figures() diff --git a/setupext.py b/setupext.py index e2c6ea5f6b0d..417748be5299 100755 --- a/setupext.py +++ b/setupext.py @@ -15,7 +15,6 @@ import shutil import versioneer -print(123) PY3min = (sys.version_info[0] >= 3) PY32min = (PY3min and sys.version_info[1] >= 2 or sys.version_info[0] > 3) From d6456f564bff7da596df0a1f60eab4d675d0b23a Mon Sep 17 00:00:00 2001 From: Herbert Kruitbosch Date: Wed, 11 May 2016 15:28:09 +0200 Subject: [PATCH 3/8] check freetype version also specifies what is wrong --- lib/matplotlib/__init__.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/matplotlib/__init__.py b/lib/matplotlib/__init__.py index 63698180788a..bc57dca6aa44 100644 --- a/lib/matplotlib/__init__.py +++ b/lib/matplotlib/__init__.py @@ -1553,7 +1553,12 @@ def _init_tests(): warnings.warn( "matplotlib is not built with the correct FreeType version to run " "tests. Set local_freetype=True in setup.cfg and rebuild. " - "Expect many image comparison failures below.") + "Expect many image comparison failures below. " + "Expected {0} != found {1}".format( + ft2font.__freetype_version__, + LOCAL_FREETYPE_VERSION + ) + ) try: import nose From f4de6df162fa0589fd7e91c9b97ed4ee939beb86 Mon Sep 17 00:00:00 2001 From: Herbert Kruitbosch Date: Tue, 19 Jul 2016 15:35:50 +0200 Subject: [PATCH 4/8] decorated freetype error message with more information --- lib/matplotlib/__init__.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/matplotlib/__init__.py b/lib/matplotlib/__init__.py index bc57dca6aa44..1dc0347d1438 100644 --- a/lib/matplotlib/__init__.py +++ b/lib/matplotlib/__init__.py @@ -1554,9 +1554,12 @@ def _init_tests(): "matplotlib is not built with the correct FreeType version to run " "tests. Set local_freetype=True in setup.cfg and rebuild. " "Expect many image comparison failures below. " - "Expected {0} != found {1}".format( + "Expected freetype version {0}. " + "Found freetype version {1}." + "Freetype build type is {2}local".format( ft2font.__freetype_version__, - LOCAL_FREETYPE_VERSION + LOCAL_FREETYPE_VERSION, + "" if ft2font.__freetype_build_type__ != 'local' else "not " ) ) From 2c5b61eadd25769398d321b1e82d747bba2b3622 Mon Sep 17 00:00:00 2001 From: Herbert Kruitbosch Date: Tue, 19 Jul 2016 15:38:35 +0200 Subject: [PATCH 5/8] fixed important !=/== typo --- lib/matplotlib/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/matplotlib/__init__.py b/lib/matplotlib/__init__.py index 1dc0347d1438..eef5b3a87629 100644 --- a/lib/matplotlib/__init__.py +++ b/lib/matplotlib/__init__.py @@ -1559,7 +1559,7 @@ def _init_tests(): "Freetype build type is {2}local".format( ft2font.__freetype_version__, LOCAL_FREETYPE_VERSION, - "" if ft2font.__freetype_build_type__ != 'local' else "not " + "" if ft2font.__freetype_build_type__ == 'local' else "not " ) ) From 2400b3f009f37a362abcc0435311033d29ecb962 Mon Sep 17 00:00:00 2001 From: Herbert Kruitbosch Date: Tue, 19 Jul 2016 17:02:19 +0200 Subject: [PATCH 6/8] removed encode_as, since not really part of the PR. --- lib/matplotlib/figure.py | 11 ----------- lib/matplotlib/pyplot.py | 15 --------------- 2 files changed, 26 deletions(-) diff --git a/lib/matplotlib/figure.py b/lib/matplotlib/figure.py index a4df9021e6cd..dfd6f1d16a5b 100644 --- a/lib/matplotlib/figure.py +++ b/lib/matplotlib/figure.py @@ -1701,17 +1701,6 @@ def savefig(self, *args, **kwargs): ax.patch.set_facecolor(cc[0]) ax.patch.set_edgecolor(cc[1]) - def encode_as(self, **kwargs): - """ Equivalent of savefig, but does not store to a file, but returns a bytestring - using io.BytesIO. All kwargs are passed to savefig.""" - assert 'format' in kwargs, "Make sure to specify the format" - assert 'fname' not in kwargs, "Do not provide a filename, this method returns a bytestring and does not write to a file" - - in_memory_file = io.BytesIO() - self.savefig(in_memory_file, **kwargs) - in_memory_file.seek(0) - return in_memory_file.getvalue() - @docstring.dedent_interpd def colorbar(self, mappable, cax=None, ax=None, use_gridspec=True, **kw): """ diff --git a/lib/matplotlib/pyplot.py b/lib/matplotlib/pyplot.py index 23a6c7a26246..ec42ca123f7d 100644 --- a/lib/matplotlib/pyplot.py +++ b/lib/matplotlib/pyplot.py @@ -690,21 +690,6 @@ def savefig(*args, **kwargs): return res -def encode_as(**kwargs): - """ Equivalent of savefig, but does not store to a file, but returns a - bytestring using io.BytesIO. All kwargs are passed to savefig.""" - if 'format' not in kwargs: - raise ArgumentError("Make sure to specify the format") - if 'fname' in kwargs: - raise ArgumentError("Do not provide a filename, this function returns " - "a bytestring and does not write to a file") - - in_memory_file = io.BytesIO() - savefig(in_memory_file, **kwargs) - in_memory_file.seek(0) - return in_memory_file.getvalue() - - @docstring.copy_dedent(Figure.ginput) def ginput(*args, **kwargs): """ From b97e741d9d688418c37d6e345cfa92ae4bf407d7 Mon Sep 17 00:00:00 2001 From: Herbert Kruitbosch Date: Tue, 19 Jul 2016 17:11:09 +0200 Subject: [PATCH 7/8] removed subplots_iterator, as not really part of this PR --- lib/matplotlib/__init__.py | 1 - lib/matplotlib/figure.py | 27 - lib/matplotlib/pyplot.py | 18 - .../subplots_offset_text.pdf | Bin 9208 -> 0 bytes .../subplots_offset_text.png | Bin 35299 -> 0 bytes .../subplots_offset_text.svg | 1774 ----------------- .../tests/test_subplots_iterator.py | 151 -- 7 files changed, 1971 deletions(-) delete mode 100644 lib/matplotlib/tests/baseline_images/test_subplots_iterator/subplots_offset_text.pdf delete mode 100644 lib/matplotlib/tests/baseline_images/test_subplots_iterator/subplots_offset_text.png delete mode 100644 lib/matplotlib/tests/baseline_images/test_subplots_iterator/subplots_offset_text.svg delete mode 100644 lib/matplotlib/tests/test_subplots_iterator.py diff --git a/lib/matplotlib/__init__.py b/lib/matplotlib/__init__.py index c75f19e99c92..bb119ff10504 100644 --- a/lib/matplotlib/__init__.py +++ b/lib/matplotlib/__init__.py @@ -1530,7 +1530,6 @@ def _jupyter_nbextension_paths(): 'matplotlib.tests.test_streamplot', 'matplotlib.tests.test_style', 'matplotlib.tests.test_subplots', - 'matplotlib.tests.test_subplots_iterator', 'matplotlib.tests.test_table', 'matplotlib.tests.test_text', 'matplotlib.tests.test_texmanager', diff --git a/lib/matplotlib/figure.py b/lib/matplotlib/figure.py index b23b081375e5..ac6e5dca031e 100644 --- a/lib/matplotlib/figure.py +++ b/lib/matplotlib/figure.py @@ -1145,33 +1145,6 @@ def subplots(self, nrows=1, ncols=1, sharex=False, sharey=False, # Returned axis array will be always 2-d, even if nrows=ncols=1. return axarr - def subplots_iterator(self, nrows=1, ncols=1, show_in_between=False, - sharex=False, sharey=False, squeeze=True, - subplot_kw=None, gridspec_kw=None): - """ Iteratively yields the axis object of a rows x cols subplot and - creates new subplots when needed""" - while True: - axes = self.subplots( - nrows=nrows, - ncols=ncols, - sharex=sharex, - sharey=sharey, - squeeze=False, - subplot_kw=subplot_kw, - gridspec_kw=gridspec_kw - ) - if axes.shape != (nrows, ncols): - raise AssertionError("Matplotlib panic: the returned shape of" - "subplots() is not what was expected:" - "{0} != {1}" - .format(axes.shape, (nrows, ncols)) - ) - for row in range(nrows): - for col in range(ncols): - yield axes[row, col] - if show_in_between: - self.show(block=False) - def __remove_ax(self, ax): def _reset_loc_form(axis): axis.set_major_formatter(axis.get_major_formatter()) diff --git a/lib/matplotlib/pyplot.py b/lib/matplotlib/pyplot.py index e7d34a4fcdab..02ef9b0695e2 100644 --- a/lib/matplotlib/pyplot.py +++ b/lib/matplotlib/pyplot.py @@ -1156,24 +1156,6 @@ def subplots(nrows=1, ncols=1, sharex=False, sharey=False, squeeze=True, gridspec_kw=gridspec_kw) return fig, axs -def subplots_iterator(nrows=1, ncols=1, show_in_between=False, sharex=False, - sharey=False, squeeze=True, subplot_kw=None, - gridspec_kw=None, **fig_kw): - """ Iteratively yields the axis object of a rows x cols subplot and creates new subplots when needed""" - for axis in ( - figure(**fig_kw).subplots_iterator( - nrows=nrows, - ncols=ncols, - sharex=sharex, - sharey=sharey, - squeeze=squeeze, - subplot_kw=subplot_kw, - gridspec_kw=gridspec_kw - ) - ): - yield axis - - def subplot2grid(shape, loc, rowspan=1, colspan=1, fig=None, **kwargs): """ Create a subplot in a grid. The grid is specified by *shape*, at diff --git a/lib/matplotlib/tests/baseline_images/test_subplots_iterator/subplots_offset_text.pdf b/lib/matplotlib/tests/baseline_images/test_subplots_iterator/subplots_offset_text.pdf deleted file mode 100644 index 5fdc39730c4f81fc248f175698d540c471faee28..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9208 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 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/test_subplots_iterator.py b/lib/matplotlib/tests/test_subplots_iterator.py deleted file mode 100644 index 4c4d0251531e..000000000000 --- a/lib/matplotlib/tests/test_subplots_iterator.py +++ /dev/null @@ -1,151 +0,0 @@ -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -import warnings -from matplotlib.externals import six -from matplotlib.externals.six.moves import xrange - -import numpy -import matplotlib.pyplot as plt -from matplotlib.testing.decorators import image_comparison, cleanup - -from nose.tools import assert_raises - - -def check_shared(axs, x_shared, y_shared): - """ - x_shared and y_shared are n x n boolean matrices; entry (i, j) indicates - whether the x (or y) axes of subplots i and j should be shared. - """ - shared = [axs[0]._shared_x_axes, axs[0]._shared_y_axes] - for (i1, ax1), (i2, ax2), (i3, (name, shared)) in zip( - enumerate(axs), - enumerate(axs), - enumerate(zip("xy", [x_shared, y_shared]))): - if i2 <= i1: - continue - assert shared[i3].joined(ax1, ax2) == shared[i1, i2], \ - "axes %i and %i incorrectly %ssharing %s axis" % ( - i1, i2, "not " if shared[i1, i2] else "", name) - - -def check_visible(axs, x_visible, y_visible): - tostr = lambda v: "invisible" if v else "visible" - for (ax, vx, vy) in zip(axs, x_visible, y_visible): - for l in ax.get_xticklabels() + [ax.get_xaxis().offsetText]: - assert l.get_visible() == vx, \ - "X axis was incorrectly %s" % (tostr(vx)) - for l in ax.get_yticklabels() + [ax.get_yaxis().offsetText]: - assert l.get_visible() == vy, \ - "Y axis was incorrectly %s" % (tostr(vy)) - - -@cleanup -def test_shared(): - rdim = (4, 4, 2) - share = { - 'all': numpy.ones(rdim[:2], dtype=bool), - 'none': numpy.zeros(rdim[:2], dtype=bool), - 'row': numpy.array([ - [False, True, False, False], - [True, False, False, False], - [False, False, False, True], - [False, False, True, False]]), - 'col': numpy.array([ - [False, False, True, False], - [False, False, False, True], - [True, False, False, False], - [False, True, False, False]]), - } - visible = { - 'x': { - 'all': [False, False, True, True], - 'col': [False, False, True, True], - 'row': [True] * 4, - 'none': [True] * 4, - False: [True] * 4, - True: [False, False, True, True], - }, - 'y': { - 'all': [True, False, True, False], - 'col': [True] * 4, - 'row': [True, False, True, False], - 'none': [True] * 4, - False: [True] * 4, - True: [True, False, True, False], - }, - } - share[False] = share['none'] - share[True] = share['all'] - - # test default - axs = [axis for axis, _ in zip(plt.subplots_iterator(2, 2), range(4))] - check_shared(axs, share['none'], share['none']) - plt.close(axs[0].figure) - - # test all option combinations - ops = [False, True, 'all', 'none', 'row', 'col'] - for xo in ops: - for yo in ops: - axs = [axis for axis, _ in zip(plt.subplots_iterator(2, 2, sharex=xo, sharey=yo), range(4))] - check_shared(axs, share[xo], share[yo]) - check_visible(axs, visible['x'][xo], visible['y'][yo]) - plt.close(axs[0].figure) - - # test label_outer - axs = [axis for axis, _ in zip(plt.subplots_iterator(2, 2, sharex=True, sharey=True), range(4))] - for ax in axs: - ax.label_outer() - check_visible(axs, [False, False, True, True], [True, False, True, False]) - - -def test_exceptions(): - # TODO should this test more options? - assert_raises(ValueError, lambda: next(plt.subplots_iterator(2, 2, sharex='blah')) ) - assert_raises(ValueError, lambda: next(plt.subplots_iterator(2, 2, sharey='blah')) ) - # We filter warnings in this test which are genuine since - # the point of this test is to ensure that this raises. - with warnings.catch_warnings(): - warnings.filterwarnings('ignore', - message='.*sharex\ argument\ to\ subplots', - category=UserWarning) - assert_raises(ValueError, lambda: next(plt.subplots_iterator(2, 2, sharex=-1)) ) - assert_raises(ValueError, lambda: next(plt.subplots_iterator(2, 2, sharex=0)) ) - assert_raises(ValueError, lambda: next(plt.subplots_iterator(2, 2, sharex=5)) ) - - -@image_comparison(baseline_images=['subplots_offset_text'], remove_text=False) -def test_subplots_offsettext(): - x = numpy.arange(0, 1e10, 1e9) - y = numpy.arange(0, 100, 10)+1e4 - it = plt.subplots_iterator(2, 2, sharex='col', sharey='all') - next(it).plot(x, x) - next(it).plot(y, x) - next(it).plot(x, x) - next(it).plot(y, x) - - -@cleanup -def test_multiple_figures(): - x = numpy.arange(0, 1e10, 1e9) - y = numpy.arange(0, 100, 10)+1e4 - it = plt.subplots_iterator(2, 2, sharex='col', sharey='all') - for _ in range(12): - next(it).plot(x, y) - - -@cleanup -def test_subplots(): - # things to test - # - are axes actually shared? - # - are tickmarks correctly hidden? - test_shared() - # - are exceptions thrown correctly - test_exceptions() - # - no problem to get more axes than nrows x ncols - test_multiple_figures() - - -if __name__ == "__main__": - import nose - nose.runmodule(argv=['-s', '--with-doctest'], exit=False) From eef6b93d82a5099f30dc0271389bcfff85888ad5 Mon Sep 17 00:00:00 2001 From: Herbert Kruitbosch Date: Tue, 19 Jul 2016 17:15:21 +0200 Subject: [PATCH 8/8] inserted/removed unused blank lines for pep and removed unused imports --- lib/matplotlib/figure.py | 3 +-- lib/matplotlib/pyplot.py | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/matplotlib/figure.py b/lib/matplotlib/figure.py index ac6e5dca031e..89922fc61161 100644 --- a/lib/matplotlib/figure.py +++ b/lib/matplotlib/figure.py @@ -49,8 +49,6 @@ TransformedBbox) from matplotlib.backend_bases import NonGuiException -import io - docstring.interpd.update(projection_names=get_projection_names()) @@ -1084,6 +1082,7 @@ def subplots(self, nrows=1, ncols=1, sharex=False, sharey=False, -------- pyplot.subplots : pyplot API; docstring includes examples. """ + # for backwards compatibility if isinstance(sharex, bool): sharex = "all" if sharex else "none" diff --git a/lib/matplotlib/pyplot.py b/lib/matplotlib/pyplot.py index 02ef9b0695e2..2f57dd7e11e4 100644 --- a/lib/matplotlib/pyplot.py +++ b/lib/matplotlib/pyplot.py @@ -21,7 +21,6 @@ import six import sys -import io import warnings import types @@ -67,7 +66,6 @@ LinearLocator, LogLocator, AutoLocator, MultipleLocator,\ MaxNLocator from matplotlib.backends import pylab_setup -from argparse import ArgumentError ## Backend detection ## def _backend_selection(): @@ -1156,6 +1154,7 @@ def subplots(nrows=1, ncols=1, sharex=False, sharey=False, squeeze=True, gridspec_kw=gridspec_kw) return fig, axs + def subplot2grid(shape, loc, rowspan=1, colspan=1, fig=None, **kwargs): """ Create a subplot in a grid. The grid is specified by *shape*, at