SourceForge logo
SourceForge logo
Menu

matplotlib-devel

From: Baptiste C. <bap...@al...> - 2005年01月23日 22:00:43
Attachments: twin.diff
Hello,
I tried to improve the way of plotting two scales (cf 
examples/two_scales.py). The attached patch contains the following changes:
in axis.py: allow right side label, so both y axes can get one. axis 
instances get a new property: label_position, which is left or right for 
yaxis, top or bottom for xaxis.
in axes.py: a new Axes subclass (TwinAxes) that shares the x axis with 
another. Transforms are set accordingly (lazy values for x lims are 
shared). This avoids having to change the xlim or xlabel (and so on) 2 
times.
in pylab.py: a new command (twin) that returns the twin of an axes 
instance (the current one by default), thus making it into a two scales 
plot.
How to use: see the new examples/two_scales.py for the typical use case.
Cheers,
BC
From: Baptiste C. <bap...@al...> - 2005年01月24日 00:27:25
Hello,
I got confused with my two patches. The pylab.py chunk from the other 
patch actually belongs here.
Sorry for that, I'll send a corrected version tomorrow, I need some sleep :)
Cheers,
BC
From: Baptiste C. <bap...@al...> - 2005年01月24日 21:30:57
Attachments: twin.diff
Hello,
here is the corrected patch, sorry for the noise.
Cheers,
BC
From: John H. <jdh...@ac...> - 2005年01月26日 19:57:41
>>>>> "Baptiste" == Baptiste Carvello <bap...@al...> writes:
 Baptiste> Hello, I tried to improve the way of plotting two scales
 Baptiste> (cf examples/two_scales.py). The attached patch contains
 Baptiste> the following changes:
Hi Baptiste -- I applied your patch and am very impressed. It takes a
lot of hacking through matplotlib internals to get everything working
right together with transform, axis limits and the like. Your
approach is also a significant improvement over what we currently
have.
Here is what I think would be ideal, and I wanted to sketch some of
these ideas in hopes that you might have some ideas on how to apply
them. Basically, the idea is that we want one axes to be able to
share the x or y limits with another axes in a more general way. Your
approach works fine as long as the two axes are overlayed. It would
be nice if we could do something like
 # separate axes
 ax1 = subplot(211)
 plot([1,2,3])
 ax2 = subplot(212, twinx=ax1)
 plot([4,5,6])
To do overlayed axes, you could do
 # overalyed axes
 ax1 = subplot(111)
 plot([1,2,3])
 ax2 = subplot(111, twinx=ax1, yticks='right')
 plot([4,5,6])
