External transform api #1090

Merged
merged 4 commits into from Aug 20, 2012
@@ -3,7 +3,8 @@
import matplotlib
import matplotlib.cbook as cbook
from matplotlib import docstring, rcParams
-from transforms import Bbox, IdentityTransform, TransformedBbox, TransformedPath
+from transforms import Bbox, IdentityTransform, TransformedBbox, \
@efiring
efiring Aug 20, 2012 Member

For later cleanup, at leisure: use parentheses instead of backslash; I'm pretty sure this is supported for 2.6 and later.

+ TransformedPath, Transform
from path import Path
## Note, matplotlib artists use the doc strings for set and get
@@ -223,7 +224,7 @@ def set_transform(self, t):
ACCEPTS: :class:`~matplotlib.transforms.Transform` instance
"""
self._transform = t
- self._transformSet = True
+ self._transformSet = t is not None
@pelson
pelson Aug 30, 2012 Member

Turns out this is bad. Reverted in #1176 (along with a suitable test).

self.pchanged()
def get_transform(self):
@@ -233,6 +234,9 @@ def get_transform(self):
"""
if self._transform is None:
self._transform = IdentityTransform()
+ elif (not isinstance(self._transform, Transform)
+ and hasattr(self._transform, '_as_mpl_transform')):
@efiring
efiring Aug 20, 2012 Member

Is there any point in checking for the _as_mpl_transform attribute? If it is not None, and it is not a Transform, and it can't be made into one, shouldn't it just raise an exception? Or is the idea that something not inheriting from Transform can still function as if it did?

@pelson
pelson Aug 20, 2012 Member

The idea was simply to not break anything else that was already passing something fruity. I think it might just get down to the point where the transform_path etc. methods are called and blow up if they don't exist on the thing in self._transform, though I am not entirely sure.

I'm not too fussed either way, but I am happy to be less generous and just try calling the _as_mpl_transform method, and if it doesn't exist, oh well... what is your preference?

