Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Return arrow collection as 2nd argument of streamplot. #803

Merged
merged 4 commits into from

5 participants

@tonysyu

Return arrow patches so users can modify or remove them after calling streamplot. This was listed as a todo in the original implementation, but never actually done.

Maybe adding arrows to the axes should be delayed until the arrow collection is completely populated (and then the collection can be added to the axes all at once, just like the streamline collection)?

@efiring
Owner

I don't think this is a good idea; what is really needed is some sort of compound mappable artist. It doesn't have to be a new kind of collection, but it needs to be a single ScalarMappable so that when sci() is used and the colormap is changed, the lines and arrows change together.
Also, when a cmap kwarg is allowed, a norm kwarg should also be allowed.

@tonysyu

Hmm,... I was hoping it wouldn't come to that :)

I guess I'll take a look at the ContourSet object (as you suggested in the original streamplot PR) and emulate it's behavior.

BTW, after looking back at the original PR, I realized never flagged the streamplot function as experimental, as you suggested. I'm not really sure where that should be marked. Maybe in the return value itself (assuming that's the only major part that's likely change)?

@efiring
Owner

The ContourSet is a model in the sense that it produces and contains more than a single primitive Artist, and in that it requires extensive computation to generate those Artists, but it may not be an ideal model. It evolved a long time ago. It is possible that the Container base class would provide a good starting point. This is just speculation, though; I haven't looked closely.

@tonysyu

In the newest PR, streamplot returns a Container object with lines and arrows. This needs careful review because I had to override the __new__ constructor which didn't play well with Collections. I don't really understand the container object (e.g. why does it subclass tuple?), so I could be breaking something with this hack.

@leejjoon
Owner

The original purpose of the Container object was to support legend for complex plot commands. For example, errorbar command used to return a tuple of artists, thus I ended up with a simple Container class inherited from tuple. And it never meant to be a full implementation of artist.

I'm not sure what the streamplot need to return. Maybe a single object of a class inherited from a ScallarMappable (and Artist). And I think it might not be a good idea to use the Container class for this purpose.

@tonysyu

Thanks for your comments, @leejjoon. After rereading @efiring's comments, I realize that he suggested that Container would be a good starting point---not necessarily the base class for a streamplot container.

In my most recent commit, I change the base class to a simple object and give it attributes lines and arrows. As mentioned in the commit message, this is just a temporary fix since this object doesn't allow the user to set the properties of the lines and arrows from the object itself. Nevertheless, it does at least give users access to the arrows, and (I think) future changes (e.g. subclassing ScalarMappable and Artist) could be made backward-compatible with this simple object.

@efiring
Owner

@tonysu, sorry for the extra work, but would you rebase this against master, please? Then I will merge it. I should have done so a long time ago. It definitely needs to be done before the RC.

@efiring
Owner

@tonysyu, also, while you are at it, you might want to note, in docstrings, and/or comments, something about the limitations and likely evolution.

tonysyu added some commits
@tonysyu tonysyu Return arrow collection as 2nd argument of streamplot. 391c24a
@tonysyu tonysyu Return container object containing lines and arrows. 57a7d3d
@tonysyu tonysyu Change return value of `streamplot`.
- Return object that derives from `object` since deriving from `Container` was not beneficial.
- This return value is a stopgap; the final return value should allow users to set the colormap, alpha, etc. for both lines and arrows.
9875323
@tonysyu tonysyu DOC: Add note about future changes to return value a7248d9
@tonysyu

@efiring Rebased and added note about future changes to streamplot return value.

@tonysyu

Hmm, Github seems to be screwing up the order of the commits. The discussion page for this PR shows commits in order: 1, 3, 2, 4. The commit page shows them in sequential order, and the diff page looks fine so it's probably just a bug in the discussion page.

@travisbot

This pull request fails (merged a7248d9 into cadd152).

@efiring efiring merged commit 7a61238 into from
@pelson

Very late, I know, but this looks like a modification to an auto generated pyplot function. Do you know if that is the case?

Indeed. That was definitely a mistake on my part. @mdboom has already taken care of it though.

Collaborator

Aha! Thanks - didn't see that one go by.

