From 06a934cc875d4779f260a77f4760073d555e7015 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Mon, 22 Dec 2014 17:31:56 -0800 Subject: [PATCH 1/8] MNT : remove unused imports --- lib/matplotlib/axes/_axes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/matplotlib/axes/_axes.py b/lib/matplotlib/axes/_axes.py index fb82fd59b256..db0264feb0a9 100644 --- a/lib/matplotlib/axes/_axes.py +++ b/lib/matplotlib/axes/_axes.py @@ -13,7 +13,7 @@ import matplotlib import matplotlib.cbook as cbook -from matplotlib.cbook import _string_to_bool, mplDeprecation +from matplotlib.cbook import mplDeprecation import matplotlib.collections as mcoll import matplotlib.colors as mcolors import matplotlib.contour as mcontour From 6f31a563e09beb1211b525edca6efe77d9910c97 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Sun, 14 Dec 2014 16:38:44 -0500 Subject: [PATCH 2/8] WIP : made Container inherit from Artist - add broadcasting draw method to Container - special-case BarContainer __new__ - remove duplicate functions from Container --- lib/matplotlib/artist.py | 3 ++ lib/matplotlib/container.py | 98 ++++++++----------------------------- 2 files changed, 23 insertions(+), 78 deletions(-) diff --git a/lib/matplotlib/artist.py b/lib/matplotlib/artist.py index 7fb492367f1d..0af5081c00fc 100644 --- a/lib/matplotlib/artist.py +++ b/lib/matplotlib/artist.py @@ -701,6 +701,9 @@ def get_rasterized(self): "return True if the artist is to be rasterized" return self._rasterized + def set_remove_method(self, f): + self._remove_method = f + def set_rasterized(self, rasterized): """ Force rasterized (bitmap) drawing in vector backend output. diff --git a/lib/matplotlib/container.py b/lib/matplotlib/container.py index 4603e7e7bee0..ea1c217065b1 100644 --- a/lib/matplotlib/container.py +++ b/lib/matplotlib/container.py @@ -2,11 +2,11 @@ unicode_literals) import six - +from matplotlib.artist import Artist import matplotlib.cbook as cbook -class Container(tuple): +class Container(tuple, Artist): """ Base class for containers. """ @@ -17,92 +17,34 @@ def __repr__(self): def __new__(cls, *kl, **kwargs): return tuple.__new__(cls, kl[0]) - def __init__(self, kl, label=None): - - self.eventson = False # fire events only if eventson - self._oid = 0 # an observer id - self._propobservers = {} # a dict from oids to funcs - - self._remove_method = None - - self.set_label(label) - - def set_remove_method(self, f): - self._remove_method = f + def __init__(self, kl, label=None, **kwargs): + Artist.__init__(self, **kwargs) + self.set_label(label=label) def remove(self): + # remove the children for c in self: c.remove() - - if self._remove_method: - self._remove_method(self) - - def __getstate__(self): - d = self.__dict__.copy() - # remove the unpicklable remove method, this will get re-added on load - # (by the axes) if the artist lives on an axes. - d['_remove_method'] = None - return d - - def get_label(self): - """ - Get the label used for this artist in the legend. - """ - return self._label - - def set_label(self, s): - """ - Set the label to *s* for auto legend. - - ACCEPTS: string or anything printable with '%s' conversion. - """ - if s is not None: - self._label = '%s' % (s, ) - else: - self._label = None - self.pchanged() - - def add_callback(self, func): - """ - Adds a callback function that will be called whenever one of - the :class:`Artist`'s properties changes. - - Returns an *id* that is useful for removing the callback with - :meth:`remove_callback` later. - """ - oid = self._oid - self._propobservers[oid] = func - self._oid += 1 - return oid - - def remove_callback(self, oid): - """ - Remove a callback based on its *id*. - - .. seealso:: - - :meth:`add_callback` - For adding callbacks - - """ - try: - del self._propobservers[oid] - except KeyError: - pass - - def pchanged(self): - """ - Fire an event when property changed, calling all of the - registered callbacks. - """ - for oid, func in list(six.iteritems(self._propobservers)): - func(self) + # call up to the Artist remove method + super(Container, self).remove(self) def get_children(self): return list(cbook.flatten(self)) + def draw(self, renderer, *args, **kwargs): + # just broadcast the draw down to children + for a in self: + a.draw(renderer, *args, **kwargs) + class BarContainer(Container): + def __new__(cls, patches, errorbar=None, **kwargs): + if errorbar is None: + errorbar = tuple() + else: + errorbar = tuple(errorbar) + patches = tuple(patches) + return super(BarContainer, cls).__new__(patches + errorbar, **kwargs) def __init__(self, patches, errorbar=None, **kwargs): self.patches = patches From 81e1d69c6cfd4b2b0363595bec4f3e6a20541428 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Mon, 15 Dec 2014 01:37:42 -0500 Subject: [PATCH 3/8] ENH : make container broadcast {get,set}_* functions This uses magic in the `__getattribute__` method which _works_ but does not play nice with IDE's, documentation, or tab-complete. Some Artist properties we don't want to broadcast, like the label. --- lib/matplotlib/container.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/lib/matplotlib/container.py b/lib/matplotlib/container.py index ea1c217065b1..2349ad9a60de 100644 --- a/lib/matplotlib/container.py +++ b/lib/matplotlib/container.py @@ -10,6 +10,7 @@ class Container(tuple, Artist): """ Base class for containers. """ + _no_broadcast = ['label', ] def __repr__(self): return "" % (len(self)) @@ -18,7 +19,9 @@ def __new__(cls, *kl, **kwargs): return tuple.__new__(cls, kl[0]) def __init__(self, kl, label=None, **kwargs): + # set up the artist details Artist.__init__(self, **kwargs) + # for some reason we special case label self.set_label(label=label) def remove(self): @@ -31,6 +34,23 @@ def remove(self): def get_children(self): return list(cbook.flatten(self)) + def __getattribute__(self, key): + + # broadcast set_* and get_* methods across members + # except for these explicitly not. + if (('set' in key or 'get' in key) and + all(k not in key for k in self._no_broadcast)): + + def inner(*args, **kwargs): + return [getattr(a, key)(*args, **kwargs) + for a in self] + inner.__name__ = key + doc = getattr(self[0], key).__doc__ + inner.__doc__ = doc + return inner + else: + return super(Container, self).__getattribute__(key) + def draw(self, renderer, *args, **kwargs): # just broadcast the draw down to children for a in self: From 7de5e0ae7536734ccda0d2dc8e02a092375dcce0 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Sun, 14 Dec 2014 16:06:54 -0500 Subject: [PATCH 4/8] WIP : helper list-class Starting ground work for re-factoring Axes to use a single tree for storing the Artists in an Axes. --- lib/matplotlib/artist.py | 4 +++ lib/matplotlib/cbook.py | 64 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+) diff --git a/lib/matplotlib/artist.py b/lib/matplotlib/artist.py index 0af5081c00fc..980958fd12c3 100644 --- a/lib/matplotlib/artist.py +++ b/lib/matplotlib/artist.py @@ -138,6 +138,10 @@ def remove(self): # protected attribute if Python supported that sort of thing. The # callback has one parameter, which is the child to be removed. if self._remove_method is not None: + # set the current axes to None + self._axes = None + # use the call back registered by the axes when the artist + # was added to remove it the artist from the axes self._remove_method(self) else: raise NotImplementedError('cannot remove artist') diff --git a/lib/matplotlib/cbook.py b/lib/matplotlib/cbook.py index c0f66c9f27cd..22e8974a5d2c 100644 --- a/lib/matplotlib/cbook.py +++ b/lib/matplotlib/cbook.py @@ -2311,6 +2311,70 @@ def get_instancemethod(self): return getattr(self.parent_obj, self.instancemethod_name) +_art_list_msg = ("The use of Axes.lines, Axes.patches, Axes.texts " + "Axes.tables, Axes.artists, Axes.collections, " + "Axes.containers, " + "and Axes.images have been " + "deprecated. All artists are now stored is a single " + "tree accessible via the Axes.artist_tree property. " + "Please use the ``remove`` method on the artists to remove" + "them from an Axes. \n\n" + "These lists will be removed in 1.7 or 2.0.") + + +class MPLRemoverList(list): + """ + + This is a sub-class of list which implements the logic to manage the + backwards compatibility during deprecation of the lines, patches, + texts, tables, artists, images, collections, and containers + attributes from the Axes class. This will allow users to continue + to use `ax.lines.pop()` to remove lines from an axes, even though + the draw method no longer looks at those lists at render time. + + This class will be removed when the list are. + + """ + def __delslice__(self, a, b): + # warn + warnings.warn(_art_list_msg, mplDeprecation, stacklevel=1) + # grab what we will be removing + res = self[a:b] + # remove it from this list + super(MPLRemoverList, self).__delslice__(self, a, b) + # see if we need to call the real remove + # Artist.remove sets _axes = None so if this is called + # remove it won't be called again, but if a user removes + # an artist from these lists directly, remove will correctly + # be called. + for a in res: + # this works because of details of how Artist.remove works + if a.axes: + a.remove() + + def __delitem__(self, y): + # see __delslice__ for explanation of logic + warnings.warn(_art_list_msg, mplDeprecation, stacklevel=1) + res = self[y] + super(MPLRemoverList, self).__delitem__(self, y) + if res.axes: + res.remove() + + def pop(self, i): + # see __delslice__ for explanation of logic + warnings.warn(_art_list_msg, mplDeprecation, stacklevel=1) + res = super(MPLRemoverList, self).pop(self, i) + if res.axes: + res.remove() + + def remove(self, item): + # see __delslice__ for explanation of logic + warnings.warn(_art_list_msg, mplDeprecation, stacklevel=1) + res = super(MPLRemoverList, self).remove(self, item) + if item.axes: + res.remove() + + # Numpy > 1.6.x deprecates putmask in favor of the new copyto. # So long as we support versions 1.6.x and less, we need the # following local version of putmask. We choose to make a From 503dd4d6e3ced88c856e65dbd5036a31c9d5d9eb Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Mon, 22 Dec 2014 18:49:18 -0800 Subject: [PATCH 5/8] ENH : allow rasterization on Container.draw --- lib/matplotlib/container.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/matplotlib/container.py b/lib/matplotlib/container.py index 2349ad9a60de..1357954adc8e 100644 --- a/lib/matplotlib/container.py +++ b/lib/matplotlib/container.py @@ -2,7 +2,7 @@ unicode_literals) import six -from matplotlib.artist import Artist +from matplotlib.artist import Artist, allow_rasterization import matplotlib.cbook as cbook @@ -51,6 +51,7 @@ def inner(*args, **kwargs): else: return super(Container, self).__getattribute__(key) + @allow_rasterization def draw(self, renderer, *args, **kwargs): # just broadcast the draw down to children for a in self: From 75bb0e829dfccee198215ec3bf4af64de1cbddfd Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Mon, 22 Dec 2014 18:56:33 -0800 Subject: [PATCH 6/8] PEP8 : whitespace changes --- lib/matplotlib/axes/_axes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/matplotlib/axes/_axes.py b/lib/matplotlib/axes/_axes.py index db0264feb0a9..28e4cda87091 100644 --- a/lib/matplotlib/axes/_axes.py +++ b/lib/matplotlib/axes/_axes.py @@ -2805,7 +2805,7 @@ def xywhere(xs, ys, mask): else: marker = mlines.CARETLEFT caplines.extend( - self.plot(leftlo, ylo, ls='None', marker=marker, + self.plot(leftlo, ylo, ls='None', marker=marker, **plot_kw)) if capsize > 0: xup, yup = xywhere(x, y, xuplims & everymask) From dd4051e181d3ae52f4868be17bd330d40ed72ba7 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Tue, 23 Dec 2014 07:17:20 -0800 Subject: [PATCH 7/8] WIP : use container to draw errorbar tests are still failing --- lib/matplotlib/axes/_axes.py | 21 +++++++++++++-------- lib/matplotlib/axes/_base.py | 13 ++++++++++--- lib/matplotlib/container.py | 5 +++-- 3 files changed, 26 insertions(+), 13 deletions(-) diff --git a/lib/matplotlib/axes/_axes.py b/lib/matplotlib/axes/_axes.py index 28e4cda87091..5086cfca03f2 100644 --- a/lib/matplotlib/axes/_axes.py +++ b/lib/matplotlib/axes/_axes.py @@ -3,7 +3,7 @@ import six from six.moves import reduce, xrange, zip, zip_longest - +import itertools import math import warnings @@ -35,7 +35,8 @@ import matplotlib.transforms as mtransforms import matplotlib.tri as mtri import matplotlib.transforms as mtrans -from matplotlib.container import BarContainer, ErrorbarContainer, StemContainer +from matplotlib.container import (BarContainer, ErrorbarContainer, + StemContainer, Container) from matplotlib.axes._base import _AxesBase from matplotlib.axes._base import _process_plot_format @@ -2755,7 +2756,7 @@ def xywhere(xs, ys, mask): if xerr is not None: if (iterable(xerr) and len(xerr) == 2 and - iterable(xerr[0]) and iterable(xerr[1])): + iterable(xerr[0]) and iterable(xerr[1])): # using list comps rather than arrays to preserve units left = [thisx - thiserr for (thisx, thiserr) in cbook.safezip(x, xerr[0])] @@ -2886,14 +2887,18 @@ def xywhere(xs, ys, mask): self.autoscale_view() self._hold = holdstate - errorbar_container = ErrorbarContainer((l0, tuple(caplines), - tuple(barcols)), + # hack to put these artist in the right place in the + # draw tree + for ll in itertools.chain((l0, ), caplines, barcols): + ll.remove() + + errorbar_container = ErrorbarContainer((l0, + Container(caplines), + Container(barcols)), has_xerr=(xerr is not None), has_yerr=(yerr is not None), label=label) - self.containers.append(errorbar_container) - - return errorbar_container # (l0, caplines, barcols) + return self.add_container(errorbar_container) def boxplot(self, x, notch=False, sym=None, vert=True, whis=1.5, positions=None, widths=None, patch_artist=False, diff --git a/lib/matplotlib/axes/_base.py b/lib/matplotlib/axes/_base.py index e7b9696947c9..fa2b9b86aa00 100644 --- a/lib/matplotlib/axes/_base.py +++ b/lib/matplotlib/axes/_base.py @@ -1605,13 +1605,19 @@ def add_container(self, container): Add a :class:`~matplotlib.container.Container` instance to the axes. - Returns the collection. + Returns the container. """ + container.set_axes(self) + self._set_artist_props(container) + self.containers.append(container) + + container.set_clip_path(self.patch) + container.set_remove_method(lambda h: self.containers.remove(h)) + label = container.get_label() if not label: container.set_label('_container%d' % len(self.containers)) - self.containers.append(container) - container.set_remove_method(lambda h: self.containers.remove(h)) + return container def relim(self, visible_only=False): @@ -1998,6 +2004,7 @@ def draw(self, renderer=None, inframe=False): artists.extend(self.lines) artists.extend(self.texts) artists.extend(self.artists) + artists.extend(self.containers) # the frame draws the edges around the axes patch -- we # decouple these so the patch can be in the background and the diff --git a/lib/matplotlib/container.py b/lib/matplotlib/container.py index 1357954adc8e..8305798d1eba 100644 --- a/lib/matplotlib/container.py +++ b/lib/matplotlib/container.py @@ -10,7 +10,8 @@ class Container(tuple, Artist): """ Base class for containers. """ - _no_broadcast = ['label', ] + _no_broadcast = ['label', 'visible', 'zorder', 'animated', + 'agg_filter'] def __repr__(self): return "" % (len(self)) @@ -22,7 +23,7 @@ def __init__(self, kl, label=None, **kwargs): # set up the artist details Artist.__init__(self, **kwargs) # for some reason we special case label - self.set_label(label=label) + self.set_label(label) def remove(self): # remove the children From 189764eb9b5c805c006b953bf0b79cb3307c82b3 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Mon, 9 Mar 2015 11:54:47 -0400 Subject: [PATCH 8/8] ENH : make sure errorbar respects errorbar --- lib/matplotlib/axes/_axes.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/matplotlib/axes/_axes.py b/lib/matplotlib/axes/_axes.py index 5086cfca03f2..76335f7ea75b 100644 --- a/lib/matplotlib/axes/_axes.py +++ b/lib/matplotlib/axes/_axes.py @@ -2667,6 +2667,8 @@ def errorbar(self, x, y, yerr=None, xerr=None, label = kwargs.pop("label", None) + zorder = kwargs.pop('zorder', 0) + # make sure all the args are iterable; use lists not arrays to # preserve units if not iterable(x): @@ -2898,6 +2900,7 @@ def xywhere(xs, ys, mask): has_xerr=(xerr is not None), has_yerr=(yerr is not None), label=label) + errorbar_container.set_zorder(zorder) return self.add_container(errorbar_container) def boxplot(self, x, notch=False, sym=None, vert=True, whis=1.5, pFad - Phonifier reborn

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

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


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy