diff --git a/CHANGELOG b/CHANGELOG index 30159e5fd4ad..7ec19419684b 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -6,10 +6,11 @@ 2013-01-16 Till Stensitzki added a baseline feature to stackplot +2013-01-09 Deprecated the cbook module in favor of a private, not publicly + documentation module utils. 2012-12-22 Added classes for interpolation within triangular grids (LinearTriInterpolator) and to find the triangles in which points lie (TrapezoidMapTriFinder) to matplotlib.tri module. - IMT - 2012-12-05 Added MatplotlibDeprecationWarning class for signaling deprecation. Matplotlib developers can use this class as follows: diff --git a/doc/api/api_changes.rst b/doc/api/api_changes.rst index 68f818b3ea68..e1497b0d09f0 100644 --- a/doc/api/api_changes.rst +++ b/doc/api/api_changes.rst @@ -26,6 +26,7 @@ Changes in 1.3.x * The `~matplotlib.mpl` module is now deprecated. Those who relied on this module should transition to simply using `import matplotlib as mpl`. +* The module ``cbook`` is deprecated and will be removed in 1.5.x. Changes in 1.2.x ================ diff --git a/doc/api/index.rst b/doc/api/index.rst index 768e255aa229..a132f42f97e4 100644 --- a/doc/api/index.rst +++ b/doc/api/index.rst @@ -21,7 +21,6 @@ axes_api.rst axis_api.rst index_backend_api.rst - cbook_api.rst cm_api.rst collections_api.rst colorbar_api.rst diff --git a/doc/devel/coding_guide.rst b/doc/devel/coding_guide.rst index 7273fb38313d..0baf30828631 100644 --- a/doc/devel/coding_guide.rst +++ b/doc/devel/coding_guide.rst @@ -48,7 +48,7 @@ Style import numpy.ma as ma import matplotlib as mpl from matplotlib import pyplot as plt - import matplotlib.cbook as cbook + import matplotlib.utils as utils import matplotlib.collections as mcol import matplotlib.patches as mpatches @@ -257,8 +257,8 @@ distributed with matplotlib in the `lib/matplotlib/mpl-data/sample_data/` directory. Then in your example code you can load it into a file handle with:: - import matplotlib.cbook as cbook - fh = cbook.get_sample_data('mydata.dat') + import matplotlib.utils as utils + fh = utils.get_sample_data('mydata.dat') .. _new-pyplot-function: diff --git a/doc/mpl_toolkits/axes_grid/figures/demo_colorbar_of_inset_axes.py b/doc/mpl_toolkits/axes_grid/figures/demo_colorbar_of_inset_axes.py index e4e708c6685a..1f73b46155d9 100644 --- a/doc/mpl_toolkits/axes_grid/figures/demo_colorbar_of_inset_axes.py +++ b/doc/mpl_toolkits/axes_grid/figures/demo_colorbar_of_inset_axes.py @@ -4,7 +4,7 @@ from mpl_toolkits.axes_grid.colorbar import colorbar def get_demo_image(): - from matplotlib.cbook import get_sample_data + from matplotlib.utils import get_sample_data import numpy as np f = get_sample_data("axes_grid/bivariate_normal.npy", asfileobj=False) z = np.load(f) diff --git a/doc/mpl_toolkits/axes_grid/figures/simple_rgb.py b/doc/mpl_toolkits/axes_grid/figures/simple_rgb.py index 14379d3b9d45..3161b4d36ff3 100644 --- a/doc/mpl_toolkits/axes_grid/figures/simple_rgb.py +++ b/doc/mpl_toolkits/axes_grid/figures/simple_rgb.py @@ -4,7 +4,7 @@ def get_demo_image(): import numpy as np - from matplotlib.cbook import get_sample_data + from matplotlib.utils import get_sample_data f = get_sample_data("axes_grid/bivariate_normal.npy", asfileobj=False) z = np.load(f) # z is a numpy array of 15x15 diff --git a/doc/users/recipes.rst b/doc/users/recipes.rst index 4c6d60dfa3b5..c155e80223f8 100644 --- a/doc/users/recipes.rst +++ b/doc/users/recipes.rst @@ -87,7 +87,7 @@ gracefully, and here are some tricks to help you work around them. We'll load up some sample date data which contains datetime.date objects in a numpy record array:: - In [63]: datafile = cbook.get_sample_data('goog.npy') + In [63]: datafile = utils.get_sample_data('goog.npy') In [64]: r = np.load(datafile).view(np.recarray) @@ -116,8 +116,8 @@ you will see that the x tick labels are all squashed together. .. plot:: :context: - import matplotlib.cbook as cbook - datafile = cbook.get_sample_data('goog.npy') + import matplotlib.utils as utils + datafile = utils.get_sample_data('goog.npy') r = np.load(datafile).view(np.recarray) plt.figure() plt.plot(r.date, r.close) @@ -175,10 +175,10 @@ right. import matplotlib.pyplot as plt import numpy as np - import matplotlib.cbook as cbook + import matplotlib.utils as utils # load up some sample financial data - datafile = cbook.get_sample_data('goog.npy') + datafile = utils.get_sample_data('goog.npy') r = np.load(datafile).view(np.recarray) # create two subplots with the shared x and y axes diff --git a/examples/animation/old_animation/draggable_legend.py b/examples/animation/old_animation/draggable_legend.py index 93895a78d046..cb70cfcd525d 100644 --- a/examples/animation/old_animation/draggable_legend.py +++ b/examples/animation/old_animation/draggable_legend.py @@ -16,7 +16,7 @@ from matplotlib._png import read_png -from matplotlib.cbook import get_sample_data +from matplotlib.utils import get_sample_data from matplotlib.offsetbox import OffsetImage, AnnotationBbox diff --git a/examples/api/date_demo.py b/examples/api/date_demo.py index 4348c2105064..cf663a2f8d5e 100644 --- a/examples/api/date_demo.py +++ b/examples/api/date_demo.py @@ -15,7 +15,7 @@ import numpy as np import matplotlib.pyplot as plt import matplotlib.dates as mdates -import matplotlib.cbook as cbook +import matplotlib.utils as utils years = mdates.YearLocator() # every year months = mdates.MonthLocator() # every month @@ -25,7 +25,7 @@ # open, close, volume, adj_close from the mpl-data/example directory. # The record array stores python datetime.date as an object array in # the date column -datafile = cbook.get_sample_data('goog.npy') +datafile = utils.get_sample_data('goog.npy') r = np.load(datafile).view(np.recarray) fig = plt.figure() diff --git a/examples/api/date_index_formatter.py b/examples/api/date_index_formatter.py index 7b4843aac9ce..f3dbdfaa6421 100644 --- a/examples/api/date_index_formatter.py +++ b/examples/api/date_index_formatter.py @@ -7,10 +7,10 @@ import numpy as np import matplotlib.pyplot as plt import matplotlib.mlab as mlab -import matplotlib.cbook as cbook +import matplotlib.utils as utils import matplotlib.ticker as ticker -datafile = cbook.get_sample_data('aapl.csv', asfileobj=False) +datafile = utils.get_sample_data('aapl.csv', asfileobj=False) print ('loading %s' % datafile) r = mlab.csv2rec(datafile) diff --git a/examples/api/watermark_image.py b/examples/api/watermark_image.py index 3d437193a05a..e3869d8d7205 100644 --- a/examples/api/watermark_image.py +++ b/examples/api/watermark_image.py @@ -4,11 +4,11 @@ from __future__ import print_function import numpy as np import matplotlib -import matplotlib.cbook as cbook +import matplotlib.utils as utils import matplotlib.image as image import matplotlib.pyplot as plt -datafile = cbook.get_sample_data('logo2.png', asfileobj=False) +datafile = utils.get_sample_data('logo2.png', asfileobj=False) print ('loading %s' % datafile) im = image.imread(datafile) im[:,:,-1] = 0.5 # set the alpha channel diff --git a/examples/axes_grid/demo_axes_divider.py b/examples/axes_grid/demo_axes_divider.py index 5a0652cf1052..78b2e3111d6e 100644 --- a/examples/axes_grid/demo_axes_divider.py +++ b/examples/axes_grid/demo_axes_divider.py @@ -2,7 +2,7 @@ def get_demo_image(): import numpy as np - from matplotlib.cbook import get_sample_data + from matplotlib.utils import get_sample_data f = get_sample_data("axes_grid/bivariate_normal.npy", asfileobj=False) z = np.load(f) # z is a numpy array of 15x15 diff --git a/examples/axes_grid/demo_axes_grid.py b/examples/axes_grid/demo_axes_grid.py index d28f50efbd40..566d7909ddbf 100644 --- a/examples/axes_grid/demo_axes_grid.py +++ b/examples/axes_grid/demo_axes_grid.py @@ -3,7 +3,7 @@ def get_demo_image(): import numpy as np - from matplotlib.cbook import get_sample_data + from matplotlib.utils import get_sample_data f = get_sample_data("axes_grid/bivariate_normal.npy", asfileobj=False) z = np.load(f) # z is a numpy array of 15x15 diff --git a/examples/axes_grid/demo_axes_grid2.py b/examples/axes_grid/demo_axes_grid2.py index 9fa682ab8e17..9c1c3ff80527 100644 --- a/examples/axes_grid/demo_axes_grid2.py +++ b/examples/axes_grid/demo_axes_grid2.py @@ -3,7 +3,7 @@ import numpy as np def get_demo_image(): - from matplotlib.cbook import get_sample_data + from matplotlib.utils import get_sample_data f = get_sample_data("axes_grid/bivariate_normal.npy", asfileobj=False) z = np.load(f) # z is a numpy array of 15x15 diff --git a/examples/axes_grid/demo_axes_rgb.py b/examples/axes_grid/demo_axes_rgb.py index 08c704c08ed2..3f6c3ae51efd 100644 --- a/examples/axes_grid/demo_axes_rgb.py +++ b/examples/axes_grid/demo_axes_rgb.py @@ -4,7 +4,7 @@ from mpl_toolkits.axes_grid1.axes_rgb import make_rgb_axes, RGBAxes def get_demo_image(): - from matplotlib.cbook import get_sample_data + from matplotlib.utils import get_sample_data f = get_sample_data("axes_grid/bivariate_normal.npy", asfileobj=False) z = np.load(f) # z is a numpy array of 15x15 diff --git a/examples/axes_grid/demo_curvelinear_grid.py b/examples/axes_grid/demo_curvelinear_grid.py index 1a738b50d71d..e5b88d95dd65 100644 --- a/examples/axes_grid/demo_curvelinear_grid.py +++ b/examples/axes_grid/demo_curvelinear_grid.py @@ -2,7 +2,7 @@ #from matplotlib.path import Path import matplotlib.pyplot as plt -import matplotlib.cbook as cbook +import matplotlib.utils as utils from mpl_toolkits.axisartist.grid_helper_curvelinear import GridHelperCurveLinear from mpl_toolkits.axisartist import Subplot @@ -109,7 +109,7 @@ def curvelinear_test2(fig): # note that ax2.transData == tr + ax1.transData # Anthing you draw in ax2 will match the ticks and grids of ax1. ax1.parasites.append(ax2) - intp = cbook.simple_linear_interpolation + intp = utils.simple_linear_interpolation ax2.plot(intp(np.array([0, 30]), 50), intp(np.array([10., 10.]), 50)) diff --git a/examples/axes_grid/demo_edge_colorbar.py b/examples/axes_grid/demo_edge_colorbar.py index 6e25d02a0d12..8ca38dee0c06 100644 --- a/examples/axes_grid/demo_edge_colorbar.py +++ b/examples/axes_grid/demo_edge_colorbar.py @@ -3,7 +3,7 @@ def get_demo_image(): import numpy as np - from matplotlib.cbook import get_sample_data + from matplotlib.utils import get_sample_data f = get_sample_data("axes_grid/bivariate_normal.npy", asfileobj=False) z = np.load(f) # z is a numpy array of 15x15 diff --git a/examples/axes_grid/inset_locator_demo2.py b/examples/axes_grid/inset_locator_demo2.py index a4e08be34931..d061e41427ce 100644 --- a/examples/axes_grid/inset_locator_demo2.py +++ b/examples/axes_grid/inset_locator_demo2.py @@ -6,7 +6,7 @@ import numpy as np def get_demo_image(): - from matplotlib.cbook import get_sample_data + from matplotlib.utils import get_sample_data import numpy as np f = get_sample_data("axes_grid/bivariate_normal.npy", asfileobj=False) z = np.load(f) diff --git a/examples/axes_grid/simple_axesgrid2.py b/examples/axes_grid/simple_axesgrid2.py index efd7fb45a9bd..41e9e8f23aba 100644 --- a/examples/axes_grid/simple_axesgrid2.py +++ b/examples/axes_grid/simple_axesgrid2.py @@ -3,7 +3,7 @@ def get_demo_image(): import numpy as np - from matplotlib.cbook import get_sample_data + from matplotlib.utils import get_sample_data f = get_sample_data("axes_grid/bivariate_normal.npy", asfileobj=False) z = np.load(f) # z is a numpy array of 15x15 diff --git a/examples/misc/developer_commit_history.py b/examples/misc/developer_commit_history.py index e4577c73e73b..0f1995dc8982 100644 --- a/examples/misc/developer_commit_history.py +++ b/examples/misc/developer_commit_history.py @@ -10,9 +10,9 @@ """ import os, datetime -import matplotlib.cbook as cbook +import matplotlib.utils as utils -todate = cbook.todate('%Y-%m-%d') +todate = utils.todate('%Y-%m-%d') today = datetime.date.today() if not os.path.exists('log.txt'): print('You must place the "svn log" output into a file "log.txt"') diff --git a/examples/misc/rc_traits.py b/examples/misc/rc_traits.py index ffad4701a282..9dfbb7496f60 100644 --- a/examples/misc/rc_traits.py +++ b/examples/misc/rc_traits.py @@ -7,7 +7,7 @@ import sys, os, re import traits.api as traits -from matplotlib.cbook import is_string_like +from matplotlib.utils import is_string_like from matplotlib.artist import Artist doprint = True diff --git a/examples/misc/rec_groupby_demo.py b/examples/misc/rec_groupby_demo.py index cdda0a011efe..6dba3147ba21 100644 --- a/examples/misc/rec_groupby_demo.py +++ b/examples/misc/rec_groupby_demo.py @@ -1,9 +1,9 @@ from __future__ import print_function import numpy as np import matplotlib.mlab as mlab -import matplotlib.cbook as cbook +import matplotlib.utils as utils -datafile = cbook.get_sample_data('aapl.csv', asfileobj=False) +datafile = utils.get_sample_data('aapl.csv', asfileobj=False) print('loading', datafile) r = mlab.csv2rec(datafile) r.sort() diff --git a/examples/misc/rec_join_demo.py b/examples/misc/rec_join_demo.py index 75289170a988..654c4ceab42c 100644 --- a/examples/misc/rec_join_demo.py +++ b/examples/misc/rec_join_demo.py @@ -1,9 +1,9 @@ from __future__ import print_function import numpy as np import matplotlib.mlab as mlab -import matplotlib.cbook as cbook +import matplotlib.utils as utils -datafile = cbook.get_sample_data('aapl.csv', asfileobj=False) +datafile = utils.get_sample_data('aapl.csv', asfileobj=False) print('loading', datafile) r = mlab.csv2rec(datafile) diff --git a/examples/misc/sample_data_demo.py b/examples/misc/sample_data_demo.py index 1e60b1e90854..81169c76298b 100644 --- a/examples/misc/sample_data_demo.py +++ b/examples/misc/sample_data_demo.py @@ -3,7 +3,7 @@ fetch it from github and cache it """ from __future__ import print_function -import matplotlib.cbook as cbook +import matplotlib.utils as utils import matplotlib.pyplot as plt fname = cbook.get_sample_data('ada.png', asfileobj=False) diff --git a/examples/pylab_examples/centered_ticklabels.py b/examples/pylab_examples/centered_ticklabels.py index b6e40deb50fd..c2943571ea5f 100644 --- a/examples/pylab_examples/centered_ticklabels.py +++ b/examples/pylab_examples/centered_ticklabels.py @@ -15,13 +15,13 @@ import datetime import numpy as np import matplotlib -import matplotlib.cbook as cbook +import matplotlib.utils as utils import matplotlib.dates as dates import matplotlib.ticker as ticker import matplotlib.pyplot as plt # load some financial data; apple's stock price -fh = cbook.get_sample_data('aapl.npy.gz') +fh = utils.get_sample_data('aapl.npy.gz') r = np.load(fh); fh.close() r = r[-250:] # get the last 250 days diff --git a/examples/pylab_examples/data_helper.py b/examples/pylab_examples/data_helper.py index c6e83abfc9e4..27cfe1cb1cd3 100755 --- a/examples/pylab_examples/data_helper.py +++ b/examples/pylab_examples/data_helper.py @@ -2,7 +2,9 @@ # Some functions to load a return data for the plot demos from numpy import fromstring, argsort, take, array, resize -import matplotlib.cbook as cbook +import matplotlib.utils as utils + + def get_two_stock_data(): """ load stock time and price data for two stocks The return values @@ -11,8 +13,8 @@ def get_two_stock_data(): """ ticker1, ticker2 = 'INTC', 'AAPL' - file1 = cbook.get_sample_data('INTC.dat.gz') - file2 = cbook.get_sample_data('AAPL.dat.gz') + file1 = utils.get_sample_data('INTC.dat.gz') + file2 = utils.get_sample_data('AAPL.dat.gz') M1 = fromstring( file1.read(), 'func - self.callbacks = cbook.CallbackRegistry() + self.callbacks = utils.CallbackRegistry() self.widgetlock = widgets.LockDraw() self._button = None # the button pressed self._key = None # the key pressed @@ -1863,7 +1863,8 @@ def get_width_height(self): # compare_images_decorator (decorators.py line 112) # if the backend has not already been loaded earlier on. Simple trigger: # >>> import matplotlib.tests.test_spines - # >>> list(matplotlib.tests.test_spines.test_spines_axes_positions())[0][0]() + # >>> list( + # matplotlib.tests.test_spines.test_spines_axes_positions())[0][0]() def print_emf(self, *args, **kwargs): from backends.backend_emf import FigureCanvasEMF # lazy import @@ -1937,7 +1938,7 @@ def print_jpg(self, filename_or_obj, *args, **kwargs): if kwargs.pop("dryrun", False): return image = Image.frombuffer('RGBA', size, buf, 'raw', 'RGBA', 0, 1) - options = cbook.restrict_dict(kwargs, ['quality', 'optimize', + options = utils.restrict_dict(kwargs, ['quality', 'optimize', 'progressive']) return image.save(filename_or_obj, format='jpeg', **options) print_jpeg = print_jpg @@ -2042,11 +2043,11 @@ def print_figure(self, filename, dpi=None, facecolor='w', edgecolor='w', """ if format is None: # get format from filename, or from backend's default filetype - if cbook.is_string_like(filename): + if utils.is_string_like(filename): format = os.path.splitext(filename)[1][1:] if format is None or format == '': format = self.get_default_filetype() - if cbook.is_string_like(filename): + if utils.is_string_like(filename): filename = filename.rstrip('.') + '.' + format format = format.lower() @@ -2094,7 +2095,8 @@ def print_figure(self, filename, dpi=None, facecolor='w', edgecolor='w', bbox_extra_artists = kwargs.pop("bbox_extra_artists", None) if bbox_extra_artists is None: - bbox_extra_artists = self.figure.get_default_bbox_extra_artists() + bbox_extra_artists = \ + self.figure.get_default_bbox_extra_artists() bb = [a.get_window_extent(renderer) for a in bbox_extra_artists] @@ -2594,15 +2596,14 @@ class NavigationToolbar2(object): ('Zoom', 'Zoom to rectangle', 'zoom_to_rect', 'zoom'), (None, None, None, None), ('Subplots', 'Configure subplots', 'subplots', 'configure_subplots'), - ('Save', 'Save the figure', 'filesave', 'save_figure'), - ) + ('Save', 'Save the figure', 'filesave', 'save_figure')) def __init__(self, canvas): self.canvas = canvas canvas.toolbar = self # a dict from axes index to a list of view limits - self._views = cbook.Stack() - self._positions = cbook.Stack() # stack of subplot positions + self._views = utils.Stack() + self._positions = utils.Stack() # stack of subplot positions self._xypress = None # the location and axis info at the time # of the press self._idPress = None diff --git a/lib/matplotlib/backends/backend_agg.py b/lib/matplotlib/backends/backend_agg.py index ec6370cdaed8..40a33d2dad23 100644 --- a/lib/matplotlib/backends/backend_agg.py +++ b/lib/matplotlib/backends/backend_agg.py @@ -27,7 +27,7 @@ from matplotlib import verbose, rcParams from matplotlib.backend_bases import RendererBase,\ FigureManagerBase, FigureCanvasBase -from matplotlib.cbook import is_string_like, maxdict +from matplotlib.utils import is_string_like, maxdict from matplotlib.figure import Figure from matplotlib.font_manager import findfont from matplotlib.ft2font import FT2Font, LOAD_FORCE_AUTOHINT, LOAD_NO_HINTING, \ diff --git a/lib/matplotlib/backends/backend_cairo.py b/lib/matplotlib/backends/backend_cairo.py index b89314b539ff..15b6c023920d 100644 --- a/lib/matplotlib/backends/backend_cairo.py +++ b/lib/matplotlib/backends/backend_cairo.py @@ -40,7 +40,7 @@ def _fn_name(): return sys._getframe(1).f_code.co_name from matplotlib.backend_bases import RendererBase, GraphicsContextBase,\ FigureManagerBase, FigureCanvasBase -from matplotlib.cbook import is_string_like +from matplotlib.utils import is_string_like from matplotlib.figure import Figure from matplotlib.mathtext import MathTextParser from matplotlib.path import Path diff --git a/lib/matplotlib/backends/backend_fltkagg.py b/lib/matplotlib/backends/backend_fltkagg.py index 52d4bd3b1efd..5dee5223b37d 100644 --- a/lib/matplotlib/backends/backend_fltkagg.py +++ b/lib/matplotlib/backends/backend_fltkagg.py @@ -20,7 +20,7 @@ import matplotlib from matplotlib import rcParams, verbose -from matplotlib.cbook import is_string_like +from matplotlib.utils import is_string_like from matplotlib.backend_bases import \ RendererBase, GraphicsContextBase, FigureManagerBase, FigureCanvasBase,\ NavigationToolbar2, cursors diff --git a/lib/matplotlib/backends/backend_gdk.py b/lib/matplotlib/backends/backend_gdk.py index e66827782d7a..6dc32da1194f 100644 --- a/lib/matplotlib/backends/backend_gdk.py +++ b/lib/matplotlib/backends/backend_gdk.py @@ -22,7 +22,7 @@ def fn_name(): return sys._getframe(1).f_code.co_name from matplotlib._pylab_helpers import Gcf from matplotlib.backend_bases import RendererBase, GraphicsContextBase, \ FigureManagerBase, FigureCanvasBase -from matplotlib.cbook import is_string_like +from matplotlib.utils import is_string_like from matplotlib.figure import Figure from matplotlib.mathtext import MathTextParser from matplotlib.transforms import Affine2D diff --git a/lib/matplotlib/backends/backend_gtk.py b/lib/matplotlib/backends/backend_gtk.py index 6a6d6c38f3c9..5b891abc4342 100644 --- a/lib/matplotlib/backends/backend_gtk.py +++ b/lib/matplotlib/backends/backend_gtk.py @@ -31,14 +31,13 @@ def fn_name(): return sys._getframe(1).f_code.co_name from matplotlib.backend_bases import ShowBase from matplotlib.backends.backend_gdk import RendererGDK, FigureCanvasGDK -from matplotlib.cbook import is_string_like, is_writable_file_like +from matplotlib.utils import is_string_like, is_writable_file_like from matplotlib.colors import colorConverter from matplotlib.figure import Figure from matplotlib.widgets import SubplotTool from matplotlib import lines from matplotlib import markers -from matplotlib import cbook from matplotlib import verbose from matplotlib import rcParams @@ -1103,7 +1102,7 @@ class DialogLineprops: linestyled = dict([ (s,i) for i,s in enumerate(linestyles)]) - markers = [m for m in markers.MarkerStyle.markers if cbook.is_string_like(m)] + markers = [m for m in markers.MarkerStyle.markers if is_string_like(m)] markerd = dict([(s,i) for i,s in enumerate(markers)]) diff --git a/lib/matplotlib/backends/backend_gtk3.py b/lib/matplotlib/backends/backend_gtk3.py index cd2af590ab78..127311b95fd7 100644 --- a/lib/matplotlib/backends/backend_gtk3.py +++ b/lib/matplotlib/backends/backend_gtk3.py @@ -14,13 +14,12 @@ def fn_name(): return sys._getframe(1).f_code.co_name FigureManagerBase, FigureCanvasBase, NavigationToolbar2, cursors, TimerBase from matplotlib.backend_bases import ShowBase -from matplotlib.cbook import is_string_like, is_writable_file_like +from matplotlib.utils import is_string_like, is_writable_file_like from matplotlib.colors import colorConverter from matplotlib.figure import Figure from matplotlib.widgets import SubplotTool from matplotlib import lines -from matplotlib import cbook from matplotlib import verbose from matplotlib import rcParams @@ -902,7 +901,7 @@ class DialogLineprops: linestyled = dict([ (s,i) for i,s in enumerate(linestyles)]) - markers = [m for m in lines.Line2D.markers if cbook.is_string_like(m)] + markers = [m for m in lines.Line2D.markers if is_string_like(m)] markerd = dict([(s,i) for i,s in enumerate(markers)]) diff --git a/lib/matplotlib/backends/backend_macosx.py b/lib/matplotlib/backends/backend_macosx.py index ed17506e4a79..7605ce010835 100644 --- a/lib/matplotlib/backends/backend_macosx.py +++ b/lib/matplotlib/backends/backend_macosx.py @@ -8,7 +8,7 @@ FigureManagerBase, FigureCanvasBase, NavigationToolbar2, TimerBase from matplotlib.backend_bases import ShowBase -from matplotlib.cbook import maxdict +from matplotlib.utils import maxdict from matplotlib.figure import Figure from matplotlib.path import Path from matplotlib.mathtext import MathTextParser diff --git a/lib/matplotlib/backends/backend_pdf.py b/lib/matplotlib/backends/backend_pdf.py index e039e8d22a9b..97c100cea6f3 100644 --- a/lib/matplotlib/backends/backend_pdf.py +++ b/lib/matplotlib/backends/backend_pdf.py @@ -33,7 +33,7 @@ from matplotlib.backend_bases import RendererBase, GraphicsContextBase,\ FigureManagerBase, FigureCanvasBase from matplotlib.backends.backend_mixed import MixedModeRenderer -from matplotlib.cbook import Bunch, is_string_like, reverse_dict, \ +from matplotlib.utils import Bunch, is_string_like, \ get_realpath_and_stat, is_writable_file_like, maxdict from matplotlib.mlab import quad2cubic from matplotlib.figure import Figure diff --git a/lib/matplotlib/backends/backend_pgf.py b/lib/matplotlib/backends/backend_pgf.py index 82c3718c7dad..e3a42459deef 100644 --- a/lib/matplotlib/backends/backend_pgf.py +++ b/lib/matplotlib/backends/backend_pgf.py @@ -20,8 +20,8 @@ from matplotlib import _png, rcParams from matplotlib import font_manager from matplotlib.ft2font import FT2Font -from matplotlib.cbook import is_string_like, is_writable_file_like -from matplotlib.cbook import check_output +from matplotlib.utils import is_string_like, is_writable_file_like +from matplotlib.utils import check_output ############################################################################### diff --git a/lib/matplotlib/backends/backend_ps.py b/lib/matplotlib/backends/backend_ps.py index 008c9561114f..8b92e223299a 100644 --- a/lib/matplotlib/backends/backend_ps.py +++ b/lib/matplotlib/backends/backend_ps.py @@ -23,7 +23,7 @@ def _fn_name(): return sys._getframe(1).f_code.co_name from matplotlib.backend_bases import RendererBase, GraphicsContextBase,\ FigureManagerBase, FigureCanvasBase -from matplotlib.cbook import is_string_like, get_realpath_and_stat, \ +from matplotlib.utils import is_string_like, get_realpath_and_stat, \ is_writable_file_like, maxdict from matplotlib.mlab import quad2cubic from matplotlib.figure import Figure diff --git a/lib/matplotlib/backends/backend_qt.py b/lib/matplotlib/backends/backend_qt.py index 9b009cf5ac8d..0e638f58abe0 100644 --- a/lib/matplotlib/backends/backend_qt.py +++ b/lib/matplotlib/backends/backend_qt.py @@ -12,7 +12,7 @@ import matplotlib from matplotlib import verbose -from matplotlib.cbook import is_string_like, onetrue +from matplotlib.utils import is_string_like, onetrue from matplotlib.backend_bases import RendererBase, GraphicsContextBase, \ FigureManagerBase, FigureCanvasBase, NavigationToolbar2, cursors from matplotlib.backend_bases import ShowBase diff --git a/lib/matplotlib/backends/backend_qt4.py b/lib/matplotlib/backends/backend_qt4.py index e31bb38ab073..83f8f544017e 100644 --- a/lib/matplotlib/backends/backend_qt4.py +++ b/lib/matplotlib/backends/backend_qt4.py @@ -6,7 +6,7 @@ import matplotlib from matplotlib import verbose -from matplotlib.cbook import is_string_like, onetrue +from matplotlib.utils import is_string_like from matplotlib.backend_bases import RendererBase, GraphicsContextBase, \ FigureManagerBase, FigureCanvasBase, NavigationToolbar2, IdleEvent, \ cursors, TimerBase diff --git a/lib/matplotlib/backends/backend_svg.py b/lib/matplotlib/backends/backend_svg.py index 76e5d2f94925..39ca94339047 100644 --- a/lib/matplotlib/backends/backend_svg.py +++ b/lib/matplotlib/backends/backend_svg.py @@ -13,7 +13,7 @@ from matplotlib.backend_bases import RendererBase, GraphicsContextBase,\ FigureManagerBase, FigureCanvasBase from matplotlib.backends.backend_mixed import MixedModeRenderer -from matplotlib.cbook import is_string_like, is_writable_file_like, maxdict +from matplotlib.utils import is_string_like, is_writable_file_like, maxdict from matplotlib.colors import rgb2hex from matplotlib.figure import Figure from matplotlib.font_manager import findfont, FontProperties diff --git a/lib/matplotlib/backends/backend_tkagg.py b/lib/matplotlib/backends/backend_tkagg.py index fe0e145be3f1..b3504f04deaf 100644 --- a/lib/matplotlib/backends/backend_tkagg.py +++ b/lib/matplotlib/backends/backend_tkagg.py @@ -14,7 +14,7 @@ import matplotlib.backends.windowing as windowing import matplotlib -from matplotlib.cbook import is_string_like +from matplotlib.utils import is_string_like from matplotlib.backend_bases import RendererBase, GraphicsContextBase from matplotlib.backend_bases import FigureManagerBase, FigureCanvasBase from matplotlib.backend_bases import NavigationToolbar2, cursors, TimerBase @@ -25,8 +25,6 @@ from matplotlib.widgets import SubplotTool -import matplotlib.cbook as cbook - rcParams = matplotlib.rcParams verbose = matplotlib.verbose diff --git a/lib/matplotlib/backends/backend_wx.py b/lib/matplotlib/backends/backend_wx.py index f9cd226f1001..e1a173ff1bb5 100644 --- a/lib/matplotlib/backends/backend_wx.py +++ b/lib/matplotlib/backends/backend_wx.py @@ -131,7 +131,7 @@ def bind(actor,event,action,id=None): from matplotlib._pylab_helpers import Gcf from matplotlib.artist import Artist -from matplotlib.cbook import exception_to_str, is_string_like, is_writable_file_like +from matplotlib.utils import is_string_like, is_writable_file_like from matplotlib.figure import Figure from matplotlib.path import Path from matplotlib.text import _process_text_args, Text diff --git a/lib/matplotlib/blocking_input.py b/lib/matplotlib/blocking_input.py index 378995f51f02..2c454409a300 100644 --- a/lib/matplotlib/blocking_input.py +++ b/lib/matplotlib/blocking_input.py @@ -24,7 +24,7 @@ from __future__ import print_function from matplotlib import verbose -from matplotlib.cbook import is_sequence_of_strings +from matplotlib.utils import is_sequence_of_strings import matplotlib.lines as mlines diff --git a/lib/matplotlib/cbook.py b/lib/matplotlib/cbook.py index 58f38dae7ef8..32a6f83275f8 100644 --- a/lib/matplotlib/cbook.py +++ b/lib/matplotlib/cbook.py @@ -1,1903 +1,8 @@ -""" -A collection of utility functions and classes. Many (but not all) -from the Python Cookbook -- hence the name cbook -""" -from __future__ import print_function - -import datetime -import errno -from functools import reduce -import glob -import gzip -import io -import locale -import os -import re -import subprocess -import sys -import threading -import time -import traceback import warnings -from weakref import ref, WeakKeyDictionary +from matplotlib.utils._cbook import * -import matplotlib from matplotlib import MatplotlibDeprecationWarning as mplDeprecation -import numpy as np -import numpy.ma as ma - - - -import types - - -# On some systems, locale.getpreferredencoding returns None, -# which can break unicode; and the sage project reports that -# some systems have incorrect locale specifications, e.g., -# an encoding instead of a valid locale name. Another -# pathological case that has been reported is an empty string. - -# On some systems, getpreferredencoding sets the locale, which has -# side effects. Passing False eliminates those side effects. - -if sys.version_info[0] >= 3: - def unicode_safe(s): - import matplotlib - - try: - preferredencoding = locale.getpreferredencoding( - matplotlib.rcParams['axes.formatter.use_locale']).strip() - if not preferredencoding: - preferredencoding = None - except (ValueError, ImportError, AttributeError): - preferredencoding = None - - if isinstance(s, bytes): - if preferredencoding is None: - return unicode(s) - else: - # We say "unicode" and not "str" here so it passes through - # 2to3 correctly. - return unicode(s, preferredencoding) - return s -else: - def unicode_safe(s): - import matplotlib - - try: - preferredencoding = locale.getpreferredencoding( - matplotlib.rcParams['axes.formatter.use_locale']).strip() - if not preferredencoding: - preferredencoding = None - except (ValueError, ImportError, AttributeError): - preferredencoding = None - - if preferredencoding is None: - return unicode(s) - else: - return unicode(s, preferredencoding) - - -class converter: - """ - Base class for handling string -> python type with support for - missing values - """ - def __init__(self, missing='Null', missingval=None): - self.missing = missing - self.missingval = missingval - - def __call__(self, s): - if s == self.missing: - return self.missingval - return s - - def is_missing(self, s): - return not s.strip() or s == self.missing - - -class tostr(converter): - 'convert to string or None' - def __init__(self, missing='Null', missingval=''): - converter.__init__(self, missing=missing, missingval=missingval) - - -class todatetime(converter): - 'convert to a datetime or None' - def __init__(self, fmt='%Y-%m-%d', missing='Null', missingval=None): - 'use a :func:`time.strptime` format string for conversion' - converter.__init__(self, missing, missingval) - self.fmt = fmt - - def __call__(self, s): - if self.is_missing(s): - return self.missingval - tup = time.strptime(s, self.fmt) - return datetime.datetime(*tup[:6]) - - -class todate(converter): - 'convert to a date or None' - def __init__(self, fmt='%Y-%m-%d', missing='Null', missingval=None): - 'use a :func:`time.strptime` format string for conversion' - converter.__init__(self, missing, missingval) - self.fmt = fmt - - def __call__(self, s): - if self.is_missing(s): - return self.missingval - tup = time.strptime(s, self.fmt) - return datetime.date(*tup[:3]) - - -class tofloat(converter): - 'convert to a float or None' - def __init__(self, missing='Null', missingval=None): - converter.__init__(self, missing) - self.missingval = missingval - - def __call__(self, s): - if self.is_missing(s): - return self.missingval - return float(s) - - -class toint(converter): - 'convert to an int or None' - def __init__(self, missing='Null', missingval=None): - converter.__init__(self, missing) - - def __call__(self, s): - if self.is_missing(s): - return self.missingval - return int(s) - - -class _BoundMethodProxy(object): - ''' - Our own proxy object which enables weak references to bound and unbound - methods and arbitrary callables. Pulls information about the function, - class, and instance out of a bound method. Stores a weak reference to the - instance to support garbage collection. - - @organization: IBM Corporation - @copyright: Copyright (c) 2005, 2006 IBM Corporation - @license: The BSD License - - Minor bugfixes by Michael Droettboom - ''' - def __init__(self, cb): - try: - try: - self.inst = ref(cb.im_self) - except TypeError: - self.inst = None - self.func = cb.im_func - self.klass = cb.im_class - except AttributeError: - self.inst = None - self.func = cb - self.klass = None - - def __getstate__(self): - d = self.__dict__.copy() - # de-weak reference inst - inst = d['inst'] - if inst is not None: - d['inst'] = inst() - return d - - def __setstate__(self, statedict): - self.__dict__ = statedict - inst = statedict['inst'] - # turn inst back into a weakref - if inst is not None: - self.inst = ref(inst) - - def __call__(self, *args, **kwargs): - ''' - Proxy for a call to the weak referenced object. Take - arbitrary params to pass to the callable. - - Raises `ReferenceError`: When the weak reference refers to - a dead object - ''' - if self.inst is not None and self.inst() is None: - raise ReferenceError - elif self.inst is not None: - # build a new instance method with a strong reference to the - # instance - - mtd = types.MethodType(self.func, self.inst()) - - else: - # not a bound method, just return the func - mtd = self.func - # invoke the callable and return the result - return mtd(*args, **kwargs) - - def __eq__(self, other): - ''' - Compare the held function and instance with that held by - another proxy. - ''' - try: - if self.inst is None: - return self.func == other.func and other.inst is None - else: - return self.func == other.func and self.inst() == other.inst() - except Exception: - return False - - def __ne__(self, other): - ''' - Inverse of __eq__. - ''' - return not self.__eq__(other) - - -class CallbackRegistry: - """ - Handle registering and disconnecting for a set of signals and - callbacks: - - >>> def oneat(x): - ... print 'eat', x - >>> def ondrink(x): - ... print 'drink', x - - >>> from matplotlib.cbook import CallbackRegistry - >>> callbacks = CallbackRegistry() - - >>> id_eat = callbacks.connect('eat', oneat) - >>> id_drink = callbacks.connect('drink', ondrink) - - >>> callbacks.process('drink', 123) - drink 123 - >>> callbacks.process('eat', 456) - eat 456 - >>> callbacks.process('be merry', 456) # nothing will be called - >>> callbacks.disconnect(id_eat) - >>> callbacks.process('eat', 456) # nothing will be called - - In practice, one should always disconnect all callbacks when they - are no longer needed to avoid dangling references (and thus memory - leaks). However, real code in matplotlib rarely does so, and due - to its design, it is rather difficult to place this kind of code. - To get around this, and prevent this class of memory leaks, we - instead store weak references to bound methods only, so when the - destination object needs to die, the CallbackRegistry won't keep - it alive. The Python stdlib weakref module can not create weak - references to bound methods directly, so we need to create a proxy - object to handle weak references to bound methods (or regular free - functions). This technique was shared by Peter Parente on his - `"Mindtrove" blog - `_. - """ - def __init__(self, *args): - if len(args): - warnings.warn( - 'CallbackRegistry no longer requires a list of callback types.' - ' Ignoring arguments', - mplDeprecation) - self.callbacks = dict() - self._cid = 0 - self._func_cid_map = {} - - def __getstate__(self): - # We cannot currently pickle the callables in the registry, so - # return an empty dictionary. - return {} - - def __setstate__(self, state): - # re-initialise an empty callback registry - self.__init__() - - def connect(self, s, func): - """ - register *func* to be called when a signal *s* is generated - func will be called - """ - self._func_cid_map.setdefault(s, WeakKeyDictionary()) - if func in self._func_cid_map[s]: - return self._func_cid_map[s][func] - - self._cid += 1 - cid = self._cid - self._func_cid_map[s][func] = cid - self.callbacks.setdefault(s, dict()) - proxy = _BoundMethodProxy(func) - self.callbacks[s][cid] = proxy - return cid - - def disconnect(self, cid): - """ - disconnect the callback registered with callback id *cid* - """ - for eventname, callbackd in self.callbacks.items(): - try: - del callbackd[cid] - except KeyError: - continue - else: - for category, functions in self._func_cid_map.items(): - for function, value in functions.items(): - if value == cid: - del functions[function] - return - - def process(self, s, *args, **kwargs): - """ - process signal *s*. All of the functions registered to receive - callbacks on *s* will be called with *\*args* and *\*\*kwargs* - """ - if s in self.callbacks: - for cid, proxy in self.callbacks[s].items(): - # Clean out dead references - if proxy.inst is not None and proxy.inst() is None: - del self.callbacks[s][cid] - else: - proxy(*args, **kwargs) - - -class Scheduler(threading.Thread): - """ - Base class for timeout and idle scheduling - """ - idlelock = threading.Lock() - id = 0 - - def __init__(self): - threading.Thread.__init__(self) - self.id = Scheduler.id - self._stopped = False - Scheduler.id += 1 - self._stopevent = threading.Event() - - def stop(self): - if self._stopped: - return - self._stopevent.set() - self.join() - self._stopped = True - - -class Timeout(Scheduler): - """ - Schedule recurring events with a wait time in seconds - """ - def __init__(self, wait, func): - Scheduler.__init__(self) - self.wait = wait - self.func = func - - def run(self): - - while not self._stopevent.isSet(): - self._stopevent.wait(self.wait) - Scheduler.idlelock.acquire() - b = self.func(self) - Scheduler.idlelock.release() - if not b: - break - - -class Idle(Scheduler): - """ - Schedule callbacks when scheduler is idle - """ - # the prototype impl is a bit of a poor man's idle handler. It - # just implements a short wait time. But it will provide a - # placeholder for a proper impl ater - waittime = 0.05 - - def __init__(self, func): - Scheduler.__init__(self) - self.func = func - - def run(self): - - while not self._stopevent.isSet(): - self._stopevent.wait(Idle.waittime) - Scheduler.idlelock.acquire() - b = self.func(self) - Scheduler.idlelock.release() - if not b: - break - - -class silent_list(list): - """ - override repr when returning a list of matplotlib artists to - prevent long, meaningless output. This is meant to be used for a - homogeneous list of a given type - """ - def __init__(self, type, seq=None): - self.type = type - if seq is not None: - self.extend(seq) - - def __repr__(self): - return '' % (len(self), self.type) - - def __str__(self): - return repr(self) - - def __getstate__(self): - # store a dictionary of this SilentList's state - return {'type': self.type, 'seq': self[:]} - - def __setstate__(self, state): - self.type = state['type'] - self.extend(state['seq']) - - -def strip_math(s): - 'remove latex formatting from mathtext' - remove = (r'\mathdefault', r'\rm', r'\cal', r'\tt', r'\it', '\\', '{', '}') - s = s[1:-1] - for r in remove: - s = s.replace(r, '') - return s - - -class Bunch: - """ - Often we want to just collect a bunch of stuff together, naming each - item of the bunch; a dictionary's OK for that, but a small do- nothing - class is even handier, and prettier to use. Whenever you want to - group a few variables:: - - >>> point = Bunch(datum=2, squared=4, coord=12) - >>> point.datum - - By: Alex Martelli - From: http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52308 - """ - def __init__(self, **kwds): - self.__dict__.update(kwds) - - def __repr__(self): - keys = self.__dict__.iterkeys() - return 'Bunch(%s)' % ', '.join(['%s=%s' % (k, self.__dict__[k]) - for k - in keys]) - - -def unique(x): - 'Return a list of unique elements of *x*' - return dict([(val, 1) for val in x]).keys() - - -def iterable(obj): - 'return true if *obj* is iterable' - try: - iter(obj) - except TypeError: - return False - return True - - -def is_string_like(obj): - 'Return True if *obj* looks like a string' - if isinstance(obj, (str, unicode)): - return True - # numpy strings are subclass of str, ma strings are not - if ma.isMaskedArray(obj): - if obj.ndim == 0 and obj.dtype.kind in 'SU': - return True - else: - return False - try: - obj + '' - except: - return False - return True - - -def is_sequence_of_strings(obj): - """ - Returns true if *obj* is iterable and contains strings - """ - if not iterable(obj): - return False - if is_string_like(obj): - return False - for o in obj: - if not is_string_like(o): - return False - return True - - -def is_writable_file_like(obj): - 'return true if *obj* looks like a file object with a *write* method' - return hasattr(obj, 'write') and callable(obj.write) - - -def is_scalar(obj): - 'return true if *obj* is not string like and is not iterable' - return not is_string_like(obj) and not iterable(obj) - - -def is_numlike(obj): - 'return true if *obj* looks like a number' - try: - obj + 1 - except: - return False - else: - return True - - -def to_filehandle(fname, flag='rU', return_opened=False): - """ - *fname* can be a filename or a file handle. Support for gzipped - files is automatic, if the filename ends in .gz. *flag* is a - read/write flag for :func:`file` - """ - if is_string_like(fname): - if fname.endswith('.gz'): - import gzip - # get rid of 'U' in flag for gzipped files. - flag = flag.replace('U', '') - fh = gzip.open(fname, flag) - elif fname.endswith('.bz2'): - # get rid of 'U' in flag for bz2 files - flag = flag.replace('U', '') - import bz2 - fh = bz2.BZ2File(fname, flag) - else: - fh = open(fname, flag) - opened = True - elif hasattr(fname, 'seek'): - fh = fname - opened = False - else: - raise ValueError('fname must be a string or file handle') - if return_opened: - return fh, opened - return fh - - -def is_scalar_or_string(val): - """Return whether the given object is a scalar or string like.""" - return is_string_like(val) or not iterable(val) - - -def get_sample_data(fname, asfileobj=True): - """ - Return a sample data file. *fname* is a path relative to the - `mpl-data/sample_data` directory. If *asfileobj* is `True` - return a file object, otherwise just a file path. - - Set the rc parameter examples.directory to the directory where we should - look, if sample_data files are stored in a location different than - default (which is 'mpl-data/sample_data` at the same level of 'matplotlib` - Python module files). - - If the filename ends in .gz, the file is implicitly ungzipped. - """ - if matplotlib.rcParams['examples.directory']: - root = matplotlib.rcParams['examples.directory'] - else: - root = os.path.join(os.path.dirname(__file__), "mpl-data", "sample_data") - path = os.path.join(root, fname) - - if asfileobj: - if (os.path.splitext(fname)[-1].lower() in - ('.csv', '.xrc', '.txt')): - mode = 'r' - else: - mode = 'rb' - - base, ext = os.path.splitext(fname) - if ext == '.gz': - return gzip.open(path, mode) - else: - return open(path, mode) - else: - return path - - -def flatten(seq, scalarp=is_scalar_or_string): - """ - Returns a generator of flattened nested containers - - For example: - - >>> from matplotlib.cbook import flatten - >>> l = (('John', ['Hunter']), (1, 23), [[([42, (5, 23)], )]]) - >>> print list(flatten(l)) - ['John', 'Hunter', 1, 23, 42, 5, 23] - - By: Composite of Holger Krekel and Luther Blissett - From: http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/121294 - and Recipe 1.12 in cookbook - """ - for item in seq: - if scalarp(item): - yield item - else: - for subitem in flatten(item, scalarp): - yield subitem - - -class Sorter: - """ - Sort by attribute or item - - Example usage:: - - sort = Sorter() - - list = [(1, 2), (4, 8), (0, 3)] - dict = [{'a': 3, 'b': 4}, {'a': 5, 'b': 2}, {'a': 0, 'b': 0}, - {'a': 9, 'b': 9}] - - - sort(list) # default sort - sort(list, 1) # sort by index 1 - sort(dict, 'a') # sort a list of dicts by key 'a' - - """ - - def _helper(self, data, aux, inplace): - aux.sort() - result = [data[i] for junk, i in aux] - if inplace: - data[:] = result - return result - - def byItem(self, data, itemindex=None, inplace=1): - if itemindex is None: - if inplace: - data.sort() - result = data - else: - result = data[:] - result.sort() - return result - else: - aux = [(data[i][itemindex], i) for i in range(len(data))] - return self._helper(data, aux, inplace) - - def byAttribute(self, data, attributename, inplace=1): - aux = [(getattr(data[i], attributename), i) for i in range(len(data))] - return self._helper(data, aux, inplace) - - # a couple of handy synonyms - sort = byItem - __call__ = byItem - - -class Xlator(dict): - """ - All-in-one multiple-string-substitution class - - Example usage:: - - text = "Larry Wall is the creator of Perl" - adict = { - "Larry Wall" : "Guido van Rossum", - "creator" : "Benevolent Dictator for Life", - "Perl" : "Python", - } - - print multiple_replace(adict, text) - - xlat = Xlator(adict) - print xlat.xlat(text) - """ - - def _make_regex(self): - """ Build re object based on the keys of the current dictionary """ - return re.compile("|".join(map(re.escape, self.iterkeys()))) - - def __call__(self, match): - """ Handler invoked for each regex *match* """ - return self[match.group(0)] - - def xlat(self, text): - """ Translate *text*, returns the modified text. """ - return self._make_regex().sub(self, text) - - -def soundex(name, len=4): - """ soundex module conforming to Odell-Russell algorithm """ - - # digits holds the soundex values for the alphabet - soundex_digits = '01230120022455012623010202' - sndx = '' - fc = '' - - # Translate letters in name to soundex digits - for c in name.upper(): - if c.isalpha(): - if not fc: - fc = c # Remember first letter - d = soundex_digits[ord(c) - ord('A')] - # Duplicate consecutive soundex digits are skipped - if not sndx or (d != sndx[-1]): - sndx += d - - # Replace first digit with first letter - sndx = fc + sndx[1:] - - # Remove all 0s from the soundex code - sndx = sndx.replace('0', '') - - # Return soundex code truncated or 0-padded to len characters - return (sndx + (len * '0'))[:len] - - -class Null: - """ Null objects always and reliably "do nothing." """ - - def __init__(self, *args, **kwargs): - pass - - def __call__(self, *args, **kwargs): - return self - - def __str__(self): - return "Null()" - - def __repr__(self): - return "Null()" - - def __nonzero__(self): - return 0 - - def __getattr__(self, name): - return self - - def __setattr__(self, name, value): - return self - - def __delattr__(self, name): - return self - - -def mkdirs(newdir, mode=0o777): - """ - make directory *newdir* recursively, and set *mode*. Equivalent to :: - - > mkdir -p NEWDIR - > chmod MODE NEWDIR - """ - try: - if not os.path.exists(newdir): - parts = os.path.split(newdir) - for i in range(1, len(parts) + 1): - thispart = os.path.join(*parts[:i]) - if not os.path.exists(thispart): - os.makedirs(thispart, mode) - - except OSError as err: - # Reraise the error unless it's about an already existing directory - if err.errno != errno.EEXIST or not os.path.isdir(newdir): - raise - - -class GetRealpathAndStat: - def __init__(self): - self._cache = {} - - def __call__(self, path): - result = self._cache.get(path) - if result is None: - realpath = os.path.realpath(path) - if sys.platform == 'win32': - stat_key = realpath - else: - stat = os.stat(realpath) - stat_key = (stat.st_ino, stat.st_dev) - result = realpath, stat_key - self._cache[path] = result - return result -get_realpath_and_stat = GetRealpathAndStat() - - -def dict_delall(d, keys): - 'delete all of the *keys* from the :class:`dict` *d*' - for key in keys: - try: - del d[key] - except KeyError: - pass - - -class RingBuffer: - """ class that implements a not-yet-full buffer """ - def __init__(self, size_max): - self.max = size_max - self.data = [] - - class __Full: - """ class that implements a full buffer """ - def append(self, x): - """ Append an element overwriting the oldest one. """ - self.data[self.cur] = x - self.cur = (self.cur + 1) % self.max - - def get(self): - """ return list of elements in correct order """ - return self.data[self.cur:] + self.data[:self.cur] - - def append(self, x): - """append an element at the end of the buffer""" - self.data.append(x) - if len(self.data) == self.max: - self.cur = 0 - # Permanently change self's class from non-full to full - self.__class__ = __Full - - def get(self): - """ Return a list of elements from the oldest to the newest. """ - return self.data - - def __get_item__(self, i): - return self.data[i % len(self.data)] - - -def get_split_ind(seq, N): - """ - *seq* is a list of words. Return the index into seq such that:: - - len(' '.join(seq[:ind])<=N - - . - """ - - sLen = 0 - # todo: use Alex's xrange pattern from the cbook for efficiency - for (word, ind) in zip(seq, xrange(len(seq))): - sLen += len(word) + 1 # +1 to account for the len(' ') - if sLen >= N: - return ind - return len(seq) - - -def wrap(prefix, text, cols): - 'wrap *text* with *prefix* at length *cols*' - pad = ' ' * len(prefix.expandtabs()) - available = cols - len(pad) - - seq = text.split(' ') - Nseq = len(seq) - ind = 0 - lines = [] - while ind < Nseq: - lastInd = ind - ind += get_split_ind(seq[ind:], available) - lines.append(seq[lastInd:ind]) - - # add the prefix to the first line, pad with spaces otherwise - ret = prefix + ' '.join(lines[0]) + '\n' - for line in lines[1:]: - ret += pad + ' '.join(line) + '\n' - return ret - -# A regular expression used to determine the amount of space to -# remove. It looks for the first sequence of spaces immediately -# following the first newline, or at the beginning of the string. -_find_dedent_regex = re.compile("(?:(?:\n\r?)|^)( *)\S") -# A cache to hold the regexs that actually remove the indent. -_dedent_regex = {} - - -def dedent(s): - """ - Remove excess indentation from docstring *s*. - - Discards any leading blank lines, then removes up to n whitespace - characters from each line, where n is the number of leading - whitespace characters in the first line. It differs from - textwrap.dedent in its deletion of leading blank lines and its use - of the first non-blank line to determine the indentation. - - It is also faster in most cases. - """ - # This implementation has a somewhat obtuse use of regular - # expressions. However, this function accounted for almost 30% of - # matplotlib startup time, so it is worthy of optimization at all - # costs. - - if not s: # includes case of s is None - return '' - - match = _find_dedent_regex.match(s) - if match is None: - return s - - # This is the number of spaces to remove from the left-hand side. - nshift = match.end(1) - match.start(1) - if nshift == 0: - return s - - # Get a regex that will remove *up to* nshift spaces from the - # beginning of each line. If it isn't in the cache, generate it. - unindent = _dedent_regex.get(nshift, None) - if unindent is None: - unindent = re.compile("\n\r? {0,%d}" % nshift) - _dedent_regex[nshift] = unindent - - result = unindent.sub("\n", s).strip() - return result - - -def listFiles(root, patterns='*', recurse=1, return_folders=0): - """ - Recursively list files - - from Parmar and Martelli in the Python Cookbook - """ - import os.path - import fnmatch - # Expand patterns from semicolon-separated string to list - pattern_list = patterns.split(';') - results = [] - - for dirname, dirs, files in os.walk(root): - # Append to results all relevant files (and perhaps folders) - for name in files: - fullname = os.path.normpath(os.path.join(dirname, name)) - if return_folders or os.path.isfile(fullname): - for pattern in pattern_list: - if fnmatch.fnmatch(name, pattern): - results.append(fullname) - break - # Block recursion if recursion was disallowed - if not recurse: - break - - return results - - -def get_recursive_filelist(args): - """ - Recurse all the files and dirs in *args* ignoring symbolic links - and return the files as a list of strings - """ - files = [] - - for arg in args: - if os.path.isfile(arg): - files.append(arg) - continue - if os.path.isdir(arg): - newfiles = listFiles(arg, recurse=1, return_folders=1) - files.extend(newfiles) - - return [f for f in files if not os.path.islink(f)] - - -def pieces(seq, num=2): - "Break up the *seq* into *num* tuples" - start = 0 - while 1: - item = seq[start:start + num] - if not len(item): - break - yield item - start += num - - -def exception_to_str(s=None): - - sh = io.StringIO() - if s is not None: - print(s, file=sh) - traceback.print_exc(file=sh) - return sh.getvalue() - - -def allequal(seq): - """ - Return *True* if all elements of *seq* compare equal. If *seq* is - 0 or 1 length, return *True* - """ - if len(seq) < 2: - return True - val = seq[0] - for i in xrange(1, len(seq)): - thisval = seq[i] - if thisval != val: - return False - return True - - -def alltrue(seq): - """ - Return *True* if all elements of *seq* evaluate to *True*. If - *seq* is empty, return *False*. - """ - if not len(seq): - return False - for val in seq: - if not val: - return False - return True - - -def onetrue(seq): - """ - Return *True* if one element of *seq* is *True*. It *seq* is - empty, return *False*. - """ - if not len(seq): - return False - for val in seq: - if val: - return True - return False - - -def allpairs(x): - """ - return all possible pairs in sequence *x* - - Condensed by Alex Martelli from this thread_ on c.l.python - - .. _thread: http://groups.google.com/groups?q=all+pairs+group:*python*&hl=en&lr=&ie=UTF-8&selm=mailman.4028.1096403649.5135.python-list%40python.org&rnum=1 - """ - return [(s, f) for i, f in enumerate(x) for s in x[i + 1:]] - - -class maxdict(dict): - """ - A dictionary with a maximum size; this doesn't override all the - relevant methods to contrain size, just setitem, so use with - caution - """ - def __init__(self, maxsize): - dict.__init__(self) - self.maxsize = maxsize - self._killkeys = [] - - def __setitem__(self, k, v): - if k not in self: - if len(self) >= self.maxsize: - del self[self._killkeys[0]] - del self._killkeys[0] - self._killkeys.append(k) - dict.__setitem__(self, k, v) - - -class Stack(object): - """ - Implement a stack where elements can be pushed on and you can move - back and forth. But no pop. Should mimic home / back / forward - in a browser - """ - - def __init__(self, default=None): - self.clear() - self._default = default - - def __call__(self): - 'return the current element, or None' - if not len(self._elements): - return self._default - else: - return self._elements[self._pos] - - def __len__(self): - return self._elements.__len__() - - def __getitem__(self, ind): - return self._elements.__getitem__(ind) - - def forward(self): - 'move the position forward and return the current element' - N = len(self._elements) - if self._pos < N - 1: - self._pos += 1 - return self() - - def back(self): - 'move the position back and return the current element' - if self._pos > 0: - self._pos -= 1 - return self() - - def push(self, o): - """ - push object onto stack at current position - all elements - occurring later than the current position are discarded - """ - self._elements = self._elements[:self._pos + 1] - self._elements.append(o) - self._pos = len(self._elements) - 1 - return self() - - def home(self): - 'push the first element onto the top of the stack' - if not len(self._elements): - return - self.push(self._elements[0]) - return self() - - def empty(self): - return len(self._elements) == 0 - - def clear(self): - 'empty the stack' - self._pos = -1 - self._elements = [] - - def bubble(self, o): - """ - raise *o* to the top of the stack and return *o*. *o* must be - in the stack - """ - - if o not in self._elements: - raise ValueError('Unknown element o') - old = self._elements[:] - self.clear() - bubbles = [] - for thiso in old: - if thiso == o: - bubbles.append(thiso) - else: - self.push(thiso) - for thiso in bubbles: - self.push(o) - return o - - def remove(self, o): - 'remove element *o* from the stack' - if o not in self._elements: - raise ValueError('Unknown element o') - old = self._elements[:] - self.clear() - for thiso in old: - if thiso == o: - continue - else: - self.push(thiso) - - -def popall(seq): - 'empty a list' - for i in xrange(len(seq)): - seq.pop() - - -def finddir(o, match, case=False): - """ - return all attributes of *o* which match string in match. if case - is True require an exact case match. - """ - if case: - names = [(name, name) for name in dir(o) if is_string_like(name)] - else: - names = [(name.lower(), name) for name in dir(o) - if is_string_like(name)] - match = match.lower() - return [orig for name, orig in names if name.find(match) >= 0] - - -def reverse_dict(d): - 'reverse the dictionary -- may lose data if values are not unique!' - return dict([(v, k) for k, v in d.iteritems()]) - - -def restrict_dict(d, keys): - """ - Return a dictionary that contains those keys that appear in both - d and keys, with values from d. - """ - return dict([(k, v) for (k, v) in d.iteritems() if k in keys]) - - -def report_memory(i=0): # argument may go away - 'return the memory consumed by process' - from subprocess import Popen, PIPE - pid = os.getpid() - if sys.platform == 'sunos5': - a2 = Popen('ps -p %d -o osz' % pid, shell=True, - stdout=PIPE).stdout.readlines() - mem = int(a2[-1].strip()) - elif sys.platform.startswith('linux'): - a2 = Popen('ps -p %d -o rss,sz' % pid, shell=True, - stdout=PIPE).stdout.readlines() - mem = int(a2[1].split()[1]) - elif sys.platform.startswith('darwin'): - a2 = Popen('ps -p %d -o rss,vsz' % pid, shell=True, - stdout=PIPE).stdout.readlines() - mem = int(a2[1].split()[0]) - elif sys.platform.startswith('win'): - try: - a2 = Popen(["tasklist", "/nh", "/fi", "pid eq %d" % pid], - stdout=PIPE).stdout.read() - except OSError: - raise NotImplementedError( - "report_memory works on Windows only if " - "the 'tasklist' program is found") - mem = int(a2.strip().split()[-2].replace(',', '')) - else: - raise NotImplementedError( - "We don't have a memory monitor for %s" % sys.platform) - return mem - -_safezip_msg = 'In safezip, len(args[0])=%d but len(args[%d])=%d' - - -def safezip(*args): - 'make sure *args* are equal len before zipping' - Nx = len(args[0]) - for i, arg in enumerate(args[1:]): - if len(arg) != Nx: - raise ValueError(_safezip_msg % (Nx, i + 1, len(arg))) - return zip(*args) - - -def issubclass_safe(x, klass): - 'return issubclass(x, klass) and return False on a TypeError' - - try: - return issubclass(x, klass) - except TypeError: - return False - - -def safe_masked_invalid(x): - x = np.asanyarray(x) - try: - xm = np.ma.masked_invalid(x, copy=False) - xm.shrink_mask() - except TypeError: - return x - return xm - - -class MemoryMonitor: - def __init__(self, nmax=20000): - self._nmax = nmax - self._mem = np.zeros((self._nmax,), np.int32) - self.clear() - - def clear(self): - self._n = 0 - self._overflow = False - - def __call__(self): - mem = report_memory() - if self._n < self._nmax: - self._mem[self._n] = mem - self._n += 1 - else: - self._overflow = True - return mem - - def report(self, segments=4): - n = self._n - segments = min(n, segments) - dn = int(n / segments) - ii = range(0, n, dn) - ii[-1] = n - 1 - print() - print('memory report: i, mem, dmem, dmem/nloops') - print(0, self._mem[0]) - for i in range(1, len(ii)): - di = ii[i] - ii[i - 1] - if di == 0: - continue - dm = self._mem[ii[i]] - self._mem[ii[i - 1]] - print('%5d %5d %3d %8.3f' % (ii[i], self._mem[ii[i]], - dm, dm / float(di))) - if self._overflow: - print("Warning: array size was too small for the number of calls.") - - def xy(self, i0=0, isub=1): - x = np.arange(i0, self._n, isub) - return x, self._mem[i0:self._n:isub] - - def plot(self, i0=0, isub=1, fig=None): - if fig is None: - from pylab import figure, show - fig = figure() - - ax = fig.add_subplot(111) - ax.plot(*self.xy(i0, isub)) - fig.canvas.draw() - - -def print_cycles(objects, outstream=sys.stdout, show_progress=False): - """ - *objects* - A list of objects to find cycles in. It is often useful to - pass in gc.garbage to find the cycles that are preventing some - objects from being garbage collected. - - *outstream* - The stream for output. - - *show_progress* - If True, print the number of objects reached as they are found. - """ - import gc - from types import FrameType - - def print_path(path): - for i, step in enumerate(path): - # next "wraps around" - next = path[(i + 1) % len(path)] - - outstream.write(" %s -- " % str(type(step))) - if isinstance(step, dict): - for key, val in step.iteritems(): - if val is next: - outstream.write("[%s]" % repr(key)) - break - if key is next: - outstream.write("[key] = %s" % repr(val)) - break - elif isinstance(step, list): - outstream.write("[%d]" % step.index(next)) - elif isinstance(step, tuple): - outstream.write("( tuple )") - else: - outstream.write(repr(step)) - outstream.write(" ->\n") - outstream.write("\n") - - def recurse(obj, start, all, current_path): - if show_progress: - outstream.write("%d\r" % len(all)) - - all[id(obj)] = None - - referents = gc.get_referents(obj) - for referent in referents: - # If we've found our way back to the start, this is - # a cycle, so print it out - if referent is start: - print_path(current_path) - - # Don't go back through the original list of objects, or - # through temporary references to the object, since those - # are just an artifact of the cycle detector itself. - elif referent is objects or isinstance(referent, FrameType): - continue - - # We haven't seen this object before, so recurse - elif id(referent) not in all: - recurse(referent, start, all, current_path + [obj]) - - for obj in objects: - outstream.write("Examining: %r\n" % (obj,)) - recurse(obj, obj, {}, []) - - -class Grouper(object): - """ - This class provides a lightweight way to group arbitrary objects - together into disjoint sets when a full-blown graph data structure - would be overkill. - - Objects can be joined using :meth:`join`, tested for connectedness - using :meth:`joined`, and all disjoint sets can be retreived by - using the object as an iterator. - - The objects being joined must be hashable and weak-referenceable. - - For example: - - >>> from matplotlib.cbook import Grouper - >>> class Foo(object): - ... def __init__(self, s): - ... self.s = s - ... def __repr__(self): - ... return self.s - ... - >>> a, b, c, d, e, f = [Foo(x) for x in 'abcdef'] - >>> grp = Grouper() - >>> grp.join(a, b) - >>> grp.join(b, c) - >>> grp.join(d, e) - >>> sorted(map(tuple, grp)) - [(d, e), (a, b, c)] - >>> grp.joined(a, b) - True - >>> grp.joined(a, c) - True - >>> grp.joined(a, d) - False - - """ - def __init__(self, init=[]): - mapping = self._mapping = {} - for x in init: - mapping[ref(x)] = [ref(x)] - - def __contains__(self, item): - return ref(item) in self._mapping - - def clean(self): - """ - Clean dead weak references from the dictionary - """ - mapping = self._mapping - to_drop = [key for key in mapping if key() is None] - for key in to_drop: - val = mapping.pop(key) - val.remove(key) - - def join(self, a, *args): - """ - Join given arguments into the same set. Accepts one or more - arguments. - """ - mapping = self._mapping - set_a = mapping.setdefault(ref(a), [ref(a)]) - - for arg in args: - set_b = mapping.get(ref(arg)) - if set_b is None: - set_a.append(ref(arg)) - mapping[ref(arg)] = set_a - elif set_b is not set_a: - if len(set_b) > len(set_a): - set_a, set_b = set_b, set_a - set_a.extend(set_b) - for elem in set_b: - mapping[elem] = set_a - - self.clean() - - def joined(self, a, b): - """ - Returns True if *a* and *b* are members of the same set. - """ - self.clean() - - mapping = self._mapping - try: - return mapping[ref(a)] is mapping[ref(b)] - except KeyError: - return False - - def __iter__(self): - """ - Iterate over each of the disjoint sets as a list. - - The iterator is invalid if interleaved with calls to join(). - """ - self.clean() - - class Token: - pass - token = Token() - - # Mark each group as we come across if by appending a token, - # and don't yield it twice - for group in self._mapping.itervalues(): - if not group[-1] is token: - yield [x() for x in group] - group.append(token) - - # Cleanup the tokens - for group in self._mapping.itervalues(): - if group[-1] is token: - del group[-1] - - def get_siblings(self, a): - """ - Returns all of the items joined with *a*, including itself. - """ - self.clean() - - siblings = self._mapping.get(ref(a), [ref(a)]) - return [x() for x in siblings] - - -def simple_linear_interpolation(a, steps): - if steps == 1: - return a - - steps = np.floor(steps) - new_length = ((len(a) - 1) * steps) + 1 - new_shape = list(a.shape) - new_shape[0] = new_length - result = np.zeros(new_shape, a.dtype) - - result[0] = a[0] - a0 = a[0:-1] - a1 = a[1:] - delta = ((a1 - a0) / steps) - - for i in range(1, int(steps)): - result[i::steps] = delta * i + a0 - result[steps::steps] = a1 - - return result - - -def recursive_remove(path): - if os.path.isdir(path): - for fname in glob.glob(os.path.join(path, '*')) + \ - glob.glob(os.path.join(path, '.*')): - if os.path.isdir(fname): - recursive_remove(fname) - os.removedirs(fname) - else: - os.remove(fname) - #os.removedirs(path) - else: - os.remove(path) - - -def delete_masked_points(*args): - """ - Find all masked and/or non-finite points in a set of arguments, - and return the arguments with only the unmasked points remaining. - - Arguments can be in any of 5 categories: - - 1) 1-D masked arrays - 2) 1-D ndarrays - 3) ndarrays with more than one dimension - 4) other non-string iterables - 5) anything else - - The first argument must be in one of the first four categories; - any argument with a length differing from that of the first - argument (and hence anything in category 5) then will be - passed through unchanged. - - Masks are obtained from all arguments of the correct length - in categories 1, 2, and 4; a point is bad if masked in a masked - array or if it is a nan or inf. No attempt is made to - extract a mask from categories 2, 3, and 4 if :meth:`np.isfinite` - does not yield a Boolean array. - - All input arguments that are not passed unchanged are returned - as ndarrays after removing the points or rows corresponding to - masks in any of the arguments. - - A vastly simpler version of this function was originally - written as a helper for Axes.scatter(). - - """ - if not len(args): - return () - if (is_string_like(args[0]) or not iterable(args[0])): - raise ValueError("First argument must be a sequence") - nrecs = len(args[0]) - margs = [] - seqlist = [False] * len(args) - for i, x in enumerate(args): - if (not is_string_like(x)) and iterable(x) and len(x) == nrecs: - seqlist[i] = True - if ma.isMA(x): - if x.ndim > 1: - raise ValueError("Masked arrays must be 1-D") - else: - x = np.asarray(x) - margs.append(x) - masks = [] # list of masks that are True where good - for i, x in enumerate(margs): - if seqlist[i]: - if x.ndim > 1: - continue # Don't try to get nan locations unless 1-D. - if ma.isMA(x): - masks.append(~ma.getmaskarray(x)) # invert the mask - xd = x.data - else: - xd = x - try: - mask = np.isfinite(xd) - if isinstance(mask, np.ndarray): - masks.append(mask) - except: # Fixme: put in tuple of possible exceptions? - pass - if len(masks): - mask = reduce(np.logical_and, masks) - igood = mask.nonzero()[0] - if len(igood) < nrecs: - for i, x in enumerate(margs): - if seqlist[i]: - margs[i] = x.take(igood, axis=0) - for i, x in enumerate(margs): - if seqlist[i] and ma.isMA(x): - margs[i] = x.filled() - return margs - - -def unmasked_index_ranges(mask, compressed=True): - ''' - Find index ranges where *mask* is *False*. - - *mask* will be flattened if it is not already 1-D. - - Returns Nx2 :class:`numpy.ndarray` with each row the start and stop - indices for slices of the compressed :class:`numpy.ndarray` - corresponding to each of *N* uninterrupted runs of unmasked - values. If optional argument *compressed* is *False*, it returns - the start and stop indices into the original :class:`numpy.ndarray`, - not the compressed :class:`numpy.ndarray`. Returns *None* if there - are no unmasked values. - - Example:: - - y = ma.array(np.arange(5), mask = [0,0,1,0,0]) - ii = unmasked_index_ranges(ma.getmaskarray(y)) - # returns array [[0,2,] [2,4,]] - - y.compressed()[ii[1,0]:ii[1,1]] - # returns array [3,4,] - - ii = unmasked_index_ranges(ma.getmaskarray(y), compressed=False) - # returns array [[0, 2], [3, 5]] - - y.filled()[ii[1,0]:ii[1,1]] - # returns array [3,4,] - - Prior to the transforms refactoring, this was used to support - masked arrays in Line2D. - - ''' - mask = mask.reshape(mask.size) - m = np.concatenate(((1,), mask, (1,))) - indices = np.arange(len(mask) + 1) - mdif = m[1:] - m[:-1] - i0 = np.compress(mdif == -1, indices) - i1 = np.compress(mdif == 1, indices) - assert len(i0) == len(i1) - if len(i1) == 0: - return None # Maybe this should be np.zeros((0,2), dtype=int) - if not compressed: - return np.concatenate((i0[:, np.newaxis], i1[:, np.newaxis]), axis=1) - seglengths = i1 - i0 - breakpoints = np.cumsum(seglengths) - ic0 = np.concatenate(((0,), breakpoints[:-1])) - ic1 = breakpoints - return np.concatenate((ic0[:, np.newaxis], ic1[:, np.newaxis]), axis=1) - -# a dict to cross-map linestyle arguments -_linestyles = [('-', 'solid'), - ('--', 'dashed'), - ('-.', 'dashdot'), - (':', 'dotted')] - -ls_mapper = dict(_linestyles) -ls_mapper.update([(ls[1], ls[0]) for ls in _linestyles]) - - -def less_simple_linear_interpolation(x, y, xi, extrap=False): - """ - This function has been moved to matplotlib.mlab -- please import - it from there - """ - # deprecated from cbook in 0.98.4 - warnings.warn('less_simple_linear_interpolation has been moved to ' - 'matplotlib.mlab -- please import it from there', - mplDeprecation) - import matplotlib.mlab as mlab - return mlab.less_simple_linear_interpolation(x, y, xi, extrap=extrap) - - -def vector_lengths(X, P=2.0, axis=None): - """ - This function has been moved to matplotlib.mlab -- please import - it from there - """ - # deprecated from cbook in 0.98.4 - warnings.warn('vector_lengths has been moved to matplotlib.mlab -- ' - 'please import it from there', mplDeprecation) - import matplotlib.mlab as mlab - return mlab.vector_lengths(X, P=2.0, axis=axis) - - -def distances_along_curve(X): - """ - This function has been moved to matplotlib.mlab -- please import - it from there - """ - # deprecated from cbook in 0.98.4 - warnings.warn('distances_along_curve has been moved to matplotlib.mlab ' - '-- please import it from there', mplDeprecation) - import matplotlib.mlab as mlab - return mlab.distances_along_curve(X) - - -def path_length(X): - """ - This function has been moved to matplotlib.mlab -- please import - it from there - """ - # deprecated from cbook in 0.98.4 - warnings.warn('path_length has been moved to matplotlib.mlab ' - '-- please import it from there', mplDeprecation) - import matplotlib.mlab as mlab - return mlab.path_length(X) - - -def is_closed_polygon(X): - """ - This function has been moved to matplotlib.mlab -- please import - it from there - """ - # deprecated from cbook in 0.98.4 - warnings.warn('is_closed_polygon has been moved to matplotlib.mlab ' - '-- please import it from there', mplDeprecation) - import matplotlib.mlab as mlab - return mlab.is_closed_polygon(X) - - -def quad2cubic(q0x, q0y, q1x, q1y, q2x, q2y): - """ - This function has been moved to matplotlib.mlab -- please import - it from there - """ - # deprecated from cbook in 0.98.4 - warnings.warn('quad2cubic has been moved to matplotlib.mlab -- please ' - 'import it from there', mplDeprecation) - import matplotlib.mlab as mlab - return mlab.quad2cubic(q0x, q0y, q1x, q1y, q2x, q2y) - - -def align_iterators(func, *iterables): - """ - This generator takes a bunch of iterables that are ordered by func - It sends out ordered tuples:: - - (func(row), [rows from all iterators matching func(row)]) - - It is used by :func:`matplotlib.mlab.recs_join` to join record arrays - """ - class myiter: - def __init__(self, it): - self.it = it - self.key = self.value = None - self.iternext() - - def iternext(self): - try: - self.value = next(self.it) - self.key = func(self.value) - except StopIteration: - self.value = self.key = None - - def __call__(self, key): - retval = None - if key == self.key: - retval = self.value - self.iternext() - elif self.key and key > self.key: - raise ValueError("Iterator has been left behind") - return retval - - # This can be made more efficient by not computing the minimum key for each - # iteration - iters = [myiter(it) for it in iterables] - minvals = minkey = True - while 1: - minvals = ([_f for _f in [it.key for it in iters] if _f]) - if minvals: - minkey = min(minvals) - yield (minkey, [it(minkey) for it in iters]) - else: - break - - -def is_math_text(s): - # Did we find an even number of non-escaped dollar signs? - # If so, treat is as math text. - try: - s = unicode(s) - except UnicodeDecodeError: - raise ValueError( - "matplotlib display text must have all code points < 128 or use " - "Unicode strings") - - dollar_count = s.count(r'$') - s.count(r'\$') - even_dollars = (dollar_count > 0 and dollar_count % 2 == 0) - - return even_dollars - - -class _NestedClassGetter(object): - # recipe from http://stackoverflow.com/a/11493777/741316 - """ - When called with the containing class as the first argument, - and the name of the nested class as the second argument, - returns an instance of the nested class. - """ - def __call__(self, containing_class, class_name): - nested_class = getattr(containing_class, class_name) - - # make an instance of a simple object (this one will do), for which we - # can change the __class__ later on. - nested_instance = _NestedClassGetter() - - # set the class of the instance, the __init__ will never be called on - # the class but the original state will be set later on by pickle. - nested_instance.__class__ = nested_class - return nested_instance - - -class _InstanceMethodPickler(object): - """ - Pickle cannot handle instancemethod saving. _InstanceMethodPickler - provides a solution to this. - """ - def __init__(self, instancemethod): - """Takes an instancemethod as its only argument.""" - self.parent_obj = instancemethod.im_self - self.instancemethod_name = instancemethod.im_func.__name__ - - def get_instancemethod(self): - return getattr(self.parent_obj, self.instancemethod_name) - - -# Numpy > 1.6.x deprecates putmask in favor of the new copyto. -# So long as we support versions 1.6.x and less, we need the -# following local version of putmask. We choose to make a -# local version of putmask rather than of copyto because the -# latter includes more functionality than the former. Therefore -# it is easy to make a local version that gives full putmask -# behavior, but duplicating the full copyto behavior would be -# more difficult. - -try: - np.copyto -except AttributeError: - _putmask = np.putmask -else: - def _putmask(a, mask, values): - return np.copyto(a, values, where=mask) - - -def _check_output(*popenargs, **kwargs): - r"""Run command with arguments and return its output as a byte - string. - - If the exit code was non-zero it raises a CalledProcessError. The - CalledProcessError object will have the return code in the - returncode - attribute and output in the output attribute. - - The arguments are the same as for the Popen constructor. Example:: - - >>> check_output(["ls", "-l", "/dev/null"]) - 'crw-rw-rw- 1 root root 1, 3 Oct 18 2007 /dev/null\n' - - The stdout argument is not allowed as it is used internally. - To capture standard error in the result, use stderr=STDOUT.:: - - >>> check_output(["/bin/sh", "-c", - ... "ls -l non_existent_file ; exit 0"], - ... stderr=STDOUT) - 'ls: non_existent_file: No such file or directory\n' - """ - if 'stdout' in kwargs: - raise ValueError('stdout argument not allowed, it will be overridden.') - process = subprocess.Popen(stdout=subprocess.PIPE, *popenargs, **kwargs) - output, unused_err = process.communicate() - retcode = process.poll() - if retcode: - cmd = kwargs.get("args") - if cmd is None: - cmd = popenargs[0] - raise subprocess.CalledProcessError(retcode, cmd, output=output) - return output - - -# python2.7's subprocess provides a check_output method -if hasattr(subprocess, 'check_output'): - check_output = subprocess.check_output -else: - check_output = _check_output - - -if __name__ == '__main__': - assert(allequal([1, 1, 1])) - assert(not allequal([1, 1, 0])) - assert(allequal([])) - assert(allequal(('a', 'a'))) - assert(not allequal(('a', 'b'))) +warnings.warn("The module cbook is deprecated. It will be removed in 1.5.x. " + "For more information, please see CHANGELOG files or XXX", + mplDeprecation) diff --git a/lib/matplotlib/cm.py b/lib/matplotlib/cm.py index 0566adc59195..50a8a8e534e0 100644 --- a/lib/matplotlib/cm.py +++ b/lib/matplotlib/cm.py @@ -6,13 +6,11 @@ """ from __future__ import print_function, division -import os - import numpy as np from numpy import ma import matplotlib as mpl import matplotlib.colors as colors -import matplotlib.cbook as cbook +import matplotlib.utils as utils from matplotlib._cm import datad from matplotlib._cm import cubehelix @@ -117,7 +115,7 @@ def register_cmap(name=None, cmap=None, data=None, lut=None): except AttributeError: raise ValueError("Arguments must include a name or a Colormap") - if not cbook.is_string_like(name): + if not utils.is_string_like(name): raise ValueError("Colormap name must be a string") if isinstance(cmap, colors.Colormap): @@ -174,7 +172,7 @@ def __init__(self, norm=None, cmap=None): :mod:`cm` colormap instance, for example :data:`cm.jet` """ - self.callbacksSM = cbook.CallbackRegistry() + self.callbacksSM = utils.CallbackRegistry() if cmap is None: cmap = get_cmap() @@ -276,7 +274,7 @@ def set_clim(self, vmin=None, vmax=None): ACCEPTS: a length 2 sequence of floats """ if (vmin is not None and vmax is None and - cbook.iterable(vmin) and len(vmin) == 2): + utils.iterable(vmin) and len(vmin) == 2): vmin, vmax = vmin if vmin is not None: diff --git a/lib/matplotlib/collections.py b/lib/matplotlib/collections.py index c6d96e6a7116..f11facc6943e 100644 --- a/lib/matplotlib/collections.py +++ b/lib/matplotlib/collections.py @@ -13,8 +13,8 @@ import numpy as np import numpy.ma as ma import matplotlib as mpl -import matplotlib.cbook as cbook import matplotlib.colors as mcolors +import matplotlib.utils as utils import matplotlib.cm as cm from matplotlib import docstring import matplotlib.transforms as transforms @@ -133,7 +133,7 @@ def _get_value(val): try: return (float(val), ) except TypeError: - if cbook.iterable(val) and len(val): + if utils.iterable(val) and len(val): try: float(val[0]) except (TypeError, ValueError): @@ -145,7 +145,7 @@ def _get_value(val): @staticmethod def _get_bool(val): - if not cbook.iterable(val): + if not utils.iterable(val): val = (val,) try: bool(val[0]) @@ -346,7 +346,7 @@ def set_hatch(self, hatch): can only be specified for the collection as a whole, not separately for each member. - ACCEPTS: [ '/' | '\\\\' | '|' | '-' | '+' | 'x' | 'o' | 'O' | '.' | '*' ] + ACCEPTS: ['/' | '\\\\' | '|' | '-' | '+' | 'x' | 'o' | 'O' | '.' | '*'] """ self._hatch = hatch @@ -431,25 +431,25 @@ def set_linestyle(self, ls): """ try: dashd = backend_bases.GraphicsContextBase.dashd - if cbook.is_string_like(ls): + if utils.is_string_like(ls): if ls in dashd: dashes = [dashd[ls]] - elif ls in cbook.ls_mapper: - dashes = [dashd[cbook.ls_mapper[ls]]] + elif ls in utils.ls_mapper: + dashes = [dashd[utils.ls_mapper[ls]]] else: raise ValueError() - elif cbook.iterable(ls): + elif utils.iterable(ls): try: dashes = [] for x in ls: - if cbook.is_string_like(x): + if utils.is_string_like(x): if x in dashd: dashes.append(dashd[x]) - elif x in cbook.ls_mapper: - dashes.append(dashd[cbook.ls_mapper[x]]) + elif x in utils.ls_mapper: + dashes.append(dashd[utils.ls_mapper[x]]) else: raise ValueError() - elif cbook.iterable(x) and len(x) == 2: + elif utils.iterable(x) and len(x) == 2: dashes.append(x) else: raise ValueError() diff --git a/lib/matplotlib/colorbar.py b/lib/matplotlib/colorbar.py index 380022f3fe15..dc8ee1ec774e 100644 --- a/lib/matplotlib/colorbar.py +++ b/lib/matplotlib/colorbar.py @@ -25,7 +25,7 @@ import matplotlib as mpl import matplotlib.artist as martist -import matplotlib.cbook as cbook +import matplotlib.utils as utils import matplotlib.collections as collections import matplotlib.colors as colors import matplotlib.contour as contour @@ -288,7 +288,7 @@ def __init__(self, ax, cmap=None, self.patch = None self.dividers = None self.set_label('') - if cbook.iterable(ticks): + if utils.iterable(ticks): self.locator = ticker.FixedLocator(ticks, nbins=len(ticks)) else: self.locator = ticks # Handle default in _ticker() @@ -297,7 +297,7 @@ def __init__(self, ax, cmap=None, self.formatter = ticker.LogFormatterMathtext() else: self.formatter = ticker.ScalarFormatter() - elif cbook.is_string_like(format): + elif utils.is_string_like(format): self.formatter = ticker.FormatStrFormatter(format) else: self.formatter = format # Assume it is a Formatter @@ -367,7 +367,7 @@ def set_ticks(self, ticks, update_ticks=True): update_ticks is *False*. To manually update the ticks, call *update_ticks* method explicitly. """ - if cbook.iterable(ticks): + if utils.iterable(ticks): self.locator = ticker.FixedLocator(ticks, nbins=len(ticks)) else: self.locator = ticks @@ -509,9 +509,9 @@ def add_lines(self, levels, colors, linewidths, erase=True): y = self._locate(levels) igood = (y < 1.001) & (y > -0.001) y = y[igood] - if cbook.iterable(colors): + if utils.iterable(colors): colors = np.asarray(colors)[igood] - if cbook.iterable(linewidths): + if utils.iterable(linewidths): linewidths = np.asarray(linewidths)[igood] N = len(y) x = np.array([0.0, 1.0]) diff --git a/lib/matplotlib/colors.py b/lib/matplotlib/colors.py index e27b2b141e5c..c650609121d0 100644 --- a/lib/matplotlib/colors.py +++ b/lib/matplotlib/colors.py @@ -51,7 +51,7 @@ import re import numpy as np from numpy import ma -import matplotlib.cbook as cbook +import matplotlib.utils as utils parts = np.__version__.split('.') NP_MAJOR, NP_MINOR = map(int, parts[:2]) @@ -290,7 +290,7 @@ def to_rgb(self, arg): % (str(arg),)) try: - if cbook.is_string_like(arg): + if utils.is_string_like(arg): argl = arg.lower() color = self.colors.get(argl, None) if color is None: @@ -303,7 +303,7 @@ def to_rgb(self, arg): raise ValueError( 'gray (string) must be in range 0-1') color = tuple([fl] * 3) - elif cbook.iterable(arg): + elif utils.iterable(arg): if len(arg) > 4 or len(arg) < 3: raise ValueError( 'sequence length is %d; must be 3 or 4' % len(arg)) @@ -343,7 +343,7 @@ def to_rgba(self, arg, alpha=None): pass try: - if not cbook.is_string_like(arg) and cbook.iterable(arg): + if not utils.is_string_like(arg) and utils.iterable(arg): if len(arg) == 4: if [x for x in arg if (float(x) < 0) or (x > 1)]: # This will raise TypeError if x is not a number. @@ -522,7 +522,7 @@ def __call__(self, X, alpha=None, bytes=False): if not self._isinit: self._init() mask_bad = None - if not cbook.iterable(X): + if not utils.iterable(X): vtype = 'scalar' xa = np.array([X]) else: @@ -542,7 +542,7 @@ def __call__(self, X, alpha=None, bytes=False): # Treat 1.0 as slightly less than 1. vals = np.array([1, 0], dtype=xa.dtype) almost_one = np.nextafter(*vals) - cbook._putmask(xa, xa == 1.0, almost_one) + utils._putmask(xa, xa == 1.0, almost_one) # The following clip is fast, and prevents possible # conversion of large positive values to negative integers. @@ -554,15 +554,15 @@ def __call__(self, X, alpha=None, bytes=False): # ensure that all 'under' values will still have negative # value after casting to int - cbook._putmask(xa, xa < 0.0, -1) + utils._putmask(xa, xa < 0.0, -1) xa = xa.astype(int) # Set the over-range indices before the under-range; # otherwise the under-range values get converted to over-range. - cbook._putmask(xa, xa > self.N - 1, self._i_over) - cbook._putmask(xa, xa < 0, self._i_under) + utils._putmask(xa, xa > self.N - 1, self._i_over) + utils._putmask(xa, xa < 0, self._i_under) if mask_bad is not None: if mask_bad.shape == xa.shape: - cbook._putmask(xa, mask_bad, self._i_bad) + utils._putmask(xa, mask_bad, self._i_bad) elif mask_bad: xa.fill(self._i_bad) if bytes: @@ -731,11 +731,11 @@ def from_list(name, colors, N=256, gamma=1.0): to divide the range unevenly. """ - if not cbook.iterable(colors): + if not utils.iterable(colors): raise ValueError('colors must be iterable') - if cbook.iterable(colors[0]) and len(colors[0]) == 2 and \ - not cbook.is_string_like(colors[0]): + if utils.iterable(colors[0]) and len(colors[0]) == 2 and \ + not utils.is_string_like(colors[0]): # List of value, color pairs vals, colors = zip(*colors) else: @@ -788,10 +788,10 @@ def __init__(self, colors, name='from_list', N=None): if N is None: N = len(self.colors) else: - if cbook.is_string_like(self.colors): + if utils.is_string_like(self.colors): self.colors = [self.colors] * N self.monochrome = True - elif cbook.iterable(self.colors): + elif utils.iterable(self.colors): self.colors = list(self.colors) # in case it was a tuple if len(self.colors) == 1: self.monochrome = True @@ -857,7 +857,7 @@ def process_value(value): Experimental; we may want to add an option to force the use of float32. """ - if cbook.iterable(value): + if utils.iterable(value): is_scalar = False result = ma.asarray(value) if result.dtype.kind == 'f': @@ -906,7 +906,7 @@ def inverse(self, value): vmin = float(self.vmin) vmax = float(self.vmax) - if cbook.iterable(value): + if utils.iterable(value): val = ma.asarray(value) return vmin + val * (vmax - vmin) else: @@ -963,7 +963,7 @@ def __call__(self, value, clip=None): mask = (resdat <= 0) else: mask |= resdat <= 0 - cbook._putmask(resdat, mask, 1) + utils._putmask(resdat, mask, 1) np.log(resdat, resdat) resdat -= np.log(vmin) resdat /= (np.log(vmax) - np.log(vmin)) @@ -977,7 +977,7 @@ def inverse(self, value): raise ValueError("Not invertible until scaled") vmin, vmax = self.vmin, self.vmax - if cbook.iterable(value): + if utils.iterable(value): val = ma.asarray(value) return vmin * ma.power((vmax / vmin), val) else: diff --git a/lib/matplotlib/container.py b/lib/matplotlib/container.py index ac6f2de2f0ec..827fd2f1ef5f 100644 --- a/lib/matplotlib/container.py +++ b/lib/matplotlib/container.py @@ -1,4 +1,4 @@ -import matplotlib.cbook as cbook +import matplotlib.utils as utils class Container(tuple): @@ -87,7 +87,7 @@ def pchanged(self): func(self) def get_children(self): - return list(cbook.flatten(self)) + return list(utils.flatten(self)) class BarContainer(Container): diff --git a/lib/matplotlib/contour.py b/lib/matplotlib/contour.py index aa7cc0a6a4a8..31349eccbb2b 100644 --- a/lib/matplotlib/contour.py +++ b/lib/matplotlib/contour.py @@ -15,7 +15,7 @@ import matplotlib.collections as mcoll import matplotlib.font_manager as font_manager import matplotlib.text as text -import matplotlib.cbook as cbook +import matplotlib.utils as utils import matplotlib.mlab as mlab import matplotlib.mathtext as mathtext import matplotlib.patches as mpatches @@ -203,7 +203,7 @@ def clabel(self, *args, **kwargs): #self.labelCValues = [] # same self.labelXYs = [] - if cbook.iterable(self.labelManual): + if utils.iterable(self.labelManual): for x, y in self.labelManual: self.add_label_near(x, y, inline, inline_spacing) @@ -226,7 +226,7 @@ def clabel(self, *args, **kwargs): self.cl_xy = self.labelXYs self.cl_cvalues = self.labelCValues - self.labelTextsList = cbook.silent_list('text.Text', self.labelTexts) + self.labelTextsList = utils.silent_list('text.Text', self.labelTexts) return self.labelTextsList def print_label(self, linecontour, labelwidth): @@ -282,7 +282,7 @@ def get_label_width(self, lev, fmt, fsize): """ Return the width of the label in points. """ - if not cbook.is_string_like(lev): + if not utils.is_string_like(lev): lev = self.get_text(lev, fmt) lev, ismath = text.Text.is_math_text(lev) @@ -338,7 +338,7 @@ def set_label_props(self, label, text, color): def get_text(self, lev, fmt): "get the text of the label" - if cbook.is_string_like(lev): + if utils.is_string_like(lev): return lev else: if isinstance(fmt, dict): @@ -796,9 +796,9 @@ def __init__(self, ax, *args, **kwargs): ncolors -= 1 cmap = colors.ListedColormap(self.colors, N=ncolors) if self.filled: - self.collections = cbook.silent_list('mcoll.PathCollection') + self.collections = utils.silent_list('mcoll.PathCollection') else: - self.collections = cbook.silent_list('mcoll.LineCollection') + self.collections = utils.silent_list('mcoll.LineCollection') # label lists must be initialized here self.labelTexts = [] self.labelCValues = [] @@ -1172,7 +1172,7 @@ def _process_linewidths(self): if linewidths is None: tlinewidths = [(mpl.rcParams['lines.linewidth'],)] * Nlev else: - if not cbook.iterable(linewidths): + if not utils.iterable(linewidths): linewidths = [linewidths] * Nlev else: linewidths = list(linewidths) @@ -1196,9 +1196,9 @@ def _process_linestyles(self): if lev < eps: tlinestyles[i] = neg_ls else: - if cbook.is_string_like(linestyles): + if utils.is_string_like(linestyles): tlinestyles = [linestyles] * Nlev - elif cbook.iterable(linestyles): + elif utils.iterable(linestyles): tlinestyles = list(linestyles) if len(tlinestyles) < Nlev: nreps = int(np.ceil(Nlev / len(linestyles))) diff --git a/lib/matplotlib/dates.py b/lib/matplotlib/dates.py index ccceb4699182..ac632756ad0d 100755 --- a/lib/matplotlib/dates.py +++ b/lib/matplotlib/dates.py @@ -117,7 +117,7 @@ import numpy as np import matplotlib.units as units -import matplotlib.cbook as cbook +import matplotlib.utils as utils import matplotlib.ticker as ticker from dateutil.rrule import rrule, MO, TU, WE, TH, FR, SA, SU, YEARLY, \ @@ -246,7 +246,7 @@ def datestr2num(d): :func:`dateutil.parser.parse`. *d* can be a single string or a sequence of strings. """ - if cbook.is_string_like(d): + if utils.is_string_like(d): dt = dateutil.parser.parse(d) return date2num(dt) else: @@ -264,7 +264,7 @@ def date2num(d): that the Gregorian calendar is assumed; this is not universal practice. For details, see the module docstring. """ - if not cbook.iterable(d): + if not utils.iterable(d): return _to_ordinalf(d) else: return np.asarray([_to_ordinalf(val) for val in d]) @@ -272,14 +272,14 @@ def date2num(d): def julian2num(j): 'Convert a Julian date (or sequence) to a matplotlib date (or sequence).' - if cbook.iterable(j): + if utils.iterable(j): j = np.asarray(j) return j - 1721424.5 def num2julian(n): 'Convert a matplotlib date (or sequence) to a Julian date (or sequence).' - if cbook.iterable(n): + if utils.iterable(n): n = np.asarray(n) return n + 1721424.5 @@ -301,7 +301,7 @@ def num2date(x, tz=None): """ if tz is None: tz = _get_rc_timezone() - if not cbook.iterable(x): + if not utils.iterable(x): return _from_ordinalf(x, tz) else: return [_from_ordinalf(val, tz) for val in x] @@ -392,7 +392,7 @@ def strftime(self, dt, fmt): fmt = self.illegal_s.sub(r"\1", fmt) fmt = fmt.replace("%s", "s") if dt.year > 1900: - return cbook.unicode_safe(dt.strftime(fmt)) + return utils.unicode_safe(dt.strftime(fmt)) year = dt.year # For every non-leap year century, advance by @@ -420,7 +420,7 @@ def strftime(self, dt, fmt): for site in sites: s = s[:site] + syear + s[site + 4:] - return cbook.unicode_safe(s) + return utils.unicode_safe(s) class IndexDateFormatter(ticker.Formatter): @@ -447,7 +447,7 @@ def __call__(self, x, pos=0): dt = num2date(self.t[ind], self.tz) - return cbook.unicode_safe(dt.strftime(self.fmt)) + return utils.unicode_safe(dt.strftime(self.fmt)) class AutoDateFormatter(ticker.Formatter): @@ -1091,7 +1091,7 @@ def mx2num(mxdates): instances) to the new date format. """ scalar = False - if not cbook.iterable(mxdates): + if not utils.iterable(mxdates): scalar = True mxdates = [mxdates] ret = epoch2num([m.ticks() for m in mxdates]) diff --git a/lib/matplotlib/docstring.py b/lib/matplotlib/docstring.py index dd2f23885e19..1449ced292e3 100644 --- a/lib/matplotlib/docstring.py +++ b/lib/matplotlib/docstring.py @@ -1,5 +1,5 @@ from __future__ import print_function -from matplotlib import cbook +import matplotlib.utils as utils import sys import types @@ -85,7 +85,7 @@ def __call__(self, func): def dedent(func): "Dedent a docstring (if present)" - func.__doc__ = func.__doc__ and cbook.dedent(func.__doc__) + func.__doc__ = func.__doc__ and utils.dedent(func.__doc__) return func def copy(source): diff --git a/lib/matplotlib/dviread.py b/lib/matplotlib/dviread.py index 6bc3793ee3f1..81724f168ed5 100644 --- a/lib/matplotlib/dviread.py +++ b/lib/matplotlib/dviread.py @@ -20,9 +20,8 @@ """ from __future__ import print_function -import errno import matplotlib -import matplotlib.cbook as mpl_cbook +import matplotlib.utils as utils import numpy as np import struct import subprocess @@ -32,7 +31,7 @@ def ord(x): return x -_dvistate = mpl_cbook.Bunch(pre=0, outer=1, inpage=2, post_post=3, finale=4) +_dvistate = utils.Bunch(pre=0, outer=1, inpage=2, post_post=3, finale=4) class Dvi(object): """ @@ -103,7 +102,7 @@ def _output(self): if self.dpi is None: # special case for ease of debugging: output raw dvi coordinates - return mpl_cbook.Bunch(text=self.text, boxes=self.boxes, + return utils.Bunch(text=self.text, boxes=self.boxes, width=maxx-minx, height=maxy_pure-miny, descent=maxy-maxy_pure) @@ -112,7 +111,7 @@ def _output(self): for (x,y,f,g,w) in self.text ] boxes = [ ((x-minx)*d, (maxy-y)*d, h*d, w*d) for (x,y,h,w) in self.boxes ] - return mpl_cbook.Bunch(text=text, boxes=boxes, + return utils.Bunch(text=text, boxes=boxes, width=(maxx-minx)*d, height=(maxy_pure-miny)*d, descent=(maxy-maxy_pure)*d) @@ -545,7 +544,7 @@ def _init_packet(self, pl, cc, tfm): self.f = self._first_font def _finalize_packet(self): - self._chars[self._packet_char] = mpl_cbook.Bunch( + self._chars[self._packet_char] = utils.Bunch( text=self.text, boxes=self.boxes, width = self._packet_width) self.state = _dvistate.outer @@ -764,7 +763,7 @@ def _register(self, words): except ValueError: pass - self._font[texname] = mpl_cbook.Bunch( + self._font[texname] = utils.Bunch( texname=texname, psname=psname, effects=effects, encoding=encoding, filename=filename) diff --git a/lib/matplotlib/figure.py b/lib/matplotlib/figure.py index de436c01873a..5cb88398f50f 100644 --- a/lib/matplotlib/figure.py +++ b/lib/matplotlib/figure.py @@ -24,9 +24,9 @@ import matplotlib.artist as martist from matplotlib.artist import Artist, allow_rasterization -import matplotlib.cbook as cbook +import matplotlib.utils as utils -from matplotlib.cbook import Stack, iterable +from matplotlib.utils import Stack, iterable from matplotlib import _image from matplotlib.image import FigureImage @@ -234,7 +234,7 @@ class Figure(Artist): """ The Figure instance supports callbacks through a *callbacks* - attribute which is a :class:`matplotlib.cbook.CallbackRegistry` + attribute which is a :class:`matplotlib.utils.CallbackRegistry` instance. The events you can connect to are 'dpi_changed', and the callback will be called with ``func(fig)`` where fig is the :class:`Figure` instance. @@ -292,7 +292,7 @@ def __init__(self, """ Artist.__init__(self) - self.callbacks = cbook.CallbackRegistry() + self.callbacks = utils.CallbackRegistry() if figsize is None : figsize = rcParams['figure.figsize'] if dpi is None : dpi = rcParams['figure.dpi'] @@ -900,7 +900,7 @@ def clf(self, keep_observers=False): a gui widget is tracking the axes in the figure. """ self.suppressComposite = None - self.callbacks = cbook.CallbackRegistry() + self.callbacks = utils.CallbackRegistry() for ax in tuple(self.axes): # Iterate over the copy. ax.cla() @@ -963,7 +963,7 @@ def draw(self, renderer): not_composite = self.suppressComposite if len(self.images)<=1 or not_composite or \ - not cbook.allequal([im.origin for im in self.images]): + not utils.allequal([im.origin for im in self.images]): for a in self.images: dsu.append( (a.get_zorder(), a, a.draw, [renderer])) else: diff --git a/lib/matplotlib/finance.py b/lib/matplotlib/finance.py index fa4c391cad5a..8a366857b8f4 100644 --- a/lib/matplotlib/finance.py +++ b/lib/matplotlib/finance.py @@ -19,7 +19,7 @@ from matplotlib import verbose, get_configdir from matplotlib.dates import date2num -from matplotlib.cbook import iterable, mkdirs +from matplotlib.utils import iterable, mkdirs from matplotlib.collections import LineCollection, PolyCollection from matplotlib.colors import colorConverter from matplotlib.lines import Line2D, TICKLEFT, TICKRIGHT @@ -79,7 +79,7 @@ def parse_yahoo_historical(fh, adjusted=True, asobject=False): library datetime.date instance. The name of this kwarg is a historical artifact. Formerly, - True returned a cbook Bunch + True returned a utils.Bunch holding 1-D ndarrays. The behavior of a numpy recarray is very similar to the Bunch. diff --git a/lib/matplotlib/font_manager.py b/lib/matplotlib/font_manager.py index 373601875d22..485dba7e343d 100644 --- a/lib/matplotlib/font_manager.py +++ b/lib/matplotlib/font_manager.py @@ -44,23 +44,16 @@ """ import os, sys, subprocess, warnings -try: - set -except NameError: - from sets import Set as set +import pickle import matplotlib from matplotlib import afm from matplotlib import ft2font from matplotlib import rcParams, get_configdir -from matplotlib.cbook import is_string_like -import matplotlib.cbook as cbook +from matplotlib.utils import is_string_like +import matplotlib.utils as utils from matplotlib.fontconfig_pattern import \ parse_fontconfig_pattern, generate_fontconfig_pattern -try: - import cPickle as pickle -except ImportError: - import pickle USE_FONTCONFIG = False @@ -168,7 +161,7 @@ def list_fonts(directory, extensions): """ pattern = ';'.join(['*.%s;*.%s' % (ext, ext.upper()) for ext in extensions]) - return cbook.listFiles(directory, pattern) + return utils.listFiles(directory, pattern) def win32FontDirectory(): """ @@ -254,7 +247,7 @@ def OSXInstalledFonts(directories=None, fontext='ttf'): files = [] for path in directories: if fontext is None: - files.extend(cbook.listFiles(path, '*')) + files.extend(utils.listFiles(path, '*')) else: files.extend(list_fonts(path, fontext)) return files diff --git a/lib/matplotlib/image.py b/lib/matplotlib/image.py index f1292309bdbe..7a651587d119 100644 --- a/lib/matplotlib/image.py +++ b/lib/matplotlib/image.py @@ -5,17 +5,15 @@ """ from __future__ import division, print_function import os, warnings -import math import numpy as np -from numpy import ma from matplotlib import rcParams import matplotlib.artist as martist from matplotlib.artist import allow_rasterization import matplotlib.colors as mcolors import matplotlib.cm as cm -import matplotlib.cbook as cbook +import matplotlib.utils as utils # For clarity, names from _image are given explicitly in this module: import matplotlib._image as _image @@ -412,7 +410,7 @@ def set_data(self, A): if hasattr(A,'getpixel'): self._A = pil_to_array(A) else: - self._A = cbook.safe_masked_invalid(A) + self._A = utils.safe_masked_invalid(A) if self._A.dtype != np.uint8 and not np.can_cast(self._A.dtype, np.float): raise TypeError("Image data can not convert to float") @@ -736,7 +734,7 @@ def set_data(self, x, y, A): """ x = np.asarray(x,np.float32) y = np.asarray(y,np.float32) - A = cbook.safe_masked_invalid(A) + A = utils.safe_masked_invalid(A) if len(x.shape) != 1 or len(y.shape) != 1\ or A.shape[0:2] != (y.shape[0], x.shape[0]): raise TypeError("Axes don't match array shape") @@ -869,7 +867,7 @@ def draw(self, renderer, *args, **kwargs): def set_data(self, x, y, A): - A = cbook.safe_masked_invalid(A) + A = utils.safe_masked_invalid(A) if x is None: x = np.arange(0, A.shape[1]+1, dtype=np.float64) else: @@ -968,7 +966,7 @@ def get_extent(self): def set_data(self, A): """Set the image array.""" - cm.ScalarMappable.set_array(self, cbook.safe_masked_invalid(A)) + cm.ScalarMappable.set_array(self, utils.safe_masked_invalid(A)) def set_array(self, A): """Deprecated; use set_data for consistency with other image types.""" @@ -1193,7 +1191,7 @@ def pilread(fname): from PIL import Image except ImportError: return None - if cbook.is_string_like(fname): + if utils.is_string_like(fname): # force close the file after reading the image with open(fname, "rb") as fh: image = Image.open(fh) @@ -1204,7 +1202,7 @@ def pilread(fname): handlers = {'png' :_png.read_png, } if format is None: - if cbook.is_string_like(fname): + if utils.is_string_like(fname): basename, ext = os.path.splitext(fname) ext = ext.lower()[1:] elif hasattr(fname, 'name'): @@ -1226,7 +1224,7 @@ def pilread(fname): # To handle Unicode filenames, we pass a file object to the PNG # reader extension, since Python handles them quite well, but it's # tricky in C. - if cbook.is_string_like(fname): + if utils.is_string_like(fname): with open(fname, 'rb') as fd: return handler(fd) else: diff --git a/lib/matplotlib/legend.py b/lib/matplotlib/legend.py index 07b7f5cd6f1c..fa1442324a3b 100644 --- a/lib/matplotlib/legend.py +++ b/lib/matplotlib/legend.py @@ -18,7 +18,7 @@ from matplotlib import rcParams from matplotlib.artist import Artist, allow_rasterization -from matplotlib.cbook import is_string_like, iterable, silent_list, safezip +from matplotlib.utils import is_string_like, iterable, silent_list, safezip from matplotlib.font_manager import FontProperties from matplotlib.lines import Line2D from matplotlib.patches import Patch, Rectangle, Shadow, FancyBboxPatch diff --git a/lib/matplotlib/lines.py b/lib/matplotlib/lines.py index 18def5423b32..33168c23a204 100644 --- a/lib/matplotlib/lines.py +++ b/lib/matplotlib/lines.py @@ -13,8 +13,7 @@ from matplotlib import verbose import artist from artist import Artist -from cbook import iterable, is_string_like, is_numlike, ls_mapper, dedent,\ -flatten, is_math_text +from matplotlib.utils import iterable, is_string_like, is_numlike, ls_mapper from colors import colorConverter from path import Path from transforms import Affine2D, Bbox, TransformedPath, IdentityTransform diff --git a/lib/matplotlib/markers.py b/lib/matplotlib/markers.py index ec41869b22ed..562dbe5fe284 100644 --- a/lib/matplotlib/markers.py +++ b/lib/matplotlib/markers.py @@ -8,7 +8,7 @@ import numpy as np -from cbook import is_math_text, is_string_like, is_numlike, iterable +from matplotlib.utils import is_math_text, is_string_like, is_numlike, iterable import docstring from matplotlib import rcParams from path import Path diff --git a/lib/matplotlib/mathtext.py b/lib/matplotlib/mathtext.py index 3742aecf0e1e..d147e03a1040 100644 --- a/lib/matplotlib/mathtext.py +++ b/lib/matplotlib/mathtext.py @@ -49,7 +49,7 @@ ParserElement.enablePackrat() from matplotlib.afm import AFM -from matplotlib.cbook import Bunch, get_realpath_and_stat, \ +from matplotlib.utils import Bunch, get_realpath_and_stat, \ is_string_like, maxdict from matplotlib.ft2font import FT2Font, FT2Image, KERNING_DEFAULT, LOAD_FORCE_AUTOHINT, LOAD_NO_HINTING from matplotlib.font_manager import findfont, FontProperties diff --git a/lib/matplotlib/mlab.py b/lib/matplotlib/mlab.py index 9dfc522f4bb5..765462b015b7 100644 --- a/lib/matplotlib/mlab.py +++ b/lib/matplotlib/mlab.py @@ -150,7 +150,7 @@ from matplotlib import verbose from matplotlib import MatplotlibDeprecationWarning as mplDeprecation -import matplotlib.cbook as cbook +import matplotlib.utils as utils from matplotlib import docstring from matplotlib.path import Path @@ -248,7 +248,7 @@ def _spectral_helper(x, y, NFFT=256, Fs=2, detrend=detrend_none, raise ValueError("sides must be one of: 'default', 'onesided', or " "'twosided'") - if cbook.iterable(window): + if utils.iterable(window): assert(len(window) == NFFT) windowVals = window else: @@ -299,7 +299,7 @@ def _spectral_helper(x, y, NFFT=256, Fs=2, detrend=detrend_none, return Pxy, freqs, t #Split out these keyword docs so that they can be used elsewhere -docstring.interpd.update(PSD=cbook.dedent(""" +docstring.interpd.update(PSD=utils.dedent(""" Keyword arguments: *NFFT*: integer @@ -629,7 +629,7 @@ def cohere_pairs( X, ij, NFFT=256, Fs=2, detrend=detrend_none, # cache the FFT of every windowed, detrended NFFT length segement # of every channel. If preferSpeedOverMemory, cache the conjugate # as well - if cbook.iterable(window): + if utils.iterable(window): assert(len(window) == NFFT) windowVals = window else: @@ -930,7 +930,7 @@ def _interpolate(a, b, fraction): return a + (b - a)*fraction scalar = True - if cbook.iterable(p): + if utils.iterable(p): scalar = False per = np.array(p) values = np.array(x).ravel() # copy @@ -968,7 +968,7 @@ def prctile_rank(x, p): indicates how many quantiles of data you want ranked. """ - if not cbook.iterable(p): + if not utils.iterable(p): p = np.arange(100.0/p, 100.0, 100.0/p) else: p = np.asarray(p) @@ -1171,7 +1171,7 @@ def fftsurr(x, detrend=detrend_none, window=window_none): """ Compute an FFT phase randomized surrogate of *x*. """ - if cbook.iterable(window): + if utils.iterable(window): x=window*detrend(x) else: x = window(detrend(x)) @@ -1343,7 +1343,7 @@ def save(fname, X, fmt='%.18e',delimiter=' '): warnings.warn("use numpy.savetxt", mplDeprecation) # 2009/06/13 - if cbook.is_string_like(fname): + if utils.is_string_like(fname): if fname.endswith('.gz'): import gzip fh = gzip.open(fname,'wb') @@ -1431,7 +1431,7 @@ def load(fname,comments='#',delimiter=None, converters=None,skiprows=0, warnings.warn("use numpy.loadtxt", mplDeprecation) # 2009/06/13 if converters is None: converters = {} - fh = cbook.to_filehandle(fname) + fh = utils.to_filehandle(fname) X = [] if delimiter==' ': @@ -1758,7 +1758,7 @@ def isvector(X): def safe_isnan(x): ':func:`numpy.isnan` for arbitrary types' - if cbook.is_string_like(x): + if utils.is_string_like(x): return False try: b = np.isnan(x) except NotImplementedError: return False @@ -1767,7 +1767,7 @@ def safe_isnan(x): def safe_isinf(x): ':func:`numpy.isinf` for arbitrary types' - if cbook.is_string_like(x): + if utils.is_string_like(x): return False try: b = np.isinf(x) except NotImplementedError: return False @@ -1781,8 +1781,8 @@ def rec_append_fields(rec, names, arrs, dtypes=None): *arrs* and *dtypes* do not have to be lists. They can just be the values themselves. """ - if (not cbook.is_string_like(names) and cbook.iterable(names) \ - and len(names) and cbook.is_string_like(names[0])): + if (not utils.is_string_like(names) and utils.iterable(names) \ + and len(names) and utils.is_string_like(names[0])): if len(names) != len(arrs): raise ValueError("number of arrays do not match number of names") else: # we have only 1 name and 1 array @@ -1791,7 +1791,7 @@ def rec_append_fields(rec, names, arrs, dtypes=None): arrs = map(np.asarray, arrs) if dtypes is None: dtypes = [a.dtype for a in arrs] - elif not cbook.iterable(dtypes): + elif not utils.iterable(dtypes): dtypes = [dtypes] if len(arrs) != len(dtypes): if len(dtypes) == 1: @@ -1829,7 +1829,7 @@ def rec_keep_fields(rec, names): Return a new numpy record array with only fields listed in names """ - if cbook.is_string_like(names): + if utils.is_string_like(names): names = names.split(',') arrays = [] @@ -1930,7 +1930,7 @@ def rec_join(key, r1, r2, jointype='inner', defaults=None, r1postfix='1', r2post (other than keys) that are both in *r1* and *r2*. """ - if cbook.is_string_like(key): + if utils.is_string_like(key): key = (key, ) for name in key: @@ -2069,7 +2069,7 @@ def recs_join(key, name, recs, jointype='outer', missing=0., postfixes=None): """ results = [] - aligned_iters = cbook.align_iterators(operator.attrgetter(key), *[iter(r) for r in recs]) + aligned_iters = utils.align_iterators(operator.attrgetter(key), *[iter(r) for r in recs]) def extract(r): if r is None: return missing @@ -2143,7 +2143,7 @@ def csv2rec(fname, comments='#', skiprows=0, checkrows=0, delimiter=',', import dateutil.parser import datetime - fh = cbook.to_filehandle(fname) + fh = utils.to_filehandle(fname) class FH: @@ -2300,7 +2300,7 @@ def get_converters(reader): seen[item] = cnt+1 else: - if cbook.is_string_like(names): + if utils.is_string_like(names): names = [n.strip() for n in names.split(',')] # get the converter functions by inspecting checkrows @@ -2533,7 +2533,7 @@ def rec2txt(r, header=None, padding=3, precision=3, fields=None): if fields is not None: r = rec_keep_fields(r, fields) - if cbook.is_numlike(precision): + if utils.is_numlike(precision): precision = [precision]*len(r.dtype) def get_type(item,atype=int): @@ -2658,7 +2658,7 @@ def newfunc(val, mask, mval): for i, name in enumerate(r.dtype.names): funcs.append(with_mask(csvformat_factory(formatd[name]).tostr)) - fh, opened = cbook.to_filehandle(fname, 'wb', return_opened=True) + fh, opened = utils.to_filehandle(fname, 'wb', return_opened=True) writer = csv.writer(fh, delimiter=delimiter) header = r.dtype.names if withheader: @@ -2809,7 +2809,7 @@ def griddata(x,y,z,xi,yi,interp='nn'): def less_simple_linear_interpolation( x, y, xi, extrap=False ): """ This function provides simple (but somewhat less so than - :func:`cbook.simple_linear_interpolation`) linear interpolation. + :func:`utils.simple_linear_interpolation`) linear interpolation. :func:`simple_linear_interpolation` will give a list of point between a start and an end, while this does true linear interpolation at an arbitrary set of points. @@ -2818,7 +2818,7 @@ def less_simple_linear_interpolation( x, y, xi, extrap=False ): only for a small number of points in relatively non-intensive use cases. For real linear interpolation, use scipy. """ - if cbook.is_scalar(xi): xi = [xi] + if utils.is_scalar(xi): xi = [xi] x = np.asarray(x) y = np.asarray(y) @@ -3040,10 +3040,10 @@ def poly_between(x, ylower, yupper): numpy = np Nx = len(x) - if not cbook.iterable(ylower): + if not utils.iterable(ylower): ylower = ylower*numpy.ones(Nx) - if not cbook.iterable(yupper): + if not utils.iterable(yupper): yupper = yupper*numpy.ones(Nx) x = numpy.concatenate( (x, x[::-1]) ) @@ -3211,7 +3211,7 @@ def offset_line(y, yerr): show() """ - if cbook.is_numlike(yerr) or (cbook.iterable(yerr) and len(yerr) == len(y)): + if utils.is_numlike(yerr) or (utils.iterable(yerr) and len(yerr) == len(y)): ymin = y - yerr ymax = y + yerr elif len(yerr) == 2: diff --git a/lib/matplotlib/mpl-data/sample_data/README.txt b/lib/matplotlib/mpl-data/sample_data/README.txt index 75a534951d60..970e177b44c6 100644 --- a/lib/matplotlib/mpl-data/sample_data/README.txt +++ b/lib/matplotlib/mpl-data/sample_data/README.txt @@ -1,2 +1,2 @@ This is the sample data needed for some of matplotlib's examples and -docs. See matplotlib.cbook.get_sample_data for more info. +docs. See matplotlib.utils.get_sample_data for more info. diff --git a/lib/matplotlib/mpl.py b/lib/matplotlib/mpl.py index 51e8a3204b73..7deadffc4e02 100644 --- a/lib/matplotlib/mpl.py +++ b/lib/matplotlib/mpl.py @@ -9,7 +9,7 @@ from matplotlib import artist from matplotlib import axis from matplotlib import axes -from matplotlib import cbook +from matplotlib.utils import _cbook from matplotlib import collections from matplotlib import colors from matplotlib import colorbar diff --git a/lib/matplotlib/offsetbox.py b/lib/matplotlib/offsetbox.py index d8b281a4b8a1..654cfd4b06b4 100644 --- a/lib/matplotlib/offsetbox.py +++ b/lib/matplotlib/offsetbox.py @@ -148,7 +148,7 @@ def __getstate__(self): state = martist.Artist.__getstate__(self) # pickle cannot save instancemethods, so handle them here - from cbook import _InstanceMethodPickler + from .utils import _InstanceMethodPickler import inspect offset = state['_offset'] @@ -158,7 +158,7 @@ def __getstate__(self): def __setstate__(self, state): self.__dict__ = state - from cbook import _InstanceMethodPickler + from .utils import _InstanceMethodPickler if isinstance(self._offset, _InstanceMethodPickler): self._offset = self._offset.get_instancemethod() diff --git a/lib/matplotlib/patches.py b/lib/matplotlib/patches.py index 54328f593583..732b56a4c3fd 100644 --- a/lib/matplotlib/patches.py +++ b/lib/matplotlib/patches.py @@ -5,7 +5,7 @@ import matplotlib as mpl import numpy as np -import matplotlib.cbook as cbook +import matplotlib.utils as utils import matplotlib.artist as artist from matplotlib.artist import allow_rasterization import matplotlib.colors as colors @@ -1811,8 +1811,8 @@ def __call__(self, x0, y0, width, height, mutation_size, def __reduce__(self): # because we have decided to nest thes classes, we need to # add some more information to allow instance pickling. - import matplotlib.cbook as cbook - return (cbook._NestedClassGetter(), + import matplotlib.utils as utils + return (utils._NestedClassGetter(), (BoxStyle, self.__class__.__name__), self.__dict__ ) @@ -2179,7 +2179,7 @@ def transmute(self, x0, y0, width, height, mutation_size): _style_list["roundtooth"] = Roundtooth if __doc__: # __doc__ could be None if -OO optimization is enabled - __doc__ = cbook.dedent(__doc__) % \ + __doc__ = utils.dedent(__doc__) % \ {"AvailableBoxstyles": _pprint_styles(_style_list)} docstring.interpd.update( @@ -2538,8 +2538,7 @@ def __call__(self, posA, posB, def __reduce__(self): # because we have decided to nest thes classes, we need to # add some more information to allow instance pickling. - import matplotlib.cbook as cbook - return (cbook._NestedClassGetter(), + return (utils._NestedClassGetter(), (ConnectionStyle, self.__class__.__name__), self.__dict__ ) @@ -2867,7 +2866,7 @@ def connect(self, posA, posB): _style_list["bar"] = Bar if __doc__: - __doc__ = cbook.dedent(__doc__) % \ + __doc__ = utils.dedent(__doc__) % \ {"AvailableConnectorstyles": _pprint_styles(_style_list)} @@ -2996,7 +2995,7 @@ def __call__(self, path, mutation_size, linewidth, path_mutated, fillable = self.transmute(path_shrinked, linewidth, mutation_size) - if cbook.iterable(fillable): + if utils.iterable(fillable): path_list = [] for p in zip(path_mutated): v, c = p.vertices, p.codes @@ -3012,8 +3011,7 @@ def __call__(self, path, mutation_size, linewidth, def __reduce__(self): # because we have decided to nest thes classes, we need to # add some more information to allow instance pickling. - import matplotlib.cbook as cbook - return (cbook._NestedClassGetter(), + return (utils._NestedClassGetter(), (ArrowStyle, self.__class__.__name__), self.__dict__ ) @@ -3709,7 +3707,7 @@ def transmute(self, path, mutation_size, linewidth): _style_list["wedge"] = Wedge if __doc__: - __doc__ = cbook.dedent(__doc__) % \ + __doc__ = utils.dedent(__doc__) % \ {"AvailableArrowstyles": _pprint_styles(_style_list)} @@ -3953,7 +3951,7 @@ def get_path(self): """ _path, fillable = self.get_path_in_displaycoord() - if cbook.iterable(fillable): + if utils.iterable(fillable): _path = concatenate_paths(_path) return self.get_transform().inverted().transform_path(_path) @@ -4026,7 +4024,7 @@ def draw(self, renderer): self.set_dpi_cor(renderer.points_to_pixels(1.)) path, fillable = self.get_path_in_displaycoord() - if not cbook.iterable(fillable): + if not utils.iterable(fillable): path = [path] fillable = [fillable] diff --git a/lib/matplotlib/path.py b/lib/matplotlib/path.py index d863e6324874..1b053b42fb61 100644 --- a/lib/matplotlib/path.py +++ b/lib/matplotlib/path.py @@ -3,7 +3,6 @@ """ from __future__ import print_function -import math from weakref import WeakValueDictionary import numpy as np @@ -13,7 +12,7 @@ point_in_path_collection, get_path_collection_extents, \ path_in_path, path_intersects_path, convert_path_to_polygons, \ cleanup_path, points_in_path -from matplotlib.cbook import simple_linear_interpolation, maxdict +from matplotlib.utils import simple_linear_interpolation, maxdict from matplotlib import rcParams class Path(object): diff --git a/lib/matplotlib/projections/geo.py b/lib/matplotlib/projections/geo.py index 23fe596174fe..bfad4ed96ff1 100644 --- a/lib/matplotlib/projections/geo.py +++ b/lib/matplotlib/projections/geo.py @@ -7,7 +7,6 @@ import matplotlib rcParams = matplotlib.rcParams from matplotlib.axes import Axes -from matplotlib import cbook from matplotlib.patches import Circle from matplotlib.path import Path import matplotlib.spines as mspines diff --git a/lib/matplotlib/projections/polar.py b/lib/matplotlib/projections/polar.py index cf83c4a04ee3..45747831d6d4 100644 --- a/lib/matplotlib/projections/polar.py +++ b/lib/matplotlib/projections/polar.py @@ -8,7 +8,7 @@ rcParams = matplotlib.rcParams from matplotlib.axes import Axes import matplotlib.axis as maxis -from matplotlib import cbook +import matplotlib.utils as utils from matplotlib import docstring from matplotlib.patches import Circle from matplotlib.path import Path @@ -235,7 +235,7 @@ def __init__(self, *args, **kwargs): warnings.warn( """The resolution kwarg to Polar plots is now ignored. If you need to interpolate data points, consider running -cbook.simple_linear_interpolation on the data before passing to matplotlib.""") +utils.simple_linear_interpolation on the data before passing to matplotlib.""") Axes.__init__(self, *args, **kwargs) self.set_aspect('equal', adjustable='box', anchor='C') self.cla() @@ -603,7 +603,7 @@ def start_pan(self, x, y, button): elif button == 3: mode = 'zoom' - self._pan_start = cbook.Bunch( + self._pan_start = utils.Bunch( rmax = self.get_rmax(), trans = self.transData.frozen(), trans_inverse = self.transData.inverted().frozen(), diff --git a/lib/matplotlib/pylab.py b/lib/matplotlib/pylab.py index 816b0dbb67d5..cba68a26ed48 100644 --- a/lib/matplotlib/pylab.py +++ b/lib/matplotlib/pylab.py @@ -214,9 +214,9 @@ """ from __future__ import print_function -import sys, warnings +import sys -from matplotlib.cbook import flatten, is_string_like, exception_to_str, \ +from matplotlib.utils import flatten, is_string_like, exception_to_str, \ silent_list, iterable, dedent import matplotlib as mpl @@ -258,7 +258,7 @@ rec_append_fields, rec_drop_fields, rec_join, csv2rec, rec2csv, isvector import matplotlib.mlab as mlab -import matplotlib.cbook as cbook +import matplotlib.utils as utils from numpy import * from numpy.fft import * diff --git a/lib/matplotlib/pyplot.py b/lib/matplotlib/pyplot.py index 45d2a96769da..5b13b0e5969e 100644 --- a/lib/matplotlib/pyplot.py +++ b/lib/matplotlib/pyplot.py @@ -20,8 +20,8 @@ import sys, warnings import matplotlib -from matplotlib import _pylab_helpers, interactive -from matplotlib.cbook import dedent, silent_list, is_string_like, is_numlike +from matplotlib import _pylab_helpers +from matplotlib.utils import silent_list, is_string_like, is_numlike from matplotlib import docstring from matplotlib.figure import Figure, figaspect from matplotlib.backend_bases import FigureCanvasBase @@ -30,15 +30,13 @@ from matplotlib import rcParams, rcParamsDefault, get_backend from matplotlib import rc_context from matplotlib.rcsetup import interactive_bk as _interactive_bk -from matplotlib.artist import getp, get, Artist +from matplotlib.artist import Artist from matplotlib.artist import setp as _setp -from matplotlib.axes import Axes, Subplot, _string_to_bool +from matplotlib.axes import Axes, _string_to_bool from matplotlib.projections import PolarAxes from matplotlib import mlab # for csv2rec, detrend_none, window_hanning -from matplotlib.scale import get_scale_docs, get_scale_names from matplotlib import cm -from matplotlib.cm import get_cmap, register_cmap import numpy as np @@ -48,6 +46,7 @@ from matplotlib.text import Text, Annotation from matplotlib.patches import Polygon, Rectangle, Circle, Arrow from matplotlib.widgets import SubplotTool, Button, Slider, Widget +from matplotlib.cm import get_cmap, register_cmap from ticker import TickHelper, Formatter, FixedFormatter, NullFormatter,\ FuncFormatter, FormatStrFormatter, ScalarFormatter,\ diff --git a/lib/matplotlib/quiver.py b/lib/matplotlib/quiver.py index cf764f7eb4cf..2e7e5a922e9e 100644 --- a/lib/matplotlib/quiver.py +++ b/lib/matplotlib/quiver.py @@ -25,8 +25,8 @@ from matplotlib.artist import allow_rasterization from matplotlib import docstring import matplotlib.font_manager as font_manager -import matplotlib.cbook as cbook -from matplotlib.cbook import delete_masked_points +import matplotlib.utils as utils +from matplotlib.utils import delete_masked_points from matplotlib.patches import CirclePolygon import math @@ -625,8 +625,8 @@ def _h_arrows(self, length): Y0 = shrink * Y0[np.newaxis, :] short = np.repeat(length < minsh, 8, axis=1) # Now select X0, Y0 if short, otherwise X, Y - cbook._putmask(X, short, X0) - cbook._putmask(Y, short, Y0) + utils._putmask(X, short, X0) + utils._putmask(Y, short, Y0) if self.pivot[:3] == 'mid': X -= 0.5 * X[:, 3, np.newaxis] elif self.pivot[:3] == 'tip': @@ -642,8 +642,8 @@ def _h_arrows(self, length): X1 = np.repeat(x1[np.newaxis, :], N, axis=0) Y1 = np.repeat(y1[np.newaxis, :], N, axis=0) tooshort = np.repeat(tooshort, 8, 1) - cbook._putmask(X, tooshort, X1) - cbook._putmask(Y, tooshort, Y1) + utils._putmask(X, tooshort, X1) + utils._putmask(Y, tooshort, Y1) # Mask handling is deferred to the caller, _make_verts. return X, Y diff --git a/lib/matplotlib/sankey.py b/lib/matplotlib/sankey.py index 349f0decfb02..5b75f1ee7062 100755 --- a/lib/matplotlib/sankey.py +++ b/lib/matplotlib/sankey.py @@ -38,7 +38,7 @@ import numpy as np -from matplotlib.cbook import iterable, Bunch +from matplotlib.utils import iterable, Bunch from matplotlib.path import Path from matplotlib.patches import PathPatch from matplotlib.transforms import Affine2D diff --git a/lib/matplotlib/scale.py b/lib/matplotlib/scale.py index ade2123e1df7..284ad34d6bdb 100644 --- a/lib/matplotlib/scale.py +++ b/lib/matplotlib/scale.py @@ -3,7 +3,7 @@ import numpy as np from numpy import ma -from matplotlib.cbook import dedent +from matplotlib.utils import dedent from matplotlib.ticker import (NullFormatter, ScalarFormatter, LogFormatterMathtext) from matplotlib.ticker import (NullLocator, LogLocator, AutoLocator, diff --git a/lib/matplotlib/sphinxext/plot_directive.py b/lib/matplotlib/sphinxext/plot_directive.py index ac96d5fa3568..98d14d2de0cd 100644 --- a/lib/matplotlib/sphinxext/plot_directive.py +++ b/lib/matplotlib/sphinxext/plot_directive.py @@ -151,7 +151,7 @@ def format_template(template, **kw): return jinja.from_string(template, **kw) import matplotlib -import matplotlib.cbook as cbook +import matplotlib.utils as utils matplotlib.use('Agg') import matplotlib.pyplot as plt from matplotlib import _pylab_helpers @@ -798,7 +798,7 @@ def run(arguments, content, options, state_machine, state, lineno): # copy image files to builder's output directory, if necessary if not os.path.exists(dest_dir): - cbook.mkdirs(dest_dir) + utils.mkdirs(dest_dir) for code_piece, images in results: for img in images: diff --git a/lib/matplotlib/spines.py b/lib/matplotlib/spines.py index 55bc58462e1f..6efdb0a1732b 100644 --- a/lib/matplotlib/spines.py +++ b/lib/matplotlib/spines.py @@ -10,7 +10,7 @@ import matplotlib.lines as mlines import matplotlib.patches as mpatches import matplotlib.path as mpath -import matplotlib.cbook as cbook +import matplotlib.utils as utils import numpy as np import warnings @@ -166,7 +166,7 @@ def is_frame_like(self): """ self._ensure_position_is_set() position = self._position - if cbook.is_string_like(position): + if utils.is_string_like(position): if position == 'center': position = ('axes', 0.5) elif position == 'zero': @@ -272,7 +272,7 @@ def _calc_offset_transform(self): """calculate the offset transform performed by the spine""" self._ensure_position_is_set() position = self._position - if cbook.is_string_like(position): + if utils.is_string_like(position): if position == 'center': position = ('axes', 0.5) elif position == 'zero': diff --git a/lib/matplotlib/table.py b/lib/matplotlib/table.py index b0036bc953c5..63394354424e 100644 --- a/lib/matplotlib/table.py +++ b/lib/matplotlib/table.py @@ -25,7 +25,7 @@ import artist from artist import Artist, allow_rasterization from patches import Rectangle -from cbook import is_string_like +from matplotlib.utils import is_string_like from matplotlib import docstring from text import Text from transforms import Bbox diff --git a/lib/matplotlib/testing/jpl_units/EpochConverter.py b/lib/matplotlib/testing/jpl_units/EpochConverter.py index ae0d8b600c64..b59e4847a860 100644 --- a/lib/matplotlib/testing/jpl_units/EpochConverter.py +++ b/lib/matplotlib/testing/jpl_units/EpochConverter.py @@ -13,7 +13,7 @@ from __future__ import print_function import matplotlib.units as units import matplotlib.dates as date_ticker -from matplotlib.cbook import iterable +from matplotlib.utils import iterable # # Place all imports before here. #=========================================================================== diff --git a/lib/matplotlib/testing/jpl_units/StrConverter.py b/lib/matplotlib/testing/jpl_units/StrConverter.py index 74a16987f6f7..5e75f9e035e6 100644 --- a/lib/matplotlib/testing/jpl_units/StrConverter.py +++ b/lib/matplotlib/testing/jpl_units/StrConverter.py @@ -12,7 +12,7 @@ # from __future__ import print_function import matplotlib.units as units -from matplotlib.cbook import iterable +from matplotlib.utils import iterable # Place all imports before here. #=========================================================================== diff --git a/lib/matplotlib/testing/jpl_units/UnitDblConverter.py b/lib/matplotlib/testing/jpl_units/UnitDblConverter.py index c76a5039a8d8..6b1baa9090de 100644 --- a/lib/matplotlib/testing/jpl_units/UnitDblConverter.py +++ b/lib/matplotlib/testing/jpl_units/UnitDblConverter.py @@ -15,7 +15,7 @@ import matplotlib.units as units import matplotlib.ticker as ticker import matplotlib.projections.polar as polar -from matplotlib.cbook import iterable +from matplotlib.utils import iterable # # Place all imports before here. #=========================================================================== diff --git a/lib/matplotlib/tests/test_cbook.py b/lib/matplotlib/tests/test_utils.py similarity index 69% rename from lib/matplotlib/tests/test_cbook.py rename to lib/matplotlib/tests/test_utils.py index 734fdbc4ee7f..b462e6068fa9 100644 --- a/lib/matplotlib/tests/test_cbook.py +++ b/lib/matplotlib/tests/test_utils.py @@ -1,44 +1,47 @@ from __future__ import print_function import numpy as np from numpy.testing.utils import assert_array_equal -import matplotlib.cbook as cbook +import matplotlib.utils as utils import matplotlib.colors as mcolors + +from matplotlib.utils import delete_masked_points as dmp from nose.tools import assert_equal, raises from datetime import datetime + def test_is_string_like(): - y = np.arange( 10 ) - assert_equal( cbook.is_string_like( y ), False ) + y = np.arange(10) + assert_equal(utils.is_string_like(y), False) y.shape = 10, 1 - assert_equal( cbook.is_string_like( y ), False ) + assert_equal(utils.is_string_like(y), False) y.shape = 1, 10 - assert_equal( cbook.is_string_like( y ), False ) + assert_equal(utils.is_string_like(y), False) + + assert utils.is_string_like("hello world") + assert_equal(utils.is_string_like(10), False) - assert cbook.is_string_like( "hello world" ) - assert_equal( cbook.is_string_like(10), False ) def test_restrict_dict(): d = {'foo': 'bar', 1: 2} - d1 = cbook.restrict_dict(d, ['foo', 1]) + d1 = utils.restrict_dict(d, ['foo', 1]) assert_equal(d1, d) - d2 = cbook.restrict_dict(d, ['bar', 2]) + d2 = utils.restrict_dict(d, ['bar', 2]) assert_equal(d2, {}) - d3 = cbook.restrict_dict(d, {'foo': 1}) + d3 = utils.restrict_dict(d, {'foo': 1}) assert_equal(d3, {'foo': 'bar'}) - d4 = cbook.restrict_dict(d, {}) + d4 = utils.restrict_dict(d, {}) assert_equal(d4, {}) - d5 = cbook.restrict_dict(d, set(['foo',2])) + d5 = utils.restrict_dict(d, set(['foo', 2])) assert_equal(d5, {'foo': 'bar'}) # check that d was not modified assert_equal(d, {'foo': 'bar', 1: 2}) -from matplotlib.cbook import delete_masked_points as dmp class Test_delete_masked_points: def setUp(self): self.mask1 = [False, False, True, True, False, False] - self.arr0 = np.arange(1.0,7.0) - self.arr1 = [1,2,3,np.nan,np.nan,6] + self.arr0 = np.arange(1.0, 7.0) + self.arr1 = [1, 2, 3, np.nan, np.nan, 6] self.arr2 = np.array(self.arr1) self.arr3 = np.ma.array(self.arr2, mask=self.mask1) self.arr_s = ['a', 'b', 'c', 'd', 'e', 'f'] @@ -78,3 +81,13 @@ def test_rgba(self): assert_array_equal(actual[1], expected[1]) +def test_allequal(): + assert(utils.allequal([1, 1, 1])) + assert(not utils.allequal([1, 1, 0])) + assert(utils.allequal([])) + assert(utils.allequal(('a', 'a'))) + assert(not utils.allequal(('a', 'b'))) + +if __name__ == "__main__": + import nose + nose.runmodule(argv=['-s', '--with-doctest'], exit=False) diff --git a/lib/matplotlib/texmanager.py b/lib/matplotlib/texmanager.py index 3023d8fec5bb..7de326df1aed 100644 --- a/lib/matplotlib/texmanager.py +++ b/lib/matplotlib/texmanager.py @@ -50,7 +50,7 @@ import matplotlib as mpl from matplotlib import rcParams from matplotlib._png import read_png -from matplotlib.cbook import mkdirs +from matplotlib.utils import mkdirs import matplotlib.dviread as dviread import re diff --git a/lib/matplotlib/text.py b/lib/matplotlib/text.py index 102f19ddc512..4c2f3cd23559 100644 --- a/lib/matplotlib/text.py +++ b/lib/matplotlib/text.py @@ -6,11 +6,11 @@ import numpy as np -from matplotlib import cbook +from matplotlib import utils from matplotlib import rcParams import matplotlib.artist as artist from matplotlib.artist import Artist -from matplotlib.cbook import is_string_like, maxdict +from matplotlib.utils import is_string_like, maxdict from matplotlib import docstring from matplotlib.font_manager import FontProperties from matplotlib.patches import bbox_artist, YAArrow, FancyBboxPatch @@ -1010,7 +1010,7 @@ def is_math_text(s): s = r'\ ' return s, 'TeX' - if cbook.is_math_text(s): + if utils.is_math_text(s): return s, True else: return s.replace(r'\$', '$'), False diff --git a/lib/matplotlib/textpath.py b/lib/matplotlib/textpath.py index 35634092cf83..173854e50a2c 100644 --- a/lib/matplotlib/textpath.py +++ b/lib/matplotlib/textpath.py @@ -32,7 +32,7 @@ def __init__(self): self.mathtext_parser = MathTextParser('path') self.tex_font_map = None - from matplotlib.cbook import maxdict + from matplotlib.utils import maxdict self._ps_fontd = maxdict(50) self._texmanager = None diff --git a/lib/matplotlib/ticker.py b/lib/matplotlib/ticker.py index 175508880926..55a872f6b084 100644 --- a/lib/matplotlib/ticker.py +++ b/lib/matplotlib/ticker.py @@ -128,7 +128,7 @@ import math import numpy as np from matplotlib import rcParams -from matplotlib import cbook +from matplotlib import utils from matplotlib import transforms as mtransforms @@ -647,7 +647,7 @@ def __call__(self, x, pos=None): def format_data(self, value): b = self.labelOnlyBase self.labelOnlyBase = False - value = cbook.strip_math(self.__call__(value)) + value = utils.strip_math(self.__call__(value)) self.labelOnlyBase = b return value diff --git a/lib/matplotlib/tri/triplot.py b/lib/matplotlib/tri/triplot.py index ce4bd1194764..516ebfd93731 100644 --- a/lib/matplotlib/tri/triplot.py +++ b/lib/matplotlib/tri/triplot.py @@ -1,10 +1,11 @@ from __future__ import print_function -from matplotlib.cbook import ls_mapper +from matplotlib.utils import ls_mapper from matplotlib.patches import PathPatch from matplotlib.path import Path from matplotlib.tri.triangulation import Triangulation import numpy as np + def triplot(ax, *args, **kwargs): """ Draw a unstructured triangular grid as lines and/or markers. @@ -64,7 +65,7 @@ def triplot(ax, *args, **kwargs): kw['facecolor'] = None vertices = np.column_stack((x[edges].flatten(), y[edges].flatten())) - codes = ([Path.MOVETO] + [Path.LINETO])*len(edges) + codes = ([Path.MOVETO] + [Path.LINETO]) * len(edges) path = Path(vertices, codes) pathpatch = PathPatch(path, **kw) diff --git a/lib/matplotlib/type1font.py b/lib/matplotlib/type1font.py index 522cd1fd5324..bc8f6712c0ec 100644 --- a/lib/matplotlib/type1font.py +++ b/lib/matplotlib/type1font.py @@ -23,7 +23,6 @@ """ from __future__ import print_function -import matplotlib.cbook as cbook import io import itertools import numpy as np diff --git a/lib/matplotlib/units.py b/lib/matplotlib/units.py index 0bbe697b54f8..defc8745dcff 100644 --- a/lib/matplotlib/units.py +++ b/lib/matplotlib/units.py @@ -43,7 +43,7 @@ def default_units(x, axis): """ from __future__ import print_function -from matplotlib.cbook import iterable, is_numlike +from matplotlib.utils import iterable, is_numlike class AxisInfo: diff --git a/lib/matplotlib/utils/__init__.py b/lib/matplotlib/utils/__init__.py new file mode 100644 index 000000000000..d4303f989aa5 --- /dev/null +++ b/lib/matplotlib/utils/__init__.py @@ -0,0 +1,1217 @@ +from __future__ import print_function + +import os +import io +import traceback +import gzip +import re +import sys +import types +import new +import warnings +import errno +import subprocess +import numpy.ma as ma +import locale +from weakref import ref, WeakKeyDictionary + +import numpy as np + +import matplotlib +from matplotlib import MatplotlibDeprecationWarning as mplDeprecation + +# On some systems, locale.getpreferredencoding returns None, +# which can break unicode; and the sage project reports that +# some systems have incorrect locale specifications, e.g., +# an encoding instead of a valid locale name. Another +# pathological case that has been reported is an empty string. + +# On some systems, getpreferredencoding sets the locale, which has +# side effects. Passing False eliminates those side effects. + +if sys.version_info[0] >= 3: + def unicode_safe(s): + try: + preferredencoding = locale.getpreferredencoding( + matplotlib.rcParams['axes.formatter.use_locale']).strip() + if not preferredencoding: + preferredencoding = None + except (ValueError, ImportError, AttributeError): + preferredencoding = None + + if isinstance(s, bytes): + if preferredencoding is None: + return unicode(s) + else: + # We say "unicode" and not "str" here so it passes through + # 2to3 correctly. + return unicode(s, preferredencoding) + return s +else: + def unicode_safe(s): + try: + preferredencoding = locale.getpreferredencoding( + matplotlib.rcParams['axes.formatter.use_locale']).strip() + if not preferredencoding: + preferredencoding = None + except (ValueError, ImportError, AttributeError): + preferredencoding = None + + if preferredencoding is None: + return unicode(s) + else: + return unicode(s, preferredencoding) + + +# a dict to cross-map linestyle arguments +_linestyles = [('-', 'solid'), + ('--', 'dashed'), + ('-.', 'dashdot'), + (':', 'dotted')] + +ls_mapper = dict(_linestyles) +ls_mapper.update([(ls[1], ls[0]) for ls in _linestyles]) + + +# TODO rename this method is_iterable +def iterable(obj): + """return true if *obj* is iterable""" + try: + iter(obj) + except TypeError: + return False + return True + + +def is_writable_file_like(obj): + """return true if *obj* looks like a file object with a *write* method""" + return hasattr(obj, 'write') and callable(obj.write) + + +def is_string_like(obj): + """Return True if *obj* looks like a string""" + if isinstance(obj, (str, unicode)): + return True + # numpy strings are subclass of str, ma strings are not + if ma.isMaskedArray(obj): + if obj.ndim == 0 and obj.dtype.kind in 'SU': + return True + else: + return False + try: + obj + '' + except: + return False + return True + + +def is_numlike(obj): + """return true if *obj* looks like a number""" + try: + obj + 1 + except: + return False + else: + return True + + +def is_scalar(obj): + """return true if *obj* is not string like and is not iterable""" + return not is_string_like(obj) and not iterable(obj) + + +def is_scalar_or_string(val): + """Return whether the given object is a scalar or string like.""" + return is_string_like(val) or not iterable(val) + + +def is_math_text(s): + # Did we find an even number of non-escaped dollar signs? + # If so, treat is as math text. + try: + s = unicode(s) + except UnicodeDecodeError: + raise ValueError( + "matplotlib display text must have all code points < 128 or use " + "Unicode strings") + + dollar_count = s.count(r'$') - s.count(r'\$') + even_dollars = (dollar_count > 0 and dollar_count % 2 == 0) + + return even_dollars + + +def is_sequence_of_strings(obj): + """ + Returns true if *obj* is iterable and contains strings + """ + if not iterable(obj): + return False + if is_string_like(obj): + return False + for o in obj: + if not is_string_like(o): + return False + return True + + +def issubclass_safe(x, klass): + """return issubclass(x, klass) and return False on a TypeError""" + + try: + return issubclass(x, klass) + except TypeError: + return False + + +def reverse_dict(d): + """reverse the dictionary -- may lose data if values are not unique!""" + return dict([(v, k) for k, v in d.iteritems()]) + + +def allequal(seq): + """ + Return *True* if all elements of *seq* compare equal. If *seq* is + 0 or 1 length, return *True* + """ + if len(seq) < 2: + return True + val = seq[0] + for i in xrange(1, len(seq)): + thisval = seq[i] + if thisval != val: + return False + return True + + +def popall(seq): + """empty a list""" + for i in xrange(len(seq)): + seq.pop() + + +def strip_math(s): + """remove latex formatting from mathtext""" + remove = (r'\mathdefault', r'\rm', r'\cal', r'\tt', r'\it', '\\', '{', '}') + s = s[1:-1] + for r in remove: + s = s.replace(r, '') + return s + + +def to_filehandle(fname, flag='rU', return_opened=False): + """ + *fname* can be a filename or a file handle. Support for gzipped + files is automatic, if the filename ends in .gz. *flag* is a + read/write flag for :func:`file` + """ + if is_string_like(fname): + if fname.endswith('.gz'): + # get rid of 'U' in flag for gzipped files. + flag = flag.replace('U', '') + fh = gzip.open(fname, flag) + elif fname.endswith('.bz2'): + # get rid of 'U' in flag for bz2 files + flag = flag.replace('U', '') + import bz2 + fh = bz2.BZ2File(fname, flag) + else: + fh = open(fname, flag) + opened = True + elif hasattr(fname, 'seek'): + fh = fname + opened = False + else: + raise ValueError('fname must be a string or file handle') + if return_opened: + return fh, opened + return fh + + +def align_iterators(func, *iterables): + """ + This generator takes a bunch of iterables that are ordered by func + It sends out ordered tuples:: + + (func(row), [rows from all iterators matching func(row)]) + + It is used by :func:`matplotlib.mlab.recs_join` to join record arrays + """ + class myiter: + def __init__(self, it): + self.it = it + self.key = self.value = None + self.iternext() + + def iternext(self): + try: + self.value = next(self.it) + self.key = func(self.value) + except StopIteration: + self.value = self.key = None + + def __call__(self, key): + retval = None + if key == self.key: + retval = self.value + self.iternext() + elif self.key and key > self.key: + raise ValueError("Iterator has been left behind") + return retval + + # This can be made more efficient by not computing the minimum key for each + # iteration + iters = [myiter(it) for it in iterables] + minvals = minkey = True + while 1: + minvals = ([_f for _f in [it.key for it in iters] if _f]) + if minvals: + minkey = min(minvals) + yield (minkey, [it(minkey) for it in iters]) + else: + break + + +def mkdirs(newdir, mode=0o777): + """ + make directory *newdir* recursively, and set *mode*. Equivalent to :: + + > mkdir -p NEWDIR + > chmod MODE NEWDIR + """ + try: + if not os.path.exists(newdir): + parts = os.path.split(newdir) + for i in range(1, len(parts) + 1): + thispart = os.path.join(*parts[:i]) + if not os.path.exists(thispart): + os.makedirs(thispart, mode) + + except OSError as err: + # Reraise the error unless it's about an already existing directory + if err.errno != errno.EEXIST or not os.path.isdir(newdir): + raise + + +def flatten(seq, scalarp=is_scalar_or_string): + """ + Returns a generator of flattened nested containers + + For example: + + >>> from matplotlib.utils import flatten + >>> l = (('John', ['Hunter']), (1, 23), [[([42, (5, 23)], )]]) + >>> print list(flatten(l)) + ['John', 'Hunter', 1, 23, 42, 5, 23] + + By: Composite of Holger Krekel and Luther Blissett + From: http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/121294 + and Recipe 1.12 in cookbook + """ + for item in seq: + if scalarp(item): + yield item + else: + for subitem in flatten(item, scalarp): + yield subitem + + +class Grouper(object): + """ + This class provides a lightweight way to group arbitrary objects + together into disjoint sets when a full-blown graph data structure + would be overkill. + + Objects can be joined using :meth:`join`, tested for connectedness + using :meth:`joined`, and all disjoint sets can be retreived by + using the object as an iterator. + + The objects being joined must be hashable and weak-referenceable. + + For example: + + >>> from matplotlib.utils import Grouper + >>> class Foo(object): + ... def __init__(self, s): + ... self.s = s + ... def __repr__(self): + ... return self.s + ... + >>> a, b, c, d, e, f = [Foo(x) for x in 'abcdef'] + >>> grp = Grouper() + >>> grp.join(a, b) + >>> grp.join(b, c) + >>> grp.join(d, e) + >>> sorted(map(tuple, grp)) + [(d, e), (a, b, c)] + >>> grp.joined(a, b) + True + >>> grp.joined(a, c) + True + >>> grp.joined(a, d) + False + + """ + def __init__(self, init=[]): + mapping = self._mapping = {} + for x in init: + mapping[ref(x)] = [ref(x)] + + def __contains__(self, item): + return ref(item) in self._mapping + + def clean(self): + """ + Clean dead weak references from the dictionary + """ + mapping = self._mapping + to_drop = [key for key in mapping if key() is None] + for key in to_drop: + val = mapping.pop(key) + val.remove(key) + + def join(self, a, *args): + """ + Join given arguments into the same set. Accepts one or more + arguments. + """ + mapping = self._mapping + set_a = mapping.setdefault(ref(a), [ref(a)]) + + for arg in args: + set_b = mapping.get(ref(arg)) + if set_b is None: + set_a.append(ref(arg)) + mapping[ref(arg)] = set_a + elif set_b is not set_a: + if len(set_b) > len(set_a): + set_a, set_b = set_b, set_a + set_a.extend(set_b) + for elem in set_b: + mapping[elem] = set_a + + self.clean() + + def joined(self, a, b): + """ + Returns True if *a* and *b* are members of the same set. + """ + self.clean() + + mapping = self._mapping + try: + return mapping[ref(a)] is mapping[ref(b)] + except KeyError: + return False + + def __iter__(self): + """ + Iterate over each of the disjoint sets as a list. + + The iterator is invalid if interleaved with calls to join(). + """ + self.clean() + + class Token: + pass + token = Token() + + # Mark each group as we come across if by appending a token, + # and don't yield it twice + for group in self._mapping.itervalues(): + if not group[-1] is token: + yield [x() for x in group] + group.append(token) + + # Cleanup the tokens + for group in self._mapping.itervalues(): + if group[-1] is token: + del group[-1] + + def get_siblings(self, a): + """ + Returns all of the items joined with *a*, including itself. + """ + self.clean() + + siblings = self._mapping.get(ref(a), [ref(a)]) + return [x() for x in siblings] + + +class _BoundMethodProxy(object): + """ + Our own proxy object which enables weak references to bound and unbound + methods and arbitrary callables. Pulls information about the function, + class, and instance out of a bound method. Stores a weak reference to the + instance to support garbage collection. + + @organization: IBM Corporation + @copyright: Copyright (c) 2005, 2006 IBM Corporation + @license: The BSD License + + Minor bugfixes by Michael Droettboom + """ + def __init__(self, cb): + try: + try: + self.inst = ref(cb.im_self) + except TypeError: + self.inst = None + self.func = cb.im_func + self.klass = cb.im_class + except AttributeError: + self.inst = None + self.func = cb + self.klass = None + + def __getstate__(self): + d = self.__dict__.copy() + # de-weak reference inst + inst = d['inst'] + if inst is not None: + d['inst'] = inst() + return d + + def __setstate__(self, statedict): + self.__dict__ = statedict + inst = statedict['inst'] + # turn inst back into a weakref + if inst is not None: + self.inst = ref(inst) + + def __call__(self, *args, **kwargs): + """ + Proxy for a call to the weak referenced object. Take + arbitrary params to pass to the callable. + + Raises `ReferenceError`: When the weak reference refers to + a dead object + """ + if self.inst is not None and self.inst() is None: + raise ReferenceError + elif self.inst is not None: + # build a new instance method with a strong reference to the + # instance + if sys.version_info[0] >= 3: + mtd = types.MethodType(self.func, self.inst()) + else: + mtd = new.instancemethod(self.func, self.inst(), self.klass) + else: + # not a bound method, just return the func + mtd = self.func + # invoke the callable and return the result + return mtd(*args, **kwargs) + + def __eq__(self, other): + """ + Compare the held function and instance with that held by + another proxy. + """ + try: + if self.inst is None: + return self.func == other.func and other.inst is None + else: + return self.func == other.func and self.inst() == other.inst() + except Exception: + return False + + def __ne__(self, other): + """ + Inverse of __eq__. + """ + return not self.__eq__(other) + + +class CallbackRegistry: + """ + Handle registering and disconnecting for a set of signals and + callbacks: + + >>> def oneat(x): + ... print 'eat', x + >>> def ondrink(x): + ... print 'drink', x + + >>> from matplotlib.utils import CallbackRegistry + >>> callbacks = CallbackRegistry() + + >>> id_eat = callbacks.connect('eat', oneat) + >>> id_drink = callbacks.connect('drink', ondrink) + + >>> callbacks.process('drink', 123) + drink 123 + >>> callbacks.process('eat', 456) + eat 456 + >>> callbacks.process('be merry', 456) # nothing will be called + >>> callbacks.disconnect(id_eat) + >>> callbacks.process('eat', 456) # nothing will be called + + In practice, one should always disconnect all callbacks when they + are no longer needed to avoid dangling references (and thus memory + leaks). However, real code in matplotlib rarely does so, and due + to its design, it is rather difficult to place this kind of code. + To get around this, and prevent this class of memory leaks, we + instead store weak references to bound methods only, so when the + destination object needs to die, the CallbackRegistry won't keep + it alive. The Python stdlib weakref module can not create weak + references to bound methods directly, so we need to create a proxy + object to handle weak references to bound methods (or regular free + functions). This technique was shared by Peter Parente on his + `"Mindtrove" blog + `_. + + .. deprecated:: 1.3.0 + """ + def __init__(self, *args): + if len(args): + warnings.warn( + "CallbackRegistry no longer requires a list of callback " + "types. Ignoring arguments. *args will be removed in 1.5", + mplDeprecation) + self.callbacks = dict() + self._cid = 0 + self._func_cid_map = {} + + def __getstate__(self): + # We cannot currently pickle the callables in the registry, so + # return an empty dictionary. + return {} + + def __setstate__(self, state): + # re-initialise an empty callback registry + self.__init__() + + def connect(self, s, func): + """ + register *func* to be called when a signal *s* is generated + func will be called + """ + self._func_cid_map.setdefault(s, WeakKeyDictionary()) + if func in self._func_cid_map[s]: + return self._func_cid_map[s][func] + + self._cid += 1 + cid = self._cid + self._func_cid_map[s][func] = cid + self.callbacks.setdefault(s, dict()) + proxy = _BoundMethodProxy(func) + self.callbacks[s][cid] = proxy + return cid + + def disconnect(self, cid): + """ + disconnect the callback registered with callback id *cid* + """ + for eventname, callbackd in self.callbacks.items(): + try: + del callbackd[cid] + except KeyError: + continue + else: + for key, value in self._func_cid_map.items(): + if value == cid: + del self._func_cid_map[key] + return + + def process(self, s, *args, **kwargs): + """ + process signal *s*. All of the functions registered to receive + callbacks on *s* will be called with *\*args* and *\*\*kwargs* + """ + if s in self.callbacks: + for cid, proxy in self.callbacks[s].items(): + # Clean out dead references + if proxy.inst is not None and proxy.inst() is None: + del self.callbacks[s][cid] + else: + proxy(*args, **kwargs) + + +class silent_list(list): + """ + override repr when returning a list of matplotlib artists to + prevent long, meaningless output. This is meant to be used for a + homogeneous list of a given type + """ + def __init__(self, type, seq=None): + self.type = type + if seq is not None: + self.extend(seq) + + def __repr__(self): + return '' % (len(self), self.type) + + def __str__(self): + return repr(self) + + def __getstate__(self): + # store a dictionary of this SilentList's state + return {'type': self.type, 'seq': self[:]} + + def __setstate__(self, state): + self.type = state['type'] + self.extend(state['seq']) + + +class Bunch: + """ + Often we want to just collect a bunch of stuff together, naming each + item of the bunch; a dictionary's OK for that, but a small do- nothing + class is even handier, and prettier to use. Whenever you want to + group a few variables:: + + >>> point = Bunch(datum=2, squared=4, coord=12) + >>> point.datum + + By: Alex Martelli + From: http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52308 + """ + def __init__(self, **kwds): + self.__dict__.update(kwds) + + def __repr__(self): + keys = self.__dict__.iterkeys() + return 'Bunch(%s)' % ', '.join(['%s=%s' % (k, self.__dict__[k]) + for k + in keys]) + + +_safezip_msg = 'In safezip, len(args[0])=%d but len(args[%d])=%d' + + +def safezip(*args): + """make sure *args* are equal len before zipping""" + Nx = len(args[0]) + for i, arg in enumerate(args[1:]): + if len(arg) != Nx: + raise ValueError(_safezip_msg % (Nx, i + 1, len(arg))) + return zip(*args) + + +def delete_masked_points(*args): + """ + Find all masked and/or non-finite points in a set of arguments, + and return the arguments with only the unmasked points remaining. + + Arguments can be in any of 5 categories: + + 1) 1-D masked arrays + 2) 1-D ndarrays + 3) ndarrays with more than one dimension + 4) other non-string iterables + 5) anything else + + The first argument must be in one of the first four categories; + any argument with a length differing from that of the first + argument (and hence anything in category 5) then will be + passed through unchanged. + + Masks are obtained from all arguments of the correct length + in categories 1, 2, and 4; a point is bad if masked in a masked + array or if it is a nan or inf. No attempt is made to + extract a mask from categories 2, 3, and 4 if :meth:`np.isfinite` + does not yield a Boolean array. + + All input arguments that are not passed unchanged are returned + as ndarrays after removing the points or rows corresponding to + masks in any of the arguments. + + A vastly simpler version of this function was originally + written as a helper for Axes.scatter(). + + """ + if not len(args): + return () + if (is_string_like(args[0]) or not iterable(args[0])): + raise ValueError("First argument must be a sequence") + nrecs = len(args[0]) + margs = [] + seqlist = [False] * len(args) + for i, x in enumerate(args): + if (not is_string_like(x)) and iterable(x) and len(x) == nrecs: + seqlist[i] = True + if ma.isMA(x): + if x.ndim > 1: + raise ValueError("Masked arrays must be 1-D") + else: + x = np.asarray(x) + margs.append(x) + masks = [] # list of masks that are True where good + for i, x in enumerate(margs): + if seqlist[i]: + if x.ndim > 1: + continue # Don't try to get nan locations unless 1-D. + if ma.isMA(x): + masks.append(~ma.getmaskarray(x)) # invert the mask + xd = x.data + else: + xd = x + try: + mask = np.isfinite(xd) + if isinstance(mask, np.ndarray): + masks.append(mask) + except: # Fixme: put in tuple of possible exceptions? + pass + if len(masks): + mask = reduce(np.logical_and, masks) + igood = mask.nonzero()[0] + if len(igood) < nrecs: + for i, x in enumerate(margs): + if seqlist[i]: + margs[i] = x.take(igood, axis=0) + for i, x in enumerate(margs): + if seqlist[i] and ma.isMA(x): + margs[i] = x.filled() + return margs + + +def restrict_dict(d, keys): + """ + Return a dictionary that contains those keys that appear in both + d and keys, with values from d. + """ + return dict([(k, v) for (k, v) in d.iteritems() if k in keys]) + + +class Stack(object): + """ + Implement a stack where elements can be pushed on and you can move + back and forth. But no pop. Should mimic home / back / forward + in a browser + """ + + def __init__(self, default=None): + self.clear() + self._default = default + + def __call__(self): + 'return the current element, or None' + if not len(self._elements): + return self._default + else: + return self._elements[self._pos] + + def __len__(self): + return self._elements.__len__() + + def __getitem__(self, ind): + return self._elements.__getitem__(ind) + + def forward(self): + 'move the position forward and return the current element' + N = len(self._elements) + if self._pos < N - 1: + self._pos += 1 + return self() + + def back(self): + 'move the position back and return the current element' + if self._pos > 0: + self._pos -= 1 + return self() + + def push(self, o): + """ + push object onto stack at current position - all elements + occurring later than the current position are discarded + """ + self._elements = self._elements[:self._pos + 1] + self._elements.append(o) + self._pos = len(self._elements) - 1 + return self() + + def home(self): + 'push the first element onto the top of the stack' + if not len(self._elements): + return + self.push(self._elements[0]) + return self() + + def empty(self): + return len(self._elements) == 0 + + def clear(self): + 'empty the stack' + self._pos = -1 + self._elements = [] + + def bubble(self, o): + """ + raise *o* to the top of the stack and return *o*. *o* must be + in the stack + """ + + if o not in self._elements: + raise ValueError('Unknown element o') + old = self._elements[:] + self.clear() + bubbles = [] + for thiso in old: + if thiso == o: + bubbles.append(thiso) + else: + self.push(thiso) + for thiso in bubbles: + self.push(o) + return o + + def remove(self, o): + 'remove element *o* from the stack' + if o not in self._elements: + raise ValueError('Unknown element o') + old = self._elements[:] + self.clear() + for thiso in old: + if thiso == o: + continue + else: + self.push(thiso) + + +class maxdict(dict): + """ + A dictionary with a maximum size; this doesn't override all the + relevant methods to contrain size, just setitem, so use with + caution + """ + def __init__(self, maxsize): + dict.__init__(self) + self.maxsize = maxsize + self._killkeys = [] + + def __setitem__(self, k, v): + if k not in self: + if len(self) >= self.maxsize: + del self[self._killkeys[0]] + del self._killkeys[0] + self._killkeys.append(k) + dict.__setitem__(self, k, v) + + +class GetRealpathAndStat: + def __init__(self): + self._cache = {} + + def __call__(self, path): + result = self._cache.get(path) + if result is None: + realpath = os.path.realpath(path) + if sys.platform == 'win32': + stat_key = realpath + else: + stat = os.stat(realpath) + stat_key = (stat.st_ino, stat.st_dev) + result = realpath, stat_key + self._cache[path] = result + return result + +get_realpath_and_stat = GetRealpathAndStat() + + +def _check_output(*popenargs, **kwargs): + r"""Run command with arguments and return its output as a byte + string. + + If the exit code was non-zero it raises a CalledProcessError. The + CalledProcessError object will have the return code in the + returncode + attribute and output in the output attribute. + + The arguments are the same as for the Popen constructor. Example:: + + >>> check_output(["ls", "-l", "/dev/null"]) + 'crw-rw-rw- 1 root root 1, 3 Oct 18 2007 /dev/null\n' + + The stdout argument is not allowed as it is used internally. + To capture standard error in the result, use stderr=STDOUT.:: + + >>> check_output(["/bin/sh", "-c", + ... "ls -l non_existent_file ; exit 0"], + ... stderr=STDOUT) + 'ls: non_existent_file: No such file or directory\n' + """ + if 'stdout' in kwargs: + raise ValueError('stdout argument not allowed, it will be overridden.') + process = subprocess.Popen(stdout=subprocess.PIPE, *popenargs, **kwargs) + output, unused_err = process.communicate() + retcode = process.poll() + if retcode: + cmd = kwargs.get("args") + if cmd is None: + cmd = popenargs[0] + raise subprocess.CalledProcessError(retcode, cmd, output=output) + return output + + +# A regular expression used to determine the amount of space to +# remove. It looks for the first sequence of spaces immediately +# following the first newline, or at the beginning of the string. +_find_dedent_regex = re.compile("(?:(?:\n\r?)|^)( *)\S") +# A cache to hold the regexs that actually remove the indent. +_dedent_regex = {} + + +def dedent(s): + """ + Remove excess indentation from docstring *s*. + + Discards any leading blank lines, then removes up to n whitespace + characters from each line, where n is the number of leading + whitespace characters in the first line. It differs from + textwrap.dedent in its deletion of leading blank lines and its use + of the first non-blank line to determine the indentation. + + It is also faster in most cases. + """ + # This implementation has a somewhat obtuse use of regular + # expressions. However, this function accounted for almost 30% of + # matplotlib startup time, so it is worthy of optimization at all + # costs. + + if not s: # includes case of s is None + return '' + + match = _find_dedent_regex.match(s) + if match is None: + return s + + # This is the number of spaces to remove from the left-hand side. + nshift = match.end(1) - match.start(1) + if nshift == 0: + return s + + # Get a regex that will remove *up to* nshift spaces from the + # beginning of each line. If it isn't in the cache, generate it. + unindent = _dedent_regex.get(nshift, None) + if unindent is None: + unindent = re.compile("\n\r? {0,%d}" % nshift) + _dedent_regex[nshift] = unindent + + result = unindent.sub("\n", s).strip() + return result + + +# python2.7's subprocess provides a check_output method +if hasattr(subprocess, 'check_output'): + check_output = subprocess.check_output +else: + check_output = _check_output + + +# Numpy > 1.6.x deprecates putmask in favor of the new copyto. +# So long as we support versions 1.6.x and less, we need the +# following local version of putmask. We choose to make a +# local version of putmask rather than of copyto because the +# latter includes more functionality than the former. Therefore +# it is easy to make a local version that gives full putmask +# behavior, but duplicating the full copyto behavior would be +# more difficult. + +try: + np.copyto +except AttributeError: + _putmask = np.putmask +else: + def _putmask(a, mask, values): + return np.copyto(a, values, where=mask) + + +def exception_to_str(s=None): + + sh = io.StringIO() + if s is not None: + print(s, file=sh) + traceback.print_exc(file=sh) + return sh.getvalue() + + +def listFiles(root, patterns='*', recurse=1, return_folders=0): + """ + Recursively list files + + from Parmar and Martelli in the Python Cookbook + """ + import os.path + import fnmatch + # Expand patterns from semicolon-separated string to list + pattern_list = patterns.split(';') + results = [] + + for dirname, dirs, files in os.walk(root): + # Append to results all relevant files (and perhaps folders) + for name in files: + fullname = os.path.normpath(os.path.join(dirname, name)) + if return_folders or os.path.isfile(fullname): + for pattern in pattern_list: + if fnmatch.fnmatch(name, pattern): + results.append(fullname) + break + # Block recursion if recursion was disallowed + if not recurse: + break + + return results + + +def safe_masked_invalid(x): + x = np.asanyarray(x) + try: + xm = np.ma.masked_invalid(x, copy=False) + xm.shrink_mask() + except TypeError: + return x + return xm + + +class _InstanceMethodPickler(object): + """ + Pickle cannot handle instancemethod saving. _InstanceMethodPickler + provides a solution to this. + """ + def __init__(self, instancemethod): + """Takes an instancemethod as its only argument.""" + self.parent_obj = instancemethod.im_self + self.instancemethod_name = instancemethod.im_func.__name__ + + def get_instancemethod(self): + return getattr(self.parent_obj, self.instancemethod_name) + + +class _NestedClassGetter(object): + # recipe from http://stackoverflow.com/a/11493777/741316 + """ + When called with the containing class as the first argument, + and the name of the nested class as the second argument, + returns an instance of the nested class. + """ + def __call__(self, containing_class, class_name): + nested_class = getattr(containing_class, class_name) + + # make an instance of a simple object (this one will do), for which we + # can change the __class__ later on. + nested_instance = _NestedClassGetter() + + # set the class of the instance, the __init__ will never be called on + # the class but the original state will be set later on by pickle. + nested_instance.__class__ = nested_class + return nested_instance + + +def simple_linear_interpolation(a, steps): + if steps == 1: + return a + + steps = np.floor(steps) + new_length = ((len(a) - 1) * steps) + 1 + new_shape = list(a.shape) + new_shape[0] = new_length + result = np.zeros(new_shape, a.dtype) + + result[0] = a[0] + a0 = a[0:-1] + a1 = a[1:] + delta = ((a1 - a0) / steps) + + for i in range(1, int(steps)): + result[i::steps] = delta * i + a0 + result[steps::steps] = a1 + + return result + + +def report_memory(i=0): # argument may go away + """return the memory consumed by process""" + from subprocess import Popen, PIPE + pid = os.getpid() + if sys.platform == 'sunos5': + a2 = Popen('ps -p %d -o osz' % pid, shell=True, + stdout=PIPE).stdout.readlines() + mem = int(a2[-1].strip()) + elif sys.platform.startswith('linux'): + a2 = Popen('ps -p %d -o rss,sz' % pid, shell=True, + stdout=PIPE).stdout.readlines() + mem = int(a2[1].split()[1]) + elif sys.platform.startswith('darwin'): + a2 = Popen('ps -p %d -o rss,vsz' % pid, shell=True, + stdout=PIPE).stdout.readlines() + mem = int(a2[1].split()[0]) + elif sys.platform.startswith('win'): + try: + a2 = Popen(["tasklist", "/nh", "/fi", "pid eq %d" % pid], + stdout=PIPE).stdout.read() + except OSError: + raise NotImplementedError( + "report_memory works on Windows only if " + "the 'tasklist' program is found") + mem = int(a2.strip().split()[-2].replace(',', '')) + else: + raise NotImplementedError( + "We don't have a memory monitor for %s" % sys.platform) + return mem + + +def print_cycles(objects, outstream=sys.stdout, show_progress=False): + """ + *objects* + A list of objects to find cycles in. It is often useful to + pass in gc.garbage to find the cycles that are preventing some + objects from being garbage collected. + + *outstream* + The stream for output. + + *show_progress* + If True, print the number of objects reached as they are found. + """ + import gc + from types import FrameType + + def print_path(path): + for i, step in enumerate(path): + # next "wraps around" + next = path[(i + 1) % len(path)] + + outstream.write(" %s -- " % str(type(step))) + if isinstance(step, dict): + for key, val in step.iteritems(): + if val is next: + outstream.write("[%s]" % repr(key)) + break + if key is next: + outstream.write("[key] = %s" % repr(val)) + break + elif isinstance(step, list): + outstream.write("[%d]" % step.index(next)) + elif isinstance(step, tuple): + outstream.write("( tuple )") + else: + outstream.write(repr(step)) + outstream.write(" ->\n") + outstream.write("\n") + + def recurse(obj, start, all, current_path): + if show_progress: + outstream.write("%d\r" % len(all)) + + all[id(obj)] = None + + referents = gc.get_referents(obj) + for referent in referents: + # If we've found our way back to the start, this is + # a cycle, so print it out + if referent is start: + print_path(current_path) + + # Don't go back through the original list of objects, or + # through temporary references to the object, since those + # are just an artifact of the cycle detector itself. + elif referent is objects or isinstance(referent, FrameType): + continue + + # We haven't seen this object before, so recurse + elif id(referent) not in all: + recurse(referent, start, all, current_path + [obj]) + + for obj in objects: + outstream.write("Examining: %r\n" % (obj,)) + recurse(obj, obj, {}, []) diff --git a/lib/matplotlib/utils/_cbook.py b/lib/matplotlib/utils/_cbook.py new file mode 100644 index 000000000000..9473297db302 --- /dev/null +++ b/lib/matplotlib/utils/_cbook.py @@ -0,0 +1,618 @@ +""" +A collection of utility functions and classes. Many (but not all) +from the Python Cookbook -- hence the name _cbook +""" +from __future__ import print_function + +import datetime +import glob +import gzip +import os +import re +import sys +import threading +import time + +import matplotlib + +import numpy as np +from matplotlib.utils import * + + +class converter(object): + """ + Base class for handling string -> python type with support for + missing values + """ + def __init__(self, missing='Null', missingval=None): + self.missing = missing + self.missingval = missingval + + def __call__(self, s): + if s == self.missing: + return self.missingval + return s + + def is_missing(self, s): + return not s.strip() or s == self.missing + + +class tostr(converter): + 'convert to string or None' + def __init__(self, missing='Null', missingval=''): + converter.__init__(self, missing=missing, missingval=missingval) + + +class todatetime(converter): + 'convert to a datetime or None' + def __init__(self, fmt='%Y-%m-%d', missing='Null', missingval=None): + 'use a :func:`time.strptime` format string for conversion' + converter.__init__(self, missing, missingval) + self.fmt = fmt + + def __call__(self, s): + if self.is_missing(s): + return self.missingval + tup = time.strptime(s, self.fmt) + return datetime.datetime(*tup[:6]) + + +class todate(converter): + 'convert to a date or None' + def __init__(self, fmt='%Y-%m-%d', missing='Null', missingval=None): + 'use a :func:`time.strptime` format string for conversion' + converter.__init__(self, missing, missingval) + self.fmt = fmt + + def __call__(self, s): + if self.is_missing(s): + return self.missingval + tup = time.strptime(s, self.fmt) + return datetime.date(*tup[:3]) + + +class tofloat(converter): + 'convert to a float or None' + def __init__(self, missing='Null', missingval=None): + converter.__init__(self, missing) + self.missingval = missingval + + def __call__(self, s): + if self.is_missing(s): + return self.missingval + return float(s) + + +class toint(converter): + 'convert to an int or None' + def __init__(self, missing='Null', missingval=None): + converter.__init__(self, missing) + + def __call__(self, s): + if self.is_missing(s): + return self.missingval + return int(s) + + +class Scheduler(threading.Thread): + """ + Base class for timeout and idle scheduling + """ + idlelock = threading.Lock() + id = 0 + + def __init__(self): + threading.Thread.__init__(self) + self.id = Scheduler.id + self._stopped = False + Scheduler.id += 1 + self._stopevent = threading.Event() + + def stop(self): + if self._stopped: + return + self._stopevent.set() + self.join() + self._stopped = True + + +class Timeout(Scheduler): + """ + Schedule recurring events with a wait time in seconds + """ + def __init__(self, wait, func): + Scheduler.__init__(self) + self.wait = wait + self.func = func + + def run(self): + + while not self._stopevent.isSet(): + self._stopevent.wait(self.wait) + Scheduler.idlelock.acquire() + b = self.func(self) + Scheduler.idlelock.release() + if not b: + break + + +class Idle(Scheduler): + """ + Schedule callbacks when scheduler is idle + """ + # the prototype impl is a bit of a poor man's idle handler. It + # just implements a short wait time. But it will provide a + # placeholder for a proper impl ater + waittime = 0.05 + + def __init__(self, func): + Scheduler.__init__(self) + self.func = func + + def run(self): + + while not self._stopevent.isSet(): + self._stopevent.wait(Idle.waittime) + Scheduler.idlelock.acquire() + b = self.func(self) + Scheduler.idlelock.release() + if not b: + break + + +def unique(x): + 'Return a list of unique elements of *x*' + return dict([(val, 1) for val in x]).keys() + + +def get_sample_data(fname, asfileobj=True): + """ + Return a sample data file. *fname* is a path relative to the + `mpl-data/sample_data` directory. If *asfileobj* is `True` + return a file object, otherwise just a file path. + + Set the rc parameter examples.directory to the directory where we should + look, if sample_data files are stored in a location different than + default (which is 'mpl-data/sample_data` at the same level of 'matplotlib` + Python module files). + + If the filename ends in .gz, the file is implicitly ungzipped. + """ + if matplotlib.rcParams['examples.directory']: + root = matplotlib.rcParams['examples.directory'] + else: + root = os.path.join(os.path.dirname(__file__), + "mpl-data", "sample_data") + path = os.path.join(root, fname) + + if asfileobj: + if (os.path.splitext(fname)[-1].lower() in + ('.csv', '.xrc', '.txt')): + mode = 'r' + else: + mode = 'rb' + + base, ext = os.path.splitext(fname) + if ext == '.gz': + return gzip.open(path, mode) + else: + return open(path, mode) + else: + return path + + +class Sorter: + """ + Sort by attribute or item + + Example usage:: + + sort = Sorter() + + list = [(1, 2), (4, 8), (0, 3)] + dict = [{'a': 3, 'b': 4}, {'a': 5, 'b': 2}, {'a': 0, 'b': 0}, + {'a': 9, 'b': 9}] + + + sort(list) # default sort + sort(list, 1) # sort by index 1 + sort(dict, 'a') # sort a list of dicts by key 'a' + + """ + + def _helper(self, data, aux, inplace): + aux.sort() + result = [data[i] for junk, i in aux] + if inplace: + data[:] = result + return result + + def byItem(self, data, itemindex=None, inplace=1): + if itemindex is None: + if inplace: + data.sort() + result = data + else: + result = data[:] + result.sort() + return result + else: + aux = [(data[i][itemindex], i) for i in range(len(data))] + return self._helper(data, aux, inplace) + + def byAttribute(self, data, attributename, inplace=1): + aux = [(getattr(data[i], attributename), i) for i in range(len(data))] + return self._helper(data, aux, inplace) + + # a couple of handy synonyms + sort = byItem + __call__ = byItem + + +class Xlator(dict): + """ + All-in-one multiple-string-substitution class + + Example usage:: + + text = "Larry Wall is the creator of Perl" + adict = { + "Larry Wall" : "Guido van Rossum", + "creator" : "Benevolent Dictator for Life", + "Perl" : "Python", + } + + print multiple_replace(adict, text) + + xlat = Xlator(adict) + print xlat.xlat(text) + """ + + def _make_regex(self): + """ Build re object based on the keys of the current dictionary """ + return re.compile("|".join(map(re.escape, self.iterkeys()))) + + def __call__(self, match): + """ Handler invoked for each regex *match* """ + return self[match.group(0)] + + def xlat(self, text): + """ Translate *text*, returns the modified text. """ + return self._make_regex().sub(self, text) + + +def soundex(name, len=4): + """ soundex module conforming to Odell-Russell algorithm """ + + # digits holds the soundex values for the alphabet + soundex_digits = '01230120022455012623010202' + sndx = '' + fc = '' + + # Translate letters in name to soundex digits + for c in name.upper(): + if c.isalpha(): + if not fc: + fc = c # Remember first letter + d = soundex_digits[ord(c) - ord('A')] + # Duplicate consecutive soundex digits are skipped + if not sndx or (d != sndx[-1]): + sndx += d + + # Replace first digit with first letter + sndx = fc + sndx[1:] + + # Remove all 0s from the soundex code + sndx = sndx.replace('0', '') + + # Return soundex code truncated or 0-padded to len characters + return (sndx + (len * '0'))[:len] + + +class Null: + """ Null objects always and reliably "do nothing." """ + + def __init__(self, *args, **kwargs): + pass + + def __call__(self, *args, **kwargs): + return self + + def __str__(self): + return "Null()" + + def __repr__(self): + return "Null()" + + def __nonzero__(self): + return 0 + + def __getattr__(self, name): + return self + + def __setattr__(self, name, value): + return self + + def __delattr__(self, name): + return self + + +def dict_delall(d, keys): + 'delete all of the *keys* from the :class:`dict` *d*' + for key in keys: + try: + del d[key] + except KeyError: + pass + + +class RingBuffer: + """ class that implements a not-yet-full buffer """ + def __init__(self, size_max): + self.max = size_max + self.data = [] + + class __Full: + """ class that implements a full buffer """ + def append(self, x): + """ Append an element overwriting the oldest one. """ + self.data[self.cur] = x + self.cur = (self.cur + 1) % self.max + + def get(self): + """ return list of elements in correct order """ + return self.data[self.cur:] + self.data[:self.cur] + + def append(self, x): + """append an element at the end of the buffer""" + self.data.append(x) + if len(self.data) == self.max: + self.cur = 0 + # Permanently change self's class from non-full to full + # FIXME __Full is not defined + self.__class__ = __Full + + def get(self): + """ Return a list of elements from the oldest to the newest. """ + return self.data + + def __get_item__(self, i): + return self.data[i % len(self.data)] + + +def get_split_ind(seq, N): + """ + *seq* is a list of words. Return the index into seq such that:: + + len(' '.join(seq[:ind])<=N + + . + """ + + sLen = 0 + # todo: use Alex's xrange pattern from the cbook for efficiency + for (word, ind) in zip(seq, xrange(len(seq))): + sLen += len(word) + 1 # +1 to account for the len(' ') + if sLen >= N: + return ind + return len(seq) + + +def wrap(prefix, text, cols): + 'wrap *text* with *prefix* at length *cols*' + pad = ' ' * len(prefix.expandtabs()) + available = cols - len(pad) + + seq = text.split(' ') + Nseq = len(seq) + ind = 0 + lines = [] + while ind < Nseq: + lastInd = ind + ind += get_split_ind(seq[ind:], available) + lines.append(seq[lastInd:ind]) + + # add the prefix to the first line, pad with spaces otherwise + ret = prefix + ' '.join(lines[0]) + '\n' + for line in lines[1:]: + ret += pad + ' '.join(line) + '\n' + return ret + + +def get_recursive_filelist(args): + """ + Recurse all the files and dirs in *args* ignoring symbolic links + and return the files as a list of strings + """ + files = [] + + for arg in args: + if os.path.isfile(arg): + files.append(arg) + continue + if os.path.isdir(arg): + newfiles = listFiles(arg, recurse=1, return_folders=1) + files.extend(newfiles) + + return [f for f in files if not os.path.islink(f)] + + +def pieces(seq, num=2): + "Break up the *seq* into *num* tuples" + start = 0 + while 1: + item = seq[start:start + num] + if not len(item): + break + yield item + start += num + + +def alltrue(seq): + """ + Return *True* if all elements of *seq* evaluate to *True*. If + *seq* is empty, return *False*. + """ + if not len(seq): + return False + for val in seq: + if not val: + return False + return True + + +def onetrue(seq): + """ + Return *True* if one element of *seq* is *True*. It *seq* is + empty, return *False*. + """ + if not len(seq): + return False + for val in seq: + if val: + return True + return False + + +def allpairs(x): + """ + return all possible pairs in sequence *x* + + Condensed by Alex Martelli from this thread_ on c.l.python + + .. _thread: http://groups.google.com/groups?q=all+pairs+group:*python*&hl=en&lr=&ie=UTF-8&selm=mailman.4028.1096403649.5135.python-list%40python.org&rnum=1 + """ + return [(s, f) for i, f in enumerate(x) for s in x[i + 1:]] + + +def finddir(o, match, case=False): + """ + return all attributes of *o* which match string in match. if case + is True require an exact case match. + """ + if case: + names = [(name, name) for name in dir(o) if is_string_like(name)] + else: + names = [(name.lower(), name) for name in dir(o) + if is_string_like(name)] + match = match.lower() + return [orig for name, orig in names if name.find(match) >= 0] + + + +class MemoryMonitor: + def __init__(self, nmax=20000): + self._nmax = nmax + self._mem = np.zeros((self._nmax,), np.int32) + self.clear() + + def clear(self): + self._n = 0 + self._overflow = False + + def __call__(self): + mem = report_memory() + if self._n < self._nmax: + self._mem[self._n] = mem + self._n += 1 + else: + self._overflow = True + return mem + + def report(self, segments=4): + n = self._n + segments = min(n, segments) + dn = int(n / segments) + ii = range(0, n, dn) + ii[-1] = n - 1 + print() + print('memory report: i, mem, dmem, dmem/nloops') + print(0, self._mem[0]) + for i in range(1, len(ii)): + di = ii[i] - ii[i - 1] + if di == 0: + continue + dm = self._mem[ii[i]] - self._mem[ii[i - 1]] + print('%5d %5d %3d %8.3f' % (ii[i], self._mem[ii[i]], + dm, dm / float(di))) + if self._overflow: + print("Warning: array size was too small for the number of calls.") + + def xy(self, i0=0, isub=1): + x = np.arange(i0, self._n, isub) + return x, self._mem[i0:self._n:isub] + + def plot(self, i0=0, isub=1, fig=None): + if fig is None: + from pylab import figure + fig = figure() + + ax = fig.add_subplot(111) + ax.plot(*self.xy(i0, isub)) + fig.canvas.draw() + + + +def recursive_remove(path): + if os.path.isdir(path): + for fname in glob.glob(os.path.join(path, '*')) + \ + glob.glob(os.path.join(path, '.*')): + if os.path.isdir(fname): + recursive_remove(fname) + os.removedirs(fname) + else: + os.remove(fname) + #os.removedirs(path) + else: + os.remove(path) + + +# FIXME I don't think this is used anywhere +def unmasked_index_ranges(mask, compressed=True): + """ + Find index ranges where *mask* is *False*. + + *mask* will be flattened if it is not already 1-D. + + Returns Nx2 :class:`numpy.ndarray` with each row the start and stop + indices for slices of the compressed :class:`numpy.ndarray` + corresponding to each of *N* uninterrupted runs of unmasked + values. If optional argument *compressed* is *False*, it returns + the start and stop indices into the original :class:`numpy.ndarray`, + not the compressed :class:`numpy.ndarray`. Returns *None* if there + are no unmasked values. + + Example:: + + y = ma.array(np.arange(5), mask = [0,0,1,0,0]) + ii = unmasked_index_ranges(ma.getmaskarray(y)) + # returns array [[0,2,] [2,4,]] + + y.compressed()[ii[1,0]:ii[1,1]] + # returns array [3,4,] + + ii = unmasked_index_ranges(ma.getmaskarray(y), compressed=False) + # returns array [[0, 2], [3, 5]] + + y.filled()[ii[1,0]:ii[1,1]] + # returns array [3,4,] + + Prior to the transforms refactoring, this was used to support + masked arrays in Line2D. + """ + mask = mask.reshape(mask.size) + m = np.concatenate(((1,), mask, (1,))) + indices = np.arange(len(mask) + 1) + mdif = m[1:] - m[:-1] + i0 = np.compress(mdif == -1, indices) + i1 = np.compress(mdif == 1, indices) + assert len(i0) == len(i1) + if len(i1) == 0: + return None # Maybe this should be np.zeros((0,2), dtype=int) + if not compressed: + return np.concatenate((i0[:, np.newaxis], i1[:, np.newaxis]), axis=1) + seglengths = i1 - i0 + breakpoints = np.cumsum(seglengths) + ic0 = np.concatenate(((0,), breakpoints[:-1])) + ic1 = breakpoints + return np.concatenate((ic0[:, np.newaxis], ic1[:, np.newaxis]), axis=1) diff --git a/lib/mpl_toolkits/axes_grid/colorbar.py b/lib/mpl_toolkits/axes_grid/colorbar.py index db224189520a..e3bb17b1485e 100644 --- a/lib/mpl_toolkits/axes_grid/colorbar.py +++ b/lib/mpl_toolkits/axes_grid/colorbar.py @@ -25,7 +25,7 @@ import matplotlib.cm as cm from matplotlib import docstring import matplotlib.ticker as ticker -import matplotlib.cbook as cbook +import matplotlib.utils as utils import matplotlib.collections as collections import matplotlib.contour as contour from matplotlib.path import Path @@ -376,7 +376,7 @@ def __init__(self, ax, cmap=None, formatter = ticker.LogFormatter() else: formatter = None - elif cbook.is_string_like(format): + elif utils.is_string_like(format): formatter = ticker.FormatStrFormatter(format) else: formatter = format # Assume it is a Formatter @@ -386,7 +386,7 @@ def __init__(self, ax, cmap=None, else: self.cbar_axis.set_major_formatter(formatter) - if cbook.iterable(ticks): + if utils.iterable(ticks): self.cbar_axis.set_ticks(ticks) elif ticks is not None: self.cbar_axis.set_major_locator(ticks) diff --git a/lib/mpl_toolkits/axes_grid1/axes_grid.py b/lib/mpl_toolkits/axes_grid1/axes_grid.py index 45bff69737fd..837eeebc01cb 100644 --- a/lib/mpl_toolkits/axes_grid1/axes_grid.py +++ b/lib/mpl_toolkits/axes_grid1/axes_grid.py @@ -1,4 +1,4 @@ -import matplotlib.cbook as cbook +import matplotlib.utils as utils import matplotlib.pyplot as plt import matplotlib.axes as maxes @@ -240,7 +240,7 @@ def __init__(self, fig, h = [] v = [] - if cbook.is_string_like(rect) or cbook.is_numlike(rect): + if utils.is_string_like(rect) or utils.is_numlike(rect): self._divider = SubplotDivider(fig, rect, horizontal=h, vertical=v, aspect=False) elif isinstance(rect, SubplotSpec): @@ -554,7 +554,7 @@ def __init__(self, fig, h = [] v = [] - if cbook.is_string_like(rect) or cbook.is_numlike(rect): + if utils.is_string_like(rect) or utils.is_numlike(rect): self._divider = SubplotDivider(fig, rect, horizontal=h, vertical=v, aspect=aspect) elif isinstance(rect, SubplotSpec): diff --git a/lib/mpl_toolkits/axes_grid1/axes_size.py b/lib/mpl_toolkits/axes_grid1/axes_size.py index 33f40ea92e28..cf4c0ecdc899 100644 --- a/lib/mpl_toolkits/axes_grid1/axes_size.py +++ b/lib/mpl_toolkits/axes_grid1/axes_size.py @@ -11,7 +11,7 @@ class (or others) to determine the size of each axes. The unit """ -import matplotlib.cbook as cbook +import matplotlib.utils as utils from matplotlib.axes import Axes class _Base(object): @@ -230,9 +230,9 @@ def from_any(size, fraction_ref=None): >>> Size.from_any("50%", a) # => Size.Fraction(0.5, a) """ - if cbook.is_numlike(size): + if utils.is_numlike(size): return Fixed(size) - elif cbook.is_string_like(size): + elif utils.is_string_like(size): if size[-1] == "%": return Fraction(float(size[:-1])/100., fraction_ref) diff --git a/lib/mpl_toolkits/axes_grid1/colorbar.py b/lib/mpl_toolkits/axes_grid1/colorbar.py index 0420a79040e1..234366f15e80 100644 --- a/lib/mpl_toolkits/axes_grid1/colorbar.py +++ b/lib/mpl_toolkits/axes_grid1/colorbar.py @@ -25,7 +25,7 @@ import matplotlib.cm as cm from matplotlib import docstring import matplotlib.ticker as ticker -import matplotlib.cbook as cbook +import matplotlib.utils as utils import matplotlib.collections as collections import matplotlib.contour as contour from matplotlib.path import Path @@ -376,7 +376,7 @@ def __init__(self, ax, cmap=None, formatter = ticker.LogFormatter() else: formatter = None - elif cbook.is_string_like(format): + elif utils.is_string_like(format): formatter = ticker.FormatStrFormatter(format) else: formatter = format # Assume it is a Formatter @@ -386,7 +386,7 @@ def __init__(self, ax, cmap=None, else: self.cbar_axis.set_major_formatter(formatter) - if cbook.iterable(ticks): + if utils.iterable(ticks): self.cbar_axis.set_ticks(ticks) elif ticks is not None: self.cbar_axis.set_major_locator(ticks) diff --git a/lib/mpl_toolkits/axes_grid1/parasite_axes.py b/lib/mpl_toolkits/axes_grid1/parasite_axes.py index 3d0b9d8e8904..ac9ee88a371b 100644 --- a/lib/mpl_toolkits/axes_grid1/parasite_axes.py +++ b/lib/mpl_toolkits/axes_grid1/parasite_axes.py @@ -14,8 +14,8 @@ import numpy as np -import matplotlib.cbook as cbook -is_string_like = cbook.is_string_like +import matplotlib.utils as utils +is_string_like = utils.is_string_like class ParasiteAxesBase: diff --git a/lib/mpl_toolkits/axisartist/grid_finder.py b/lib/mpl_toolkits/axisartist/grid_finder.py index 7486bc721737..cc908ac25c49 100644 --- a/lib/mpl_toolkits/axisartist/grid_finder.py +++ b/lib/mpl_toolkits/axisartist/grid_finder.py @@ -1,7 +1,6 @@ from __future__ import print_function import numpy as np -import matplotlib.cbook as mcbook from matplotlib.transforms import Bbox import clip_path clip_line_to_rect = clip_path.clip_line_to_rect diff --git a/lib/mpl_toolkits/axisartist/grid_helper_curvelinear.py b/lib/mpl_toolkits/axisartist/grid_helper_curvelinear.py index e841ba09c02a..08eb6b308f92 100644 --- a/lib/mpl_toolkits/axisartist/grid_helper_curvelinear.py +++ b/lib/mpl_toolkits/axisartist/grid_helper_curvelinear.py @@ -580,7 +580,7 @@ def curvelinear_test2(fig): from mpl_toolkits.axes_grid.parasite_axes import SubplotHost, \ ParasiteAxesAuxTrans - import matplotlib.cbook as cbook + import matplotlib.utils as utils # PolarAxes.PolarTransform takes radian. However, we want our coordinate # system in degree @@ -649,7 +649,7 @@ def curvelinear_test2(fig): # note that ax2.transData == tr + ax1.transData # Anthing you draw in ax2 will match the ticks and grids of ax1. ax1.parasites.append(ax2) - intp = cbook.simple_linear_interpolation + intp = utils.simple_linear_interpolation ax2.plot(intp(np.array([0, 30]), 50), intp(np.array([10., 10.]), 50)) @@ -747,7 +747,7 @@ def curvelinear_test3(fig): # # note that ax2.transData == tr + ax1.transData # # Anthing you draw in ax2 will match the ticks and grids of ax1. # ax1.parasites.append(ax2) -# intp = cbook.simple_linear_interpolation +# intp = utils.simple_linear_interpolation # ax2.plot(intp(np.array([0, 30]), 50), # intp(np.array([10., 10.]), 50)) diff --git a/lib/mpl_toolkits/exceltools.py b/lib/mpl_toolkits/exceltools.py index 0f26c8aa4d57..dc80b904bce4 100644 --- a/lib/mpl_toolkits/exceltools.py +++ b/lib/mpl_toolkits/exceltools.py @@ -24,7 +24,7 @@ import xlwt as excel -import matplotlib.cbook as cbook +import matplotlib.utils as utils import matplotlib.mlab as mlab @@ -83,7 +83,7 @@ def rec2excel(r, ws, formatd=None, rownum=0, colnum=0, nanstr='NaN', infstr='Inf """ autosave = False - if cbook.is_string_like(ws): + if utils.is_string_like(ws): filename = ws wb = excel.Workbook() ws = wb.add_sheet('worksheet') diff --git a/lib/mpl_toolkits/gtktools.py b/lib/mpl_toolkits/gtktools.py index b0daf60a99fe..1e462935a138 100644 --- a/lib/mpl_toolkits/gtktools.py +++ b/lib/mpl_toolkits/gtktools.py @@ -34,7 +34,7 @@ import copy import gtk, gobject import numpy as npy -import matplotlib.cbook as cbook +import matplotlib.utils as utils import matplotlib.mlab as mlab @@ -356,7 +356,7 @@ class RecListStore(gtk.ListStore): * stringd - a dict mapping dtype names to a list of valid strings for the combo drop downs - * callbacks - a matplotlib.cbook.CallbackRegistry. Connect to the cell_changed with + * callbacks - a matplotlib.utils.CallbackRegistry. Connect to the cell_changed with def mycallback(liststore, rownum, colname, oldval, newval): print 'verify: old=%s, new=%s, rec=%s'%(oldval, newval, liststore.r[rownum][colname]) @@ -381,7 +381,7 @@ def __init__(self, r, formatd=None, stringd=None): formatd = mlab.get_formatd(r) self.stringd = stringd - self.callbacks = cbook.CallbackRegistry(['cell_changed']) + self.callbacks = utils.CallbackRegistry(['cell_changed']) self.r = r @@ -439,7 +439,7 @@ def position_edited(self, renderer, path, newtext, position): oldval = self.r[rownum][colname] try: newval = format.fromstr(newtext) except ValueError: - msg = cbook.exception_to_str('Error converting "%s"'%newtext) + msg = utils.exception_to_str('Error converting "%s"'%newtext) error_message(msg, title='Error') return self.r[rownum][colname] = newval diff --git a/lib/mpl_toolkits/mplot3d/art3d.py b/lib/mpl_toolkits/mplot3d/art3d.py index 53ba0fe2e559..569debef95ba 100644 --- a/lib/mpl_toolkits/mplot3d/art3d.py +++ b/lib/mpl_toolkits/mplot3d/art3d.py @@ -14,7 +14,7 @@ from matplotlib.cm import ScalarMappable from matplotlib.patches import Patch from matplotlib.colors import Normalize -from matplotlib.cbook import iterable +from matplotlib.utils import iterable import warnings import numpy as np diff --git a/lib/mpl_toolkits/mplot3d/axes3d.py b/lib/mpl_toolkits/mplot3d/axes3d.py index e8c8bd7a0fd8..c87b63030189 100755 --- a/lib/mpl_toolkits/mplot3d/axes3d.py +++ b/lib/mpl_toolkits/mplot3d/axes3d.py @@ -15,7 +15,7 @@ import matplotlib.axes as maxes from matplotlib.axes import Axes, rcParams -from matplotlib import cbook +import matplotlib.utils as utils import matplotlib.transforms as mtransforms from matplotlib.transforms import Bbox import matplotlib.collections as mcoll @@ -38,7 +38,7 @@ class Axes3D(Axes): 3D axes object. """ name = '3d' - _shared_z_axes = cbook.Grouper() + _shared_z_axes = utils.Grouper() def __init__(self, fig, rect=None, *args, **kwargs): ''' @@ -547,7 +547,7 @@ def get_w_lims(self): return minx, maxx, miny, maxy, minz, maxz def _determine_lims(self, xmin=None, xmax=None, *args, **kwargs): - if xmax is None and cbook.iterable(xmin): + if xmax is None and utils.iterable(xmin): xmin, xmax = xmin if xmin == xmax: xmin -= 0.05 @@ -568,7 +568,7 @@ def set_xlim3d(self, left=None, right=None, emit=True, auto=False, **kw): if kw: raise ValueError("unrecognized kwargs: %s" % kw.keys()) - if right is None and cbook.iterable(left): + if right is None and utils.iterable(left): left, right = left self._process_unit_info(xdata=(left, right)) @@ -623,7 +623,7 @@ def set_ylim3d(self, bottom=None, top=None, emit=True, auto=False, **kw): if kw: raise ValueError("unrecognized kwargs: %s" % kw.keys()) - if top is None and cbook.iterable(bottom): + if top is None and utils.iterable(bottom): bottom, top = bottom self._process_unit_info(ydata=(bottom, top)) @@ -677,7 +677,7 @@ def set_zlim3d(self, bottom=None, top=None, emit=True, auto=False, **kw): if kw: raise ValueError("unrecognized kwargs: %s" % kw.keys()) - if top is None and cbook.iterable(bottom): + if top is None and utils.iterable(bottom): bottom, top = bottom self._process_unit_info(zdata=(bottom, top)) @@ -827,7 +827,7 @@ def get_zmajorticklabels(self) : .. versionadded :: 1.1.0 """ - return cbook.silent_list('Text zticklabel', + return utils.silent_list('Text zticklabel', self.zaxis.get_majorticklabels()) def get_zminorticklabels(self) : @@ -840,7 +840,7 @@ def get_zminorticklabels(self) : .. versionadded :: 1.1.0 """ - return cbook.silent_list('Text zticklabel', + return utils.silent_list('Text zticklabel', self.zaxis.get_minorticklabels()) def set_zticklabels(self, *args, **kwargs) : @@ -865,7 +865,7 @@ def get_zticklabels(self, minor=False) : .. versionadded:: 1.1.0 """ - return cbook.silent_list('Text zticklabel', + return utils.silent_list('Text zticklabel', self.zaxis.get_ticklabels(minor=minor)) def zaxis_date(self, tz=None) : @@ -1425,7 +1425,7 @@ def set_zbound(self, lower=None, upper=None): .. versionadded :: 1.1.0 This function was added, but not tested. Please report any bugs. """ - if upper is None and cbook.iterable(lower): + if upper is None and utis.iterable(lower): lower,upper = lower old_lower,old_upper = self.get_zbound() @@ -1491,23 +1491,23 @@ def plot(self, xs, ys, *args, **kwargs): argsi = 0 # First argument is array of zs - if len(args) > 0 and cbook.iterable(args[0]) and \ + if len(args) > 0 and utils.iterable(args[0]) and \ len(xs) == len(args[0]) : # So, we know that it is an array with # first dimension the same as xs. # Next, check to see if the data contained # therein (if any) is scalar (and not another array). - if len(args[0]) == 0 or cbook.is_scalar(args[0][0]) : + if len(args[0]) == 0 or utils.is_scalar(args[0][0]) : zs = args[argsi] argsi += 1 # First argument is z value - elif len(args) > 0 and cbook.is_scalar(args[0]): + elif len(args) > 0 and utils.is_scalar(args[0]): zs = args[argsi] argsi += 1 # Match length - if not cbook.iterable(zs): + if not utils.iterable(zs): zs = np.ones(len(xs)) * zs lines = Axes.plot(self, xs, ys, *args[argsi:], **kwargs) @@ -2169,16 +2169,16 @@ def scatter(self, xs, ys, zs=0, zdir='z', s=20, c='b', *args, **kwargs): s = np.ma.ravel(s) # This doesn't have to match x, y in size. - cstr = cbook.is_string_like(c) or cbook.is_sequence_of_strings(c) + cstr = utils.is_string_like(c) or utils.is_sequence_of_strings(c) if not cstr: c = np.asanyarray(c) if c.size == xs.size: c = np.ma.ravel(c) - xs, ys, zs, s, c = cbook.delete_masked_points(xs, ys, zs, s, c) + xs, ys, zs, s, c = utils.delete_masked_points(xs, ys, zs, s, c) patches = Axes.scatter(self, xs, ys, s=s, c=c, *args, **kwargs) - if not cbook.iterable(zs): + if not utils.iterable(zs): is_2d = True zs = np.ones(len(xs)) * zs else: @@ -2220,7 +2220,7 @@ def bar(self, left, height, zs=0, zdir='z', *args, **kwargs): patches = Axes.bar(self, left, height, *args, **kwargs) - if not cbook.iterable(zs): + if not utils.iterable(zs): zs = np.ones(len(left)) * zs verts = [] @@ -2282,18 +2282,18 @@ def bar3d(self, x, y, z, dx, dy, dz, color='b', ''' had_data = self.has_data() - if not cbook.iterable(x): + if not utils.iterable(x): x = [x] - if not cbook.iterable(y): + if not utils.iterable(y): y = [y] - if not cbook.iterable(z): + if not utils.iterable(z): z = [z] - if not cbook.iterable(dx): + if not utils.iterable(dx): dx = [dx] - if not cbook.iterable(dy): + if not utils.iterable(dy): dy = [dy] - if not cbook.iterable(dz): + if not utils.iterable(dz): dz = [dz] if len(dx) == 1: diff --git a/setup.py b/setup.py index 8d471415d79c..a807fc28d402 100644 --- a/setup.py +++ b/setup.py @@ -60,6 +60,7 @@ 'matplotlib.testing', 'matplotlib.testing.jpl_units', 'matplotlib.tests', + 'matplotlib.utils', 'mpl_toolkits', 'mpl_toolkits.mplot3d', 'mpl_toolkits.axes_grid', diff --git a/unit/memleak_gui.py b/unit/memleak_gui.py index 77570c86a5c2..bd736d892f03 100755 --- a/unit/memleak_gui.py +++ b/unit/memleak_gui.py @@ -11,7 +11,7 @@ The default number of loops typically will not yield a stable estimate--for that you may need many hundreds of loops and some patience. -You may need to edit cbook.report_memory to support your platform +You may need to edit utils.report_memory to support your platform ''' from __future__ import print_function @@ -48,7 +48,7 @@ if options.backend: matplotlib.use(options.backend) import pylab -import matplotlib.cbook as cbook +import matplotlib.utils as utils print('# columns are: iteration, OS memory (k), number of python objects') print('#') @@ -59,7 +59,7 @@ fig.clf() pylab.close(fig) gc.collect() - val = cbook.report_memory(i) + val = utils.report_memory(i) if options.verbose: if i % 10 == 0: #print ("iter: %4d OS memory: %8d Python objects: %8d" % @@ -106,4 +106,4 @@ print('# Average memory consumed per loop: %1.4fk bytes\n' % ((end-start)/float(indEnd-indStart))) if options.cycles: - cbook.print_cycles(gc.garbage) + utils.print_cycles(gc.garbage) diff --git a/unit/memleak_hawaii3.py b/unit/memleak_hawaii3.py index 6aab771e46dd..b875665498dd 100755 --- a/unit/memleak_hawaii3.py +++ b/unit/memleak_hawaii3.py @@ -6,7 +6,7 @@ import matplotlib matplotlib.use('PDF') -from matplotlib.cbook import report_memory +from matplotlib.utils import report_memory import numpy as np from pylab import figure, show, close diff --git a/unit/memleak_nongui.py b/unit/memleak_nongui.py index e3ac8321d00b..6e92e328350a 100644 --- a/unit/memleak_nongui.py +++ b/unit/memleak_nongui.py @@ -2,7 +2,7 @@ import os,matplotlib matplotlib.use('Agg') from matplotlib.figure import Figure -from matplotlib.cbook import report_memory +from matplotlib.utils import report_memory def plot(): fig = Figure()