From 1b0ac37a3c1e0f7b31b0608243bc5018dc928433 Mon Sep 17 00:00:00 2001 From: David Stansby Date: Fri, 2 Jun 2017 15:51:18 +0100 Subject: [PATCH 01/27] Clarify how a FancyArrowPatch behaves --- lib/matplotlib/patches.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/matplotlib/patches.py b/lib/matplotlib/patches.py index 10bc425b7734..91c86f0df537 100644 --- a/lib/matplotlib/patches.py +++ b/lib/matplotlib/patches.py @@ -3995,6 +3995,10 @@ def transmute(self, path, mutation_size, linewidth): class FancyArrowPatch(Patch): """ A fancy arrow patch. It draws an arrow using the :class:`ArrowStyle`. + + The head and tail positions are fixed at the specified start and end points + of the arrow, but the size and shape of the arrow does not change when the + axis is moved or zoomed. """ _edge_default = True From 070a578db5b70526efe3caefb4885b91b7931914 Mon Sep 17 00:00:00 2001 From: David Stansby Date: Wed, 7 Jun 2017 15:09:38 +0100 Subject: [PATCH 02/27] Clarify in display units --- lib/matplotlib/patches.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/matplotlib/patches.py b/lib/matplotlib/patches.py index 91c86f0df537..36a9c8e30b93 100644 --- a/lib/matplotlib/patches.py +++ b/lib/matplotlib/patches.py @@ -3997,8 +3997,8 @@ class FancyArrowPatch(Patch): A fancy arrow patch. It draws an arrow using the :class:`ArrowStyle`. The head and tail positions are fixed at the specified start and end points - of the arrow, but the size and shape of the arrow does not change when the - axis is moved or zoomed. + of the arrow, but the size and shape (in display coordinates) of the arrow + does not change when the axis is moved or zoomed. """ _edge_default = True From 089818b0e8f26396bf65670be2f2bd965695436a Mon Sep 17 00:00:00 2001 From: David Stansby Date: Fri, 9 Jun 2017 17:55:37 +0100 Subject: [PATCH 03/27] Allow divmod to be overridden by numpy --- lib/matplotlib/tests/test_basic.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/matplotlib/tests/test_basic.py b/lib/matplotlib/tests/test_basic.py index 236e0d9e7d8d..945e78322b3d 100644 --- a/lib/matplotlib/tests/test_basic.py +++ b/lib/matplotlib/tests/test_basic.py @@ -20,7 +20,8 @@ def test_override_builtins(): '__spec__', 'any', 'all', - 'sum' + 'sum', + 'divmod' } # We could use six.moves.builtins here, but that seems From b87778ea676dbb440a8f2397932e2695d179a6b2 Mon Sep 17 00:00:00 2001 From: Antony Lee Date: Sat, 3 Jun 2017 12:46:51 -0700 Subject: [PATCH 04/27] Various cleanups to backends code. Removed some debug statements and old comments; whitespace / line wrapping. In particular, debug comments which simply indicate that a function has been called can easily be replaced by tools such as https://pypi.python.org/pypi/hunter or https://pypi.python.org/pypi/smiley. --- lib/matplotlib/backends/backend_agg.py | 34 ------------- lib/matplotlib/backends/backend_cairo.py | 18 ------- lib/matplotlib/backends/backend_gdk.py | 6 +-- lib/matplotlib/backends/backend_gtk.py | 20 -------- lib/matplotlib/backends/backend_gtk3.py | 51 +++++++------------- lib/matplotlib/backends/backend_gtkcairo.py | 14 ++---- lib/matplotlib/backends/backend_ps.py | 1 - lib/matplotlib/backends/backend_qt4.py | 11 ++--- lib/matplotlib/backends/backend_qt5.py | 48 +++---------------- lib/matplotlib/backends/backend_tkagg.py | 53 ++++++++------------- 10 files changed, 53 insertions(+), 203 deletions(-) diff --git a/lib/matplotlib/backends/backend_agg.py b/lib/matplotlib/backends/backend_agg.py index 223e088d71ba..35df7b6a3617 100644 --- a/lib/matplotlib/backends/backend_agg.py +++ b/lib/matplotlib/backends/backend_agg.py @@ -84,25 +84,18 @@ class RendererAgg(RendererBase): lock = threading.RLock() def __init__(self, width, height, dpi): - if __debug__: verbose.report('RendererAgg.__init__', 'debug-annoying') RendererBase.__init__(self) self.dpi = dpi self.width = width self.height = height - if __debug__: verbose.report('RendererAgg.__init__ width=%s, height=%s'%(width, height), 'debug-annoying') self._renderer = _RendererAgg(int(width), int(height), dpi, debug=False) self._filter_renderers = [] - if __debug__: verbose.report('RendererAgg.__init__ _RendererAgg done', - 'debug-annoying') - self._update_methods() self.mathtext_parser = MathTextParser('Agg') self.bbox = Bbox.from_bounds(0, 0, self.width, self.height) - if __debug__: verbose.report('RendererAgg.__init__ done', - 'debug-annoying') def __getstate__(self): # We only want to preserve the init keywords of the Renderer. @@ -178,8 +171,6 @@ def draw_mathtext(self, gc, x, y, s, prop, angle): """ Draw the math text using matplotlib.mathtext """ - if __debug__: verbose.report('RendererAgg.draw_mathtext', - 'debug-annoying') ox, oy, width, height, descent, font_image, used_characters = \ self.mathtext_parser.parse(s, self.dpi, prop) @@ -193,8 +184,6 @@ def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None): """ Render the text """ - if __debug__: verbose.report('RendererAgg.draw_text', 'debug-annoying') - if ismath: return self.draw_mathtext(gc, x, y, s, prop, angle) @@ -279,9 +268,6 @@ def _get_agg_font(self, prop): """ Get the font for text instance t, cacheing for efficiency """ - if __debug__: verbose.report('RendererAgg._get_agg_font', - 'debug-annoying') - fname = findfont(prop) font = get_font( fname, @@ -298,23 +284,15 @@ def points_to_pixels(self, points): convert point measures to pixes using dpi and the pixels per inch of the display """ - if __debug__: verbose.report('RendererAgg.points_to_pixels', - 'debug-annoying') return points*self.dpi/72.0 def tostring_rgb(self): - if __debug__: verbose.report('RendererAgg.tostring_rgb', - 'debug-annoying') return self._renderer.tostring_rgb() def tostring_argb(self): - if __debug__: verbose.report('RendererAgg.tostring_argb', - 'debug-annoying') return self._renderer.tostring_argb() def buffer_rgba(self): - if __debug__: verbose.report('RendererAgg.buffer_rgba', - 'debug-annoying') return self._renderer.buffer_rgba() def clear(self): @@ -423,10 +401,6 @@ def new_figure_manager(num, *args, **kwargs): """ Create a new figure manager instance """ - if __debug__: verbose.report('backend_agg.new_figure_manager', - 'debug-annoying') - - FigureClass = kwargs.pop('FigureClass', Figure) thisFig = FigureClass(*args, **kwargs) return new_figure_manager_given_figure(num, thisFig) @@ -465,8 +439,6 @@ def draw(self): """ Draw the figure using the renderer """ - if __debug__: verbose.report('FigureCanvasAgg.draw', 'debug-annoying') - self.renderer = self.get_renderer(cleared=True) # acquire a lock on the shared font cache RendererAgg.lock.acquire() @@ -500,8 +472,6 @@ def tostring_rgb(self): ------- bytes ''' - if __debug__: verbose.report('FigureCanvasAgg.tostring_rgb', - 'debug-annoying') return self.renderer.tostring_rgb() def tostring_argb(self): @@ -515,8 +485,6 @@ def tostring_argb(self): bytes ''' - if __debug__: verbose.report('FigureCanvasAgg.tostring_argb', - 'debug-annoying') return self.renderer.tostring_argb() def buffer_rgba(self): @@ -529,8 +497,6 @@ def buffer_rgba(self): ------- bytes ''' - if __debug__: verbose.report('FigureCanvasAgg.buffer_rgba', - 'debug-annoying') return self.renderer.buffer_rgba() def print_raw(self, filename_or_obj, *args, **kwargs): diff --git a/lib/matplotlib/backends/backend_cairo.py b/lib/matplotlib/backends/backend_cairo.py index 7396452fa0e3..c41c74711214 100644 --- a/lib/matplotlib/backends/backend_cairo.py +++ b/lib/matplotlib/backends/backend_cairo.py @@ -27,8 +27,6 @@ import numpy as np -def _fn_name(): return sys._getframe(1).f_code.co_name - try: import cairocffi as cairo except ImportError: @@ -58,9 +56,6 @@ def _fn_name(): return sys._getframe(1).f_code.co_name from matplotlib.transforms import Bbox, Affine2D from matplotlib.font_manager import ttfFontProperty -_debug = False -#_debug = True - # Image::color_conv(format) for draw_image() if sys.byteorder == 'little': BYTE_FORMAT = 0 # BGRA @@ -114,7 +109,6 @@ class RendererCairo(RendererBase): def __init__(self, dpi): """ """ - if _debug: print('%s.%s()' % (self.__class__.__name__, _fn_name())) self.dpi = dpi self.gc = GraphicsContextCairo (renderer=self) self.text_ctx = cairo.Context ( @@ -227,8 +221,6 @@ def draw_markers(self, gc, marker_path, marker_trans, path, transform, rgbFace=N def draw_image(self, gc, x, y, im): # bbox - not currently used - if _debug: print('%s.%s()' % (self.__class__.__name__, _fn_name())) - if sys.byteorder == 'little': im = im[:, :, (2, 1, 0, 3)] else: @@ -266,8 +258,6 @@ def draw_image(self, gc, x, y, im): def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None): # Note: x,y are device/display coords, not user-coords, unlike other # draw_* methods - if _debug: print('%s.%s()' % (self.__class__.__name__, _fn_name())) - if ismath: self._draw_mathtext(gc, x, y, s, prop, angle) @@ -297,8 +287,6 @@ def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None): ctx.restore() def _draw_mathtext(self, gc, x, y, s, prop, angle): - if _debug: print('%s.%s()' % (self.__class__.__name__, _fn_name())) - ctx = gc.ctx width, height, descent, glyphs, rects = self.mathtext_parser.parse( s, self.dpi, prop) @@ -335,19 +323,16 @@ def _draw_mathtext(self, gc, x, y, s, prop, angle): def flipy(self): - if _debug: print('%s.%s()' % (self.__class__.__name__, _fn_name())) return True #return False # tried - all draw objects ok except text (and images?) # which comes out mirrored! def get_canvas_width_height(self): - if _debug: print('%s.%s()' % (self.__class__.__name__, _fn_name())) return self.width, self.height def get_text_width_height_descent(self, s, prop, ismath): - if _debug: print('%s.%s()' % (self.__class__.__name__, _fn_name())) if ismath: width, height, descent, fonts, used_characters = self.mathtext_parser.parse( s, self.dpi, prop) @@ -376,7 +361,6 @@ def get_text_width_height_descent(self, s, prop, ismath): def new_gc(self): - if _debug: print('%s.%s()' % (self.__class__.__name__, _fn_name())) self.gc.ctx.save() self.gc._alpha = 1.0 self.gc._forced_alpha = False # if True, _alpha overrides A from RGBA @@ -384,7 +368,6 @@ def new_gc(self): def points_to_pixels(self, points): - if _debug: print('%s.%s()' % (self.__class__.__name__, _fn_name())) return points/72.0 * self.dpi @@ -488,7 +471,6 @@ def new_figure_manager(num, *args, **kwargs): # called by backends/__init__.py """ Create a new figure manager instance """ - if _debug: print('%s()' % (_fn_name())) FigureClass = kwargs.pop('FigureClass', Figure) thisFig = FigureClass(*args, **kwargs) return new_figure_manager_given_figure(num, thisFig) diff --git a/lib/matplotlib/backends/backend_gdk.py b/lib/matplotlib/backends/backend_gdk.py index 36583cf44402..8e9d424a8075 100644 --- a/lib/matplotlib/backends/backend_gdk.py +++ b/lib/matplotlib/backends/backend_gdk.py @@ -7,7 +7,6 @@ import os import sys import warnings -def fn_name(): return sys._getframe(1).f_code.co_name import gobject import gtk; gdk = gtk.gdk @@ -24,8 +23,8 @@ def fn_name(): return sys._getframe(1).f_code.co_name import matplotlib from matplotlib import rcParams from matplotlib._pylab_helpers import Gcf -from matplotlib.backend_bases import RendererBase, GraphicsContextBase, \ - FigureManagerBase, FigureCanvasBase +from matplotlib.backend_bases import ( + RendererBase, GraphicsContextBase, FigureManagerBase, FigureCanvasBase) from matplotlib.cbook import restrict_dict, warn_deprecated from matplotlib.figure import Figure from matplotlib.mathtext import MathTextParser @@ -33,7 +32,6 @@ def fn_name(): return sys._getframe(1).f_code.co_name from matplotlib.backends._backend_gdk import pixbuf_get_pixels_array backend_version = "%d.%d.%d" % gtk.pygtk_version -_debug = False # Image formats that this backend supports - for FileChooser and print_figure() IMAGE_FORMAT = sorted(['bmp', 'eps', 'jpg', 'png', 'ps', 'svg']) # 'raw', 'rgb' diff --git a/lib/matplotlib/backends/backend_gtk.py b/lib/matplotlib/backends/backend_gtk.py index f9a2fa47edd0..a5dec05faeaa 100644 --- a/lib/matplotlib/backends/backend_gtk.py +++ b/lib/matplotlib/backends/backend_gtk.py @@ -4,7 +4,6 @@ import six import os, sys, warnings -def fn_name(): return sys._getframe(1).f_code.co_name if six.PY3: warnings.warn( @@ -44,9 +43,6 @@ def fn_name(): return sys._getframe(1).f_code.co_name backend_version = "%d.%d.%d" % gtk.pygtk_version -_debug = False -#_debug = True - # the true dots per inch on the screen; should be display dependent # see http://groups.google.com/groups?q=screen+dpi+x11&hl=en&lr=&ie=UTF-8&oe=UTF-8&safe=off&selm=7077.26e81ad5%40swift.cs.tcd.ie&rnum=5 for some info about screen dpi PIXELS_PER_INCH = 96 @@ -225,7 +221,6 @@ def __init__(self, figure): "See Matplotlib usage FAQ for" " more info on backends.", alternative="GTKAgg") - if _debug: print('FigureCanvasGTK.%s' % fn_name()) FigureCanvasBase.__init__(self, figure) gtk.DrawingArea.__init__(self) @@ -261,7 +256,6 @@ def destroy(self): gobject.source_remove(self._idle_draw_id) def scroll_event(self, widget, event): - if _debug: print('FigureCanvasGTK.%s' % fn_name()) x = event.x # flipy so y=0 is bottom of canvas y = self.allocation.height - event.y @@ -273,7 +267,6 @@ def scroll_event(self, widget, event): return False # finish event propagation? def button_press_event(self, widget, event): - if _debug: print('FigureCanvasGTK.%s' % fn_name()) x = event.x # flipy so y=0 is bottom of canvas y = self.allocation.height - event.y @@ -297,7 +290,6 @@ def button_press_event(self, widget, event): return False # finish event propagation? def button_release_event(self, widget, event): - if _debug: print('FigureCanvasGTK.%s' % fn_name()) x = event.x # flipy so y=0 is bottom of canvas y = self.allocation.height - event.y @@ -305,21 +297,16 @@ def button_release_event(self, widget, event): return False # finish event propagation? def key_press_event(self, widget, event): - if _debug: print('FigureCanvasGTK.%s' % fn_name()) key = self._get_key(event) - if _debug: print("hit", key) FigureCanvasBase.key_press_event(self, key, guiEvent=event) return True # stop event propagation def key_release_event(self, widget, event): - if _debug: print('FigureCanvasGTK.%s' % fn_name()) key = self._get_key(event) - if _debug: print("release", key) FigureCanvasBase.key_release_event(self, key, guiEvent=event) return True # stop event propagation def motion_notify_event(self, widget, event): - if _debug: print('FigureCanvasGTK.%s' % fn_name()) if event.is_hint: x, y, state = event.window.get_pointer() else: @@ -355,7 +342,6 @@ def _get_key(self, event): return key def configure_event(self, widget, event): - if _debug: print('FigureCanvasGTK.%s' % fn_name()) if widget.window is None: return w, h = event.width, event.height @@ -408,8 +394,6 @@ def _pixmap_prepare(self, width, height): Make sure _._pixmap is at least width, height, create new pixmap if necessary """ - if _debug: print('FigureCanvasGTK.%s' % fn_name()) - create_pixmap = False if width > self._pixmap_width: # increase the pixmap in 10%+ (rather than 1 pixel) steps @@ -438,8 +422,6 @@ def _render_figure(self, pixmap, width, height): def expose_event(self, widget, event): """Expose_event for all GTK backends. Should not be overridden. """ - if _debug: print('FigureCanvasGTK.%s' % fn_name()) - if GTK_WIDGET_DRAWABLE(self): if self._need_redraw: x, y, w, h = self.allocation @@ -556,7 +538,6 @@ class FigureManagerGTK(FigureManagerBase): """ def __init__(self, canvas, num): - if _debug: print('FigureManagerGTK.%s' % fn_name()) FigureManagerBase.__init__(self, canvas, num) self.window = gtk.Window() @@ -610,7 +591,6 @@ def notify_axes_change(fig): self.canvas.grab_focus() def destroy(self, *args): - if _debug: print('FigureManagerGTK.%s' % fn_name()) if hasattr(self, 'toolbar') and self.toolbar is not None: self.toolbar.destroy() if hasattr(self, 'vbox'): diff --git a/lib/matplotlib/backends/backend_gtk3.py b/lib/matplotlib/backends/backend_gtk3.py index 6a1f74a30c65..c084f6d6dccc 100644 --- a/lib/matplotlib/backends/backend_gtk3.py +++ b/lib/matplotlib/backends/backend_gtk3.py @@ -4,7 +4,6 @@ import six import os, sys -def fn_name(): return sys._getframe(1).f_code.co_name try: import gi @@ -28,23 +27,21 @@ def fn_name(): return sys._getframe(1).f_code.co_name import matplotlib from matplotlib._pylab_helpers import Gcf -from matplotlib.backend_bases import RendererBase, GraphicsContextBase, \ - FigureManagerBase, FigureCanvasBase, NavigationToolbar2, cursors, TimerBase -from matplotlib.backend_bases import (ShowBase, ToolContainerBase, - StatusbarBase) +from matplotlib.backend_bases import ( + FigureCanvasBase, FigureManagerBase, GraphicsContextBase, + NavigationToolbar2, RendererBase, TimerBase, cursors) +from matplotlib.backend_bases import ( + ShowBase, ToolContainerBase, StatusbarBase) from matplotlib.backend_managers import ToolManager -from matplotlib import backend_tools - from matplotlib.cbook import is_writable_file_like from matplotlib.figure import Figure from matplotlib.widgets import SubplotTool -from matplotlib import cbook, colors as mcolors, lines, verbose, rcParams - -backend_version = "%s.%s.%s" % (Gtk.get_major_version(), Gtk.get_micro_version(), Gtk.get_minor_version()) +from matplotlib import ( + backend_tools, cbook, colors as mcolors, lines, verbose, rcParams) -_debug = False -#_debug = True +backend_version = "%s.%s.%s" % ( + Gtk.get_major_version(), Gtk.get_micro_version(), Gtk.get_minor_version()) # the true dots per inch on the screen; should be display dependent # see http://groups.google.com/groups?q=screen+dpi+x11&hl=en&lr=&ie=UTF-8&oe=UTF-8&safe=off&selm=7077.26e81ad5%40swift.cs.tcd.ie&rnum=5 for some info about screen dpi @@ -119,7 +116,7 @@ def _on_timer(self): self._timer = None return False -class FigureCanvasGTK3 (Gtk.DrawingArea, FigureCanvasBase): +class FigureCanvasGTK3(Gtk.DrawingArea, FigureCanvasBase): keyvald = {65507 : 'control', 65505 : 'shift', 65513 : 'alt', @@ -185,7 +182,6 @@ class FigureCanvasGTK3 (Gtk.DrawingArea, FigureCanvasBase): Gdk.EventMask.SCROLL_MASK) def __init__(self, figure): - if _debug: print('FigureCanvasGTK3.%s' % fn_name()) FigureCanvasBase.__init__(self, figure) GObject.GObject.__init__(self) @@ -219,7 +215,6 @@ def destroy(self): GLib.source_remove(self._idle_draw_id) def scroll_event(self, widget, event): - if _debug: print('FigureCanvasGTK3.%s' % fn_name()) x = event.x # flipy so y=0 is bottom of canvas y = self.get_allocation().height - event.y @@ -231,7 +226,6 @@ def scroll_event(self, widget, event): return False # finish event propagation? def button_press_event(self, widget, event): - if _debug: print('FigureCanvasGTK3.%s' % fn_name()) x = event.x # flipy so y=0 is bottom of canvas y = self.get_allocation().height - event.y @@ -239,7 +233,6 @@ def button_press_event(self, widget, event): return False # finish event propagation? def button_release_event(self, widget, event): - if _debug: print('FigureCanvasGTK3.%s' % fn_name()) x = event.x # flipy so y=0 is bottom of canvas y = self.get_allocation().height - event.y @@ -247,21 +240,16 @@ def button_release_event(self, widget, event): return False # finish event propagation? def key_press_event(self, widget, event): - if _debug: print('FigureCanvasGTK3.%s' % fn_name()) key = self._get_key(event) - if _debug: print("hit", key) FigureCanvasBase.key_press_event(self, key, guiEvent=event) return True # stop event propagation def key_release_event(self, widget, event): - if _debug: print('FigureCanvasGTK3.%s' % fn_name()) key = self._get_key(event) - if _debug: print("release", key) FigureCanvasBase.key_release_event(self, key, guiEvent=event) return True # stop event propagation def motion_notify_event(self, widget, event): - if _debug: print('FigureCanvasGTK3.%s' % fn_name()) if event.is_hint: t, x, y, state = event.window.get_pointer() else: @@ -279,9 +267,6 @@ def enter_notify_event(self, widget, event): FigureCanvasBase.enter_notify_event(self, event) def size_allocate(self, widget, allocation): - if _debug: - print("FigureCanvasGTK3.%s" % fn_name()) - print("size_allocate (%d x %d)" % (allocation.width, allocation.height)) dpival = self.figure.dpi winch = allocation.width / dpival hinch = allocation.height / dpival @@ -309,7 +294,6 @@ def _get_key(self, event): return key def configure_event(self, widget, event): - if _debug: print('FigureCanvasGTK3.%s' % fn_name()) if widget.get_property("window") is None: return w, h = event.width, event.height @@ -395,7 +379,6 @@ class FigureManagerGTK3(FigureManagerBase): """ def __init__(self, canvas, num): - if _debug: print('FigureManagerGTK3.%s' % fn_name()) FigureManagerBase.__init__(self, canvas, num) self.window = Gtk.Window() @@ -468,16 +451,15 @@ def notify_axes_change(fig): self.canvas.grab_focus() def destroy(self, *args): - if _debug: print('FigureManagerGTK3.%s' % fn_name()) self.vbox.destroy() self.window.destroy() self.canvas.destroy() if self.toolbar: self.toolbar.destroy() - if Gcf.get_num_fig_managers()==0 and \ - not matplotlib.is_interactive() and \ - Gtk.main_level() >= 1: + if (Gcf.get_num_fig_managers() == 0 and + not matplotlib.is_interactive() and + Gtk.main_level() >= 1): Gtk.main_quit() def show(self): @@ -497,7 +479,7 @@ def _get_toolbar(self): # must be inited after the window, drawingArea and figure # attrs are set if rcParams['toolbar'] == 'toolbar2': - toolbar = NavigationToolbar2GTK3 (self.canvas, self.window) + toolbar = NavigationToolbar2GTK3(self.canvas, self.window) elif rcParams['toolbar'] == 'toolmanager': toolbar = ToolbarGTK3(self.toolmanager) else: @@ -941,7 +923,8 @@ def trigger(self, sender, event, data=None): icon_filename = 'matplotlib.png' else: icon_filename = 'matplotlib.svg' -window_icon = os.path.join(matplotlib.rcParams['datapath'], 'images', icon_filename) +window_icon = os.path.join( + matplotlib.rcParams['datapath'], 'images', icon_filename) def error_msg_gtk(msg, parent=None): @@ -951,7 +934,7 @@ def error_msg_gtk(msg, parent=None): parent = None if not isinstance(msg, six.string_types): - msg = ','.join(map(str,msg)) + msg = ','.join(map(str, msg)) dialog = Gtk.MessageDialog( parent = parent, diff --git a/lib/matplotlib/backends/backend_gtkcairo.py b/lib/matplotlib/backends/backend_gtkcairo.py index 93bb69857a1f..1440b85044a9 100644 --- a/lib/matplotlib/backends/backend_gtkcairo.py +++ b/lib/matplotlib/backends/backend_gtkcairo.py @@ -8,25 +8,20 @@ import six import gtk -if gtk.pygtk_version < (2,7,0): +if gtk.pygtk_version < (2, 7, 0): import cairo.gtk from matplotlib.backends import backend_cairo from matplotlib.backends.backend_gtk import * -backend_version = 'PyGTK(%d.%d.%d) ' % gtk.pygtk_version + \ - 'Pycairo(%s)' % backend_cairo.backend_version - - -_debug = False -#_debug = True +backend_version = ('PyGTK(%d.%d.%d) ' % gtk.pygtk_version + + 'Pycairo(%s)' % backend_cairo.backend_version) def new_figure_manager(num, *args, **kwargs): """ Create a new figure manager instance """ - if _debug: print('backend_gtkcairo.%s()' % fn_name()) FigureClass = kwargs.pop('FigureClass', Figure) thisFig = FigureClass(*args, **kwargs) return new_figure_manager_given_figure(num, thisFig) @@ -55,8 +50,7 @@ class FigureCanvasGTKCairo(backend_cairo.FigureCanvasCairo, FigureCanvasGTK): def _renderer_init(self): """Override to use cairo (rather than GDK) renderer""" - if _debug: print('%s.%s()' % (self.__class__.__name__, _fn_name())) - self._renderer = RendererGTKCairo (self.figure.dpi) + self._renderer = RendererGTKCairo(self.figure.dpi) class FigureManagerGTKCairo(FigureManagerGTK): diff --git a/lib/matplotlib/backends/backend_ps.py b/lib/matplotlib/backends/backend_ps.py index ffad5187c9c2..0e4e2011841c 100644 --- a/lib/matplotlib/backends/backend_ps.py +++ b/lib/matplotlib/backends/backend_ps.py @@ -9,7 +9,6 @@ from six.moves import StringIO import glob, os, shutil, sys, time, datetime -def _fn_name(): return sys._getframe(1).f_code.co_name import io from tempfile import mkstemp diff --git a/lib/matplotlib/backends/backend_qt4.py b/lib/matplotlib/backends/backend_qt4.py index a10dd19a1788..c90a36c2a648 100644 --- a/lib/matplotlib/backends/backend_qt4.py +++ b/lib/matplotlib/backends/backend_qt4.py @@ -25,12 +25,11 @@ from .qt_compat import QtCore, QtWidgets, _getSaveFileName, __version__ -from .backend_qt5 import (backend_version, SPECIAL_KEYS, SUPER, ALT, CTRL, - SHIFT, MODIFIER_KEYS, fn_name, cursord, - draw_if_interactive, _create_qApp, show, TimerQT, - MainWindow, FigureManagerQT, NavigationToolbar2QT, - SubplotToolQt, error_msg_qt, exception_handler) - +from .backend_qt5 import ( + backend_version, SPECIAL_KEYS, SUPER, ALT, CTRL, SHIFT, MODIFIER_KEYS, + cursord, draw_if_interactive, _create_qApp, show, TimerQT, MainWindow, + FigureManagerQT, NavigationToolbar2QT, SubplotToolQt, error_msg_qt, + exception_handler) from .backend_qt5 import FigureCanvasQT as FigureCanvasQT5 DEBUG = False diff --git a/lib/matplotlib/backends/backend_qt5.py b/lib/matplotlib/backends/backend_qt5.py index 9c3518ffc9e7..291c0caab68f 100644 --- a/lib/matplotlib/backends/backend_qt5.py +++ b/lib/matplotlib/backends/backend_qt5.py @@ -90,11 +90,6 @@ QtCore.Qt.Key_Meta) -def fn_name(): - return sys._getframe(1).f_code.co_name - -DEBUG = False - cursord = { cursors.MOVE: QtCore.Qt.SizeAllCursor, cursors.HAND: QtCore.Qt.PointingHandCursor, @@ -123,8 +118,6 @@ def _create_qApp(): global qApp if qApp is None: - if DEBUG: - print("Starting up QApplication") app = QtWidgets.QApplication.instance() if app is None: # check for DISPLAY env variable on X11 build of Qt @@ -233,8 +226,6 @@ class FigureCanvasQT(QtWidgets.QWidget, FigureCanvasBase): } def __init__(self, figure): - if DEBUG: - print('FigureCanvasQt qt5: ', figure) _create_qApp() # NB: Using super for this call to avoid a TypeError: @@ -292,8 +283,6 @@ def mousePressEvent(self, event): if button is not None: FigureCanvasBase.button_press_event(self, x, y, button, guiEvent=event) - if DEBUG: - print('button pressed:', event.button()) def mouseDoubleClickEvent(self, event): x, y = self.mouseEventCoords(event.pos()) @@ -302,13 +291,10 @@ def mouseDoubleClickEvent(self, event): FigureCanvasBase.button_press_event(self, x, y, button, dblclick=True, guiEvent=event) - if DEBUG: - print('button doubleclicked:', event.button()) def mouseMoveEvent(self, event): x, y = self.mouseEventCoords(event) FigureCanvasBase.motion_notify_event(self, x, y, guiEvent=event) - # if DEBUG: print('mouse move') def mouseReleaseEvent(self, event): x, y = self.mouseEventCoords(event) @@ -316,8 +302,6 @@ def mouseReleaseEvent(self, event): if button is not None: FigureCanvasBase.button_release_event(self, x, y, button, guiEvent=event) - if DEBUG: - print('button released') def wheelEvent(self, event): x, y = self.mouseEventCoords(event) @@ -326,28 +310,18 @@ def wheelEvent(self, event): steps = event.angleDelta().y() / 120 else: steps = event.pixelDelta().y() - - if steps != 0: + if steps: FigureCanvasBase.scroll_event(self, x, y, steps, guiEvent=event) - if DEBUG: - print('scroll event: delta = %i, ' - 'steps = %i ' % (event.delta(), steps)) def keyPressEvent(self, event): key = self._get_key(event) - if key is None: - return - FigureCanvasBase.key_press_event(self, key, guiEvent=event) - if DEBUG: - print('key press', key) + if key is not None: + FigureCanvasBase.key_press_event(self, key, guiEvent=event) def keyReleaseEvent(self, event): key = self._get_key(event) - if key is None: - return - FigureCanvasBase.key_release_event(self, key, guiEvent=event) - if DEBUG: - print('key release', key) + if key is not None: + FigureCanvasBase.key_release_event(self, key, guiEvent=event) @property def keyAutoRepeat(self): @@ -363,9 +337,6 @@ def keyAutoRepeat(self, val): def resizeEvent(self, event): w = event.size().width() * self._dpi_ratio h = event.size().height() * self._dpi_ratio - if DEBUG: - print('resize (%d x %d)' % (w, h)) - print("FigureCanvasQt.resizeEvent(%d, %d)" % (w, h)) dpival = self.figure.dpi winch = w / dpival hinch = h / dpival @@ -478,8 +449,6 @@ class FigureManagerQT(FigureManagerBase): """ def __init__(self, canvas, num): - if DEBUG: - print('FigureManagerQT.%s' % fn_name()) FigureManagerBase.__init__(self, canvas, num) self.canvas = canvas self.window = MainWindow() @@ -578,11 +547,8 @@ def destroy(self, *args): return self.window._destroying = True self.window.destroyed.connect(self._widgetclosed) - if self.toolbar: self.toolbar.destroy() - if DEBUG: - print("destroy figure manager") self.window.close() def get_window_title(self): @@ -712,8 +678,6 @@ def set_message(self, s): self.locLabel.setText(s) def set_cursor(self, cursor): - if DEBUG: - print('Set cursor', cursor) self.canvas.setCursor(cursord[cursor]) def draw_rubberband(self, event, x0, y0, x1, y1): @@ -724,7 +688,7 @@ def draw_rubberband(self, event, x0, y0, x1, y1): w = abs(x1 - x0) h = abs(y1 - y0) - rect = [int(val)for val in (min(x0, x1), min(y0, y1), w, h)] + rect = [int(val) for val in (min(x0, x1), min(y0, y1), w, h)] self.canvas.drawRectangle(rect) def remove_rubberband(self): diff --git a/lib/matplotlib/backends/backend_tkagg.py b/lib/matplotlib/backends/backend_tkagg.py index af0ed62f9d81..371126d3d660 100644 --- a/lib/matplotlib/backends/backend_tkagg.py +++ b/lib/matplotlib/backends/backend_tkagg.py @@ -719,7 +719,6 @@ def __init__(self, canvas, window): self.canvas = canvas self.window = window self._idle = True - #Tk.Frame.__init__(self, master=self.canvas._tkcanvas) NavigationToolbar2.__init__(self, canvas) def destroy(self, *args): @@ -731,11 +730,10 @@ def set_message(self, s): def draw_rubberband(self, event, x0, y0, x1, y1): height = self.canvas.figure.bbox.height - y0 = height-y0 - y1 = height-y1 - try: self.lastrect - except AttributeError: pass - else: self.canvas._tkcanvas.delete(self.lastrect) + y0 = height - y0 + y1 = height - y1 + if hasattr(self, "lastrect"): + self.canvas._tkcanvas.delete(self.lastrect) self.lastrect = self.canvas._tkcanvas.create_rectangle(x0, y0, x1, y1) #self.canvas.draw() @@ -751,7 +749,8 @@ def set_cursor(self, cursor): self.window.configure(cursor=cursord[cursor]) def _Button(self, text, file, command, extension='.gif'): - img_file = os.path.join(rcParams['datapath'], 'images', file + extension) + img_file = os.path.join( + rcParams['datapath'], 'images', file + extension) im = Tk.PhotoImage(master=self, file=img_file) b = Tk.Button( master=self, text=text, padx=2, pady=2, image=im, command=command) @@ -761,10 +760,11 @@ def _Button(self, text, file, command, extension='.gif'): def _Spacer(self): # Buttons are 30px high, so make this 26px tall with padding to center it - s = Tk.Frame(master=self, height=26, relief=Tk.RIDGE, pady=2, bg="DarkGray") + s = Tk.Frame( + master=self, height=26, relief=Tk.RIDGE, pady=2, bg="DarkGray") s.pack(side=Tk.LEFT, padx=5) return s - + def _init_toolbar(self): xmin, xmax = self.canvas.figure.bbox.intervalx height, width = 50, xmax-xmin @@ -776,11 +776,11 @@ def _init_toolbar(self): for text, tooltip_text, image_file, callback in self.toolitems: if text is None: - # Add a spacer -- we don't need to use the return value for anything + # Add a spacer; return value is unused. self._Spacer() else: button = self._Button(text=text, file=image_file, - command=getattr(self, callback)) + command=getattr(self, callback)) if tooltip_text is not None: ToolTip.createToolTip(button, tooltip_text) @@ -789,7 +789,6 @@ def _init_toolbar(self): self._message_label.pack(side=Tk.RIGHT) self.pack(side=Tk.BOTTOM, fill=Tk.X) - def configure_subplots(self): toolfig = Figure(figsize=(6,3)) window = Tk.Tk() @@ -846,17 +845,11 @@ def save_figure(self, *args): def set_active(self, ind): self._ind = ind - self._active = [ self._axes[i] for i in self._ind ] + self._active = [self._axes[i] for i in self._ind] def update(self): _focus = windowing.FocusManager() self._axes = self.canvas.figure.axes - naxes = len(self._axes) - #if not hasattr(self, "omenu"): - # self.set_active(range(naxes)) - # self.omenu = AxisMenu(master=self, naxes=naxes) - #else: - # self.omenu.adjust(naxes) NavigationToolbar2.update(self) @@ -900,8 +893,7 @@ def showtip(self, text): except Tk.TclError: pass label = Tk.Label(tw, text=self.text, justify=Tk.LEFT, - background="#ffffe0", relief=Tk.SOLID, borderwidth=1, - ) + background="#ffffe0", relief=Tk.SOLID, borderwidth=1) label.pack(ipadx=1) def hidetip(self): @@ -919,20 +911,13 @@ def draw_rubberband(self, x0, y0, x1, y1): height = self.figure.canvas.figure.bbox.height y0 = height - y0 y1 = height - y1 - try: - self.lastrect - except AttributeError: - pass - else: + if hasattr(self, "lastrect"): self.figure.canvas._tkcanvas.delete(self.lastrect) - self.lastrect = self.figure.canvas._tkcanvas.create_rectangle(x0, y0, x1, y1) + self.lastrect = self.figure.canvas._tkcanvas.create_rectangle( + x0, y0, x1, y1) def remove_rubberband(self): - try: - self.lastrect - except AttributeError: - pass - else: + if hasattr(self, "lastrect"): self.figure.canvas._tkcanvas.delete(self.lastrect) del self.lastrect @@ -954,8 +939,8 @@ def __init__(self, toolmanager, window): self.pack(side=Tk.TOP, fill=Tk.X) self._groups = {} - def add_toolitem(self, name, group, position, image_file, description, - toggle): + def add_toolitem( + self, name, group, position, image_file, description, toggle): frame = self._get_groupframe(group) button = self._Button(name, image_file, toggle, frame) if description is not None: From 40fa293876813f7700b697d7685f68cf58cf30e6 Mon Sep 17 00:00:00 2001 From: Elliott Sales de Andrade Date: Thu, 1 Jun 2017 21:10:28 -0400 Subject: [PATCH 05/27] Update FreeType version in test_tightlayout4. 2.5.5 is what's in my conda env, and 2.6.1 is what's built with the local_freetype option and is used on Travis and AppVeyor without issue. --- lib/matplotlib/tests/test_tightlayout.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/matplotlib/tests/test_tightlayout.py b/lib/matplotlib/tests/test_tightlayout.py index 76d9c1424212..03ac60a3e0d0 100644 --- a/lib/matplotlib/tests/test_tightlayout.py +++ b/lib/matplotlib/tests/test_tightlayout.py @@ -58,7 +58,7 @@ def test_tight_layout3(): @image_comparison(baseline_images=['tight_layout4'], - freetype_version=('2.4.5', '2.4.9')) + freetype_version=('2.5.5', '2.6.1')) def test_tight_layout4(): 'Test tight_layout for subplot2grid' From c0ecc7d31f0d2b826e0babbe2df02364bf968752 Mon Sep 17 00:00:00 2001 From: Elliott Sales de Andrade Date: Fri, 2 Jun 2017 22:44:03 -0400 Subject: [PATCH 06/27] Add a unique number to any renderer hash keys. The result of id() is only guaranteed to be unique for objects that exist at the same time. This global integer is a quick and light way to ensure that new renderers that match an old one don't produce the same caching key. --- .../2017-06-03-ES_unique_renderer.rst | 11 ++++++++++ lib/matplotlib/backend_bases.py | 20 +++++++++++++++++++ lib/matplotlib/backends/backend_mixed.py | 13 ++++++++++++ lib/matplotlib/text.py | 3 ++- 4 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 doc/api/api_changes/2017-06-03-ES_unique_renderer.rst diff --git a/doc/api/api_changes/2017-06-03-ES_unique_renderer.rst b/doc/api/api_changes/2017-06-03-ES_unique_renderer.rst new file mode 100644 index 000000000000..3dd58e0a16f3 --- /dev/null +++ b/doc/api/api_changes/2017-06-03-ES_unique_renderer.rst @@ -0,0 +1,11 @@ +Unique identifier added to `RendererBase` classes +````````````````````````````````````````````````` + +Since ``id()`` is not guaranteed to be unique between objects that exist at +different times, a new private property ``_uid`` has been added to +`RendererBase` which is used along with the renderer's ``id()`` to cache +certain expensive operations. + +If a custom renderer does not subclass `RendererBase` or `MixedModeRenderer`, +it is not required to implement this ``_uid`` property, but this may produce +incorrect behavior when the renderers' ``id()`` clashes. diff --git a/lib/matplotlib/backend_bases.py b/lib/matplotlib/backend_bases.py index 3cd6e34c73c1..f5a33c7bb610 100644 --- a/lib/matplotlib/backend_bases.py +++ b/lib/matplotlib/backend_bases.py @@ -100,6 +100,11 @@ } +# Used to ensure that caching based on renderer id() is unique without being as +# expensive as a real UUID. +_unique_renderer_id = 0 + + def register_backend(format, backend, description=None): """ Register a backend for saving to a given file format. @@ -212,10 +217,25 @@ class RendererBase(object): """ def __init__(self): + self._id = None self._texmanager = None self._text2path = textpath.TextToPath() + @property + def _uid(self): + """ + A lightweight id for unique-ification purposes. + + Along with id(self), this combination should be unique enough to use as + part of a caching key. + """ + if self._id is None: + global _unique_renderer_id + _unique_renderer_id += 1 + self._id = _unique_renderer_id + return self._id + def open_group(self, s, gid=None): """ Open a grouping element with label *s*. If *gid* is given, use diff --git a/lib/matplotlib/backends/backend_mixed.py b/lib/matplotlib/backends/backend_mixed.py index 40d7fd64398c..3bd7a8c7d647 100644 --- a/lib/matplotlib/backends/backend_mixed.py +++ b/lib/matplotlib/backends/backend_mixed.py @@ -49,6 +49,7 @@ def __init__(self, figure, width, height, dpi, vector_renderer, if raster_renderer_class is None: raster_renderer_class = RendererAgg + self._id = None self._raster_renderer_class = raster_renderer_class self._width = width self._height = height @@ -80,6 +81,18 @@ def __init__(self, figure, width, height, dpi, vector_renderer, _text2path _get_text_path_transform height width """.split() + @property + def _uid(self): + """ + See matplotlib.backend_bases.RendererBase._uid. + """ + if self._id is None: + from matplotlib import backend_bases + backend_bases._unique_renderer_id + backend_bases._unique_renderer_id += 1 + self._id = backend_bases._unique_renderer_id + return self._id + def _set_current_renderer(self, renderer): self._renderer = renderer diff --git a/lib/matplotlib/text.py b/lib/matplotlib/text.py index b11ae28ba0cc..caa5dcdaf73f 100644 --- a/lib/matplotlib/text.py +++ b/lib/matplotlib/text.py @@ -907,11 +907,12 @@ def get_prop_tup(self, renderer=None): need to know if the text has changed. """ x, y = self.get_unitless_position() + renderer = renderer or self._renderer return (x, y, self.get_text(), self._color, self._verticalalignment, self._horizontalalignment, hash(self._fontproperties), self._rotation, self._rotation_mode, - self.figure.dpi, id(renderer or self._renderer), + self.figure.dpi, id(renderer), getattr(renderer, '_uid', 0), self._linespacing ) From df672dfbaf10aa88b8ab9d0423c93da86583c86c Mon Sep 17 00:00:00 2001 From: Elliott Sales de Andrade Date: Sat, 3 Jun 2017 02:23:46 -0400 Subject: [PATCH 07/27] Update tests that are marked flaky. The Mathtext tests should no longer be flaky based on the previous change. Mark some PS tests as flaky because they require a lock that sometimes gets stuck on AppVeyor due to the multiple processes. --- lib/matplotlib/tests/test_backend_pdf.py | 2 ++ lib/matplotlib/tests/test_backend_ps.py | 2 ++ lib/matplotlib/tests/test_mathtext.py | 6 ------ 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/lib/matplotlib/tests/test_backend_pdf.py b/lib/matplotlib/tests/test_backend_pdf.py index 3529ea8541db..d52fc3efdf66 100644 --- a/lib/matplotlib/tests/test_backend_pdf.py +++ b/lib/matplotlib/tests/test_backend_pdf.py @@ -178,6 +178,8 @@ def test_grayscale_alpha(): ax.set_yticks([]) +# This tests tends to hit a TeX cache lock on AppVeyor. +@pytest.mark.flaky(reruns=3) @needs_tex def test_missing_psfont(monkeypatch): """An error is raised if a TeX font lacks a Type-1 equivalent""" diff --git a/lib/matplotlib/tests/test_backend_ps.py b/lib/matplotlib/tests/test_backend_ps.py index 8ead41d67d01..cd6e5feae14a 100644 --- a/lib/matplotlib/tests/test_backend_ps.py +++ b/lib/matplotlib/tests/test_backend_ps.py @@ -27,6 +27,8 @@ reason="This test needs a TeX installation") +# This tests tends to hit a TeX cache lock on AppVeyor. +@pytest.mark.flaky(reruns=3) @pytest.mark.parametrize('format, use_log, rcParams', [ ('ps', False, {}), needs_ghostscript(('ps', False, {'ps.usedistiller': 'ghostscript'})), diff --git a/lib/matplotlib/tests/test_mathtext.py b/lib/matplotlib/tests/test_mathtext.py index f913445ac6c1..544d3ef89201 100644 --- a/lib/matplotlib/tests/test_mathtext.py +++ b/lib/matplotlib/tests/test_mathtext.py @@ -167,9 +167,6 @@ def baseline_images(request, fontset, index): return ['%s_%s_%02d' % (request.param, fontset, index)] -# See #7911 for why these tests are flaky and #7107 for why they are not so -# easy to fix. -@pytest.mark.flaky(reruns=3) @pytest.mark.parametrize('index, test', enumerate(math_tests), ids=[str(index) for index in range(len(math_tests))]) @pytest.mark.parametrize('fontset', @@ -184,9 +181,6 @@ def test_mathtext_rendering(baseline_images, fontset, index, test): horizontalalignment='center', verticalalignment='center') -# See #7911 for why these tests are flaky and #7107 for why they are not so -# easy to fix. -@pytest.mark.flaky(reruns=3) @pytest.mark.parametrize('index, test', enumerate(font_tests), ids=[str(index) for index in range(len(font_tests))]) @pytest.mark.parametrize('fontset', From 9bf168f792e6801b64c769258dc91dbff172dc54 Mon Sep 17 00:00:00 2001 From: Elliott Sales de Andrade Date: Sat, 3 Jun 2017 20:16:40 -0400 Subject: [PATCH 08/27] Use itertools.count for renderer unique ID. As suggested by @anntzer. --- lib/matplotlib/backend_bases.py | 25 ++++++++---------------- lib/matplotlib/backends/backend_mixed.py | 17 ++++------------ 2 files changed, 12 insertions(+), 30 deletions(-) diff --git a/lib/matplotlib/backend_bases.py b/lib/matplotlib/backend_bases.py index f5a33c7bb610..72c0d7f2f6fb 100644 --- a/lib/matplotlib/backend_bases.py +++ b/lib/matplotlib/backend_bases.py @@ -41,6 +41,7 @@ from contextlib import contextmanager import importlib import io +import itertools import os import sys import time @@ -101,8 +102,9 @@ # Used to ensure that caching based on renderer id() is unique without being as -# expensive as a real UUID. -_unique_renderer_id = 0 +# expensive as a real UUID. 0 is used for renderers that don't derive from +# here, so start at 1. +_unique_renderer_id = itertools.count(1) def register_backend(format, backend, description=None): @@ -217,25 +219,14 @@ class RendererBase(object): """ def __init__(self): - self._id = None + # A lightweight id for unique-ification purposes. Along with id(self), + # the combination should be unique enough to use as part of a cache key. + self._uid = next(_unique_renderer_id) + self._texmanager = None self._text2path = textpath.TextToPath() - @property - def _uid(self): - """ - A lightweight id for unique-ification purposes. - - Along with id(self), this combination should be unique enough to use as - part of a caching key. - """ - if self._id is None: - global _unique_renderer_id - _unique_renderer_id += 1 - self._id = _unique_renderer_id - return self._id - def open_group(self, s, gid=None): """ Open a grouping element with label *s*. If *gid* is given, use diff --git a/lib/matplotlib/backends/backend_mixed.py b/lib/matplotlib/backends/backend_mixed.py index 3bd7a8c7d647..a93ef062f279 100644 --- a/lib/matplotlib/backends/backend_mixed.py +++ b/lib/matplotlib/backends/backend_mixed.py @@ -5,6 +5,7 @@ import six +import matplotlib.backend_bases from matplotlib.backends.backend_agg import RendererAgg from matplotlib.tight_bbox import process_figure_for_rasterizing @@ -49,7 +50,9 @@ def __init__(self, figure, width, height, dpi, vector_renderer, if raster_renderer_class is None: raster_renderer_class = RendererAgg - self._id = None + # See matplotlib.backend_bases.RendererBase._uid. + self._uid = next(matplotlib.backend_bases._unique_renderer_id) + self._raster_renderer_class = raster_renderer_class self._width = width self._height = height @@ -81,18 +84,6 @@ def __init__(self, figure, width, height, dpi, vector_renderer, _text2path _get_text_path_transform height width """.split() - @property - def _uid(self): - """ - See matplotlib.backend_bases.RendererBase._uid. - """ - if self._id is None: - from matplotlib import backend_bases - backend_bases._unique_renderer_id - backend_bases._unique_renderer_id += 1 - self._id = backend_bases._unique_renderer_id - return self._id - def _set_current_renderer(self, renderer): self._renderer = renderer From 454e9d633c9b4ca000425f38cd1b819592344309 Mon Sep 17 00:00:00 2001 From: Eric Firing Date: Sun, 4 Jun 2017 13:45:32 -1000 Subject: [PATCH 09/27] Simplify cla sharex/sharey code; alternative to #8710 --- lib/matplotlib/axes/_base.py | 34 ++++------------------------------ 1 file changed, 4 insertions(+), 30 deletions(-) diff --git a/lib/matplotlib/axes/_base.py b/lib/matplotlib/axes/_base.py index 7948c14de8e9..4462cd620ce6 100644 --- a/lib/matplotlib/axes/_base.py +++ b/lib/matplotlib/axes/_base.py @@ -980,21 +980,8 @@ def cla(self): self.xaxis.minor = self._sharex.xaxis.minor x0, x1 = self._sharex.get_xlim() self.set_xlim(x0, x1, emit=False, auto=None) - - # Save the current formatter/locator so we don't lose it - majf = self._sharex.xaxis.get_major_formatter() - minf = self._sharex.xaxis.get_minor_formatter() - majl = self._sharex.xaxis.get_major_locator() - minl = self._sharex.xaxis.get_minor_locator() - - # This overwrites the current formatter/locator - self.xaxis._set_scale(self._sharex.xaxis.get_scale()) - - # Reset the formatter/locator - self.xaxis.set_major_formatter(majf) - self.xaxis.set_minor_formatter(minf) - self.xaxis.set_major_locator(majl) - self.xaxis.set_minor_locator(minl) + self.xaxis._scale = mscale.scale_factory( + self._sharex.xaxis.get_scale(), self.xaxis) else: self.xaxis._set_scale('linear') try: @@ -1007,21 +994,8 @@ def cla(self): self.yaxis.minor = self._sharey.yaxis.minor y0, y1 = self._sharey.get_ylim() self.set_ylim(y0, y1, emit=False, auto=None) - - # Save the current formatter/locator so we don't lose it - majf = self._sharey.yaxis.get_major_formatter() - minf = self._sharey.yaxis.get_minor_formatter() - majl = self._sharey.yaxis.get_major_locator() - minl = self._sharey.yaxis.get_minor_locator() - - # This overwrites the current formatter/locator - self.yaxis._set_scale(self._sharey.yaxis.get_scale()) - - # Reset the formatter/locator - self.yaxis.set_major_formatter(majf) - self.yaxis.set_minor_formatter(minf) - self.yaxis.set_major_locator(majl) - self.yaxis.set_minor_locator(minl) + self.yaxis._scale = mscale.scale_factory( + self._sharey.yaxis.get_scale(), self.yaxis) else: self.yaxis._set_scale('linear') try: From edfdc539cba98b8ecf6888a161742bb1ccf1b4f7 Mon Sep 17 00:00:00 2001 From: Jody Klymak Date: Sun, 11 Jun 2017 19:22:32 -0700 Subject: [PATCH 10/27] MNT: colorbar accept numpy array input (#8739) Accept a wider range of iterables for `ax`. --- lib/matplotlib/colorbar.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/matplotlib/colorbar.py b/lib/matplotlib/colorbar.py index a080eb59247c..5894ecf123c2 100644 --- a/lib/matplotlib/colorbar.py +++ b/lib/matplotlib/colorbar.py @@ -1117,9 +1117,10 @@ def make_axes(parents, location=None, orientation=None, fraction=0.15, parent_anchor = kw.pop('panchor', loc_settings['panchor']) pad = kw.pop('pad', loc_settings['pad']) - # turn parents into a list if it is not already - if not isinstance(parents, (list, tuple)): - parents = [parents] + # turn parents into a list if it is not already. We do this w/ np + # because `plt.subplots` can return an ndarray and is natural to + # pass to `colorbar`. + parents = np.atleast_1d(parents).ravel() fig = parents[0].get_figure() if not all(fig is ax.get_figure() for ax in parents): From 2284e98a56965d98a8d7716f460a06d3b9c23bf6 Mon Sep 17 00:00:00 2001 From: Dietrich Brunn Date: Sat, 6 May 2017 13:11:22 +0200 Subject: [PATCH 11/27] Changed normalization in _spectral_helper() to obtain conistent scaling in magnitude_spectrum() and fixed doc string. --- lib/matplotlib/axes/_axes.py | 3 +-- lib/matplotlib/mlab.py | 4 ++-- .../test_axes/magnitude_spectrum_freqs_dB.png | Bin 19972 -> 18927 bytes .../magnitude_spectrum_freqs_linear.png | Bin 8077 -> 8166 bytes .../test_axes/magnitude_spectrum_noise_dB.png | Bin 42470 -> 42606 bytes .../magnitude_spectrum_noise_linear.png | Bin 15290 -> 15353 bytes 6 files changed, 3 insertions(+), 4 deletions(-) diff --git a/lib/matplotlib/axes/_axes.py b/lib/matplotlib/axes/_axes.py index 97a90c647664..90a1ef89ad7e 100644 --- a/lib/matplotlib/axes/_axes.py +++ b/lib/matplotlib/axes/_axes.py @@ -6666,8 +6666,7 @@ def magnitude_spectrum(self, x, Fs=None, Fc=None, window=None, scale : [ 'default' | 'linear' | 'dB' ] The scaling of the values in the *spec*. 'linear' is no scaling. - 'dB' returns the values in dB scale. When *mode* is 'density', - this is dB power (10 * log10). Otherwise this is dB amplitude + 'dB' returns the values in dB scale, i.e., the dB amplitude (20 * log10). 'default' is 'linear'. Fc : integer diff --git a/lib/matplotlib/mlab.py b/lib/matplotlib/mlab.py index ae9143c98f5a..971770790c40 100644 --- a/lib/matplotlib/mlab.py +++ b/lib/matplotlib/mlab.py @@ -727,12 +727,12 @@ def _spectral_helper(x, y=None, NFFT=None, Fs=None, detrend_func=None, elif mode == 'psd': result = np.conj(result) * result elif mode == 'magnitude': - result = np.abs(result) + result = np.abs(result) / np.abs(windowVals).sum() elif mode == 'angle' or mode == 'phase': # we unwrap the phase later to handle the onesided vs. twosided case result = np.angle(result) elif mode == 'complex': - pass + result /= np.abs(windowVals).sum() if mode == 'psd': diff --git a/lib/matplotlib/tests/baseline_images/test_axes/magnitude_spectrum_freqs_dB.png b/lib/matplotlib/tests/baseline_images/test_axes/magnitude_spectrum_freqs_dB.png index ebc50c676692747d0ac813b95e777688ee9494af..15d32d39920851ff27100f6246bd524219c6a161 100644 GIT binary patch literal 18927 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 delta 10 RcmaE6-)ld?W8*?sc>o)B1b_el diff --git a/lib/matplotlib/tests/baseline_images/test_axes/magnitude_spectrum_noise_dB.png b/lib/matplotlib/tests/baseline_images/test_axes/magnitude_spectrum_noise_dB.png index a18d0b40f43b14eb96668b40408c1dcae05a78d2..a8ceb982774b3d3c234fd8f389cca4b5579af54e 100644 GIT binary patch literal 42606 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 literal 42470 zcmeFYXH*p5xA)lyDu@Vzh>AoNBr8#J5Cv2~BuN$}=L}8gMg&PBNR-%0YBEU9Et0e3 z)PTeW8fc(_20A_E?>_&z_nCXwnrCLsx^HG`Ef%M$tInx9b!wk|_IH0GUuvn*UAlD% z1Om}%sH?sLfhajapmVROF91i|0oI+ z;r1X9CrCq8SQoZp17eN1C?1X$3Bn_zjBOR;V!D{dLH)YDc z{{CoL>A!>G&5t0wkMWPU=e>7kleWeSnS4E--J{~95d|MuZOu3NB76TCI`riTlFZT8 zgut#<;xlR`#$4qO7gRfBy%Kmdmo+b|zU_(Q5`WtfQJ+9@we5IFXnLXH{G6<>pn3CG zf7~vSjG5zn1XRi$Z6;wq8fskQ!0hS3c}c=y{AcYD*T0=y_a*?vel10tga13_-zJr; z7=r(4`hP8S+*edo+`X$5TG8T3TkGr6c6?!vo`PEGlUrNg|7;ehiSi^IMD@?r+#mkm zF6eUYQU%Y)aXl`08gnZja(a522!nCxM*VHhLt9yyg8ACDuV>6GEZvD|m3QuiGPv`e zd#$5$wZ>&W?Gi0*p?NH%c$ViZZo}Ox{NnO53>-}7?U?zc`#kgYpYN-N6l6eHu{=u2MdZYuKgs-+>nN z*d_Ee{`$2#|ELAWK2na5p-&O9HfxzhLf4)_SrB?ribT_h$r6o)^Nu6g^|~)*U4l6`|%64kl4a#}?hIwyE z4g@u`%b$Gh%SUD1xh2}MKu&Xv;MeOJ5?uuIW;k!Irn^RHDWq;x_E*+j?qLVIzS>7< zBw1)_p!i#Gfr}aLQkPjHgM`cNp@Y5mVxDS0h`NhzDx2$Bw}UOP2%grAg=yA9oBx%t37ijnP^r2*RJdH0JWNrpBG zFsVf^4q;r*!J3$b!D!$C&B)L9sv@m71`kN5;lnFBS3~SZ?~*%F3gnE9y2Z+L9s#cA zF)2F+3;gok592Ycr`U2t#QIQ8EN)0vwLLr>LBL~hLm4-vJ}aVz?#)*B%5B48C%1*@ zIJBw*8^~+8jjKarC1JFYeMw>$6J>oFGd-TIV|`w|R1$YKK3=B>?APXqTI6SGo)a$t zL&laf{>4vyOpCsY`>5F(!s&pRDuVDfYZp5l2_Z=n56`%$M7oRWzuJ)ku^L)uc-QPw z6QW3tt3|d*tGZ&0tPewGKpDc_wc%cKdU3zV6igjG&L#5)w1PW38p7VkLDedEv*q4> z^u1*TT1hN!vZ5I&(CKmmza?$l$<{AE`SrjvALmgrBpqJhY?7V#yq$I<^uZ#7(Nu4d zK8e-8e*MB0wAv-Jg*;xU3Wp6%G4kr>->}~v4cn++Ib0cp!Dcj(mDYijEzap+ z82H#o0o5QMcD5~sIfcJcB@hsr5h`%fFIbXbI*|;G{EnmvV;Y=xr+3$QVV-a$0S{N z+L+k8kKhwLCVlGN?;O<0N?84=O^|;H*0}yRa?ueiX0x})>QXV>WTT0x_TKopQfAhV zsB^md7GoZ8tIla@SXb-enUo!8MMc9MSb__3+8NZ^*}3VAdaylnr{gmlsau3^$?FPRAHo+i z8H>V^#U1W;O#e_JoWdCvp{^X}h*o@HmVZ<@Zg&udo9FGQb(T|1{pdNguhspTO{L`Z zlDv5$FxwvDw(fN(U!-~HkjS7&-j>f?^wz$siW=&|M2oCL%<+ydRRcfQoUJmk`{3qx z#|+8@J9g@t$Rg6)=<=`vGm{9jrtOu$Grm||Q>QE&los}MsjTUfy^PN)1WMk?=(-cT z>TWZ9{q5!})FGR9B34ec#_6WW%5rqf+EtnnI6YL@*lL%92dq`$!;h|LmLs|y;o2@@ zQTFiE?)esz2oA^t2uDygB-L}B`bVHNjP`i@$KSTLX-74s_8$R5kl4J-LAcL%b-4xS zx5zDO(Y+c-CX6YtePLMZ#}bV#EiL_NFTUsHq>=QiAiI}JE3XNf7_7T7oex-SUmwhn zUCcgD&XS+=`|GugU=Uawg0x&#&_nooxZBjw6Fy*%M~h@DlKx;^l3quC>Yjv{x=}#S zg5DmStPoP4-5fJ0v13OqlGlfq-wv56;7qf9c91CiT1tiqTr5Cxsns=S#UoqAr!+e@apjw7JcYAtVI zKDx-^M7Ho<)bu(WS%(N2y9rOW(_=Bug&%HpIW4-7U?z35p3c5I-2UXC6DLpolfzGd#WeKA8xXz!$_k@f6aaILNcP3ieWK2vDn+b0Wkyf56$ z7xFa;93@BK&_BG{Qx?P0+0L`maDC65sj{`(&o-wlz_JWCyT{AS0_6&yyybcEhx?Yx z1-j+8p%5X9Aymn?$+EShwWMM`s*&d+`?&p;Q-YM=1H*cHUCZzLX7awpKHELb!joMw zUDBrhe<(;^{(blG7-X+^6yb(K#xU`~Pp@}5&~frB-muJxB=646(LL$!qP6NTOY+P9 zNOy`aF;d0v_BW6qTf939nukQ3D)H=Q_gSrT8=Cw&uh5^jco@0aQETnyAf;NFItYJK{{|bUiU~D2 z&()Lvw4G&mN%-ogeAru#MwaW`L1p-H54juQ`)}V%4G_l1+-QRVeF}p?g*zI(ccpKb zOS2~M+>}1v3fyf@fJwe~o_ARNIaxj|Ex9GyN;H6(c>Q_54k7_XgCbOc_7&3 z4>yy>2-sMLF}N&wxEvuVQXUA#KgxNUTKD}0-h1jM(V*lv%EM)jr{n9xb@(|^6fo(( zGa5{r8M|MXIzX%}E01SfDNG-$O@H(yJQJJ`HkME;g+h0EJs(;GCBX^~(Yzg@G-pAh zrE|@|$JaXF8ng%wM+KoWk*@o1cP(DqkvZsYQSVQh9Pb=21av`y=Di8TDT|m*FX*M7m%vORzDyvYF zam`89om-tPZ){>}*gbJ{&N?&$T`%HYxSx)INiC9%?YP zpCwNqVh}O#RF%C1BW|wU`o|Id!c5EKx~F_uNoQ2uv&`2${L5R7BNicI`QS5qF2Iq% z2j-J5axWN${oxf-RS`6L%TaEtjX4Di!3!dwm}$$^0j5;gqk>himTy@gIcQ;W(mKOC z*_~9eHJ1`@1iSFM>0K=I^5NJZvDU?#1U*20&o5V_UztuM&SwS7oqP*oS5?Ufs>O=) zpHg-Bmo;wjlQN`rBj{KO7}hO09xX3+p3oM((CyuZ@bG@`?><`EO6*Y6h$D22XS~c{ zjMPEv9oV>#iA`2=MC|)H*E$QVNo_UR_Y~iX4?Q9J2HaX3D^Vm>xU#Z=w~0q7LDMM~ zG8os&1nobD<&s${2M^>ZdJ~7u*t6fzDXqRc`Emyw4&9Y*Z41~_h7bx~MMpF2KdH#= zxEhvrjlBmzg<|VjXm@&BU;Fw@W%PET`HItcX~+T+^AW3a4Z- zYeY|>+*eyCe%v8Lj`T@FsP79M1@jH4Tj-!eJI`BIHcE@Fw|`&aQpN4AZ#quZa%ihi z>%cz;8FjPS-lm=O-nt$vcgQe|-Kjghpl+6hR9hXaXE8ILu%x`OhZ87YU9439oybQp zq5J8L9hqm4_71;g7vN>H>~U0EwB zEmp_KOUGvtl$#rh3y@fOy7M%qlB{;xWFoav|090xEh!N7_OYspUXc}smr~{CSK2nI z1Tpm;F{{*PN?&dTxQwO%&U&WC&N2`t z5iRCBz6974)c#8B?H8{aq8=43klI~t`J$71Yy5-haW+3GGjj!ooEvC8`^mOt(7vu8RccJQepAHDB>#UG+ z@0`!Nt#XU2&d379m$-R)MZaO}7q#Z@A3l}0F@OyviSBWWx`bNoHu+=!978kDVmVxg z?De}{C!!E3i8t2Lz0Kwu~mqjlkb-+Gc>!Lx)6k$psz|UUT8K#T#@zmu=sd(?rsh8 z7`Mo}7;rqEva(Pex$%oOX0dKzt5uLYC>2t(U0p_KVmQ0rG)@-iZzx)GKnqFHkGg}OKT(|2Xwwr@+A%OP)(f4kx2@`Qex?}nZFx$^_gM};Ng&I%59KTX+ z5AZe_1$cw$($_(UUs_;|nFw-Le+<*r7E)sn5=welm+QG06nI6N;O25v9^ktxf@bJB zJ1^_w*5GOs-hPHS!|@gw4xcF4ekPMw$N5e1#~H1Qkd;QNZjN%-^Dk|?uVjC?vTR>s z)e`#UPE4a9;QQb`$MTWYemPH@$=;jGWax{Gp6<0dS1jh?yJmQye*b+#ZL4O(%?!_z zM}%#$Y$6UNLwR8Axe`MfyW8s@3V7Z}?S&G;+}SA>lC|ajyJsj4g@p;3NHSriWm}DX zX{92-H(Q|W!9sM^yNgqN{K7oO6~TDtIh!)p4IHv?Qi6}~VVbq!JeYUN{Uy1{pE%-P z%qr=4-Ib+0xlm8##+*CO1x2p2iVTvGYMhj|2>fC~sE$8kES+MRuQ8l-^px>689O0h z&)>!LHu@yttkP17lpeUNDZTkEPw{1KG*iYgb(%BNP&jgNw*hrXOqY~s?f2NMq@L8( z-b9<8^nTx;+w80F)2dzNYT|{7_f5d(3ZK-EA2e8&yhE4`rkz0)Nd+7h)OV!j3yTf4 z7ol^Km_t<}Ia5Z_I%q;TDN1qB0i`$o;(Cq;y1BM|u?+CUZ)VEqBVc)R@`o??oO2q{ z!d(0Y)v>(j<$7<&saxKb5d%jl<5~*eXKZ0^B+rQ=0=SQFX_xnTa;PlAE9)86&iD~W zHGWHgyt3d)&!Ta6R53O2NyO-mRp!G}Rk*o)z{3YK`o-(6SqJtQeZ&2Pq>9M~?v`mu?z7s!C&55)q<^f5St_ci*eIc2!UQknI)u+O`S#RGyuo3|%G#q2Xk>*< z-uSgC-28wf-lO$O0B0gwcYv?Nuh5sd2}6sSPbRdkmmdbKY)n|An;F(M9rVn2+8}Fv zZCxpI#-+D~Wy_b9%;$S~v2bI=V?#rJb<{P6?wL(ef-yNMtggvPuBDbR)8 z=z6Iece;O#3|bIljoU%XUrD^8HQ3grAz5Cs0#6+hGKpwC>pO9FzGP5jAoRMi*$RE$ zD{udNtV*t8X_dH(duEY- zm6!!J%T_RGwZeBXM)v$my*`$JH~;EV8a1Le9hY$C64}`>)=q z6kDu(S_-=_-6Ft!|Hw=wUD8^z{O$$L#&3OT-|L)=#O+5$S{yIL(`YM!JieB^q5bou z^?@+WEh!#j#6r+*c-KR{Nmddgix&`XCGZ=3l082neb56m{^lcy%A<>f@6HU_uHS70jx=l|Jy*1pA8E-0mn)6) z>qp6+2Q|=AsB_bCW$z}JaVAQ`+*IyY@g*J4Pm$~MHfhw;CEekib=Cs5`-U)DJbln^ng}|dNyHOouQ}-u_{kJ6rWw9+sliLGQPI+rx`S!ZF zr8P!~#K0uPAX&n3T|sVhPOjhrT}F6P@``xsLFC5cThgyucv-Ky#`gt_`kW-une#@q zUwIB)fM+I?sx`dUl7RN&=aQaXJ=)dunlft}yOvK$@5KT6tz2J0HG+U5`S#%AYXiy2 z#NlGg$lS$G?2!6>wkP2P`-#3FztKAI*LaT%1?&qXpZa1a3+rOP!XcUDy>kn5kWltc4eMH-?KxB6 zW&G+F%={*$a+X0-K6kKX+1QilU+F1HQ$I?YZfb7P6(LbSGYx;taZbfnIL%sNrs`Y| zHzWFgzVE`x?z*wNs-JuQs8HFo#eY99r$l{YQ=%>}L3c^NS?O6GVUV2Z8v^ILqUbvI!3tL!?PWripXOY~9CK@av1h5L3F8X8SD_!<6MMK>u#Jv)h7} z4F=Ru9ZXg6mo1uWEpAh&52hVM!r2{2L70}dsD#}*819h<_?(KW*Q60)b29kJTHlh$ zlGZOwV zKjseTbR*}_Si$CPnZ#&Pk@ltBQj?=G5wju;EXDR(laC3@L^1xk?Q39Z02m`=bWad2 zb3bT(z%6;M8T<&##ovCLR{wp{cRv|xwq z#~13hr>6)TYISdR8Jk%I;QS43Tp3r7bmWri^Clr_U1+v4SE~HGY^$(5EMW`ZlYchSeGZKqpnkdSH zxpqcn==>2^!_G?l|)b1_WNW8bPYm!q1j$25$+oFB$Cae^DdACCnP19V$mtom@SR>9!2t zKkNSpB?`!5CuS;?7cJ(y`;xG}Ir=$IAKAYG&lmK;H6S91Me&T;5aJ;*@{{-PA2~tf zFWR?dyf4)bIO%y+XHj}dDMC>1j!5`Tct2pTY8;m4>+$ks^p7~FPat8;>PH)G(mk7Y ziwfAa0R3HqFnzWAnag74bJ~WcI$A4r<~wfh1pk!_@X=rQS>l2&vqYw-ZYQR7wBkEH za4iry`Q&xOsk!%c7GW=rvRwg7mK1rs6Ka%7Rc?DNWghjt4DNL8YQF@aVerq>PFz)+ z#uxHt={YWs*AUv=F}Kr@p^aCh`IjR=trKo>xX-&@J>$KR!M#|E2ThA9tVP z^V92>tx!Y9MFhk26H^t=Q8Lf+PULrL5t z7e`RQ3lgh)Sm};D&{=0E_sq-_3~~Wlj_BhmL_b)LJM)2H-WV#Cswi*aS-MC z_#AdU6>5UkqvDEQZaHKenXOq^F^R2vLCMft_&O=caPOM{_f`$z9ITv;RZ?)eC8|;0 zdz@Fgn;i{pg=D&47)j(ivn;%(15;SQZXl({@2-gh(?p(ZL3@v~cHXvBxN6`RySd35 z-P(;lI|m3;#FM}hE%}K+>_h+R{rTa+z(%k4rZ)(3rG6`PD9Z!)#-v$lBiws7rReMIX%V&3D)m{D1y`RHKHZK#Mm`X`ou!VA#ol*D1guTa#*OfibcE80S)pA4`M}9yQXF=3g!EGshUsTKFm?k5Q4bt0cU?io`i9t`8CeT5j%LP*7AEq$A~UmsbMN%z9GSN?cT1mI1wp;d zdeWn82DhcKmI{m$^UVc2d$tLSpx;|577^D)cxLM#`i-#Fd@40GdX4UUmO_cLZ6cH|LUR${cKH59KbzHk9((}7H zaEh@DEipu8p{S%`j73dpzeoh#*s;oc(7qt!bsJ1oEVx;bw3p?3V>~~z zbgs|Q!nY`VO~S0f1F6?!5(gi8x22ce_93&IPVDP(K%gyS@W%QIPr|d~1C1JCv0+TY zwT5yCHbx;wO}O1ZDDmd!bSb8Jw-4a2-Yr&QQ;UU=Et`352f`(aS1+fwcf_JhFb)r@i5I}_lI>(@hz z<)a$AtA>X$(Z+J)!_Y@)!Jy|M4iDBOV6?)V4&yz@azLGI!W^3`eEGqF7JWyU?2ogT zJGFwOeY>DqcMm9`1}3EMg1Q1;z6nz5dOnHs5$2Ds|)P zxwr>_P+#D5fpf~7)oI3I#uoj+G1VvagWX!Pk5RRf?=R+%jjVu^CS$&rhAiAByrEkY zL>6d8>)KIXN`}C(4D)l^DzGA=G&xDcwfWnqy?jv;TL6ydmUzTQIpWZ|^TUM()#fs* zAM{+?XgJt&W%HB7jRO5>xb)gJOkFp6W6NeB&Dte{tA|Na@kvF=d-MDTC=(BZX8O9E z>B2WNUpCi%7<7H$Jbb6cI+|?VAM_aT>p`RChUQDWV16_y7tn>w7AP*d$*@Dd_CubF zqEaI2#)2u1qnbU;j4Xt~oy<>}#=38>oJox)?*^E@;>*@ZXoe-y-}tGmp1Gwg?OZ2p z_GwA$N$9Y`9Mr!Zh-Gy7o>I-7S&Y9(Z1mpIu8pX_X=?T(FH1fWP{`5#4a|IHuSe=_ zz+d`D&Z8j~DvrchKx=@a);0yk`(N-%6PG(p>Ct1_4MXP26db+?@-Cw1`;kVJ*U^M( z0xvo|&vV}V$FG3fN4LKVl(2d@@gSkF$K3mZ$5|K`0`QlGVy%K+wPp?>smfPBCK>ixwt3qxjp zh8ALN3;7AlO^TAFMwfAH%bX}teEo}y4pt#3;u39Uct2WlfihmY3bMF?KnurFbSN@!|x{8OIc@3p7CKfL4Z z!z>h68iXDPm4`LDWF{|3ia3I;5xh_dyXx!3{rz_uR~eyLofdrAK4bau&glhRmhDsf zrLMuNYL5^gagkV)xu|EgS)@X#K*$zzFR?)RgPX|jNz)*-KVp+7Am|Ej;k6Oxx_uc> z0prouARCN)kp;~4m{`4$zy1Jk<~o>;mA$_jlQ*}2Gne#jEYONfNk34+{yk$jRxu4d zI*`#jm9R6H3D*Z?bg5a@42s`% zw9EEg*k8=%dh{3+|I+-)~|HMYL>k+Z zzoPwRu}`KC+(Sd$2>Ygis*~VL0kZj? z$Wo&fGaqwbEt>e_p-doYLUO+6%bBll54>*+jI>wiX6yF0UkDJXVln7DH7s|z(hNv2 zKVSNq+BBB%XhwXNi$}!XT!H$-e=22RtT+XSCk!oiMC3=mDF-&^nrsgZi~jODSyC-F z3=ol3f0|LlEPrY>>k3-dJK(YdWnTz)=@ck79BwY-dH}dg%s!vb(=4v4>U7+D3Z>^e?3dt^;+;=wt)qG;yve$P7|o<1{QR(siUyV)b_4P4)|4h>BL;o43w?WvVwV6MIXdzNSt2!$5mTZIOOi zh9^2UUU$tM(NC>=dJrgFYGR0>e^h!Ae)-;fJ>&!|$}A4jDL2%Rg(m8AAsiWhJ+SIw zI75p#QXB<7%R30tgpO${lz|8Xd zi;Ys{MnG&|m*&Xk=jKB%b9NT70+W>3fX(_DU;b# z-Ex`_Iq{y_kDQ;aG{P*HO3Q6ajTw*KYnaF^FdAzBkG!A)!!=)LxLgx%{*9FR%3)c1 z_iw_(?)*B0jx{a%PT^5_ME%C6n&ncbTQfWBcOtskJ%@Ix7fx~mD6g*Lb@UtraKY4`qCT)$hL!Ub<68@0$ znzb-@EYGXzy(!9hWoo+Z+VzK;Lj7FKjfWu)Q!Y=sZ$CbqFw79!@w!T0XT=YOI6*Cd znTBQZ5_A1?cun>4TV__N$7gi@nJO1hC(qq4`K)-!Cm=VsC^sr4NW>k&3brf(j|5A>6Y zVV{a-)XY4`4tQ#G?wD&E6ehN`hWeMeCun2}@HQGiMX#`o{ckEm`^2D%V%A{?CN# zz~$x(gTH0Zb86X_8xAj$XPc%P^oKZoFg!)CAHpIIG-Ghrn3;7PPeu9FX#uZY=J2IU zVTd}kN)RmHn&fryC|`3kPbj@F1;x}|X-!B}awc{?uX8b#G-~~=DYU$1@Iz55JJ;Ck6 z!Gs|)FmHBL`>WSnTPb7d=Q;n;iSD>jduR0;x9=mjcTy}o%1SsUxdl=zhP)HEU2D{?%8yOC9@EcN44^d{}KS z)z3Tj9Wix9)3v*uEVV6gt#oHUS-|keleNvoT$*AwCQatykxkT-9g*vkq>{>`RSt&W z#7m;6dp% zsQ($`k8QG{8*ZPylmbgvKn%*;KC3hTVCq*o3bs&@=`JuHP&PwB`W0_S7qq(Z~k z4>2j`qESWTB{vB{N;7|w9n)aLB7@jxwsF2BtFy#@0lLlGczDLIo6k}wb=(=P6kKAy z2^z(Nbyl4wC`JljzPB4@hps#gYQdS@w2%mrnK3^p9C|)wQRa%K4Vke2b@_r?4ENba z&ffaP%cXCU7`xe0jM5J^E-5WQVV)}1wA_}g^0VanO19$%A+p@U#x*vY#|!a->7`!f z54zjcVy{fD<|df9ED6tFZ^=D7I>N;7Rk_+!VtAErbZ72nFJzy`xlRpjNLij6Nzgun zl?UPjr?VeTdF}K)(My-2_ideV(I|kD_oCid>+(#+l(&j5Y<`Qv(?rxPeo?bopnjG} z5m7T_%h>Z#d6Y)!miQm3bVXbS*>~yJwEZ9WN?5%qr99YcU&<3=vNV;d)Ta{Y*^k>nX9;d?)jdM< z!g39Vbq??$^95zNNut$(739=$e4NbsgccTe^IBWq)yh%#IDjS538uKEzh^w4R3FImTMYvXQ9(jWi$+dTfVH(DJ^}+;p0jB6G7YpG%~+ zR8XQ7+TYSG;M~D4+Q2(>rmFtiuOSyxSQ{)dApYX1?m7u%OfcnW`ScF+>qhyQ1Z`qu zvx!CM$r6qFO`rYFuIG7LGLfECzXB75iARPmYeSQzj*w|XjEp^={lA;gfu z4-w@WEdjP!!rahQ`vZTturrhAJ2J4G&EhTo7}uStEeSA*tEGcI{TtDr6P84e?_dAH~#>e3p7rC6NJz(jjwi2 z=(C6EmN)49tnE{v;(WQT8nk>rM(U∾DcRISgW6!Llav`CY)7{aQadW?JL$C*{x+ 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 H`;q?u#Rl^h diff --git a/lib/matplotlib/tests/baseline_images/test_axes/magnitude_spectrum_noise_linear.png b/lib/matplotlib/tests/baseline_images/test_axes/magnitude_spectrum_noise_linear.png index c2deb9e2414dd6e757af836fc73b19720975d483..95a64798607b72f9dceee6c48e23693292325c48 100644 GIT binary patch literal 15353 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 G^xptA@BA?U literal 15290 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 From 234089dc5d18ab6626afa6344b90a810416129d7 Mon Sep 17 00:00:00 2001 From: Dietrich Brunn Date: Sun, 11 Jun 2017 20:11:21 +0200 Subject: [PATCH 12/27] Added note to api_changes --- .../2017-06-11-DB_magnitude_spectrum.rst | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 doc/api/api_changes/2017-06-11-DB_magnitude_spectrum.rst diff --git a/doc/api/api_changes/2017-06-11-DB_magnitude_spectrum.rst b/doc/api/api_changes/2017-06-11-DB_magnitude_spectrum.rst new file mode 100644 index 000000000000..67efbb580a99 --- /dev/null +++ b/doc/api/api_changes/2017-06-11-DB_magnitude_spectrum.rst @@ -0,0 +1,31 @@ +Correct scaling of :func:`magnitude_spectrum()` +``````````````````````````````````````````````` + +The functions :func:`matplotlib.mlab.magnitude_spectrum()` and :func:`matplotlib.pyplot.magnitude_spectrum()` implicitly assumed the sum +of windowing function values to be one. In Matplotlib and Numpy the +standard windowing functions are scaled to have maximum value of one, +which usually results in a sum of the order of n/2 for a n-point +signal. Thus the amplitude scaling :func:`magnitude_spectrum()` was +off by that amount when using standard windowing functions (`Bug 8417 +`_ ). Now the +behavior is consistent with :func:`matplotlib.pyplot.psd()` and +:func:`scipy.signal.welch()`. The following example demonstrates the +new and old scaling:: + + import matplotlib.pyplot as plt + import numpy as np + + tau, n = 10, 1024 # 10 second signal with 1024 points + T = tau/n # sampling interval + t = np.arange(n)*T + + a = 4 # amplitude + x = a*np.sin(40*np.pi*t) # 20 Hz sine with amplitude a + + # New correct behavior: Amplitude at 20 Hz is a/2 + plt.magnitude_spectrum(x, Fs=1/T, sides='onesided', scale='linear') + + # Original behavior: Amplitude at 20 Hz is (a/2)*(n/2) for a Hanning window + w = np.hanning(n) # default window is a Hanning window + plt.magnitude_spectrum(x*np.sum(w), Fs=1/T, sides='onesided', scale='linear') + From a62d3e3051002080568c799013d7407d4a7629dd Mon Sep 17 00:00:00 2001 From: David Stansby Date: Fri, 9 Jun 2017 19:26:11 +0100 Subject: [PATCH 13/27] Fix contour colour level determination --- lib/matplotlib/contour.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/matplotlib/contour.py b/lib/matplotlib/contour.py index 82d9fb023312..5d3fc1126c0d 100644 --- a/lib/matplotlib/contour.py +++ b/lib/matplotlib/contour.py @@ -1254,11 +1254,11 @@ def _process_colors(self): i0, i1 = 0, len(self.levels) if self.filled: i1 -= 1 - # Out of range indices for over and under: - if self.extend in ('both', 'min'): - i0 = -1 - if self.extend in ('both', 'max'): - i1 += 1 + # Out of range indices for over and under: + if self.extend in ('both', 'min'): + i0 -= 1 + if self.extend in ('both', 'max'): + i1 += 1 self.cvalues = list(range(i0, i1)) self.set_norm(colors.NoNorm()) else: From 03c00d7dbd97a468d9aac33b95d2d99ec74834ff Mon Sep 17 00:00:00 2001 From: David Stansby Date: Fri, 9 Jun 2017 19:27:07 +0100 Subject: [PATCH 14/27] Correct contour level test --- .../contour_manual_colors_and_levels.png | Bin 28760 -> 28921 bytes lib/matplotlib/tests/test_contour.py | 19 +++++++++--------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/lib/matplotlib/tests/baseline_images/test_contour/contour_manual_colors_and_levels.png b/lib/matplotlib/tests/baseline_images/test_contour/contour_manual_colors_and_levels.png index 6de9c579758d6cd9cfd0a9a5b5790103dbce912d..c4ec5f0beed4e9689622b995e5e93f50a958dc90 100644 GIT binary patch literal 28921 zcmeFZbx;&+`!-BSE-Bs89fFjUk|HHYH&W6ojkKg9pp+;GA|ObEw8XM2A|W8sy;4dp zxis&!c;CP0dB2%&=Kb^gW?p9QxdpDh>dfmrkAtW8bTvqc8Hus5ut+uUs2X5l;agD5mLtH{!#KF;DOwjp;gSeD~ z^bLC{p=%F)eW5o+MgQ|j5if6N(I~@QLM*InSemN04Fj{+X97YpMkZj}bE%r9FZr)= z#tS{V^(0@U?BS34He-uY{g3&^bH<^CT4R%Lg-?Z#?uY8?YD&!%F3r2Q_1Ceu zz`tn7AQYG%e5}TL3BFHb{J-D+fA=={pRz=p=jY``^56e(&&Ws(e62%=pNy26NQ9q< zd`)E1KyS_{q2}mBEbpkOs3dItYz+=LMsMY+#!q#wh&9|mGuIz5M6W+43&r=*@)?*< z)l=+FH?f{5K{F_Z$e399(R6lpYDPDG46ZpUZkKI3iG8p*7bIrZ=b;ybh-OG+kDrJ67lOGpC|>`rIlOy$U&dd^=eL%s-KanA{2N zm-oTZ%FuS`BtAT7K)z7<)%kPC=dfuYGPfc8mV~Pz_r*#3NcLla>__;g%hFqX zURjOu*wsGO@v+-~f&Rwa%rZBfSR)-*Hv-m+PIlK*)E1>%Π7PMem<1;lZa4z@u^ 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 literal 28760 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 Date: Mon, 12 Jun 2017 05:27:37 +0200 Subject: [PATCH 15/27] sort input files when building packages (e.g. for openSUSE Linux) (random) filesystem order of input files influences ordering of functions in the output, thus without the patch, builds (in disposable VMs) would usually differ. See https://reproducible-builds.org/ for why this matters. --- setupext.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setupext.py b/setupext.py index 1b2506da2c6b..15c59053c2b9 100644 --- a/setupext.py +++ b/setupext.py @@ -1341,7 +1341,7 @@ def add_flags(self, ext): default_libraries=['qhull']) else: ext.include_dirs.append('extern') - ext.sources.extend(glob.glob('extern/libqhull/*.c')) + ext.sources.extend(sorted(glob.glob('extern/libqhull/*.c'))) class TTConv(SetupPackage): From 62aa00676ce5cc779d696433cc32070433ce2694 Mon Sep 17 00:00:00 2001 From: Jody Klymak Date: Mon, 12 Jun 2017 17:54:20 -0700 Subject: [PATCH 16/27] First pass; seems to work. More testing needed --- lib/matplotlib/colorbar.py | 41 ++++++++++++++++++++++++++++++-------- 1 file changed, 33 insertions(+), 8 deletions(-) diff --git a/lib/matplotlib/colorbar.py b/lib/matplotlib/colorbar.py index 5894ecf123c2..f06cc34a6ab9 100644 --- a/lib/matplotlib/colorbar.py +++ b/lib/matplotlib/colorbar.py @@ -1166,7 +1166,7 @@ def make_axes(parents, location=None, orientation=None, fraction=0.15, @docstring.Substitution(make_axes_kw_doc) -def make_axes_gridspec(parent, **kw): +def make_axes_gridspec(parents, **kw): ''' Resize and reposition a parent axes, and return a child axes suitable for a colorbar. This function is similar to @@ -1213,13 +1213,35 @@ def make_axes_gridspec(parent, **kw): pad_s = (1. - shrink) * 0.5 wh_ratios = [pad_s, shrink, pad_s] + # make parents a 1-d ndarray if its not already... + parents = np.atleast_1d(parents).ravel() + # get the appropriate subplot spec. Loop through the parents. + gs0 = parents[0].get_subplotspec().get_gridspec() + minind = 10000 + maxind = -10000 + for parent in parents: + gs = parent.get_subplotspec().get_gridspec() + if gs == gs0: + ss = parent.get_subplotspec().get_geometry() + if ss[2]maxind: + maxind = ss[3] + else: + pass + print(minind) + print(maxind) + subspec = gridspec.SubplotSpec(gs0,minind,maxind) + print(subspec) + print(subspec.get_geometry()) + gs_from_subplotspec = gridspec.GridSpecFromSubplotSpec if orientation == 'vertical': pad = kw.pop('pad', 0.05) wh_space = 2 * pad / (1 - pad) gs = gs_from_subplotspec(1, 2, - subplot_spec=parent.get_subplotspec(), + subplot_spec=subspec, wspace=wh_space, width_ratios=[x1 - pad, fraction] ) @@ -1229,6 +1251,8 @@ def make_axes_gridspec(parent, **kw): hspace=0., height_ratios=wh_ratios, ) + print(gs) + print(gs2) anchor = (0.0, 0.5) panchor = (1.0, 0.5) @@ -1237,7 +1261,7 @@ def make_axes_gridspec(parent, **kw): wh_space = 2 * pad / (1 - pad) gs = gs_from_subplotspec(2, 1, - subplot_spec=parent.get_subplotspec(), + subplot_spec=subspec, hspace=wh_space, height_ratios=[x1 - pad, fraction] ) @@ -1252,12 +1276,13 @@ def make_axes_gridspec(parent, **kw): anchor = (0.5, 1.0) panchor = (0.5, 0.0) - parent.set_subplotspec(gs[0]) - parent.update_params() - parent.set_position(parent.figbox) - parent.set_anchor(panchor) + for parent in parents: + parent.set_subplotspec(gs[0]) + parent.update_params() + parent.set_position(parent.figbox) + parent.set_anchor(panchor) - fig = parent.get_figure() + fig = parents[0].get_figure() cax = fig.add_subplot(gs2[1]) cax.set_aspect(aspect, anchor=anchor, adjustable='box') return cax, kw From fb3f41963f40b954236793915aa7a0e36cb77b9f Mon Sep 17 00:00:00 2001 From: Jody Klymak Date: Mon, 12 Jun 2017 17:55:03 -0700 Subject: [PATCH 17/27] First pass; seems to work. More testing needed --- lib/matplotlib/colorbar.py | 72 ++---- lib/matplotlib/figure.py | 507 +++++++++++-------------------------- 2 files changed, 162 insertions(+), 417 deletions(-) diff --git a/lib/matplotlib/colorbar.py b/lib/matplotlib/colorbar.py index f06cc34a6ab9..415da55b0ebd 100644 --- a/lib/matplotlib/colorbar.py +++ b/lib/matplotlib/colorbar.py @@ -39,7 +39,7 @@ import matplotlib.patches as mpatches import matplotlib.path as mpath import matplotlib.ticker as ticker -import matplotlib.transforms as mtransforms +import matplotlib.transforms as mtrans from matplotlib import docstring @@ -317,7 +317,7 @@ def __init__(self, ax, cmap=None, linthresh=self.norm.linthresh) else: self.formatter = ticker.ScalarFormatter() - elif isinstance(format, six.string_types): + elif cbook.is_string_like(format): self.formatter = ticker.FormatStrFormatter(format) else: self.formatter = format # Assume it is a Formatter @@ -344,7 +344,6 @@ def draw_all(self): Calculate any free parameters based on the current cmap and norm, and do all the drawing. ''' - self._process_values() self._find_range() X, Y = self._mesh() @@ -400,10 +399,6 @@ def set_ticks(self, ticks, update_ticks=True): self.update_ticks() self.stale = True - def get_ticks(self, minor=False): - """Return the x ticks as a list of locations""" - return self._tick_data_values - def set_ticklabels(self, ticklabels, update_ticks=True): """ set tick labels. Tick labels are updated immediately unless @@ -616,7 +611,6 @@ def _ticker(self): else: eps = (intv[1] - intv[0]) * 1e-10 b = b[(b <= intv[1] + eps) & (b >= intv[0] - eps)] - self._tick_data_values = b ticks = self._locate(b) formatter.set_locs(b) ticklabels = [formatter(t, i) for i, t in enumerate(b)] @@ -687,10 +681,9 @@ def _process_values(self, b=None): self.norm.vmin = 0 self.norm.vmax = 1 - self.norm.vmin, self.norm.vmax = mtransforms.nonsingular( - self.norm.vmin, - self.norm.vmax, - expander=0.1) + self.norm.vmin, self.norm.vmax = mtrans.nonsingular(self.norm.vmin, + self.norm.vmax, + expander=0.1) b = self.norm.inverse(self._uniform_y(self.cmap.N + 1)) @@ -1117,10 +1110,8 @@ def make_axes(parents, location=None, orientation=None, fraction=0.15, parent_anchor = kw.pop('panchor', loc_settings['panchor']) pad = kw.pop('pad', loc_settings['pad']) - # turn parents into a list if it is not already. We do this w/ np - # because `plt.subplots` can return an ndarray and is natural to - # pass to `colorbar`. - parents = np.atleast_1d(parents).ravel() + # turn parents into a list if it is not already + parents = np.atleast_1d(parents).ravel().tolist() fig = parents[0].get_figure() if not all(fig is ax.get_figure() for ax in parents): @@ -1128,8 +1119,8 @@ def make_axes(parents, location=None, orientation=None, fraction=0.15, 'parents share the same figure.') # take a bounding box around all of the given axes - parents_bbox = mtransforms.Bbox.union( - [ax.get_position(original=True).frozen() for ax in parents]) + parents_bbox = mtrans.Bbox.union([ax.get_position(original=True).frozen() + for ax in parents]) pb = parents_bbox if location in ('left', 'right'): @@ -1150,12 +1141,12 @@ def make_axes(parents, location=None, orientation=None, fraction=0.15, # define a transform which takes us from old axes coordinates to # new axes coordinates - shrinking_trans = mtransforms.BboxTransform(parents_bbox, pb1) + shrinking_trans = mtrans.BboxTransform(parents_bbox, pb1) # transform each of the axes in parents using the new transform for ax in parents: new_posn = shrinking_trans.transform(ax.get_position()) - new_posn = mtransforms.Bbox(new_posn) + new_posn = mtrans.Bbox(new_posn) ax.set_position(new_posn) if parent_anchor is not False: ax.set_anchor(parent_anchor) @@ -1166,7 +1157,7 @@ def make_axes(parents, location=None, orientation=None, fraction=0.15, @docstring.Substitution(make_axes_kw_doc) -def make_axes_gridspec(parents, **kw): +def make_axes_gridspec(parent, **kw): ''' Resize and reposition a parent axes, and return a child axes suitable for a colorbar. This function is similar to @@ -1213,35 +1204,13 @@ def make_axes_gridspec(parents, **kw): pad_s = (1. - shrink) * 0.5 wh_ratios = [pad_s, shrink, pad_s] - # make parents a 1-d ndarray if its not already... - parents = np.atleast_1d(parents).ravel() - # get the appropriate subplot spec. Loop through the parents. - gs0 = parents[0].get_subplotspec().get_gridspec() - minind = 10000 - maxind = -10000 - for parent in parents: - gs = parent.get_subplotspec().get_gridspec() - if gs == gs0: - ss = parent.get_subplotspec().get_geometry() - if ss[2]maxind: - maxind = ss[3] - else: - pass - print(minind) - print(maxind) - subspec = gridspec.SubplotSpec(gs0,minind,maxind) - print(subspec) - print(subspec.get_geometry()) - gs_from_subplotspec = gridspec.GridSpecFromSubplotSpec if orientation == 'vertical': pad = kw.pop('pad', 0.05) wh_space = 2 * pad / (1 - pad) gs = gs_from_subplotspec(1, 2, - subplot_spec=subspec, + subplot_spec=parent.get_subplotspec(), wspace=wh_space, width_ratios=[x1 - pad, fraction] ) @@ -1251,8 +1220,6 @@ def make_axes_gridspec(parents, **kw): hspace=0., height_ratios=wh_ratios, ) - print(gs) - print(gs2) anchor = (0.0, 0.5) panchor = (1.0, 0.5) @@ -1261,7 +1228,7 @@ def make_axes_gridspec(parents, **kw): wh_space = 2 * pad / (1 - pad) gs = gs_from_subplotspec(2, 1, - subplot_spec=subspec, + subplot_spec=parent.get_subplotspec(), hspace=wh_space, height_ratios=[x1 - pad, fraction] ) @@ -1276,13 +1243,12 @@ def make_axes_gridspec(parents, **kw): anchor = (0.5, 1.0) panchor = (0.5, 0.0) - for parent in parents: - parent.set_subplotspec(gs[0]) - parent.update_params() - parent.set_position(parent.figbox) - parent.set_anchor(panchor) + parent.set_subplotspec(gs[0]) + parent.update_params() + parent.set_position(parent.figbox) + parent.set_anchor(panchor) - fig = parents[0].get_figure() + fig = parent.get_figure() cax = fig.add_subplot(gs2[1]) cax.set_aspect(aspect, anchor=anchor, adjustable='box') return cax, kw diff --git a/lib/matplotlib/figure.py b/lib/matplotlib/figure.py index 7034ea64c0d0..288ff450a25e 100644 --- a/lib/matplotlib/figure.py +++ b/lib/matplotlib/figure.py @@ -17,6 +17,7 @@ import six import warnings +from operator import itemgetter import numpy as np @@ -38,7 +39,6 @@ from matplotlib.axes import Axes, SubplotBase, subplot_class_factory from matplotlib.blocking_input import BlockingMouseInput, BlockingKeyMouseInput -from matplotlib.gridspec import GridSpec from matplotlib.legend import Legend from matplotlib.patches import Rectangle from matplotlib.projections import (get_projection_names, @@ -94,7 +94,7 @@ def get(self, key): return item[1] def _entry_from_axes(self, e): - ind, k = {a: (ind, k) for k, (ind, a) in self._elements}[e] + ind, k = dict([(a, (ind, k)) for (k, (ind, a)) in self._elements])[e] return (k, (ind, e)) def remove(self, a): @@ -118,18 +118,17 @@ def add(self, key, a): # All the error checking may be unnecessary; but this method # is called so seldom that the overhead is negligible. if not isinstance(a, Axes): - raise ValueError("second argument, {!r}, is not an Axes".format(a)) + raise ValueError("second argument, %s, is not an Axes" % a) try: hash(key) except TypeError: - raise ValueError( - "first argument, {!r}, is not a valid key".format(key)) + raise ValueError("first argument, %s, is not a valid key" % key) a_existing = self.get(key) if a_existing is not None: Stack.remove(self, (key, a_existing)) warnings.warn( - "key {!r} already existed; Axes is being replaced".format(key)) + "key %s already existed; Axes is being replaced" % key) # I don't think the above should ever happen. if a in self: @@ -324,11 +323,7 @@ def __init__(self, if frameon is None: frameon = rcParams['figure.frameon'] - if not np.isfinite(figsize).all(): - raise ValueError('figure size must be finite not ' - '{}'.format(figsize)) self.bbox_inches = Bbox.from_bounds(0, 0, *figsize) - self.dpi_scale_trans = Affine2D().scale(dpi, dpi) # do not use property as it will trigger self._dpi = dpi @@ -338,9 +333,12 @@ def __init__(self, self.transFigure = BboxTransformTo(self.bbox) - self.patch = Rectangle( + # the figurePatch name is deprecated + self.patch = self.figurePatch = Rectangle( xy=(0, 0), width=1, height=1, - facecolor=facecolor, edgecolor=edgecolor, linewidth=linewidth) + facecolor=facecolor, edgecolor=edgecolor, + linewidth=linewidth) + self._set_artist_props(self.patch) self.patch.set_aa(False) @@ -361,10 +359,6 @@ def __init__(self, self.clf() self._cachedRenderer = None - @cbook.deprecated("2.1", alternative="Figure.patch") - def figurePatch(self): - return self.patch - # TODO: I'd like to dynamically add the _repr_html_ method # to the figure in the right context, but then IPython doesn't # use it, for some reason. @@ -426,7 +420,7 @@ def _set_dpi(self, dpi): def get_tight_layout(self): """ - Return the Boolean flag, True to use :meth:`tight_layout` when drawing. + Return the Boolean flag, True to use :meth`tight_layout` when drawing. """ return self._tight @@ -447,7 +441,7 @@ def set_tight_layout(self, tight): self._tight_parameters = tight if isinstance(tight, dict) else {} self.stale = True - def autofmt_xdate(self, bottom=0.2, rotation=30, ha='right', which=None): + def autofmt_xdate(self, bottom=0.2, rotation=30, ha='right'): """ Date ticklabels often overlap, so it is useful to rotate them and right align them. Also, a common use case is a number of @@ -456,36 +450,30 @@ def autofmt_xdate(self, bottom=0.2, rotation=30, ha='right', which=None): bottom subplot and turn them off on other subplots, as well as turn off xlabels. - Parameters - ---------- - - bottom : scalar + *bottom* The bottom of the subplots for :meth:`subplots_adjust` - rotation : angle in degrees + *rotation* The rotation of the xtick labels - ha : string + *ha* The horizontal alignment of the xticklabels - - which : {None, 'major', 'minor', 'both'} - Selects which ticklabels to rotate (default is None which works - same as major) """ - allsubplots = all(hasattr(ax, 'is_last_row') for ax in self.axes) + allsubplots = np.alltrue([hasattr(ax, 'is_last_row') for ax + in self.axes]) if len(self.axes) == 1: - for label in self.axes[0].get_xticklabels(which=which): + for label in self.axes[0].get_xticklabels(): label.set_ha(ha) label.set_rotation(rotation) else: if allsubplots: for ax in self.get_axes(): if ax.is_last_row(): - for label in ax.get_xticklabels(which=which): + for label in ax.get_xticklabels(): label.set_ha(ha) label.set_rotation(rotation) else: - for label in ax.get_xticklabels(which=which): + for label in ax.get_xticklabels(): label.set_visible(False) ax.set_xlabel('') @@ -509,11 +497,13 @@ def contains(self, mouseevent): """ Test whether the mouse event occurred on the figure. - Returns True, {}. + Returns True,{} """ - if callable(self._contains): + if six.callable(self._contains): return self._contains(self, mouseevent) + # inside = mouseevent.x >= 0 and mouseevent.y >= 0 inside = self.bbox.contains(mouseevent.x, mouseevent.y) + return inside, {} def get_window_extent(self, *args, **kwargs): @@ -666,6 +656,9 @@ def figimage(self, X, An :class:`matplotlib.image.FigureImage` instance is returned. + .. plot:: mpl_examples/pylab_examples/figimage_demo.py + + Additional kwargs are Artist kwargs passed on to :class:`~matplotlib.image.FigureImage` """ @@ -714,9 +707,8 @@ def set_size_inches(self, w, h=None, forward=True): # argument, so unpack them if h is None: w, h = w - if not all(np.isfinite(_) for _ in (w, h)): - raise ValueError('figure size must be finite not ' - '({}, {})'.format(w, h)) + + dpival = self.dpi self.bbox_inches.p1 = w, h if forward: @@ -925,9 +917,6 @@ def add_axes(self, *args, **kwargs): raise ValueError(msg) else: rect = args[0] - if not np.isfinite(rect).all(): - raise ValueError('all entries in rect must be finite ' - 'not {}'.format(rect)) projection_class, kwargs, key = process_projection_requirements( self, *args, **kwargs) @@ -1038,130 +1027,6 @@ def add_subplot(self, *args, **kwargs): a.stale_callback = _stale_figure_callback return a - def subplots(self, nrows=1, ncols=1, sharex=False, sharey=False, - squeeze=True, subplot_kw=None, gridspec_kw=None): - """ - Add a set of subplots to this figure. - - Parameters - ---------- - nrows, ncols : int, default: 1 - Number of rows/cols of the subplot grid. - - sharex, sharey : bool or {'none', 'all', 'row', 'col'}, default: False - Controls sharing of properties among x (`sharex`) or y (`sharey`) - axes: - - - True or 'all': x- or y-axis will be shared among all - subplots. - - False or 'none': each subplot x- or y-axis will be - independent. - - 'row': each subplot row will share an x- or y-axis. - - 'col': each subplot column will share an x- or y-axis. - - When subplots have a shared x-axis along a column, only the x tick - labels of the bottom subplot are visible. Similarly, when - subplots have a shared y-axis along a row, only the y tick labels - of the first column subplot are visible. - - squeeze : bool, default: True - - If True, extra dimensions are squeezed out from the returned - axis object: - - - if only one subplot is constructed (nrows=ncols=1), the - resulting single Axes object is returned as a scalar. - - for Nx1 or 1xN subplots, the returned object is a 1D numpy - object array of Axes objects are returned as numpy 1D - arrays. - - for NxM, subplots with N>1 and M>1 are returned as a 2D - arrays. - - - If False, no squeezing at all is done: the returned Axes object - is always a 2D array containing Axes instances, even if it ends - up being 1x1. - - subplot_kw : dict, default: {} - Dict with keywords passed to the - :meth:`~matplotlib.figure.Figure.add_subplot` call used to create - each subplots. - - gridspec_kw : dict, default: {} - Dict with keywords passed to the - :class:`~matplotlib.gridspec.GridSpec` constructor used to create - the grid the subplots are placed on. - - Returns - ------- - ax : single Axes object or array of Axes objects - The added axes. The dimensions of the resulting array can be - controlled with the squeeze keyword, see above. - - See Also - -------- - pyplot.subplots : pyplot API; docstring includes examples. - """ - - # for backwards compatibility - if isinstance(sharex, bool): - sharex = "all" if sharex else "none" - if isinstance(sharey, bool): - sharey = "all" if sharey else "none" - share_values = ["all", "row", "col", "none"] - if sharex not in share_values: - # This check was added because it is very easy to type - # `subplots(1, 2, 1)` when `subplot(1, 2, 1)` was intended. - # In most cases, no error will ever occur, but mysterious behavior - # will result because what was intended to be the subplot index is - # instead treated as a bool for sharex. - if isinstance(sharex, int): - warnings.warn( - "sharex argument to subplots() was an integer. " - "Did you intend to use subplot() (without 's')?") - - raise ValueError("sharex [%s] must be one of %s" % - (sharex, share_values)) - if sharey not in share_values: - raise ValueError("sharey [%s] must be one of %s" % - (sharey, share_values)) - if subplot_kw is None: - subplot_kw = {} - if gridspec_kw is None: - gridspec_kw = {} - - gs = GridSpec(nrows, ncols, **gridspec_kw) - - # Create array to hold all axes. - axarr = np.empty((nrows, ncols), dtype=object) - for row in range(nrows): - for col in range(ncols): - shared_with = {"none": None, "all": axarr[0, 0], - "row": axarr[row, 0], "col": axarr[0, col]} - subplot_kw["sharex"] = shared_with[sharex] - subplot_kw["sharey"] = shared_with[sharey] - axarr[row, col] = self.add_subplot(gs[row, col], **subplot_kw) - - # turn off redundant tick labeling - if sharex in ["col", "all"]: - # turn off all but the bottom row - for ax in axarr[:-1, :].flat: - for label in ax.get_xticklabels(): - label.set_visible(False) - ax.xaxis.offsetText.set_visible(False) - if sharey in ["row", "all"]: - # turn off all but the first column - for ax in axarr[:, 1:].flat: - for label in ax.get_yticklabels(): - label.set_visible(False) - ax.yaxis.offsetText.set_visible(False) - - if squeeze: - # Discarding unneeded dimensions that equal 1. If we only have one - # subplot, just return it instead of a 1-element array. - return axarr.item() if axarr.size == 1 else axarr.squeeze() - else: - # Returned axis array will be always 2-d, even if nrows=ncols=1. - return axarr - def __remove_ax(self, ax): def _reset_loc_form(axis): axis.set_major_formatter(axis.get_major_formatter()) @@ -1217,11 +1082,11 @@ def clf(self, keep_observers=False): self._suptitle = None self.stale = True - def clear(self, keep_observers=False): + def clear(self): """ Clear the figure -- synonym for :meth:`clf`. """ - self.clf(keep_observers=keep_observers) + self.clf() @allow_rasterization def draw(self, renderer): @@ -1234,12 +1099,34 @@ def draw(self, renderer): if not self.get_visible(): return - artists = sorted( - (artist for artist in (self.patches + self.lines + self.artists - + self.images + self.axes + self.texts - + self.legends) - if not artist.get_animated()), - key=lambda artist: artist.get_zorder()) + # a list of (zorder, func_to_call, list_of_args) + dsu = [] + + for a in self.patches: + dsu.append((a.get_zorder(), a)) + + for a in self.lines: + dsu.append((a.get_zorder(), a)) + + for a in self.artists: + dsu.append((a.get_zorder(), a)) + + for a in self.images: + dsu.append((a.get_zorder(), a)) + + # render the axes + for a in self.axes: + dsu.append((a.get_zorder(), a)) + + # render the figure text + for a in self.texts: + dsu.append((a.get_zorder(), a)) + + for a in self.legends: + dsu.append((a.get_zorder(), a)) + + dsu = [row for row in dsu if not row[1].get_animated()] + dsu.sort(key=itemgetter(0)) try: renderer.open_group('figure') @@ -1254,7 +1141,7 @@ def draw(self, renderer): self.patch.draw(renderer) mimage._draw_list_compositing_images( - renderer, self, artists, self.suppressComposite) + renderer, self, dsu, self.suppressComposite) renderer.close_group('figure') finally: @@ -1277,214 +1164,127 @@ def draw_artist(self, a): def get_axes(self): return self.axes - def legend(self, *args, **kwargs): + def legend(self, handles, labels, *args, **kwargs): """ - Place a legend on the figure. - - To make a legend from existing artists on every axes:: - - legend() + Place a legend in the figure. Labels are a sequence of + strings, handles is a sequence of + :class:`~matplotlib.lines.Line2D` or + :class:`~matplotlib.patches.Patch` instances, and loc can be a + string or an integer specifying the legend location - To make a legend for a list of lines and labels:: + USAGE:: legend( (line1, line2, line3), ('label1', 'label2', 'label3'), 'upper right') - Parameters - ---------- - loc : string or integer - The location of the legend. Possible codes are: - - =============== ============= - Location String Location Code - =============== ============= - 'upper right' 1 - 'upper left' 2 - 'lower left' 3 - 'lower right' 4 - 'right' 5 - 'center left' 6 - 'center right' 7 - 'lower center' 8 - 'upper center' 9 - 'center' 10 - =============== ============= - - *loc* can also be an (x,y) tuple in figure coords, which specifies - the lower left of the legend box. In figure coords (0,0) is the - bottom left of the figure, and (1,1) is the top right. - - prop : None or FontProperties or dict - A :class:`matplotlib.font_manager.FontProperties` instance. If - *prop* is a dictionary, a new instance will be created with *prop*. - If *None*, use rc settings. - - numpoints : integer + The *loc* location codes are:: + + 'best' : 0, (currently not supported for figure legends) + 'upper right' : 1, + 'upper left' : 2, + 'lower left' : 3, + 'lower right' : 4, + 'right' : 5, + 'center left' : 6, + 'center right' : 7, + 'lower center' : 8, + 'upper center' : 9, + 'center' : 10, + + *loc* can also be an (x,y) tuple in figure coords, which + specifies the lower left of the legend box. figure coords are + (0,0) is the left, bottom of the figure and 1,1 is the right, + top. + + Keyword arguments: + + prop: [ *None* | FontProperties | dict ] + A :class:`matplotlib.font_manager.FontProperties` + instance. If *prop* is a dictionary, a new instance will be + created with *prop*. If *None*, use rc settings. + + numpoints: integer The number of points in the legend line, default is 4 - scatterpoints : integer + scatterpoints: integer The number of points in the legend line, default is 4 - scatteryoffsets : list of floats - A list of yoffsets for scatter symbols in legend + scatteryoffsets: list of floats + a list of yoffsets for scatter symbols in legend - markerscale : None or scalar + markerscale: [ *None* | scalar ] The relative size of legend markers vs. original. If *None*, use rc settings. - markerfirst : bool - If *True*, legend marker is placed to the left of the legend label. - If *False*, legend marker is placed to the right of the legend - label. - Default is *True*. + markerfirst: [ *True* | *False* ] + if *True*, legend marker is placed to the left of the legend label + if *False*, legend marker is placed to the right of the legend + label - frameon : None or bool + frameon: [ *None* | bool ] Control whether the legend should be drawn on a patch (frame). Default is *None* which will take the value from the ``legend.frameon`` :data:`rcParam`. - fancybox : None or bool - If *True*, draw a frame with a round fancybox. If *None*, use rc - settings. + fancybox: [ *None* | *False* | *True* ] + if *True*, draw a frame with a round fancybox. If *None*, use rc - shadow : None or bool + shadow: [ *None* | *False* | *True* ] If *True*, draw a shadow behind legend. If *None*, use rc settings. - framealpha : None or float + framealpha: [ *None* | float ] Control the alpha transparency of the legend's background. Default is *None* which will take the value from the ``legend.framealpha`` :data:`rcParam`. - facecolor : None or "inherit" or a color spec + facecolor: [ *None* | "inherit" | a color spec ] Control the legend's background color. Default is *None* which will take the value from the ``legend.facecolor`` :data:`rcParam`. If ``"inherit"``, it will take the ``axes.facecolor`` :data:`rcParam`. - edgecolor : None or "inherit" or a color spec + edgecolor: [ *None* | "inherit" | a color spec ] Control the legend's background patch edge color. Default is *None* which will take the value from the ``legend.edgecolor`` :data:`rcParam`. If ``"inherit"``, it will take the ``axes.edgecolor`` :data:`rcParam`. - ncol : integer - Number of columns. Default is 1. + ncol : integer + number of columns. default is 1 - mode : "expand" or None - If mode is "expand", the legend will be horizontally expanded + mode : [ "expand" | *None* ] + if mode is "expand", the legend will be horizontally expanded to fill the axes area (or *bbox_to_anchor*) - title : string - The legend title - - borderpad : float or None - The fractional whitespace inside the legend border, measured in - font-size units. - Default is *None* which will take the value from the - ``legend.borderpad`` :data:`rcParam`. - - labelspacing : float or None - The vertical space between the legend entries, measured in - font-size units. - Default is *None* which will take the value from the - ``legend.labelspacing`` :data:`rcParam`. - - handlelength : float or None - The length of the legend handles, measured in font-size units. - Default is *None* which will take the value from the - ``legend.handlelength`` :data:`rcParam`. + title : string + the legend title - handletextpad : float or None - The padding between the legend handle and text, measured in - font-size units. - Default is *None* which will take the value from the - ``legend.handletextpad`` :data:`rcParam`. + Padding and spacing between various elements use following keywords + parameters. The dimensions of these values are given as a fraction + of the fontsize. Values from rcParams will be used if None. - borderaxespad : float or None - The padding between the axes and legend border, measured in - font-size units. - Default is *None* which will take the value from the - ``legend.borderaxespad`` :data:`rcParam`. + ================ ==================================================== + Keyword Description + ================ ==================================================== + borderpad the fractional whitespace inside the legend border + labelspacing the vertical space between the legend entries + handlelength the length of the legend handles + handletextpad the pad between the legend handle and text + borderaxespad the pad between the axes and legend border + columnspacing the spacing between columns + ================ ==================================================== - columnspacing : float or None - The spacing between columns, measured in font-size units. - Default is *None* which will take the value from the - ``legend.columnspacing`` :data:`rcParam`. + .. Note:: Not all kinds of artist are supported by the legend. + See LINK (FIXME) for details. - Returns - ------- - :class:`matplotlib.legend.Legend` instance + **Example:** - Notes - ----- - Not all kinds of artist are supported by the legend command. See - :ref:`sphx_glr_tutorials_02_intermediate_legend_guide.py` for details. + .. plot:: mpl_examples/pylab_examples/figlegend_demo.py """ - - # If no arguments given, collect up all the artists on the figure - if len(args) == 0: - handles = [] - labels = [] - - def in_handles(h, l): - # Method to check if we already have a given handle and label. - # Consider two handles to be the same if they share a label, - # color, facecolor, and edgecolor. - - # Loop through each handle and label already collected - for f_h, f_l in zip(handles, labels): - if f_l != l: - continue - if type(f_h) != type(h): - continue - try: - if f_h.get_color() != h.get_color(): - continue - except AttributeError: - pass - try: - if f_h.get_facecolor() != h.get_facecolor(): - continue - except AttributeError: - pass - try: - if f_h.get_edgecolor() != h.get_edgecolor(): - continue - except AttributeError: - pass - return True - return False - - for ax in self.axes: - ax_handles, ax_labels = ax.get_legend_handles_labels() - for h, l in zip(ax_handles, ax_labels): - if not in_handles(h, l): - handles.append(h) - labels.append(l) - if len(handles) == 0: - warnings.warn("No labeled objects found. " - "Use label='...' kwarg on individual plots.") - return None - - elif len(args) == 2: - # LINES, LABELS - handles, labels = args - - elif len(args) == 3: - # LINES, LABELS, LOC - handles, labels, loc = args - kwargs['loc'] = loc - - else: - raise TypeError('Invalid number of arguments passed to legend. ' - 'Please specify either 0 args, 2 args ' - '(artist handles, figure labels) or 3 args ' - '(artist handles, figure labels, legend location)') - - l = Legend(self, handles, labels, **kwargs) + l = Legend(self, handles, labels, *args, **kwargs) self.legends.append(l) l._remove_method = lambda h: self.legends.remove(h) self.stale = True @@ -1564,10 +1364,6 @@ def gca(self, **kwargs): # continue and a new axes will be created if key == ckey and isinstance(cax, projection_class): return cax - else: - warnings.warn('Requested projection is different from ' - 'current axis projection, creating new axis ' - 'with requested projection.', stacklevel=2) # no axes found, so create one which spans the figure return self.add_subplot(1, 1, 1, **kwargs) @@ -1841,10 +1637,17 @@ def subplots_adjust(self, *args, **kwargs): def ginput(self, n=1, timeout=30, show_clicks=True, mouse_add=1, mouse_pop=3, mouse_stop=2): """ - Blocking call to interact with a figure. + Blocking call to interact with the figure. - Wait until the user clicks *n* times on the figure, and return the - coordinates of each click in a list. + This will wait for *n* clicks from the user and return a list of the + coordinates of each click. + + If *timeout* is zero or negative, does not timeout. + + If *n* is zero or negative, accumulate clicks until a middle click + (or potentially both mouse buttons at once) terminates the input. + + Right clicking cancels last input. The buttons used for the various actions (adding points, removing points, terminating the inputs) can be overriden via the @@ -1852,30 +1655,6 @@ def ginput(self, n=1, timeout=30, show_clicks=True, mouse_add=1, the associated mouse button: 1 for left, 2 for middle, 3 for right. - Parameters - ---------- - n : int, optional, default: 1 - Number of mouse clicks to accumulate. If negative, accumulate - clicks until the input is terminated manually. - timeout : scalar, optional, default: 30 - Number of seconds to wait before timing out. If zero or negative - will never timeout. - show_clicks : bool, optional, default: False - If True, show a red cross at the location of each click. - mouse_add : int, one of (1, 2, 3), optional, default: 1 (left click) - Mouse button used to add points. - mouse_pop : int, one of (1, 2, 3), optional, default: 3 (right click) - Mouse button used to remove the most recently added point. - mouse_stop : int, one of (1, 2, 3), optional, default: 2 (middle click) - Mouse button used to stop input. - - Returns - ------- - points : list of tuples - A list of the clicked (x, y) coordinates. - - Notes - ----- The keyboard can also be used to select points in case your mouse does not have one or more of the buttons. The delete and backspace keys act like right clicking (i.e., remove last point), the enter key From 89857c744894f7bddbb9d4c9884111bc629a5ad9 Mon Sep 17 00:00:00 2001 From: Jody Klymak Date: Mon, 12 Jun 2017 17:54:20 -0700 Subject: [PATCH 18/27] First pass; seems to work. More testing needed --- lib/matplotlib/colorbar.py | 41 ++++++++++++++++++++++++++++++-------- 1 file changed, 33 insertions(+), 8 deletions(-) diff --git a/lib/matplotlib/colorbar.py b/lib/matplotlib/colorbar.py index 415da55b0ebd..4082fa1ef0da 100644 --- a/lib/matplotlib/colorbar.py +++ b/lib/matplotlib/colorbar.py @@ -1157,7 +1157,7 @@ def make_axes(parents, location=None, orientation=None, fraction=0.15, @docstring.Substitution(make_axes_kw_doc) -def make_axes_gridspec(parent, **kw): +def make_axes_gridspec(parents, **kw): ''' Resize and reposition a parent axes, and return a child axes suitable for a colorbar. This function is similar to @@ -1204,13 +1204,35 @@ def make_axes_gridspec(parent, **kw): pad_s = (1. - shrink) * 0.5 wh_ratios = [pad_s, shrink, pad_s] + # make parents a 1-d ndarray if its not already... + parents = np.atleast_1d(parents).ravel() + # get the appropriate subplot spec. Loop through the parents. + gs0 = parents[0].get_subplotspec().get_gridspec() + minind = 10000 + maxind = -10000 + for parent in parents: + gs = parent.get_subplotspec().get_gridspec() + if gs == gs0: + ss = parent.get_subplotspec().get_geometry() + if ss[2]maxind: + maxind = ss[3] + else: + pass + print(minind) + print(maxind) + subspec = gridspec.SubplotSpec(gs0,minind,maxind) + print(subspec) + print(subspec.get_geometry()) + gs_from_subplotspec = gridspec.GridSpecFromSubplotSpec if orientation == 'vertical': pad = kw.pop('pad', 0.05) wh_space = 2 * pad / (1 - pad) gs = gs_from_subplotspec(1, 2, - subplot_spec=parent.get_subplotspec(), + subplot_spec=subspec, wspace=wh_space, width_ratios=[x1 - pad, fraction] ) @@ -1220,6 +1242,8 @@ def make_axes_gridspec(parent, **kw): hspace=0., height_ratios=wh_ratios, ) + print(gs) + print(gs2) anchor = (0.0, 0.5) panchor = (1.0, 0.5) @@ -1228,7 +1252,7 @@ def make_axes_gridspec(parent, **kw): wh_space = 2 * pad / (1 - pad) gs = gs_from_subplotspec(2, 1, - subplot_spec=parent.get_subplotspec(), + subplot_spec=subspec, hspace=wh_space, height_ratios=[x1 - pad, fraction] ) @@ -1243,12 +1267,13 @@ def make_axes_gridspec(parent, **kw): anchor = (0.5, 1.0) panchor = (0.5, 0.0) - parent.set_subplotspec(gs[0]) - parent.update_params() - parent.set_position(parent.figbox) - parent.set_anchor(panchor) + for parent in parents: + parent.set_subplotspec(gs[0]) + parent.update_params() + parent.set_position(parent.figbox) + parent.set_anchor(panchor) - fig = parent.get_figure() + fig = parents[0].get_figure() cax = fig.add_subplot(gs2[1]) cax.set_aspect(aspect, anchor=anchor, adjustable='box') return cax, kw From c68a41153b06a7c4393aee7a9532808a50549012 Mon Sep 17 00:00:00 2001 From: Jody Klymak Date: Mon, 12 Jun 2017 17:55:03 -0700 Subject: [PATCH 19/27] First pass; seems to work. More testing needed --- lib/matplotlib/colorbar.py | 41 ++++++++------------------------------ 1 file changed, 8 insertions(+), 33 deletions(-) diff --git a/lib/matplotlib/colorbar.py b/lib/matplotlib/colorbar.py index 4082fa1ef0da..415da55b0ebd 100644 --- a/lib/matplotlib/colorbar.py +++ b/lib/matplotlib/colorbar.py @@ -1157,7 +1157,7 @@ def make_axes(parents, location=None, orientation=None, fraction=0.15, @docstring.Substitution(make_axes_kw_doc) -def make_axes_gridspec(parents, **kw): +def make_axes_gridspec(parent, **kw): ''' Resize and reposition a parent axes, and return a child axes suitable for a colorbar. This function is similar to @@ -1204,35 +1204,13 @@ def make_axes_gridspec(parents, **kw): pad_s = (1. - shrink) * 0.5 wh_ratios = [pad_s, shrink, pad_s] - # make parents a 1-d ndarray if its not already... - parents = np.atleast_1d(parents).ravel() - # get the appropriate subplot spec. Loop through the parents. - gs0 = parents[0].get_subplotspec().get_gridspec() - minind = 10000 - maxind = -10000 - for parent in parents: - gs = parent.get_subplotspec().get_gridspec() - if gs == gs0: - ss = parent.get_subplotspec().get_geometry() - if ss[2]maxind: - maxind = ss[3] - else: - pass - print(minind) - print(maxind) - subspec = gridspec.SubplotSpec(gs0,minind,maxind) - print(subspec) - print(subspec.get_geometry()) - gs_from_subplotspec = gridspec.GridSpecFromSubplotSpec if orientation == 'vertical': pad = kw.pop('pad', 0.05) wh_space = 2 * pad / (1 - pad) gs = gs_from_subplotspec(1, 2, - subplot_spec=subspec, + subplot_spec=parent.get_subplotspec(), wspace=wh_space, width_ratios=[x1 - pad, fraction] ) @@ -1242,8 +1220,6 @@ def make_axes_gridspec(parents, **kw): hspace=0., height_ratios=wh_ratios, ) - print(gs) - print(gs2) anchor = (0.0, 0.5) panchor = (1.0, 0.5) @@ -1252,7 +1228,7 @@ def make_axes_gridspec(parents, **kw): wh_space = 2 * pad / (1 - pad) gs = gs_from_subplotspec(2, 1, - subplot_spec=subspec, + subplot_spec=parent.get_subplotspec(), hspace=wh_space, height_ratios=[x1 - pad, fraction] ) @@ -1267,13 +1243,12 @@ def make_axes_gridspec(parents, **kw): anchor = (0.5, 1.0) panchor = (0.5, 0.0) - for parent in parents: - parent.set_subplotspec(gs[0]) - parent.update_params() - parent.set_position(parent.figbox) - parent.set_anchor(panchor) + parent.set_subplotspec(gs[0]) + parent.update_params() + parent.set_position(parent.figbox) + parent.set_anchor(panchor) - fig = parents[0].get_figure() + fig = parent.get_figure() cax = fig.add_subplot(gs2[1]) cax.set_aspect(aspect, anchor=anchor, adjustable='box') return cax, kw From 031d3565f29d81c54e9ab7e174e33fce4dacf093 Mon Sep 17 00:00:00 2001 From: Jody Klymak Date: Mon, 12 Jun 2017 20:43:40 -0700 Subject: [PATCH 20/27] First change --- lib/matplotlib/colorbar.py | 117 +++++++-- lib/matplotlib/figure.py | 511 ++++++++++++++++++++++++++----------- 2 files changed, 464 insertions(+), 164 deletions(-) diff --git a/lib/matplotlib/colorbar.py b/lib/matplotlib/colorbar.py index 415da55b0ebd..7c831678cc93 100644 --- a/lib/matplotlib/colorbar.py +++ b/lib/matplotlib/colorbar.py @@ -39,7 +39,7 @@ import matplotlib.patches as mpatches import matplotlib.path as mpath import matplotlib.ticker as ticker -import matplotlib.transforms as mtrans +import matplotlib.transforms as mtransforms from matplotlib import docstring @@ -317,7 +317,7 @@ def __init__(self, ax, cmap=None, linthresh=self.norm.linthresh) else: self.formatter = ticker.ScalarFormatter() - elif cbook.is_string_like(format): + elif isinstance(format, six.string_types): self.formatter = ticker.FormatStrFormatter(format) else: self.formatter = format # Assume it is a Formatter @@ -344,6 +344,7 @@ def draw_all(self): Calculate any free parameters based on the current cmap and norm, and do all the drawing. ''' + self._process_values() self._find_range() X, Y = self._mesh() @@ -399,6 +400,10 @@ def set_ticks(self, ticks, update_ticks=True): self.update_ticks() self.stale = True + def get_ticks(self, minor=False): + """Return the x ticks as a list of locations""" + return self._tick_data_values + def set_ticklabels(self, ticklabels, update_ticks=True): """ set tick labels. Tick labels are updated immediately unless @@ -611,6 +616,7 @@ def _ticker(self): else: eps = (intv[1] - intv[0]) * 1e-10 b = b[(b <= intv[1] + eps) & (b >= intv[0] - eps)] + self._tick_data_values = b ticks = self._locate(b) formatter.set_locs(b) ticklabels = [formatter(t, i) for i, t in enumerate(b)] @@ -681,9 +687,10 @@ def _process_values(self, b=None): self.norm.vmin = 0 self.norm.vmax = 1 - self.norm.vmin, self.norm.vmax = mtrans.nonsingular(self.norm.vmin, - self.norm.vmax, - expander=0.1) + self.norm.vmin, self.norm.vmax = mtransforms.nonsingular( + self.norm.vmin, + self.norm.vmax, + expander=0.1) b = self.norm.inverse(self._uniform_y(self.cmap.N + 1)) @@ -1110,8 +1117,10 @@ def make_axes(parents, location=None, orientation=None, fraction=0.15, parent_anchor = kw.pop('panchor', loc_settings['panchor']) pad = kw.pop('pad', loc_settings['pad']) - # turn parents into a list if it is not already - parents = np.atleast_1d(parents).ravel().tolist() + # turn parents into a list if it is not already. We do this w/ np + # because `plt.subplots` can return an ndarray and is natural to + # pass to `colorbar`. + parents = np.atleast_1d(parents).ravel() fig = parents[0].get_figure() if not all(fig is ax.get_figure() for ax in parents): @@ -1119,8 +1128,8 @@ def make_axes(parents, location=None, orientation=None, fraction=0.15, 'parents share the same figure.') # take a bounding box around all of the given axes - parents_bbox = mtrans.Bbox.union([ax.get_position(original=True).frozen() - for ax in parents]) + parents_bbox = mtransforms.Bbox.union( + [ax.get_position(original=True).frozen() for ax in parents]) pb = parents_bbox if location in ('left', 'right'): @@ -1141,12 +1150,12 @@ def make_axes(parents, location=None, orientation=None, fraction=0.15, # define a transform which takes us from old axes coordinates to # new axes coordinates - shrinking_trans = mtrans.BboxTransform(parents_bbox, pb1) + shrinking_trans = mtransforms.BboxTransform(parents_bbox, pb1) # transform each of the axes in parents using the new transform for ax in parents: new_posn = shrinking_trans.transform(ax.get_position()) - new_posn = mtrans.Bbox(new_posn) + new_posn = mtransforms.Bbox(new_posn) ax.set_position(new_posn) if parent_anchor is not False: ax.set_anchor(parent_anchor) @@ -1155,9 +1164,18 @@ def make_axes(parents, location=None, orientation=None, fraction=0.15, cax.set_aspect(aspect, anchor=anchor, adjustable='box') return cax, kw +# helper functions for row,col to index. +def index2rowcolunm(index,ncols): + col = index%ncols + 1 + row = int(np.floor(index/ncols)+1) + return row,col +def rowcolunm2index(row,col,ncols): + index = col-1+(row-1)*ncols + return index + @docstring.Substitution(make_axes_kw_doc) -def make_axes_gridspec(parent, **kw): +def make_axes_gridspec(parents, **kw): ''' Resize and reposition a parent axes, and return a child axes suitable for a colorbar. This function is similar to @@ -1204,13 +1222,52 @@ def make_axes_gridspec(parent, **kw): pad_s = (1. - shrink) * 0.5 wh_ratios = [pad_s, shrink, pad_s] + # make parents a 1-d ndarray if its not already... + parents = np.atleast_1d(parents).ravel() + # get the appropriate subplot spec. Loop through the parents. + gsp0 = parents[0].get_subplotspec().get_gridspec() + minind = 10000 + maxind = -10000 + for parent in parents: + gsp = parent.get_subplotspec().get_gridspec() + if gsp == gsp0: + ss = parent.get_subplotspec().get_geometry() + print(ss) + if ss[2]maxind: + maxind = ss[3] + else: + pass + # get from maxind and minind to nrows and ncols.. + ncols0 = gsp0.get_geometry()[1] + print(ncols0) + print(maxind) + + minrow,mincol=index2rowcolunm(minind,ncols0) + maxrow,maxcol=index2rowcolunm(maxind,ncols0) + print('mnind %d maxind %d'%(minind,maxind)) + print('mncol %d maxcol %d'%(mincol,maxcol)) + print('mnrow %d maxrow %d'%(minrow,maxrow)) + nrows = maxrow-minrow+1 + ncols = maxcol-mincol+1 + + print('nrows %d ncols %d'%(nrows,ncols)) + print(minind) + print(maxind) + subspec = gridspec.SubplotSpec(gsp0,minind,maxind) + print('GSP0') + print(gsp0.get_geometry()) + print(subspec) + print(subspec.get_geometry()) + gs_from_subplotspec = gridspec.GridSpecFromSubplotSpec if orientation == 'vertical': pad = kw.pop('pad', 0.05) wh_space = 2 * pad / (1 - pad) gs = gs_from_subplotspec(1, 2, - subplot_spec=parent.get_subplotspec(), + subplot_spec=subspec, wspace=wh_space, width_ratios=[x1 - pad, fraction] ) @@ -1220,6 +1277,8 @@ def make_axes_gridspec(parent, **kw): hspace=0., height_ratios=wh_ratios, ) + print(gs) + print(gs2) anchor = (0.0, 0.5) panchor = (1.0, 0.5) @@ -1228,7 +1287,7 @@ def make_axes_gridspec(parent, **kw): wh_space = 2 * pad / (1 - pad) gs = gs_from_subplotspec(2, 1, - subplot_spec=parent.get_subplotspec(), + subplot_spec=subspec, hspace=wh_space, height_ratios=[x1 - pad, fraction] ) @@ -1243,12 +1302,32 @@ def make_axes_gridspec(parent, **kw): anchor = (0.5, 1.0) panchor = (0.5, 0.0) - parent.set_subplotspec(gs[0]) - parent.update_params() - parent.set_position(parent.figbox) - parent.set_anchor(panchor) + # we need to repackage the parent axes into gs. + # We need to know where they are in the new gs. + # the new gs has nrows by ncols. + gsnew = gs_from_subplotspec(nrows, ncols, subplot_spec=gs[0]) + + for parent in parents: + geo=parent.get_subplotspec().get_geometry() + ncol0 = geo[1] + print("Parent Geo:") + print(geo) + oldrow,oldcol = index2rowcolunm(geo[2],ncol0) + newrow = oldrow-minrow+1 + newcol = oldcol-mincol+1 + newminind = rowcolunm2index(newrow,newcol,ncols) + oldrow,oldcol = index2rowcolunm(geo[3],ncol0) + newrow = oldrow-minrow+1 + newcol = oldcol-mincol+1 + newmaxind = rowcolunm2index(newrow,newcol,ncols) + print('newminind %d newmaxind %d'%(newminind,newmaxind)) + + parent.set_subplotspec(gridspec.SubplotSpec(gsnew,newminind,newmaxind)) + parent.update_params() + parent.set_position(parent.figbox) + parent.set_anchor(panchor) - fig = parent.get_figure() + fig = parents[0].get_figure() cax = fig.add_subplot(gs2[1]) cax.set_aspect(aspect, anchor=anchor, adjustable='box') return cax, kw diff --git a/lib/matplotlib/figure.py b/lib/matplotlib/figure.py index 288ff450a25e..1cb952b3d322 100644 --- a/lib/matplotlib/figure.py +++ b/lib/matplotlib/figure.py @@ -17,7 +17,6 @@ import six import warnings -from operator import itemgetter import numpy as np @@ -39,6 +38,7 @@ from matplotlib.axes import Axes, SubplotBase, subplot_class_factory from matplotlib.blocking_input import BlockingMouseInput, BlockingKeyMouseInput +from matplotlib.gridspec import GridSpec from matplotlib.legend import Legend from matplotlib.patches import Rectangle from matplotlib.projections import (get_projection_names, @@ -94,7 +94,7 @@ def get(self, key): return item[1] def _entry_from_axes(self, e): - ind, k = dict([(a, (ind, k)) for (k, (ind, a)) in self._elements])[e] + ind, k = {a: (ind, k) for k, (ind, a) in self._elements}[e] return (k, (ind, e)) def remove(self, a): @@ -118,17 +118,18 @@ def add(self, key, a): # All the error checking may be unnecessary; but this method # is called so seldom that the overhead is negligible. if not isinstance(a, Axes): - raise ValueError("second argument, %s, is not an Axes" % a) + raise ValueError("second argument, {!r}, is not an Axes".format(a)) try: hash(key) except TypeError: - raise ValueError("first argument, %s, is not a valid key" % key) + raise ValueError( + "first argument, {!r}, is not a valid key".format(key)) a_existing = self.get(key) if a_existing is not None: Stack.remove(self, (key, a_existing)) warnings.warn( - "key %s already existed; Axes is being replaced" % key) + "key {!r} already existed; Axes is being replaced".format(key)) # I don't think the above should ever happen. if a in self: @@ -323,7 +324,11 @@ def __init__(self, if frameon is None: frameon = rcParams['figure.frameon'] + if not np.isfinite(figsize).all(): + raise ValueError('figure size must be finite not ' + '{}'.format(figsize)) self.bbox_inches = Bbox.from_bounds(0, 0, *figsize) + self.dpi_scale_trans = Affine2D().scale(dpi, dpi) # do not use property as it will trigger self._dpi = dpi @@ -333,12 +338,9 @@ def __init__(self, self.transFigure = BboxTransformTo(self.bbox) - # the figurePatch name is deprecated - self.patch = self.figurePatch = Rectangle( + self.patch = Rectangle( xy=(0, 0), width=1, height=1, - facecolor=facecolor, edgecolor=edgecolor, - linewidth=linewidth) - + facecolor=facecolor, edgecolor=edgecolor, linewidth=linewidth) self._set_artist_props(self.patch) self.patch.set_aa(False) @@ -359,6 +361,10 @@ def __init__(self, self.clf() self._cachedRenderer = None + @cbook.deprecated("2.1", alternative="Figure.patch") + def figurePatch(self): + return self.patch + # TODO: I'd like to dynamically add the _repr_html_ method # to the figure in the right context, but then IPython doesn't # use it, for some reason. @@ -420,7 +426,7 @@ def _set_dpi(self, dpi): def get_tight_layout(self): """ - Return the Boolean flag, True to use :meth`tight_layout` when drawing. + Return the Boolean flag, True to use :meth:`tight_layout` when drawing. """ return self._tight @@ -441,7 +447,7 @@ def set_tight_layout(self, tight): self._tight_parameters = tight if isinstance(tight, dict) else {} self.stale = True - def autofmt_xdate(self, bottom=0.2, rotation=30, ha='right'): + def autofmt_xdate(self, bottom=0.2, rotation=30, ha='right', which=None): """ Date ticklabels often overlap, so it is useful to rotate them and right align them. Also, a common use case is a number of @@ -450,30 +456,36 @@ def autofmt_xdate(self, bottom=0.2, rotation=30, ha='right'): bottom subplot and turn them off on other subplots, as well as turn off xlabels. - *bottom* + Parameters + ---------- + + bottom : scalar The bottom of the subplots for :meth:`subplots_adjust` - *rotation* + rotation : angle in degrees The rotation of the xtick labels - *ha* + ha : string The horizontal alignment of the xticklabels + + which : {None, 'major', 'minor', 'both'} + Selects which ticklabels to rotate (default is None which works + same as major) """ - allsubplots = np.alltrue([hasattr(ax, 'is_last_row') for ax - in self.axes]) + allsubplots = all(hasattr(ax, 'is_last_row') for ax in self.axes) if len(self.axes) == 1: - for label in self.axes[0].get_xticklabels(): + for label in self.axes[0].get_xticklabels(which=which): label.set_ha(ha) label.set_rotation(rotation) else: if allsubplots: for ax in self.get_axes(): if ax.is_last_row(): - for label in ax.get_xticklabels(): + for label in ax.get_xticklabels(which=which): label.set_ha(ha) label.set_rotation(rotation) else: - for label in ax.get_xticklabels(): + for label in ax.get_xticklabels(which=which): label.set_visible(False) ax.set_xlabel('') @@ -497,13 +509,11 @@ def contains(self, mouseevent): """ Test whether the mouse event occurred on the figure. - Returns True,{} + Returns True, {}. """ - if six.callable(self._contains): + if callable(self._contains): return self._contains(self, mouseevent) - # inside = mouseevent.x >= 0 and mouseevent.y >= 0 inside = self.bbox.contains(mouseevent.x, mouseevent.y) - return inside, {} def get_window_extent(self, *args, **kwargs): @@ -656,9 +666,6 @@ def figimage(self, X, An :class:`matplotlib.image.FigureImage` instance is returned. - .. plot:: mpl_examples/pylab_examples/figimage_demo.py - - Additional kwargs are Artist kwargs passed on to :class:`~matplotlib.image.FigureImage` """ @@ -707,8 +714,9 @@ def set_size_inches(self, w, h=None, forward=True): # argument, so unpack them if h is None: w, h = w - - dpival = self.dpi + if not all(np.isfinite(_) for _ in (w, h)): + raise ValueError('figure size must be finite not ' + '({}, {})'.format(w, h)) self.bbox_inches.p1 = w, h if forward: @@ -917,6 +925,9 @@ def add_axes(self, *args, **kwargs): raise ValueError(msg) else: rect = args[0] + if not np.isfinite(rect).all(): + raise ValueError('all entries in rect must be finite ' + 'not {}'.format(rect)) projection_class, kwargs, key = process_projection_requirements( self, *args, **kwargs) @@ -1027,6 +1038,130 @@ def add_subplot(self, *args, **kwargs): a.stale_callback = _stale_figure_callback return a + def subplots(self, nrows=1, ncols=1, sharex=False, sharey=False, + squeeze=True, subplot_kw=None, gridspec_kw=None): + """ + Add a set of subplots to this figure. + + Parameters + ---------- + nrows, ncols : int, default: 1 + Number of rows/cols of the subplot grid. + + sharex, sharey : bool or {'none', 'all', 'row', 'col'}, default: False + Controls sharing of properties among x (`sharex`) or y (`sharey`) + axes: + + - True or 'all': x- or y-axis will be shared among all + subplots. + - False or 'none': each subplot x- or y-axis will be + independent. + - 'row': each subplot row will share an x- or y-axis. + - 'col': each subplot column will share an x- or y-axis. + + When subplots have a shared x-axis along a column, only the x tick + labels of the bottom subplot are visible. Similarly, when + subplots have a shared y-axis along a row, only the y tick labels + of the first column subplot are visible. + + squeeze : bool, default: True + - If True, extra dimensions are squeezed out from the returned + axis object: + + - if only one subplot is constructed (nrows=ncols=1), the + resulting single Axes object is returned as a scalar. + - for Nx1 or 1xN subplots, the returned object is a 1D numpy + object array of Axes objects are returned as numpy 1D + arrays. + - for NxM, subplots with N>1 and M>1 are returned as a 2D + arrays. + + - If False, no squeezing at all is done: the returned Axes object + is always a 2D array containing Axes instances, even if it ends + up being 1x1. + + subplot_kw : dict, default: {} + Dict with keywords passed to the + :meth:`~matplotlib.figure.Figure.add_subplot` call used to create + each subplots. + + gridspec_kw : dict, default: {} + Dict with keywords passed to the + :class:`~matplotlib.gridspec.GridSpec` constructor used to create + the grid the subplots are placed on. + + Returns + ------- + ax : single Axes object or array of Axes objects + The added axes. The dimensions of the resulting array can be + controlled with the squeeze keyword, see above. + + See Also + -------- + pyplot.subplots : pyplot API; docstring includes examples. + """ + + # for backwards compatibility + if isinstance(sharex, bool): + sharex = "all" if sharex else "none" + if isinstance(sharey, bool): + sharey = "all" if sharey else "none" + share_values = ["all", "row", "col", "none"] + if sharex not in share_values: + # This check was added because it is very easy to type + # `subplots(1, 2, 1)` when `subplot(1, 2, 1)` was intended. + # In most cases, no error will ever occur, but mysterious behavior + # will result because what was intended to be the subplot index is + # instead treated as a bool for sharex. + if isinstance(sharex, int): + warnings.warn( + "sharex argument to subplots() was an integer. " + "Did you intend to use subplot() (without 's')?") + + raise ValueError("sharex [%s] must be one of %s" % + (sharex, share_values)) + if sharey not in share_values: + raise ValueError("sharey [%s] must be one of %s" % + (sharey, share_values)) + if subplot_kw is None: + subplot_kw = {} + if gridspec_kw is None: + gridspec_kw = {} + + gs = GridSpec(nrows, ncols, **gridspec_kw) + + # Create array to hold all axes. + axarr = np.empty((nrows, ncols), dtype=object) + for row in range(nrows): + for col in range(ncols): + shared_with = {"none": None, "all": axarr[0, 0], + "row": axarr[row, 0], "col": axarr[0, col]} + subplot_kw["sharex"] = shared_with[sharex] + subplot_kw["sharey"] = shared_with[sharey] + axarr[row, col] = self.add_subplot(gs[row, col], **subplot_kw) + + # turn off redundant tick labeling + if sharex in ["col", "all"]: + # turn off all but the bottom row + for ax in axarr[:-1, :].flat: + for label in ax.get_xticklabels(): + label.set_visible(False) + ax.xaxis.offsetText.set_visible(False) + if sharey in ["row", "all"]: + # turn off all but the first column + for ax in axarr[:, 1:].flat: + for label in ax.get_yticklabels(): + label.set_visible(False) + ax.yaxis.offsetText.set_visible(False) + + if squeeze: + # Discarding unneeded dimensions that equal 1. If we only have one + # subplot, just return it instead of a 1-element array. + return axarr.item() if axarr.size == 1 else axarr.squeeze() + else: + # Returned axis array will be always 2-d, even if nrows=ncols=1. + return axarr + def __remove_ax(self, ax): def _reset_loc_form(axis): axis.set_major_formatter(axis.get_major_formatter()) @@ -1082,11 +1217,11 @@ def clf(self, keep_observers=False): self._suptitle = None self.stale = True - def clear(self): + def clear(self, keep_observers=False): """ Clear the figure -- synonym for :meth:`clf`. """ - self.clf() + self.clf(keep_observers=keep_observers) @allow_rasterization def draw(self, renderer): @@ -1099,34 +1234,12 @@ def draw(self, renderer): if not self.get_visible(): return - # a list of (zorder, func_to_call, list_of_args) - dsu = [] - - for a in self.patches: - dsu.append((a.get_zorder(), a)) - - for a in self.lines: - dsu.append((a.get_zorder(), a)) - - for a in self.artists: - dsu.append((a.get_zorder(), a)) - - for a in self.images: - dsu.append((a.get_zorder(), a)) - - # render the axes - for a in self.axes: - dsu.append((a.get_zorder(), a)) - - # render the figure text - for a in self.texts: - dsu.append((a.get_zorder(), a)) - - for a in self.legends: - dsu.append((a.get_zorder(), a)) - - dsu = [row for row in dsu if not row[1].get_animated()] - dsu.sort(key=itemgetter(0)) + artists = sorted( + (artist for artist in (self.patches + self.lines + self.artists + + self.images + self.axes + self.texts + + self.legends) + if not artist.get_animated()), + key=lambda artist: artist.get_zorder()) try: renderer.open_group('figure') @@ -1141,7 +1254,7 @@ def draw(self, renderer): self.patch.draw(renderer) mimage._draw_list_compositing_images( - renderer, self, dsu, self.suppressComposite) + renderer, self, artists, self.suppressComposite) renderer.close_group('figure') finally: @@ -1164,127 +1277,214 @@ def draw_artist(self, a): def get_axes(self): return self.axes - def legend(self, handles, labels, *args, **kwargs): + def legend(self, *args, **kwargs): """ - Place a legend in the figure. Labels are a sequence of - strings, handles is a sequence of - :class:`~matplotlib.lines.Line2D` or - :class:`~matplotlib.patches.Patch` instances, and loc can be a - string or an integer specifying the legend location + Place a legend on the figure. + + To make a legend from existing artists on every axes:: + + legend() - USAGE:: + To make a legend for a list of lines and labels:: legend( (line1, line2, line3), ('label1', 'label2', 'label3'), 'upper right') - The *loc* location codes are:: - - 'best' : 0, (currently not supported for figure legends) - 'upper right' : 1, - 'upper left' : 2, - 'lower left' : 3, - 'lower right' : 4, - 'right' : 5, - 'center left' : 6, - 'center right' : 7, - 'lower center' : 8, - 'upper center' : 9, - 'center' : 10, - - *loc* can also be an (x,y) tuple in figure coords, which - specifies the lower left of the legend box. figure coords are - (0,0) is the left, bottom of the figure and 1,1 is the right, - top. - - Keyword arguments: - - prop: [ *None* | FontProperties | dict ] - A :class:`matplotlib.font_manager.FontProperties` - instance. If *prop* is a dictionary, a new instance will be - created with *prop*. If *None*, use rc settings. - - numpoints: integer + Parameters + ---------- + loc : string or integer + The location of the legend. Possible codes are: + + =============== ============= + Location String Location Code + =============== ============= + 'upper right' 1 + 'upper left' 2 + 'lower left' 3 + 'lower right' 4 + 'right' 5 + 'center left' 6 + 'center right' 7 + 'lower center' 8 + 'upper center' 9 + 'center' 10 + =============== ============= + + *loc* can also be an (x,y) tuple in figure coords, which specifies + the lower left of the legend box. In figure coords (0,0) is the + bottom left of the figure, and (1,1) is the top right. + + prop : None or FontProperties or dict + A :class:`matplotlib.font_manager.FontProperties` instance. If + *prop* is a dictionary, a new instance will be created with *prop*. + If *None*, use rc settings. + + numpoints : integer The number of points in the legend line, default is 4 - scatterpoints: integer + scatterpoints : integer The number of points in the legend line, default is 4 - scatteryoffsets: list of floats - a list of yoffsets for scatter symbols in legend + scatteryoffsets : list of floats + A list of yoffsets for scatter symbols in legend - markerscale: [ *None* | scalar ] + markerscale : None or scalar The relative size of legend markers vs. original. If *None*, use rc settings. - markerfirst: [ *True* | *False* ] - if *True*, legend marker is placed to the left of the legend label - if *False*, legend marker is placed to the right of the legend - label + markerfirst : bool + If *True*, legend marker is placed to the left of the legend label. + If *False*, legend marker is placed to the right of the legend + label. + Default is *True*. - frameon: [ *None* | bool ] + frameon : None or bool Control whether the legend should be drawn on a patch (frame). Default is *None* which will take the value from the ``legend.frameon`` :data:`rcParam`. - fancybox: [ *None* | *False* | *True* ] - if *True*, draw a frame with a round fancybox. If *None*, use rc + fancybox : None or bool + If *True*, draw a frame with a round fancybox. If *None*, use rc + settings. - shadow: [ *None* | *False* | *True* ] + shadow : None or bool If *True*, draw a shadow behind legend. If *None*, use rc settings. - framealpha: [ *None* | float ] + framealpha : None or float Control the alpha transparency of the legend's background. Default is *None* which will take the value from the ``legend.framealpha`` :data:`rcParam`. - facecolor: [ *None* | "inherit" | a color spec ] + facecolor : None or "inherit" or a color spec Control the legend's background color. Default is *None* which will take the value from the ``legend.facecolor`` :data:`rcParam`. If ``"inherit"``, it will take the ``axes.facecolor`` :data:`rcParam`. - edgecolor: [ *None* | "inherit" | a color spec ] + edgecolor : None or "inherit" or a color spec Control the legend's background patch edge color. Default is *None* which will take the value from the ``legend.edgecolor`` :data:`rcParam`. If ``"inherit"``, it will take the ``axes.edgecolor`` :data:`rcParam`. - ncol : integer - number of columns. default is 1 + ncol : integer + Number of columns. Default is 1. - mode : [ "expand" | *None* ] - if mode is "expand", the legend will be horizontally expanded + mode : "expand" or None + If mode is "expand", the legend will be horizontally expanded to fill the axes area (or *bbox_to_anchor*) - title : string - the legend title + title : string + The legend title + + borderpad : float or None + The fractional whitespace inside the legend border, measured in + font-size units. + Default is *None* which will take the value from the + ``legend.borderpad`` :data:`rcParam`. + + labelspacing : float or None + The vertical space between the legend entries, measured in + font-size units. + Default is *None* which will take the value from the + ``legend.labelspacing`` :data:`rcParam`. + + handlelength : float or None + The length of the legend handles, measured in font-size units. + Default is *None* which will take the value from the + ``legend.handlelength`` :data:`rcParam`. - Padding and spacing between various elements use following keywords - parameters. The dimensions of these values are given as a fraction - of the fontsize. Values from rcParams will be used if None. + handletextpad : float or None + The padding between the legend handle and text, measured in + font-size units. + Default is *None* which will take the value from the + ``legend.handletextpad`` :data:`rcParam`. - ================ ==================================================== - Keyword Description - ================ ==================================================== - borderpad the fractional whitespace inside the legend border - labelspacing the vertical space between the legend entries - handlelength the length of the legend handles - handletextpad the pad between the legend handle and text - borderaxespad the pad between the axes and legend border - columnspacing the spacing between columns - ================ ==================================================== + borderaxespad : float or None + The padding between the axes and legend border, measured in + font-size units. + Default is *None* which will take the value from the + ``legend.borderaxespad`` :data:`rcParam`. - .. Note:: Not all kinds of artist are supported by the legend. - See LINK (FIXME) for details. + columnspacing : float or None + The spacing between columns, measured in font-size units. + Default is *None* which will take the value from the + ``legend.columnspacing`` :data:`rcParam`. - **Example:** + Returns + ------- + :class:`matplotlib.legend.Legend` instance - .. plot:: mpl_examples/pylab_examples/figlegend_demo.py + Notes + ----- + Not all kinds of artist are supported by the legend command. See + :ref:`sphx_glr_tutorials_02_intermediate_legend_guide.py` for details. """ - l = Legend(self, handles, labels, *args, **kwargs) + + # If no arguments given, collect up all the artists on the figure + if len(args) == 0: + handles = [] + labels = [] + + def in_handles(h, l): + # Method to check if we already have a given handle and label. + # Consider two handles to be the same if they share a label, + # color, facecolor, and edgecolor. + + # Loop through each handle and label already collected + for f_h, f_l in zip(handles, labels): + if f_l != l: + continue + if type(f_h) != type(h): + continue + try: + if f_h.get_color() != h.get_color(): + continue + except AttributeError: + pass + try: + if f_h.get_facecolor() != h.get_facecolor(): + continue + except AttributeError: + pass + try: + if f_h.get_edgecolor() != h.get_edgecolor(): + continue + except AttributeError: + pass + return True + return False + + for ax in self.axes: + ax_handles, ax_labels = ax.get_legend_handles_labels() + for h, l in zip(ax_handles, ax_labels): + if not in_handles(h, l): + handles.append(h) + labels.append(l) + if len(handles) == 0: + warnings.warn("No labeled objects found. " + "Use label='...' kwarg on individual plots.") + return None + + elif len(args) == 2: + # LINES, LABELS + handles, labels = args + + elif len(args) == 3: + # LINES, LABELS, LOC + handles, labels, loc = args + kwargs['loc'] = loc + + else: + raise TypeError('Invalid number of arguments passed to legend. ' + 'Please specify either 0 args, 2 args ' + '(artist handles, figure labels) or 3 args ' + '(artist handles, figure labels, legend location)') + + l = Legend(self, handles, labels, **kwargs) self.legends.append(l) l._remove_method = lambda h: self.legends.remove(h) self.stale = True @@ -1364,6 +1564,10 @@ def gca(self, **kwargs): # continue and a new axes will be created if key == ckey and isinstance(cax, projection_class): return cax + else: + warnings.warn('Requested projection is different from ' + 'current axis projection, creating new axis ' + 'with requested projection.', stacklevel=2) # no axes found, so create one which spans the figure return self.add_subplot(1, 1, 1, **kwargs) @@ -1590,12 +1794,12 @@ def colorbar(self, mappable, cax=None, ax=None, use_gridspec=True, **kw): """ if ax is None: ax = self.gca() + ax = np.atleast_1d(ax).ravel() # Store the value of gca so that we can set it back later on. current_ax = self.gca() - if cax is None: - if use_gridspec and isinstance(ax, SubplotBase): + if use_gridspec and isinstance(ax[0], SubplotBase): cax, kw = cbar.make_axes_gridspec(ax, **kw) else: cax, kw = cbar.make_axes(ax, **kw) @@ -1637,17 +1841,10 @@ def subplots_adjust(self, *args, **kwargs): def ginput(self, n=1, timeout=30, show_clicks=True, mouse_add=1, mouse_pop=3, mouse_stop=2): """ - Blocking call to interact with the figure. - - This will wait for *n* clicks from the user and return a list of the - coordinates of each click. - - If *timeout* is zero or negative, does not timeout. - - If *n* is zero or negative, accumulate clicks until a middle click - (or potentially both mouse buttons at once) terminates the input. + Blocking call to interact with a figure. - Right clicking cancels last input. + Wait until the user clicks *n* times on the figure, and return the + coordinates of each click in a list. The buttons used for the various actions (adding points, removing points, terminating the inputs) can be overriden via the @@ -1655,6 +1852,30 @@ def ginput(self, n=1, timeout=30, show_clicks=True, mouse_add=1, the associated mouse button: 1 for left, 2 for middle, 3 for right. + Parameters + ---------- + n : int, optional, default: 1 + Number of mouse clicks to accumulate. If negative, accumulate + clicks until the input is terminated manually. + timeout : scalar, optional, default: 30 + Number of seconds to wait before timing out. If zero or negative + will never timeout. + show_clicks : bool, optional, default: False + If True, show a red cross at the location of each click. + mouse_add : int, one of (1, 2, 3), optional, default: 1 (left click) + Mouse button used to add points. + mouse_pop : int, one of (1, 2, 3), optional, default: 3 (right click) + Mouse button used to remove the most recently added point. + mouse_stop : int, one of (1, 2, 3), optional, default: 2 (middle click) + Mouse button used to stop input. + + Returns + ------- + points : list of tuples + A list of the clicked (x, y) coordinates. + + Notes + ----- The keyboard can also be used to select points in case your mouse does not have one or more of the buttons. The delete and backspace keys act like right clicking (i.e., remove last point), the enter key From 1c5a14edcc47f5366bf2443485170d0195a6b79f Mon Sep 17 00:00:00 2001 From: Jody Klymak Date: Mon, 12 Jun 2017 22:28:36 -0700 Subject: [PATCH 21/27] Aded comments and cleaned up --- lib/matplotlib/colorbar.py | 45 +++++++++++++++++--------------------- 1 file changed, 20 insertions(+), 25 deletions(-) diff --git a/lib/matplotlib/colorbar.py b/lib/matplotlib/colorbar.py index 7c831678cc93..a330334b25d2 100644 --- a/lib/matplotlib/colorbar.py +++ b/lib/matplotlib/colorbar.py @@ -1179,7 +1179,7 @@ def make_axes_gridspec(parents, **kw): ''' Resize and reposition a parent axes, and return a child axes suitable for a colorbar. This function is similar to - make_axes. Prmary differences are + make_axes. Primary differences are * *make_axes_gridspec* only handles the *orientation* keyword and cannot handle the "location" keyword. @@ -1224,10 +1224,11 @@ def make_axes_gridspec(parents, **kw): # make parents a 1-d ndarray if its not already... parents = np.atleast_1d(parents).ravel() - # get the appropriate subplot spec. Loop through the parents. + # For the subplotspec that these axes belong to, loop through and get + # the maximum and minimum index into the subplotspec. The result is the + # size the new gridspec that we will create must be. gsp0 = parents[0].get_subplotspec().get_gridspec() - minind = 10000 - maxind = -10000 + minind = 10000;maxind = -10000 for parent in parents: gsp = parent.get_subplotspec().get_gridspec() if gsp == gsp0: @@ -1238,47 +1239,37 @@ def make_axes_gridspec(parents, **kw): if ss[3]>maxind: maxind = ss[3] else: - pass - # get from maxind and minind to nrows and ncols.. + raise NotImplementedError('List of axes passed to colorbar must be from the same gridspec or call to plt.subplots') + # map the extent of the gridspec from indices to rows and columns. + # We need this below to assign the parents into the new gridspec. ncols0 = gsp0.get_geometry()[1] - print(ncols0) - print(maxind) - minrow,mincol=index2rowcolunm(minind,ncols0) maxrow,maxcol=index2rowcolunm(maxind,ncols0) - print('mnind %d maxind %d'%(minind,maxind)) - print('mncol %d maxcol %d'%(mincol,maxcol)) - print('mnrow %d maxrow %d'%(minrow,maxrow)) nrows = maxrow-minrow+1 ncols = maxcol-mincol+1 - print('nrows %d ncols %d'%(nrows,ncols)) - print(minind) - print(maxind) + # this is subplot spec the region that we need to resize and add + # a colorbar to. subspec = gridspec.SubplotSpec(gsp0,minind,maxind) - print('GSP0') - print(gsp0.get_geometry()) - print(subspec) - print(subspec.get_geometry()) gs_from_subplotspec = gridspec.GridSpecFromSubplotSpec if orientation == 'vertical': pad = kw.pop('pad', 0.05) wh_space = 2 * pad / (1 - pad) + # split the subplotspec containing parents into two, with one only + # `fraction` wide for the colorbar, and the other with some padding. gs = gs_from_subplotspec(1, 2, subplot_spec=subspec, wspace=wh_space, width_ratios=[x1 - pad, fraction] ) - + # center the colorbar vertically. gs2 = gs_from_subplotspec(3, 1, subplot_spec=gs[1], hspace=0., height_ratios=wh_ratios, ) - print(gs) - print(gs2) anchor = (0.0, 0.5) panchor = (1.0, 0.5) @@ -1310,18 +1301,22 @@ def make_axes_gridspec(parents, **kw): for parent in parents: geo=parent.get_subplotspec().get_geometry() ncol0 = geo[1] - print("Parent Geo:") - print(geo) + + # remap the old min gridspec index (geo[2]) into a new + # index. oldrow,oldcol = index2rowcolunm(geo[2],ncol0) newrow = oldrow-minrow+1 newcol = oldcol-mincol+1 newminind = rowcolunm2index(newrow,newcol,ncols) + + # remap the old max gridspec index (geo[3]) into a new + # index. oldrow,oldcol = index2rowcolunm(geo[3],ncol0) newrow = oldrow-minrow+1 newcol = oldcol-mincol+1 newmaxind = rowcolunm2index(newrow,newcol,ncols) - print('newminind %d newmaxind %d'%(newminind,newmaxind)) + # change the subplotspec for this parent. parent.set_subplotspec(gridspec.SubplotSpec(gsnew,newminind,newmaxind)) parent.update_params() parent.set_position(parent.figbox) From 12737f5b8be44758a637734d6a35f32d97ae1d56 Mon Sep 17 00:00:00 2001 From: Jody Klymak Date: Mon, 12 Jun 2017 22:30:09 -0700 Subject: [PATCH 22/27] Aded comments and cleaned up --- lib/matplotlib/colorbar.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/matplotlib/colorbar.py b/lib/matplotlib/colorbar.py index a330334b25d2..0526afc97090 100644 --- a/lib/matplotlib/colorbar.py +++ b/lib/matplotlib/colorbar.py @@ -1233,7 +1233,6 @@ def make_axes_gridspec(parents, **kw): gsp = parent.get_subplotspec().get_gridspec() if gsp == gsp0: ss = parent.get_subplotspec().get_geometry() - print(ss) if ss[2]maxind: @@ -1316,7 +1315,7 @@ def make_axes_gridspec(parents, **kw): newcol = oldcol-mincol+1 newmaxind = rowcolunm2index(newrow,newcol,ncols) - # change the subplotspec for this parent. + # change the subplotspec for this parent. parent.set_subplotspec(gridspec.SubplotSpec(gsnew,newminind,newmaxind)) parent.update_params() parent.set_position(parent.figbox) From 600253e0a93d0252872bb89951a93baae1ec8d42 Mon Sep 17 00:00:00 2001 From: Jody Klymak Date: Mon, 12 Jun 2017 22:33:39 -0700 Subject: [PATCH 23/27] Colormap that handles gridspec --- lib/matplotlib/colorbar.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/matplotlib/colorbar.py b/lib/matplotlib/colorbar.py index 0526afc97090..e7887f5d707d 100644 --- a/lib/matplotlib/colorbar.py +++ b/lib/matplotlib/colorbar.py @@ -1177,7 +1177,7 @@ def rowcolunm2index(row,col,ncols): @docstring.Substitution(make_axes_kw_doc) def make_axes_gridspec(parents, **kw): ''' - Resize and reposition a parent axes, and return a child axes + Resize and reposition a list of parent axes, and return a child axes suitable for a colorbar. This function is similar to make_axes. Primary differences are @@ -1190,8 +1190,8 @@ def make_axes_gridspec(parents, **kw): creates an instance of Subplot. * *make_axes* updates the position of the - parent. *make_axes_gridspec* replaces the grid_spec attribute - of the parent with a new one. + parents. *make_axes_gridspec* replaces the grid_spec attribute + of the parents with new ones. While this function is meant to be compatible with *make_axes*, there could be some minor differences. From fd388aae8d0b46906cbcdd8552e70b094611ac4e Mon Sep 17 00:00:00 2001 From: Jody Klymak Date: Mon, 12 Jun 2017 22:34:38 -0700 Subject: [PATCH 24/27] Colormap that handles gridspec --- lib/matplotlib/colorbar.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/matplotlib/colorbar.py b/lib/matplotlib/colorbar.py index e7887f5d707d..0d2bc450833f 100644 --- a/lib/matplotlib/colorbar.py +++ b/lib/matplotlib/colorbar.py @@ -1184,7 +1184,7 @@ def make_axes_gridspec(parents, **kw): * *make_axes_gridspec* only handles the *orientation* keyword and cannot handle the "location" keyword. - * *make_axes_gridspec* should only be used with a subplot parent. + * *make_axes_gridspec* should only be used with subplot parents. * *make_axes* creates an instance of Axes. *make_axes_gridspec* creates an instance of Subplot. From 262fa33068eb729adf2c42a558a3c412a81ff96b Mon Sep 17 00:00:00 2001 From: Jody Klymak Date: Mon, 12 Jun 2017 22:43:18 -0700 Subject: [PATCH 25/27] Colormap that handles gridspec --- lib/matplotlib/colorbar.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/lib/matplotlib/colorbar.py b/lib/matplotlib/colorbar.py index 0d2bc450833f..233e705ad142 100644 --- a/lib/matplotlib/colorbar.py +++ b/lib/matplotlib/colorbar.py @@ -1242,8 +1242,8 @@ def make_axes_gridspec(parents, **kw): # map the extent of the gridspec from indices to rows and columns. # We need this below to assign the parents into the new gridspec. ncols0 = gsp0.get_geometry()[1] - minrow,mincol=index2rowcolunm(minind,ncols0) - maxrow,maxcol=index2rowcolunm(maxind,ncols0) + minrow, mincol = index2rowcolunm(minind, ncols0) + maxrow, maxcol = index2rowcolunm(maxind, ncols0) nrows = maxrow-minrow+1 ncols = maxcol-mincol+1 @@ -1298,25 +1298,25 @@ def make_axes_gridspec(parents, **kw): gsnew = gs_from_subplotspec(nrows, ncols, subplot_spec=gs[0]) for parent in parents: - geo=parent.get_subplotspec().get_geometry() + geo = parent.get_subplotspec().get_geometry() ncol0 = geo[1] # remap the old min gridspec index (geo[2]) into a new # index. - oldrow,oldcol = index2rowcolunm(geo[2],ncol0) - newrow = oldrow-minrow+1 - newcol = oldcol-mincol+1 - newminind = rowcolunm2index(newrow,newcol,ncols) + oldrow, oldcol = index2rowcolunm(geo[2], ncol0) + newrow = oldrow - minrow+1 + newcol = oldcol - mincol+1 + newminind = rowcolunm2index(newrow, newcol, ncols) # remap the old max gridspec index (geo[3]) into a new # index. - oldrow,oldcol = index2rowcolunm(geo[3],ncol0) - newrow = oldrow-minrow+1 - newcol = oldcol-mincol+1 - newmaxind = rowcolunm2index(newrow,newcol,ncols) + oldrow, oldcol = index2rowcolunm(geo[3], ncol0) + newrow = oldrow - minrow+1 + newcol = oldcol - mincol+1 + newmaxind = rowcolunm2index(newrow, newcol, ncols) # change the subplotspec for this parent. - parent.set_subplotspec(gridspec.SubplotSpec(gsnew,newminind,newmaxind)) + parent.set_subplotspec(gridspec.SubplotSpec(gsnew, newminind, newmaxind)) parent.update_params() parent.set_position(parent.figbox) parent.set_anchor(panchor) From 37998b4cd274990e8c1ff6e3f354d6d9e20c5e4c Mon Sep 17 00:00:00 2001 From: Jody Klymak Date: Tue, 13 Jun 2017 06:02:20 -0700 Subject: [PATCH 26/27] Fixed subplotspec geometry having None --- setup.cfg.template | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/setup.cfg.template b/setup.cfg.template index e8ba46861b60..3bb835d1def8 100644 --- a/setup.cfg.template +++ b/setup.cfg.template @@ -13,19 +13,19 @@ # set this to True. It will download and build a specific version of # FreeType, and then use that to build the ft2font extension. This # ensures that test images are exactly reproducible. -#local_freetype = False +local_freetype = True [status] # To suppress display of the dependencies and their versions # at the top of the build log, uncomment the following line: -#suppress = True +#suppress = True [packages] # There are a number of subpackages of Matplotlib that are considered # optional. All except tests are installed by default, but that can # be changed here. # -#tests = False +tests = True #sample_data = True #toolkits = True # Tests for the toolkits are only automatically installed From d9b49b584a87e3d56b9a6291c4fda9b16fa12d77 Mon Sep 17 00:00:00 2001 From: Jody Klymak Date: Tue, 13 Jun 2017 06:08:09 -0700 Subject: [PATCH 27/27] Fixed subplotspec geometry having None, PEP8 errors --- lib/matplotlib/colorbar.py | 39 ++++++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/lib/matplotlib/colorbar.py b/lib/matplotlib/colorbar.py index 233e705ad142..6e0d34830d87 100644 --- a/lib/matplotlib/colorbar.py +++ b/lib/matplotlib/colorbar.py @@ -1164,12 +1164,15 @@ def make_axes(parents, location=None, orientation=None, fraction=0.15, cax.set_aspect(aspect, anchor=anchor, adjustable='box') return cax, kw + # helper functions for row,col to index. -def index2rowcolunm(index,ncols): +def index2rowcolunm(index, ncols): col = index%ncols + 1 row = int(np.floor(index/ncols)+1) - return row,col -def rowcolunm2index(row,col,ncols): + return row, col + + +def rowcolunm2index(row, col, ncols): index = col-1+(row-1)*ncols return index @@ -1228,17 +1231,21 @@ def make_axes_gridspec(parents, **kw): # the maximum and minimum index into the subplotspec. The result is the # size the new gridspec that we will create must be. gsp0 = parents[0].get_subplotspec().get_gridspec() - minind = 10000;maxind = -10000 + minind = 10000 + maxind = -10000 for parent in parents: gsp = parent.get_subplotspec().get_gridspec() if gsp == gsp0: - ss = parent.get_subplotspec().get_geometry() - if ss[2]maxind: + if ss[3] > maxind: maxind = ss[3] else: - raise NotImplementedError('List of axes passed to colorbar must be from the same gridspec or call to plt.subplots') + raise NotImplementedError('List of axes passed to colorbar ' + 'must be from the same gridspec or call to plt.subplots') # map the extent of the gridspec from indices to rows and columns. # We need this below to assign the parents into the new gridspec. ncols0 = gsp0.get_geometry()[1] @@ -1249,7 +1256,7 @@ def make_axes_gridspec(parents, **kw): # this is subplot spec the region that we need to resize and add # a colorbar to. - subspec = gridspec.SubplotSpec(gsp0,minind,maxind) + subspec = gridspec.SubplotSpec(gsp0, minind, maxind) gs_from_subplotspec = gridspec.GridSpecFromSubplotSpec if orientation == 'vertical': @@ -1310,13 +1317,17 @@ def make_axes_gridspec(parents, **kw): # remap the old max gridspec index (geo[3]) into a new # index. - oldrow, oldcol = index2rowcolunm(geo[3], ncol0) - newrow = oldrow - minrow+1 - newcol = oldcol - mincol+1 - newmaxind = rowcolunm2index(newrow, newcol, ncols) + if geo[3] is None: + newmaxind = newminind + else: + oldrow, oldcol = index2rowcolunm(geo[3], ncol0) + newrow = oldrow - minrow+1 + newcol = oldcol - mincol+1 + newmaxind = rowcolunm2index(newrow, newcol, ncols) # change the subplotspec for this parent. - parent.set_subplotspec(gridspec.SubplotSpec(gsnew, newminind, newmaxind)) + parent.set_subplotspec( + gridspec.SubplotSpec(gsnew, newminind, newmaxind)) parent.update_params() parent.set_position(parent.figbox) parent.set_anchor(panchor)