Cheers

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Sep 2, 2012
  1. @tonysyu
  2. @tonysyu
  3. @tonysyu

    Change return value of `streamplot`.

    tonysyu authored
    - Return object that derives from `object` since deriving from `Container` was not beneficial.
    - This return value is a stopgap; the final return value should allow users to set the colormap, alpha, etc. for both lines and arrows.
  4. @tonysyu
This page is out of date. Refresh to see the latest.
View
22 lib/matplotlib/axes.py
@@ -6601,17 +6601,17 @@ def streamplot(self, x, y, u, v, density=1, linewidth=None, color=None,
cmap=None, norm=None, arrowsize=1, arrowstyle='-|>',
minlength=0.1, transform=None):
if not self._hold: self.cla()
- lines = mstream.streamplot(self, x, y, u, v,
- density=density,
- linewidth=linewidth,
- color=color,
- cmap=cmap,
- norm=norm,
- arrowsize=arrowsize,
- arrowstyle=arrowstyle,
- minlength=minlength,
- transform=transform)
- return lines
+ stream_container = mstream.streamplot(self, x, y, u, v,
+ density=density,
+ linewidth=linewidth,
+ color=color,
+ cmap=cmap,
+ norm=norm,
+ arrowsize=arrowsize,
+ arrowstyle=arrowstyle,
+ minlength=minlength,
+ transform=transform)
+ return stream_container
streamplot.__doc__ = mstream.streamplot.__doc__
@docstring.dedent_interpd
View
2  lib/matplotlib/pyplot.py
@@ -3055,7 +3055,7 @@ def streamplot(x, y, u, v, density=1, linewidth=None, color=None, cmap=None,
draw_if_interactive()
finally:
ax.hold(washold)
- sci(ret)
+ sci(ret.lines)
return ret
# This function was autogenerated by boilerplate.py. Do not edit as
View
30 lib/matplotlib/streamplot.py
@@ -9,6 +9,7 @@
import matplotlib.collections as mcollections
import matplotlib.patches as patches
+
__all__ = ['streamplot']
@@ -46,11 +47,16 @@ def streamplot(axes, x, y, u, v, density=1, linewidth=None, color=None,
*minlength* : float
Minimum length of streamline in axes coordinates.
- Returns *streamlines* : :class:`~matplotlib.collections.LineCollection`
- Line collection with all streamlines as a series of line segments.
- Currently, there is no way to differentiate between line segments
- on different streamlines (other than manually checking that segments
- are connected).
+ Returns
+ -------
+ *stream_container* : StreamplotSet
+ Container object with attributes
+ lines : `matplotlib.collections.LineCollection` of streamlines
+ arrows : collection of `matplotlib.patches.FancyArrowPatch` objects
+ repesenting arrows half-way along stream lines.
+ This container will probably change in the future to allow changes to
+ the colormap, alpha, etc. for both lines and arrows, but these changes
+ should be backward compatible.
"""
grid = Grid(x, y)
mask = StreamMask(density)
@@ -108,6 +114,7 @@ def streamplot(axes, x, y, u, v, density=1, linewidth=None, color=None,
cmap = cm.get_cmap(cmap)
streamlines = []
+ arrows = []
for t in trajectories:
tgx = np.array(t[0])
tgy = np.array(t[1])
@@ -139,6 +146,7 @@ def streamplot(axes, x, y, u, v, density=1, linewidth=None, color=None,
transform=transform,
**arrow_kw)
axes.add_patch(p)
+ arrows.append(p)
lc = mcollections.LineCollection(streamlines,
transform=transform,
@@ -151,7 +159,17 @@ def streamplot(axes, x, y, u, v, density=1, linewidth=None, color=None,
axes.update_datalim(((x.min(), y.min()), (x.max(), y.max())))
axes.autoscale_view(tight=True)
- return lc
+
+ ac = matplotlib.collections.PatchCollection(arrows)
+ stream_container = StreamplotSet(lc, ac)
+ return stream_container
+
+
+class StreamplotSet(object):
+
+ def __init__(self, lines, arrows, **kwargs):
+ self.lines = lines
+ self.arrows = arrows
# Coordinate definitions
Something went wrong with that request. Please try again.