Skip to content

Commit a2e35cc

Browse files
anntzerefiring
authored andcommitted
Sticky margins cancellation system.
Let artists register lists of "sticky" x and y values. If an edge of the union of bounding boxes ends up falling on a sticky value, do not add margins to that edge. Docs still missing.
1 parent b73a939 commit a2e35cc

File tree

7 files changed

+92
-225
lines changed

7 files changed

+92
-225
lines changed

lib/matplotlib/artist.py

Lines changed: 11 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
unicode_literals)
33

44
import six
5-
from collections import OrderedDict
5+
from collections import OrderedDict, namedtuple
66

77
import re
88
import warnings
@@ -76,6 +76,9 @@ def _stale_axes_callback(self, val):
7676
self.axes.stale = val
7777

7878

79+
_XYPair = namedtuple("_XYPair", "x y")
80+
81+
7982
class Artist(object):
8083
"""
8184
Abstract base class for someone who renders into a
@@ -123,8 +126,7 @@ def __init__(self):
123126
self._snap = None
124127
self._sketch = rcParams['path.sketch']
125128
self._path_effects = rcParams['path.effects']
126-
127-
self._margins = {}
129+
self._stickies = _XYPair([], [])
128130

129131
def __getstate__(self):
130132
d = self.__dict__.copy()
@@ -926,98 +928,15 @@ def set_zorder(self, level):
926928
self.pchanged()
927929
self.stale = True
928930

929-
def get_top_margin(self):
930-
"""
931-
Get whether a margin should be applied to the top of the Artist.
932-
"""
933-
return self._margins.get('top', True)
934-
935-
def set_top_margin(self, margin):
936-
"""
937-
Set whether a margin should be applied to the top of the Artist.
938-
"""
939-
if margin != self._margins.get('top', True):
940-
self.stale = True
941-
self._margins['top'] = margin
942-
943-
top_margin = property(get_top_margin, set_top_margin)
944-
945-
def get_bottom_margin(self):
946-
"""
947-
Get whether a margin should be applied to the bottom of the Artist.
948-
"""
949-
return self._margins.get('bottom', True)
950-
951-
def set_bottom_margin(self, margin):
952-
"""
953-
Set whether a margin should be applied to the bottom of the Artist.
954-
"""
955-
if margin != self._margins.get('bottom', True):
956-
self.stale = True
957-
self._margins['bottom'] = margin
958-
959-
bottom_margin = property(get_bottom_margin, set_bottom_margin)
960-
961-
def get_left_margin(self):
962-
"""
963-
Get whether a margin should be applied to the left of the Artist.
964-
"""
965-
return self._margins.get('left', True)
966-
967-
def set_left_margin(self, margin):
968-
"""
969-
Set whether a margin should be applied to the left of the Artist.
970-
"""
971-
if margin != self._margins.get('left', True):
972-
self.stale = True
973-
self._margins['left'] = margin
974-
975-
left_margin = property(get_left_margin, set_left_margin)
976-
977-
def get_right_margin(self):
978-
"""
979-
Get whether a margin should be applied to the right of the Artist.
980-
"""
981-
return self._margins.get('right', True)
982-
983-
def set_right_margin(self, margin):
984-
"""
985-
Set whether a margin should be applied to the right of the Artist.
986-
"""
987-
if margin != self._margins.get('right', True):
988-
self.stale = True
989-
self._margins['right'] = margin
990-
991-
right_margin = property(get_right_margin, set_right_margin)
992-
993-
def get_margins(self):
994-
"""
995-
Returns a dictionary describing whether a margin should be applied on
996-
each of the sides (top, bottom, left and right).
931+
@property
932+
def stickies(self):
997933
"""
998-
return self._margins
934+
The `x` and `y` sticky lists for the artist.
999935
1000-
def set_margins(self, margins):
936+
This attribute cannot be assigned to; however, the `x` and `y` lists
937+
can be modified in place as needed.
1001938
"""
1002-
Set the dictionary describing whether a margin should be applied on
1003-
each of the sides (top, bottom, left and right). Missing keys are
1004-
assumed to be `True`. If `True` or `False` are passed in, all
1005-
sides are set to that value.
1006-
"""
1007-
if margins in (True, False):
1008-
margins = {
1009-
'top': margins,
1010-
'bottom': margins,
1011-
'left': margins,
1012-
'right': margins
1013-
}
1014-
1015-
if margins != self._margins:
1016-
self.stale = True
1017-
1018-
self._margins = margins
1019-
1020-
margins = property(get_margins, set_margins)
939+
return self._stickies
1021940

1022941
def update_from(self, other):
1023942
'Copy properties from *other* to *self*.'

lib/matplotlib/axes/_axes.py

Lines changed: 36 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -2097,13 +2097,6 @@ def make_iterable(x):
20972097
if yerr is not None:
20982098
yerr = self.convert_yunits(yerr)
20992099

2100-
margins = {}
2101-
2102-
if orientation == 'vertical':
2103-
margins = {'bottom': False}
2104-
elif orientation == 'horizontal':
2105-
margins = {'left': False}
2106-
21072100
if align == 'center':
21082101
if orientation == 'vertical':
21092102
left = [left[i] - width[i] / 2. for i in xrange(len(left))]
@@ -2128,11 +2121,13 @@ def make_iterable(x):
21282121
edgecolor=e,
21292122
linewidth=lw,
21302123
label='_nolegend_',
2131-
margins=margins
21322124
)
21332125
r.update(kwargs)
21342126
r.get_path()._interpolation_steps = 100
2135-
#print r.get_label(), label, 'label' in kwargs
2127+
if orientation == 'vertical':
2128+
r.stickies.y.append(0)
2129+
elif orientation == 'horizontal':
2130+
r.stickies.x.append(0)
21362131
self.add_patch(r)
21372132
patches.append(r)
21382133

@@ -5452,7 +5447,7 @@ def pcolor(self, *args, **kwargs):
54525447

54535448
kwargs.setdefault('snap', False)
54545449

5455-
collection = mcoll.PolyCollection(verts, margins=False, **kwargs)
5450+
collection = mcoll.PolyCollection(verts, **kwargs)
54565451

54575452
collection.set_alpha(alpha)
54585453
collection.set_array(C)
@@ -5486,8 +5481,10 @@ def pcolor(self, *args, **kwargs):
54865481
miny = np.amin(y)
54875482
maxy = np.amax(y)
54885483

5489-
corners = (minx, miny), (maxx, maxy)
54905484
self.add_collection(collection, autolim=False)
5485+
corners = (minx, miny), (maxx, maxy)
5486+
collection.stickies.x[:] = [minx, maxx]
5487+
collection.stickies.y[:] = [miny, maxy]
54915488
self.update_datalim(corners)
54925489
self.autoscale_view()
54935490
return collection
@@ -5603,10 +5600,9 @@ def pcolormesh(self, *args, **kwargs):
56035600
coords[:, 0] = X
56045601
coords[:, 1] = Y
56055602

5606-
collection = mcoll.QuadMesh(
5607-
Nx - 1, Ny - 1, coords,
5608-
antialiased=antialiased, shading=shading, margins=False,
5609-
**kwargs)
5603+
collection = mcoll.QuadMesh(Nx - 1, Ny - 1, coords,
5604+
antialiased=antialiased, shading=shading,
5605+
**kwargs)
56105606
collection.set_alpha(alpha)
56115607
collection.set_array(C)
56125608
if norm is not None and not isinstance(norm, mcolors.Normalize):
@@ -5637,8 +5633,10 @@ def pcolormesh(self, *args, **kwargs):
56375633
miny = np.amin(Y)
56385634
maxy = np.amax(Y)
56395635

5640-
corners = (minx, miny), (maxx, maxy)
56415636
self.add_collection(collection, autolim=False)
5637+
corners = (minx, miny), (maxx, maxy)
5638+
collection.stickies.x[:] = [minx, maxx]
5639+
collection.stickies.y[:] = [miny, maxy]
56425640
self.update_datalim(corners)
56435641
self.autoscale_view()
56445642
return collection
@@ -5790,8 +5788,7 @@ def pcolorfast(self, *args, **kwargs):
57905788
# The QuadMesh class can also be changed to
57915789
# handle relevant superclass kwargs; the initializer
57925790
# should do much more than it does now.
5793-
collection = mcoll.QuadMesh(nc, nr, coords, 0, edgecolors="None",
5794-
margins=False)
5791+
collection = mcoll.QuadMesh(nc, nr, coords, 0, edgecolors="None")
57955792
collection.set_alpha(alpha)
57965793
collection.set_array(C)
57975794
collection.set_cmap(cmap)
@@ -5828,6 +5825,8 @@ def pcolorfast(self, *args, **kwargs):
58285825
ret.set_clim(vmin, vmax)
58295826
else:
58305827
ret.autoscale_None()
5828+
collection.stickies.x[:] = [xl, xr]
5829+
collection.stickies.y[:] = [yb, yt]
58315830
self.update_datalim(np.array([[xl, yb], [xr, yt]]))
58325831
self.autoscale_view(tight=True)
58335832
return ret
@@ -6240,21 +6239,17 @@ def _normalize_input(inp, ename='input'):
62406239
else:
62416240
n = [m[slc].cumsum()[slc] for m in n]
62426241

6243-
if orientation == 'horizontal':
6244-
margins = {'left': False}
6245-
else:
6246-
margins = {'bottom': False}
6247-
62486242
patches = []
62496243

6244+
# Save autoscale state for later restoration; turn autoscaling
6245+
# off so we can do it all a single time at the end, instead
6246+
# of having it done by bar or fill and then having to be redone.
6247+
_saved_autoscalex = self.get_autoscalex_on()
6248+
_saved_autoscaley = self.get_autoscaley_on()
6249+
self.set_autoscalex_on(False)
6250+
self.set_autoscaley_on(False)
6251+
62506252
if histtype.startswith('bar'):
6251-
# Save autoscale state for later restoration; turn autoscaling
6252-
# off so we can do it all a single time at the end, instead
6253-
# of having it done by bar or fill and then having to be redone.
6254-
_saved_autoscalex = self.get_autoscalex_on()
6255-
_saved_autoscaley = self.get_autoscaley_on()
6256-
self.set_autoscalex_on(False)
6257-
self.set_autoscaley_on(False)
62586253

62596254
totwidth = np.diff(bins)
62606255

@@ -6301,10 +6296,6 @@ def _normalize_input(inp, ename='input'):
63016296
bottom[:] = m
63026297
boffset += dw
63036298

6304-
self.set_autoscalex_on(_saved_autoscalex)
6305-
self.set_autoscaley_on(_saved_autoscaley)
6306-
self.autoscale_view()
6307-
63086299
elif histtype.startswith('step'):
63096300
# these define the perimeter of the polygon
63106301
x = np.zeros(4 * len(bins) - 3)
@@ -6384,8 +6375,13 @@ def _normalize_input(inp, ename='input'):
63846375
closed=True if fill else None,
63856376
facecolor=c,
63866377
edgecolor=None if fill else c,
6387-
fill=fill if fill else None,
6388-
margins=margins))
6378+
fill=fill if fill else None))
6379+
for patch_list in patches:
6380+
for patch in patch_list:
6381+
if orientation == 'vertical':
6382+
patch.stickies.y.append(0)
6383+
elif orientation == 'horizontal':
6384+
patch.stickies.x.append(0)
63896385

63906386
# we return patches, so put it back in the expected order
63916387
patches.reverse()
@@ -6421,6 +6417,10 @@ def _normalize_input(inp, ename='input'):
64216417
ymin = min(ymin0, ymin)
64226418
self.dataLim.intervaly = (ymin, ymax)
64236419

6420+
self.set_autoscalex_on(_saved_autoscalex)
6421+
self.set_autoscaley_on(_saved_autoscaley)
6422+
self.autoscale_view()
6423+
64246424
if label is None:
64256425
labels = [None]
64266426
elif is_string_like(label):

0 commit comments

Comments
 (0)