|
From: Gary R. <gr...@bi...> - 2006-05-18 14:54:25
|
I've been rewriting the Arrow class in patches.py to improve the look of quiver plots and am getting generally good results. The problems with current quiver plots are that arrows representing very small values are scaled along their length but not in width and also that arrowheads are not of a constant size. I have addressed both of these problems and getting results much more like Matlab quiver plots now. However, now that I am scaling arrow patches down to very small sizes, I see weird shaped arrows at some zoom levels but when I zoom in close enough to see the shape properly they look nicely formed. Is there a known problem, perhaps with Agg doing some fancy truncation in order to achieve good speed, where patches are distorted if their vertices are very close together at a particular magnification? I can provide code and graphic examples if it would help. Gary R. |
|
From: Jordan D. <jdawe@u.washington.edu> - 2006-05-18 15:17:41
|
Gary Ruben wrote:
> I've been rewriting the Arrow class in patches.py to improve the look
> of quiver plots and am getting generally good results. The problems
> with current quiver plots are that arrows representing very small
> values are scaled along their length but not in width and also that
> arrowheads are not of a constant size. I have addressed both of these
> problems and getting results much more like Matlab quiver plots now.
> However, now that I am scaling arrow patches down to very small sizes,
> I see weird shaped arrows at some zoom levels but when I zoom in close
> enough to see the shape properly they look nicely formed. Is there a
> known problem, perhaps with Agg doing some fancy truncation in order
> to achieve good speed, where patches are distorted if their vertices
> are very close together at a particular magnification? I can provide
> code and graphic examples if it would help.
Wow, serendipitously I'm working on exactly the same thing at the
moment. Question: when you zoom, do you ensure that the x-direction in
your window is the same length as the y-direction? My current theory on
this is the distorted arrows are the result of quiver measuring
everything in the x-y space of the plot, instead of in absolute terms.
Setting axis('equal') or axis('scaled') seems to improve the arrow
appearance...
Jordan
|
|
From: Gary R. <gr...@bi...> - 2006-05-18 22:16:15
Attachments:
modarrow.txt
|
Hi Jordan,
When I zoom, if the x and y zooms are not locked you will still get the
problem you mention with my modified arrows. They're still just patches
locked to the current x and y coordinates.
I've attached my modified Arrow() in case you want to look at it. It
requires a change to quiver in axes.py too to add the arrowstyle
parameter and pass it through but you can just ignore that stuff and
remove the arrowstyle references if you want to try it out. The changes
just keep the arrow head length fixed and adjust the length of the arrow
shaft until it gets so short that it becomes necessary to start scaling
down the width in proportion with the length (I'm not sure if that makes
sense).
Gary
Jordan Dawe wrote:
<snip>
> Wow, serendipitously I'm working on exactly the same thing at the
> moment. Question: when you zoom, do you ensure that the x-direction in
> your window is the same length as the y-direction? My current theory on
> this is the distorted arrows are the result of quiver measuring
> everything in the x-y space of the plot, instead of in absolute terms.
> Setting axis('equal') or axis('scaled') seems to improve the arrow
> appearance...
>
> Jordan
|
|
From: Jordan D. <jdawe@u.washington.edu> - 2006-05-18 22:35:29
|
Gary Ruben wrote:
> Hi Jordan,
> When I zoom, if the x and y zooms are not locked you will still get
> the problem you mention with my modified arrows. They're still just
> patches locked to the current x and y coordinates.
> I've attached my modified Arrow() in case you want to look at it. It
> requires a change to quiver in axes.py too to add the arrowstyle
> parameter and pass it through but you can just ignore that stuff and
> remove the arrowstyle references if you want to try it out. The
> changes just keep the arrow head length fixed and adjust the length of
> the arrow shaft until it gets so short that it becomes necessary to
> start scaling down the width in proportion with the length (I'm not
> sure if that makes sense).
> Gary
That makes a lot of sense. I've just been changing this line:
arrow[:,1] *= width
to
arrow[:,1] *= L*width
but this, of course, ends up with some weird looking arrows at the ends
of the data range
The main problem with quiver as it currently exists is that, if say you
plot:
quiver(ones([1,2]),ones([1,2]))
You end up with arrows that are twice as tall as they are wide, instead
of 45 degree arrows. This is definitely a bug, not a feature.
Here's a reference talking about the different coordinate systems
accessible in matplotlib:
http://www.scipy.org/Cookbook/Matplotlib/Transformations
I think what we need is to set the coordinate transform to be in and
absolute, instead of relative, coordinate system, or to build one
ourselves. But I don't know enough about matplotlib's internals to know
if this is right. Comments?
Jordan
|
|
From: John H. <jdh...@ac...> - 2006-05-18 23:24:01
|
>>>>> "Jordan" == Jordan Dawe <jdawe@u.washington.edu> writes:
Jordan> Here's a reference talking about the different coordinate
Jordan> systems accessible in matplotlib:
Jordan> http://www.scipy.org/Cookbook/Matplotlib/Transformations
Jordan> I think what we need is to set the coordinate transform to
Jordan> be in and absolute, instead of relative, coordinate
Jordan> system, or to build one ourselves. But I don't know
Jordan> enough about matplotlib's internals to know if this is
Jordan> right. Comments?
This is probably what you want to do. You want to define your arrow
in something like points, then do a rotation, and then apply one of
the transformation offsets to place your arrow at an x,y location.
Note there is a bug in some version of matplotlib in the affine code
which is fixes in SVN -- this arrow should have it's base at 0.5, 0.5
and be pointing NW and measure 2 inches from base to tip. The arrow
size is independent of zoom and figure window size, which may or may
not be desirable....
from matplotlib.transforms import Affine, Value, zero
from matplotlib.patches import Polygon
from pylab import figure, show, nx
fig = figure()
ax = fig.add_subplot(111, xlim=(0,1), ylim=(0,1), autoscale_on=False)
sx = 144/72.*fig.dpi.get() # 2 inches
sy = 144/72.*fig.dpi.get()
theta = 45*nx.pi/180.
# arrow drawn in pixels
trans = Affine(
Value(sx*nx.cos(theta)),
Value(sx*nx.sin(theta)),
Value(-sy*nx.sin(theta)),
Value(sy*nx.cos(theta)),
zero(),
zero())
verts = [
(-0.05,0.75),
(0, 1.),
(0.05,0.75),
(0.05,0),
(-0.05,0),
]
# offset in data coords
trans.set_offset((0.5, 0.5), ax.transData)
poly = Polygon(verts, transform=trans)
ax.add_patch(poly)
show()
|
|
From: Jordan D. <jdawe@u.washington.edu> - 2006-05-18 23:44:06
|
> Jordan> Here's a reference talking about the different coordinate > Jordan> systems accessible in matplotlib: > > Jordan> http://www.scipy.org/Cookbook/Matplotlib/Transformations > > Jordan> I think what we need is to set the coordinate transform to > Jordan> be in and absolute, instead of relative, coordinate > Jordan> system, or to build one ourselves. But I don't know > Jordan> enough about matplotlib's internals to know if this is > Jordan> right. Comments? > > This is probably what you want to do. You want to define your arrow > in something like points, then do a rotation, and then apply one of > the transformation offsets to place your arrow at an x,y location. > Note there is a bug in some version of matplotlib in the affine code > which is fixes in SVN -- this arrow should have it's base at 0.5, 0.5 > and be pointing NW and measure 2 inches from base to tip. The arrow > size is independent of zoom and figure window size, which may or may > not be desirable.... > Wow, that's service. Yeah, that's almost exactly what we want... but you are right, it would be better if the arrow scaled with the figure size, but maintained it's aspect ratio. I'll try to play around with your example and figure out how to make it work. Thanks a lot. Jordan |
|
From: Jordan D. <jdawe@u.washington.edu> - 2006-05-23 03:14:13
|
>> This is probably what you want to do. You want to define your arrow >> in something like points, then do a rotation, and then apply one of >> the transformation offsets to place your arrow at an x,y location. >> Note there is a bug in some version of matplotlib in the affine code >> which is fixes in SVN -- this arrow should have it's base at 0.5, 0.5 >> and be pointing NW and measure 2 inches from base to tip. The arrow >> size is independent of zoom and figure window size, which may or may >> not be desirable.... Ok, I've done a bunch of work on making quiver work without distorting the arrows. I have a lot of questions. I've been playing with the transforms functions all weekend and I still don't understand the different transforms between figure, axes, and absolute space. Or how to get access to the 'width' and 'height' Values that are mentioned in the comments of transform.py. The arrow size in quiver() should not be independent of zoom; it should scale with the figure and axis size. Ideally by default quiver() should ensure that the largest arrow doesn't overlap the 'gridbox' of the arrows next to it. The problem is that in order to ensure the arrow is rotated properly, the rotation must take place in absolute coordinates, but the length scaling should take place in data coordinates. Furthermore, the scaling should be a conditional: it should see if the x or the y axis is most 'in danger' of having an arrow larger than its box in data space, and then scale both the x and y coordinates equally in absolute space to ensure the arrow isn't distorted. I'm not sure this is even possible with Values; I think it would require at least a greater_than BinOp, but I don't really understand all the transform functionality or how to get access to it. Is there a way to do this? After looking at all the files this weekend, I'm still not even sure what matplotlib considers to be 'first-class' primitives. Is it patches, lines, etc? What should a call to quiver() return? A list of polygons? It's returning a collection in svn, but I don't think you can set each object in a collection to a different transform. When should a collection be used? I don't know if I'm making any sense here; I'm fairly frustrated after a weekend with little progress. Is there any hidden documentation that could help me? Jordan |
|
From: Eric F. <ef...@ha...> - 2006-05-23 18:03:22
|
Jordan, I have committed changes in color handling that allow the collection initializers to accept the usual flexible mpl color specifications. Your message about quiver prompted me to try examples/quiver_demo.py, which is not run by backend_drivers.py, and which I had therefore not tested. It doesn't work now--and it doesn't make any sense to me, either. (E.g., what on earth is "color=True" supposed to mean?) That is, it is not clear to me what the quiver invocations in the demo are supposed to do based on the quiver doc string. The simplest quiver invocation works, but it looks to me like the argument handling beyond that is broken, and I don't think it is entirely the fault of my recent changes. I can help straighten it out, given a clear specification of what quiver is actually supposed to do with various argument combinations. Let me know if and when this would be useful. Eric |
|
From: Jordan D. <jdawe@u.washington.edu> - 2006-05-23 20:32:35
|
Eric Firing wrote: > I have committed changes in color handling that allow the collection > initializers to accept the usual flexible mpl color specifications. > Your message about quiver prompted me to try examples/quiver_demo.py, > which is not run by backend_drivers.py, and which I had therefore not > tested. It doesn't work now--and it doesn't make any sense to me, > either. (E.g., what on earth is "color=True" supposed to mean?) That > is, it is not clear to me what the quiver invocations in the demo are > supposed to do based on the quiver doc string. The simplest quiver > invocation works, but it looks to me like the argument handling beyond > that is broken, and I don't think it is entirely the fault of my > recent changes. I can help straighten it out, given a clear > specification of what quiver is actually supposed to do with various > argument combinations. Let me know if and when this would be useful. I believe "color=True" is intended to give the arrows a color value based upon the arrow length. Calling quiver with color=True fails because looks_like_color( ) now treats True as a mistaken grey specification; it raises a warning saying to enclose True in brackets. quiver wants looks_like_color(True) to simply return a False. for 'color' quiver appears to want either: a) Something that looks_like_color(), in which case all arrows are that color b) A True, in which case arrows are colored by length c) An array the same size as the first data array, in which case the arrows are the colors specified in the array d) Anything else, which makes them black. I don't know if this is a good use of color=... because I don't know how uniform you want the matplotlib interface to be in its keyword use. We could set up a "color_by_length=True" keyword for quiver that would override the color setting, that would probably be my fix the problem. Jordan |
|
From: Eric F. <ef...@ha...> - 2006-05-23 21:09:28
|
Jordan,
Thanks for the explanation. It makes some sense now, but doesn't
impress me as a good API. Having color track arrow length does not seem
to me to warrant its own special and slightly bizarre syntax
("color=True"--completely non-intuitive). It would make more sense for
the user to simply provide an array to be mapped; if the user wants that
array to be the arrow length (hence redundant), the user can do that
calculation and provide that array.
What I would like to see is a reconsideration of the API and
corresponding docstring, as part of your massive re-write. This is a
good opportunity to think about what would constitute a clean and
consistent interface.
Jordan Dawe wrote:
> Eric Firing wrote:
>
>> I have committed changes in color handling that allow the collection
>> initializers to accept the usual flexible mpl color specifications.
>> Your message about quiver prompted me to try examples/quiver_demo.py,
>> which is not run by backend_drivers.py, and which I had therefore not
>> tested. It doesn't work now--and it doesn't make any sense to me,
>> either. (E.g., what on earth is "color=True" supposed to mean?) That
>> is, it is not clear to me what the quiver invocations in the demo are
>> supposed to do based on the quiver doc string. The simplest quiver
>> invocation works, but it looks to me like the argument handling beyond
>> that is broken, and I don't think it is entirely the fault of my
>> recent changes. I can help straighten it out, given a clear
>> specification of what quiver is actually supposed to do with various
>> argument combinations. Let me know if and when this would be useful.
>
> I believe "color=True" is intended to give the arrows a color value
> based upon the arrow length. Calling quiver with color=True fails
> because looks_like_color( ) now treats True as a mistaken grey
> specification; it raises a warning saying to enclose True in brackets.
> quiver wants looks_like_color(True) to simply return a False.
Aha! This is an example of why we are deprecating float-as-grayscale.
>
> for 'color' quiver appears to want either:
>
> a) Something that looks_like_color(), in which case all arrows are that
> color
> b) A True, in which case arrows are colored by length
> c) An array the same size as the first data array, in which case the
> arrows are the colors specified in the array
> d) Anything else, which makes them black.
It also looks to me like the argument parsing can incorrectly interpret
a scale factor as a color. Maybe this also used to work, but if so, it
was at best fragile.
>
> I don't know if this is a good use of color=... because I don't know how
> uniform you want the matplotlib interface to be in its keyword use. We
> could set up a "color_by_length=True" keyword for quiver that would
> override the color setting, that would probably be my fix the problem.
The length of that proposed keyword is a warning flag that it may also
be a bad design. Again, I would say either eliminate built-in support
for color-by-length, or implement it via "color='length'", and then
intercept that non-standard 'length' specification inside quiver so that
it never gets passed to the standard color-handling routines.
Now that you have explained it, I am inclined to either do a quick-fix
of the present quiver so that it works again roughly as-is, or change
the example so that it does not use the undocumented(?) "color=True"
syntax; is one of these alternatives OK with you? Do you have a
preference? Or do you already have an improved version that we can
substitute now? One way or another, I don't want to leave a
non-functioning demo in svn.
Eric
|
|
From: Jordan D. <jdawe@u.washington.edu> - 2006-05-23 22:14:06
|
> The length of that proposed keyword is a warning flag that it may also > be a bad design. Again, I would say either eliminate built-in support > for color-by-length, or implement it via "color='length'", and then > intercept that non-standard 'length' specification inside quiver so > that it never gets passed to the standard color-handling routines. > > Now that you have explained it, I am inclined to either do a quick-fix > of the present quiver so that it works again roughly as-is, or change > the example so that it does not use the undocumented(?) "color=True" > syntax; is one of these alternatives OK with you? Do you have a > preference? Or do you already have an improved version that we can > substitute now? One way or another, I don't want to leave a > non-functioning demo in svn. I would remove it; if we want a quiver function with color as length, we could create a wrapper function to do that. I would lean towards making people generate their own color array based on the array length. I'm not going to have a new quiver anytime soon I think--a friend of mine today pointed out that matlab distorts quiver arrows just like matplotlib does. In matlab it isn't as noticable, however, since matlab impliments quiver as lines instead of as polygons. In the short term, I'm seriously tempted to just make matplotlib do the same. Jordan |
|
From: Gary R. <gr...@bi...> - 2006-05-23 23:15:29
|
I did a tiny bit of work on this over the weekend too and decided to try to use a LineCollection instead of patches inspired by Chris Barker's code, but removing his polar coordinate stuff. Lines seemed a more promising way to go for the arrows, although the width should scale down when the arrows get small so that they're never wider than their length. Using a line collection may not permit this. I also haven't got it working yet. FWIW, Jordan's explanations of expected behaviour have been spot on so far. Also, I'd be happy to see the API fixed up a bit. Gary R. Jordan Dawe wrote: > >> The length of that proposed keyword is a warning flag that it may also >> be a bad design. Again, I would say either eliminate built-in support >> for color-by-length, or implement it via "color='length'", and then >> intercept that non-standard 'length' specification inside quiver so >> that it never gets passed to the standard color-handling routines. >> >> Now that you have explained it, I am inclined to either do a quick-fix >> of the present quiver so that it works again roughly as-is, or change >> the example so that it does not use the undocumented(?) "color=True" >> syntax; is one of these alternatives OK with you? Do you have a >> preference? Or do you already have an improved version that we can >> substitute now? One way or another, I don't want to leave a >> non-functioning demo in svn. > I would remove it; if we want a quiver function with color as length, we > could create a wrapper function to do that. I would lean towards making > people generate their own color array based on the array length. I'm > not going to have a new quiver anytime soon I think--a friend of mine > today pointed out that matlab distorts quiver arrows just like > matplotlib does. In matlab it isn't as noticable, however, since matlab > impliments quiver as lines instead of as polygons. In the short term, > I'm seriously tempted to just make matplotlib do the same. > > Jordan |
|
From: John H. <jdh...@ac...> - 2006-05-24 12:59:53
|
>>>>> "Gary" == Gary Ruben <gr...@bi...> writes:
Gary> I did a tiny bit of work on this over the weekend too and
Gary> decided to try to use a LineCollection instead of patches
Gary> inspired by Chris Barker's code, but removing his polar
Gary> coordinate stuff. Lines seemed a more promising way to go
Gary> for the arrows, although the width should scale down when
Gary> the arrows get small so that they're never wider than their
Gary> length. Using a line collection may not permit this. I also
Gary> haven't got it working yet. FWIW, Jordan's explanations of
Gary> expected behaviour have been spot on so far. Also, I'd be
Gary> happy to see the API fixed up a bit.
You can derive a custom line collection which has this behavior --
LineCollection supports an independent linewidth for each segment, so
as long as you keep an array of linewidths and an array of arrow
lengths, you can clip or set the linelengths at draw time or at
segment setting time. draw time is probably more appropriate, since
then you can account for figure window size under resizes, etc....
JDH
|
|
From: Gary R. <gr...@bi...> - 2006-05-24 14:56:04
|
Thanks John, I hope to have another go at this over the weekend but this sounds like a promising avenue, Gary R. |
|
From: Gary R. <gr...@bi...> - 2006-05-28 23:17:17
|
Just a quick progress report. First, an observation I should make is that despite there being quite a lot of documentation in the mpl code, I found it tough going to understand what the documentation means. I kept running into jargon and assumptions which made it hard to follow. I know it's hard to document things, but I think some diagrams and a glossary would be really helpful. I did in fact spend a few hours trying to understand transforms and hacking at the quiver plot code over the weekend and have made no real progress. I haven't given up, but given the small amount of time I can spend on this, if anyone is hanging out (Jordan?) for improved quiver plots, they may want to move ahead independently on it. Gary Gary Ruben wrote: > Thanks John, > I hope to have another go at this over the weekend but this sounds like > a promising avenue, > Gary R. |
|
From: Jordan D. <jdawe@u.washington.edu> - 2006-05-29 06:20:36
|
I've been working on quiver a little over the weekend. I refactored it so it works with non-regularly spaced X and Y data, and made it use Gary's LineArrow code. I don't have the variable colors for the arrows working yet though. I'm going to try to get that working before I submit my patch. I haven't even tried to do any of the absolute vs data coordinate stuff yet. Jordan |
|
From: Jordan D. <jdawe@u.washington.edu> - 2006-05-30 04:25:23
|
> from collections import LineCollection
> class Arrow(LineCollection):
> """
> An arrow
> """
> def __init__( self, x, y, dx, dy, width=1.0, arrowstyle='solid',
> **kwargs ):
> """Draws an arrow, starting at (x,y), direction and length
> given by (dx,dy) the width of the arrow is scaled by width.
> arrowstyle may be 'solid' or 'barbed'
> """
> L = math.hypot(dx,dy) or 1 # account for div by zero
> S = 0.1
> arrow = {'barbed': array([[0.,0.], [L,0.], [L-S,S/3],
> [L,0.], [L,-S/3], [L,0.]]),
> 'solid': array([[0.,0.], [L-S,0.], [L-S,S/3],
> [L,0.], [L-S,-S/3], [L-S,0.]])
> }[arrowstyle]
>
> cx = float(dx)/L
> sx = float(dy)/L
> M = array([[cx, sx], [-sx, cx]])
> verts = matrixmultiply(arrow, M) + [x,y]
> LineCollection.__init__(self, [tuple(t) for t in verts],
> **kwargs)
I've found one problem with your Arrow LineCollection; it's not actually
a line collection. It's one line, so some of the LineCollection
functions fail on it. You need to break up the arrow into segments,
like this:
'barbed': array([ [ [0.,0.], [L,0.] ],
[ [L,0.], [L-S,S/3] ],
[ [L,0.], [L-S,-S/3] ] ]
Except just doing this will break the matrixmultiply. Just a heads-up.
Jordan
|
|
From: Gary R. <gr...@bi...> - 2006-05-30 13:03:19
|
Hi Jordan, Thanks for your heads-up. I actually left this and went back to using polygon patches for the arrows, mainly because I thought I'd have more control over the size without having to do any fancy line collection stuff. Re. your change, the call to the LineCollection__init__ function in axes.py just needs an extra set of []'s around the list comprehension and all is OK, but your solution could work too. I do intend to look again at the transform stuff to try to get arrows transforming properly - just very busy at the moment, but then I usually am. Gary R. > I've found one problem with your Arrow LineCollection; it's not actually > a line collection. It's one line, so some of the LineCollection > functions fail on it. You need to break up the arrow into segments, > like this: > > 'barbed': array([ [ [0.,0.], [L,0.] ], > [ [L,0.], [L-S,S/3] ], > [ [L,0.], [L-S,-S/3] ] ] > > Except just doing this will break the matrixmultiply. Just a heads-up. > > Jordan |
|
From: Rob H. <he...@ta...> - 2006-05-24 14:50:46
|
On May 23, 2006, at 2:02 PM, Eric Firing wrote: > I have committed changes in color handling that allow the > collection initializers to accept the usual flexible mpl color > specifications. Your message about quiver prompted me to try > examples/quiver_demo.py, which is not run by backend_drivers.py, > and which I had therefore not tested. It doesn't work now--and it > doesn't make any sense to me, either. (E.g., what on earth is > "color=True" supposed to mean?) That is, it is not clear to me what > the quiver invocations in the demo are supposed to do based on the > quiver doc string. The simplest quiver invocation works, but it > looks to me like the argument handling beyond that is broken, and I > don't think it is entirely the fault of my recent changes. I can > help straighten it out, given a clear specification of what quiver > is actually supposed to do with various argument combinations. Let > me know if and when this would be useful. It might make some sense to rethink the quiver API, especially since it seems there are a few people working toward the same goal (I will help, too, if someone can give me some tasks..). Here's a strawman quiver API: quiver(x, y, u, v, color='b', scale=1.0, scale_to_grid=False, **kwargs) x, y - quiver should be able to handle *random* (x, y) points (right now, it seems to expect meshed positions -- it seems this is an unnecessary constraint.) color - could be a plot-style color (e.g., 'b', 'k', 'm'), a tuple, or an array the same size as x and y to be mapped using the colormap. scale - is a multiplier for the vector length. scale_to_grid - is a boolean that specifies whether the vectors should be in grid coordinates (True), or scaled to fit nicely (False -- vectors are scaled to fit nice, then multiplied by scale). Plus all the normal kwargs (e.g., cmap). Other potential things to consider include scaling the aspect of the vectors so that the grid can have an aspect ratio unequal to one, but the vectors still scale correctly (i.e., u and v have the same length, even when x is twice y). Finally, I have always wanted an easy way to do curly vectors -- similar to streaklines -- but this might be beyond the scope of the simple quiver command. -Rob ----- Rob Hetland, Assistant Professor Dept of Oceanography, Texas A&M University p: 979-458-0096, f: 979-845-6331 e: he...@ta..., w: http://pong.tamu.edu |
|
From: Gary R. <gr...@bi...> - 2006-05-24 15:39:47
|
Looks good, but I think it also needs a 'width' or 'weight' kwarg. I was also thinking of putting at least a couple of different arrow styles in via an 'arrowstyle' kwarg, so I'd pass those through to the Arrow LineCollection. Gary R. Rob Hetland wrote: > It might make some sense to rethink the quiver API, especially since it > seems there are a few people working toward the same goal (I will help, > too, if someone can give me some tasks..). > > Here's a strawman quiver API: > > quiver(x, y, u, v, color='b', scale=1.0, scale_to_grid=False, **kwargs) > > x, y - quiver should be able to handle *random* (x, y) points (right > now, it seems to expect meshed positions -- it seems this is > an unnecessary constraint.) > > color - could be a plot-style color (e.g., 'b', 'k', 'm'), a tuple, or > an array the same size as x and y to be mapped using the colormap. > > scale - is a multiplier for the vector length. > > scale_to_grid - is a boolean that specifies whether the vectors should > be in grid coordinates (True), or scaled to fit nicely (False -- vectors > are scaled to fit nice, then multiplied by scale). > > Plus all the normal kwargs (e.g., cmap). > > > Other potential things to consider include scaling the aspect of the > vectors so that the grid can have an aspect ratio unequal to one, but > the vectors still scale correctly (i.e., u and v have the same length, > even when x is twice y). > > Finally, I have always wanted an easy way to do curly vectors -- similar > to streaklines -- but this might be beyond the scope of the simple > quiver command. > > -Rob |
|
From: Eric F. <ef...@ha...> - 2006-05-23 18:44:04
|
Jordan Dawe wrote: > >>> This is probably what you want to do. You want to define your arrow >>> in something like points, then do a rotation, and then apply one of >>> the transformation offsets to place your arrow at an x,y location. >>> Note there is a bug in some version of matplotlib in the affine code >>> which is fixes in SVN -- this arrow should have it's base at 0.5, 0.5 >>> and be pointing NW and measure 2 inches from base to tip. The arrow >>> size is independent of zoom and figure window size, which may or may >>> not be desirable.... > > Ok, I've done a bunch of work on making quiver work without distorting > the arrows. I have a lot of questions. I've been playing with the > transforms functions all weekend and I still don't understand the > different transforms between figure, axes, and absolute space. Or how > to get access to the 'width' and 'height' Values that are mentioned in > the comments of transform.py. > > The arrow size in quiver() should not be independent of zoom; it should > scale with the figure and axis size. Ideally by default quiver() should > ensure that the largest arrow doesn't overlap the 'gridbox' of the > arrows next to it. The problem is that in order to ensure the arrow is > rotated properly, the rotation must take place in absolute coordinates, > but the length scaling should take place in data coordinates. > Furthermore, the scaling should be a conditional: it should see if the x > or the y axis is most 'in danger' of having an arrow larger than its box > in data space, and then scale both the x and y coordinates equally in > absolute space to ensure the arrow isn't distorted. I'm not sure this > is even possible with Values; I think it would require at least a > greater_than BinOp, but I don't really understand all the transform > functionality or how to get access to it. Is there a way to do this? > > After looking at all the files this weekend, I'm still not even sure > what matplotlib considers to be 'first-class' primitives. Is it > patches, lines, etc? What should a call to quiver() return? A list of > polygons? It's returning a collection in svn, but I don't think you can > set each object in a collection to a different transform. When should a > collection be used? I think your questions here have two aspects. The first is, exactly what functionality should quiver have? I have always thought Matlab's quiver was ugly and fairly useless for my own purposes, so I don't advocate copying it. Have you written out a docstring or other specification of what quiver should do and what its API should be? The second part is, what should Axes plotting methods return? There are two styles: contour returns a whole ContourSet object; most (all?) other methods return only the Artists (e.g. a Line or a Collection.) When I changed contour to return the ContourSet, and more recently when I did a little reorganization of axes.py, John mentioned that it might be desirable to make other methods behave similarly, but I don't think there has been any more recent discussion, and I have not gotten back to it myself. Returning higher-level objects does fit in with moving more complicated functionality out of axes.py, which I would still like to do--eventually. > > I don't know if I'm making any sense here; I'm fairly frustrated after a > weekend with little progress. Is there any hidden documentation that > could help me? I made some scratch-paper notes for myself, but never considered my understanding complete, and it fades fast. Parts are covered quite well in the transforms.py docstring, but a good overview, clearly laying out the various coordinate systems (with a good naming convention) and where and how transformations are made would be a big help. This is something I might be able to work on, but it might not be very efficient for me to do it. And I might not be able to do it fast enough to help with your present quivering. Eric |
|
From: John H. <jdh...@ac...> - 2006-05-18 15:44:30
|
>>>>> "Gary" == Gary Ruben <gr...@bi...> writes:
Gary> I've been rewriting the Arrow class in patches.py to improve
Gary> the look of quiver plots and am getting generally good
Gary> results. The problems with current quiver plots are that
Gary> arrows representing very small values are scaled along their
Gary> length but not in width and also that arrowheads are not of
Gary> a constant size. I have addressed both of these problems and
Gary> getting results much more like Matlab quiver plots
Gary> now. However, now that I am scaling arrow patches down to
Gary> very small sizes, I see weird shaped arrows at some zoom
Gary> levels but when I zoom in close enough to see the shape
Gary> properly they look nicely formed. Is there a known problem,
Gary> perhaps with Agg doing some fancy truncation in order to
Gary> achieve good speed, where patches are distorted if their
Gary> vertices are very close together at a particular
Gary> magnification? I can provide code and graphic examples if it
Gary> would help.
My guess is that this has something to do with subpixel rendering, and
it has cropped up in a number of circumstances. Unfortunately, I
don't know of an easy answer. If you tell agg to draw a line from 0,0
to 1,1, the line will look different than a line from .5,.5 to 1.5,1.5
See
http://antigrain.com/tips/line_alignment/line_alignment.agdoc.html#PAGE_LINE_ALIGNMENT
One way to confirm that this is your problem is to turn antialiasing
off
patch.set_antialiased(False)
but I just noticed that the agg draw_polygon method does not respect
the aa setting, so I just committed changes to svn to fix this. Do
you have access to svn?
With svn in the example below, the green polygon should look more
jaggy than the yellow one. My guess is that this weirdness for small
arrows will go away with antialiasing off, but then you will have
crappy, aliased arrows. Not sure what the right answer is...
from matplotlib.patches import RegularPolygon
from pylab import figure, show
p1 = RegularPolygon((1,1), 5, antialiased=True, facecolor='yellow', linewidth=5)
p2 = RegularPolygon((0,0), 5, antialiased=False, facecolor='green', linewidth=5, alpha=0.5)
fig = figure()
ax = fig.add_subplot(111, xlim=(-6,6), ylim=(-6,6), autoscale_on=False)
ax.add_patch(p1)
ax.add_patch(p2)
show()
JDH
|
|
From: Gary R. <gr...@bi...> - 2006-05-18 22:02:42
|
Hi John, I'll have a look at this over the weekend. From the link and example you provided I'm not yet sure that subpixel rendering is the problem, but it could well be - What I'm getting is the vertices displaced away from the expected position by quite a way, but I'll see if the patch you made is at the Python level, in which case I can try it easily, or if at the C level, it may be time to try my Ubuntu installation out and finally learn to build from source. thanks, Gary |
|
From: Christopher B. <Chr...@no...> - 2006-05-18 23:35:10
Attachments:
VecPlot.py
|
John Hunter wrote:
> Jordan> I think what we need is to set the coordinate transform to
> Jordan> be in and absolute, instead of relative, coordinate
> Jordan> system,
> This is probably what you want to do. You want to define your arrow
> in something like points, then do a rotation, and then apply one of
> the transformation offsets to place your arrow at an x,y location.
This sounds a lot like what a I did a while ago (following suggested
code form JDH), and posted here. My intent is to clean it up so that it
can get included in MPL, but I haven't had the chance. Meanwhile, here
it is again. Use it as you will.
-Chris
--
Christopher Barker, Ph.D.
Oceanographer
NOAA/OR&R/HAZMAT (206) 526-6959 voice
7600 Sand Point Way NE (206) 526-6329 fax
Seattle, WA 98115 (206) 526-6317 main reception
Chr...@no...
|