I think this would be a nice consistent interface and in both cases
ax2 would share the xlim with ax1. As far as I can see, the only
thing getting in the way of extending your approach to handle this
case are the tick labels, since they would be in the wrong place for
ax2 in the separate axes case. For the separate axes case, you would
typically want tick labeling on the lower axes, but it would be ideal
to be able to control that as well.
I've been meaning to decouple the axis line and tick locations from
the main axes frame so that you could have offset labels and ticks.
Perhaps this would be a good time to make both changes together.
The other problem in the current implementation (and in your patch)
stems from the fact that for event handling, only one axes gets the
event. So in your two_scales.py example, if you pan/zoom the xlimits
behave correctly but only one axes gets the pan/zoom event for y. It
would be nice to pass these events on to all the axes the user is over
to handle the case of overlapping axes.
Just some thoughts on what I think the proper behavior should be. If
you have any ideas on how to handle these, let me know. 
I just applied your two scales patch to CVS as an improved interim
solution.
Thanks!
JDH
From: Baptiste C. <bap...@al...> - 2005年01月27日 01:36:39
John Hunter a =E9crit :
> Here is what I think would be ideal, and I wanted to sketch some of
> these ideas in hopes that you might have some ideas on how to apply
> them. Basically, the idea is that we want one axes to be able to
> share the x or y limits with another axes in a more general way. Your
> approach works fine as long as the two axes are overlayed. It would
> be nice if we could do something like
>=20
> # separate axes
> ax1 =3D subplot(211)
> plot([1,2,3])
>=20
> ax2 =3D subplot(212, twinx=3Dax1)
> plot([4,5,6])
>=20
That sounds like a good syntax.
Its not a problem the share the x/ylims. As long as you can get the lazy=20
values at Axes creation, you can set the transforms correctly. The=20
question is whether or not to share the Axis instance. If you do, you=20
will have trouble drawing, if you don't, you have trouble when you want=20
to change the attributes (see below). I got away with this only because=20
I have to draw only one "physical" axis.
> To do overlayed axes, you could do
>=20
> # overalyed axes
> ax1 =3D subplot(111)
> plot([1,2,3])
>=20
> ax2 =3D subplot(111, twinx=3Dax1, yticks=3D'right')
> plot([4,5,6])
>=20
OK, you also have to set the frame to off, we'll see the details later.=20
Maybe we can keep just the twin function in pylab.py as a shortcut.
> I think this would be a nice consistent interface and in both cases
> ax2 would share the xlim with ax1. As far as I can see, the only
> thing getting in the way of extending your approach to handle this
> case are the tick labels, since they would be in the wrong place for
> ax2 in the separate axes case. For the separate axes case, you would
> typically want tick labeling on the lower axes, but it would be ideal
> to be able to control that as well.
>=20
> I've been meaning to decouple the axis line and tick locations from
> the main axes frame so that you could have offset labels and ticks.
> Perhaps this would be a good time to make both changes together.
>=20
That one is more tricky. All of matplotlib drawing model is based on the=20
premise that one objet draws at one given place. This has many=20
advantages. It allows the object to draw itself, which is good design.=20
It is also necessary for the cases where the final size matters (fonts,=20
linewidth). I don't think we want to change that.
< I stopped here, thought about it for some time, went back later >
I'm starting to wonder which properties of Axis we really want to share=20
between axes: limits, scale (linear/log), fmtdata, label, tick positions=20
(thus a common "tick factory"), tick label texts, viewLim, dataLim (we=20
need to think about update_datalim).
and which we do *not* want to share: all graphic objects, visibility of=20
labels (ticks ?), style of ticks and tick labels (you may want smaller=20
fonts in an inset), type of axis (XAxis, YAxis, ThetaAxis, Color, ...,=20
for ex. we may want to plot z(x,y) as pcolor and z(x) as line with=20
shared z lims)
Maybe we want to split an axis into 2 objects ? I need to think more=20
about this.
> The other problem in the current implementation (and in your patch)
> stems from the fact that for event handling, only one axes gets the
> event. So in your two_scales.py example, if you pan/zoom the xlimits
> behave correctly but only one axes gets the pan/zoom event for y. It
> would be nice to pass these events on to all the axes the user is over
> to handle the case of overlapping axes.
>=20
This is uncorrelated, and probably easier than the one above. We would=20
need to modify event.inaxes to be a list (in backend_bases), and act=20
upon all those axes in pan/zoom. When only one axes can be used (for ex.=20
the coordinates of the mouse in the status bar), we would use=20
event.inaxes[0], or maybe the most recently used axes (more difficult,=20
but maybe more consistent...we'll see at implementation time).
> Just some thoughts on what I think the proper behavior should be. If
> you have any ideas on how to handle these, let me know. =20
>=20
well, we need to discuss that a little bit more, so we'll get a clearer=20
view of where we go :-)
Cheers,
Baptiste
From: John H. <jdh...@ac...> - 2005年01月27日 22:12:38
>>>>> "Baptiste" == Baptiste Carvello <bap...@al...> writes:
 >> 
 Baptiste> That sounds like a good syntax. Its not a problem the
 Baptiste> share the x/ylims. As long as you can get the lazy
 Baptiste> values at Axes creation, you can set the transforms
 Baptiste> correctly. The question is whether or not to share the
 Baptiste> Axis instance. If you do, you will have trouble drawing,
 Baptiste> if you don't, you have trouble when you want to change
 Baptiste> the attributes (see below). I got away with this only
 Baptiste> because I have to draw only one "physical" axis.
Hi Baptiste,
After reading your email and studying your patch more, I now see how
to generalize this to the case of non-overlapping axes which share
either the x or y axis, eg ganged plots.
I have added some changes to CVS to support sharex and sharey kwargs
(I thought this was a better name than twinx and twiny). I had to
make some minor changes to axis to support sharing tick locators and
formatters, but nothing substantial. You can now instantiate an axes
with, eg
 subplot(212, sharex=ax1)
and ditto for sharey. The view limits, transform function, and tick
Locator and Formatter are shared. This allows you to pan and zoom on
one axes and have the others follow, which is very nice. There is a
new example showing how to use this example/shared_axis_demo.py.
I was able to remove the TwinAxes class altogether and use the shared
kwargs in its stead, which is cleaner. I preserved the "twin"
convenience function (naming it twinx) and all it does is pass the
proper kwargs and make the calls to tick_right.
examples/two_scales.py is updated
 Baptiste> I'm starting to wonder which properties of Axis we
 Baptiste> really want to share between axes: limits, scale
 Baptiste> (linear/log), fmtdata, label, tick positions (thus a
 Baptiste> common "tick factory"), tick label texts, viewLim,
 Baptiste> dataLim (we need to think about update_datalim).
 Baptiste> and which we do *not* want to share: all graphic
 Baptiste> objects, visibility of labels (ticks ?), style of ticks
 Baptiste> and tick labels (you may want smaller fonts in an
 Baptiste> inset), type of axis (XAxis, YAxis, ThetaAxis, Color,
 Baptiste> ..., for ex. we may want to plot z(x,y) as pcolor and
 Baptiste> z(x) as line with shared z lims)
 Baptiste> Maybe we want to split an axis into 2 objects ? I need
 Baptiste> to think more about this.