+ self._transform = self._transform._as_mpl_transform(self.axes)
return self._transform
def hitlist(self, event):
@@ -5965,7 +5965,7 @@ def scatter(self, x, y, s=20, c='b', marker='o', cmap=None, norm=None,
edgecolors = edgecolors,
linewidths = linewidths,
offsets = zip(x,y),
- transOffset = self.transData,
+ transOffset = kwargs.pop('transform', self.transData),
)
collection.set_transform(mtransforms.IdentityTransform())
collection.set_alpha(alpha)
@@ -6489,7 +6489,7 @@ def stackplot(self, x, *args, **kwargs):
def streamplot(self, x, y, u, v, density=1, linewidth=None, color=None,
cmap=None, norm=None, arrowsize=1, arrowstyle='-|>',
- minlength=0.1):
+ minlength=0.1, transform=None):
if not self._hold: self.cla()
lines = mstream.streamplot(self, x, y, u, v,
density=density,
@@ -6499,7 +6499,8 @@ def streamplot(self, x, y, u, v, density=1, linewidth=None, color=None,
norm=norm,
arrowsize=arrowsize,
arrowstyle=arrowstyle,
- minlength=minlength)
+ minlength=minlength,
+ transform=transform)
return lines
streamplot.__doc__ = mstream.streamplot.__doc__
@@ -156,9 +156,16 @@ def set_paths(self):
def get_transforms(self):
return self._transforms
+ def get_offset_transform(self):
+ t = self._transOffset
+ if (not isinstance(t, transforms.Transform)
+ and hasattr(t, '_as_mpl_transform')):
+ t = t._as_mpl_transform(self.axes)
+ return t
+
def get_datalim(self, transData):
transform = self.get_transform()
- transOffset = self._transOffset
+ transOffset = self.get_offset_transform()
offsets = self._offsets
paths = self.get_paths()
@@ -192,7 +199,7 @@ def _prepare_points(self):
"""Point prep for drawing and hit testing"""
transform = self.get_transform()
- transOffset = self._transOffset
+ transOffset = self.get_offset_transform()
offsets = self._offsets
paths = self.get_paths()
@@ -1407,7 +1414,7 @@ def draw(self, renderer):
if not self.get_visible(): return
renderer.open_group(self.__class__.__name__, self.get_gid())
transform = self.get_transform()
- transOffset = self._transOffset
+ transOffset = self.get_offset_transform()
offsets = self._offsets
if self.have_units():
@@ -772,6 +772,8 @@ def __init__(self, ax, *args, **kwargs):
raise ValueError('Either colors or cmap must be None')
if self.origin == 'image': self.origin = mpl.rcParams['image.origin']
+ self.transform = kwargs.get('transform', None)
+
self._process_args(*args, **kwargs)
self._process_levels()
@@ -820,6 +822,7 @@ def __init__(self, ax, *args, **kwargs):
antialiaseds = (self.antialiased,),
edgecolors= 'none',
alpha=self.alpha,
+ transform=self.transform,
zorder=zorder)
self.ax.add_collection(col)
self.collections.append(col)
@@ -839,6 +842,7 @@ def __init__(self, ax, *args, **kwargs):
linewidths = width,
linestyle = lstyle,
alpha=self.alpha,
+ transform=self.transform,
zorder=zorder)
col.set_label('_nolegend_')
self.ax.add_collection(col, False)
@@ -2994,7 +2994,7 @@ def stackplot(x, *args, **kwargs):
draw_if_interactive()
finally:
ax.hold(washold)
-
+
return ret
# This function was autogenerated by boilerplate.py. Do not edit as
@@ -3040,7 +3040,7 @@ def step(x, y, *args, **kwargs):
@autogen_docstring(Axes.streamplot)
def streamplot(x, y, u, v, density=1, linewidth=None, color=None, cmap=None,
norm=None, arrowsize=1, arrowstyle='-|>', minlength=0.1,
- hold=None):
+ transform=None, hold=None):
ax = gca()
# allow callers to override the hold state by passing hold=True|False
washold = ax.ishold()
@@ -3051,7 +3051,7 @@ def streamplot(x, y, u, v, density=1, linewidth=None, color=None, cmap=None,
ret = ax.streamplot(x, y, u, v, density=density, linewidth=linewidth,
color=color, cmap=cmap, norm=norm,
arrowsize=arrowsize, arrowstyle=arrowstyle,
- minlength=minlength)
+ minlength=minlength, transform=transform)
draw_if_interactive()
finally:
ax.hold(washold)
@@ -408,10 +408,11 @@ def __init__(self, ax, *args, **kw):
self.width = kw.pop('width', None)
self.color = kw.pop('color', 'k')
self.pivot = kw.pop('pivot', 'tail')
+ self.transform = kw.pop('transform', ax.transData)
kw.setdefault('facecolors', self.color)
kw.setdefault('linewidths', (0,))
collections.PolyCollection.__init__(self, [], offsets=self.XY,
- transOffset=ax.transData,
+ transOffset=self.transform,
closed=False,
**kw)
self.polykw = kw
@@ -529,8 +530,6 @@ def _angles_lengths(self, U, V, eps=1):
lengths = np.absolute(dxy[:,0] + dxy[:,1]*1j) / eps
return angles, lengths
-
-
def _make_verts(self, U, V):
uv = (U+V*1j)
if self.angles == 'xy' and self.scale_units == 'xy':
@@ -592,7 +591,6 @@ def _make_verts(self, U, V):
return XY
-
def _h_arrows(self, length):
""" length is in arrow width units """
# It might be possible to streamline the code
@@ -824,6 +822,7 @@ def __init__(self, ax, *args, **kw):
self.barb_increments = kw.pop('barb_increments', dict())
self.rounding = kw.pop('rounding', True)
self.flip = kw.pop('flip_barb', False)
+ transform = kw.pop('transform', ax.transData)
#Flagcolor and and barbcolor provide convenience parameters for setting
#the facecolor and edgecolor, respectively, of the barb polygon. We
@@ -851,7 +850,7 @@ def __init__(self, ax, *args, **kw):
#Make a collection
barb_size = self._length**2 / 4 #Empirically determined
collections.PolyCollection.__init__(self, [], (barb_size,), offsets=xy,
- transOffset=ax.transData, **kw)
+ transOffset=transform, **kw)
self.set_transform(transforms.IdentityTransform())
self.set_UVC(u, v, c)
@@ -14,7 +14,7 @@
def streamplot(axes, x, y, u, v, density=1, linewidth=None, color=None,
cmap=None, norm=None, arrowsize=1, arrowstyle='-|>',
- minlength=0.1):
+ minlength=0.1, transform=None):
"""Draws streamlines of a vector flow.
Parameters
@@ -138,10 +138,15 @@ def streamplot(axes, x, y, u, v, density=1, linewidth=None, color=None,
line_colors.extend(color_values)
arrow_kw['color'] = cmap(norm(color_values[n]))
- p = patches.FancyArrowPatch(arrow_tail, arrow_head, **arrow_kw)
+ p = patches.FancyArrowPatch(arrow_tail,
+ arrow_head,
+ transform=transform,
+ **arrow_kw)
axes.add_patch(p)
- lc = mcollections.LineCollection(streamlines, **line_kw)
+ lc = mcollections.LineCollection(streamlines,
+ transform=transform,
+ **line_kw)
if use_multicolor_lines:
lc.set_array(np.asarray(line_colors))
lc.set_cmap(cmap)
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Oops, something went wrong.