I don't think the datalim need to be shared because they are
responsible only for autoscaling. The new approach allows the
different axes to have different properties on their labels, eg font
size as you mentioned. While you cannot turn off labels selectively
on one axes with 
 set(ax2, xticklabels=[])
because this changes the Formatter which is shared, you can achieve
the same effect by setting the visibility property, which is not
shared
 set( ax2.get_xticklabels(), visible=False)
examples/ganged_plots.py, examples/two_scales.py, and
examples/shared_axis_demo.py show off the new features.
Let me know if this design covers the use cases you can think of.
 Baptiste> This is uncorrelated, and probably easier than the one
 Baptiste> above. We would need to modify event.inaxes to be a list
 Baptiste> (in backend_bases), and act upon all those axes in
 Baptiste> pan/zoom. When only one axes can be used (for ex. the
 Baptiste> coordinates of the mouse in the status bar), we would
 Baptiste> use event.inaxes[0], or maybe the most recently used
 Baptiste> axes (more difficult, but maybe more consistent...we'll
 Baptiste> see at implementation time).
Yes, this needs to be fixed and it is not very hard to do. There are
three event variables affected, inaxes, xdata and ydata, the latter
two give the data coords of the point in the axes the mouse is over.
As you know, the problem is that the current implementation only
registers the first axes and then breaks out of the loop. It would be
easy to fix this but I'm worried about two things: backward
compatibility (not a huge problem since only power users are using
this feature) and ease of use. It is really a corner case to be over
multiple axes, and I am hesitant to force the newbie to deal with this
in the typical case when there are no overlapping axes.
One possibility is to leave inaxes, xdata and ydata alone which
satisfies both problems above. And then to add a new attribute, axseq
which is a list of (ax, xdata, ydata ) tuples to handle the
overlapping axes case. Internally, we could use axseq so that pan/zoom
will be handled properly in the two_scales case. The draw back here
is that having more than one obvious way to do it may also confuse
people down the road. For clarity, the two interfaces I'm discussing are
def callback1(event): # current impl.
 if event.inaxes is not None:
 do_something with event.inaxes, event.xdata, event.ydata
def callback2(event): # candidate impl.
 for ax, xdata, ydata in event.axseq:
 do_something with ax, xdata, ydata
I'm weakly inclined to break backward compatibility and go with the
cleaner, comprehensive design in callback2, which on the face of it
doesn't look too hard to use. 
Suggestions?
JDH
From: Baptiste C. <bap...@al...> - 2005年01月30日 23:13:52
John Hunter a =E9crit :
> I have added some changes to CVS to support sharex and sharey kwargs
> (I thought this was a better name than twinx and twiny). I had to
> make some minor changes to axis to support sharing tick locators and
> formatters, but nothing substantial. You can now instantiate an axes
> with, eg
>=20
> subplot(212, sharex=3Dax1)
>=20
> and ditto for sharey. The view limits, transform function, and tick
> Locator and Formatter are shared. This allows you to pan and zoom on
> one axes and have the others follow, which is very nice. There is a
> new example showing how to use this example/shared_axis_demo.py.
>=20
Hi John,
I like this implementation a lot. Cool stuff !
> I was able to remove the TwinAxes class altogether and use the shared
> kwargs in its stead, which is cleaner. I preserved the "twin"
> convenience function (naming it twinx) and all it does is pass the
> proper kwargs and make the calls to tick_right.
> examples/two_scales.py is updated
>=20
you also need to call tick_left on the original axis, but that is a=20
minor correction.
> I don't think the datalim need to be shared because they are
> responsible only for autoscaling.
>
There is still a problem because autoscaling is disabled on the second=20
axes. I have an idea on how to solve this, I'll try it and send a patch=20
later in the week.
> One possibility is to leave inaxes, xdata and ydata alone which
> satisfies both problems above. And then to add a new attribute, axseq
> which is a list of (ax, xdata, ydata ) tuples to handle the
> overlapping axes case. Internally, we could use axseq so that pan/zoom
> will be handled properly in the two_scales case. The draw back here
> is that having more than one obvious way to do it may also confuse
> people down the road.
>=20
This sounds reasonable to me. I don't think it is confusing. If people=20
know what to do with multiple axes, they'll go with axseq, if not=20
inaxes, xdata and ydata will provide the most reasonable choice for them.
I'll play a little bit with this, and see if it breaks anything I use.
Cheers,
BC
Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.
Thanks for helping keep SourceForge clean.
X





Briefly describe the problem (required):
Upload screenshot of ad (required):
Select a file, or drag & drop file here.
Screenshot instructions:

Click URL instructions:
Right-click on the ad, choose "Copy Link", then paste here →
(This may not be possible with some types of ads)

More information about our ad policies

Ad destination/click URL:

AltStyle によって変換されたページ (->オリジナル) /