From: Dominique O. <Dom...@po...> - 2004-08-18 19:45:45
|
Great, this is doing the job nicely, thanks ! I am not very clear as to=20 what the 'subs' argument really does. In your example: > #full control > gca().set_xscale('log',base=3D100,subs=3D[10,20,50]) > #Major tick every 16**i, minor tick every subs*16**i (16 should be 100 right?). There's a major tick at 100, 100^2, 100^3,=20 etc. And you're saying there are minor tick marks at 10*100*i ?!? What if you'd want tick labels [0, 1, 2, 3, 4, ...] instead of (in base=20 2, say) [1, 2, 4, 8, 16, ...] ? Is that easily done? I tried to obtain=20 it based on the example custom_ticker1.py (in the examples=20 subdirectory), but haven't been successful so far. Thanks A LOT for the update of axes.py and ticker.py, Dominique Gregory Lielens wrote: > Hi, I though about this too and your message has convinced me it was > worth spending a few minutes adding this ;-) > I just patched loglocator and logformater to be able to use arbitrary > base, and also to use arbitrary "minor" ticks. Well, I put minor betwee= n > quotes because Logticker do not really use minor ticks, only discard > label for ticks that are not integer exponents of base... > Usage is like this: > Semilogx(x,y) >=20 > #compatible with previous usage > gca().set_xscale('log')=20 > # major tick every 10**i, minor tick every range(2,10)*10**I >=20 > #change base > gca().set_xscale('log',base=3D16) > #Major tick every 16**i, minor tick every range(2,16)*16**i=20 >=20 > #full control > gca().set_xscale('log',base=3D100,subs=3D[10,20,50]) > #Major tick every 16**i, minor tick every subs*16**i=20 >=20 >=20 > This gives me all the flexibility I need, and I feel it is a step in th= e > right direction, but: > -maybe a rework of log ticker is needed so that it use minor/major tic= k > mechanism? Current mechanism is not as clean as it could, imho > -maybe autoscale for loglocator should adjust the base/range to avoid > excessive ticking (A discussion I had with john, with a zoom out it is > possible to have very dense ticking)...Not so easy to do though, as sub= s > has to be adjusted too if one does not want too many minor ticks, as > this adjustment is not so easy to do if one want "usefull" minor ticks > in logscale... > I thing these 2 points are linked, I would not go to 2 if 1 is not done= , > but if one is done (using some kind of linear locator (with autoscale > capability) on 1 decade for minor ticks, and repeat this minor tick on > each decade as I have done with my subs, I think we can have a very nic= e > framework to have fully automatic and nicely configurable log ticking > :-)=20 >=20 >=20 > Best regards, >=20 > Greg. >=20 > PS: the 2 modified files are included, I made my modif relative to > CVS... >=20 >=20 >>-----Message d'origine----- >>De : mat...@li...=20 >>[mailto:mat...@li...] De la=20 >>part de Dominique Orban >>Envoy=E9 : mardi 17 ao=FBt 2004 18:57 >>=C0 : mat...@li... >>Objet : [Matplotlib-users] Log plot in base b? >> >> >>Hi, >> >>What would be the easiest way, in matplotlib, to achieve log scaling,=20 >>along the x axis, say, in a base other than 10? I see in axes.py that=20 >>semilog[xy] have LOG10 hardwired. I am using matplotlib 0.60.2. >> >>Thanks, >>Dominique |
From: Jon W. <wr...@es...> - 2004-08-19 12:06:39
|
Hi all, Is there a trick hidden somewhere for autoscaling one axis only? I am frequently plotting data which has a series of narrow peaks and a large dynamic range. After zooming on the x-axis to the region of interest, I'd like to have an option to make the y axis rescale for the data in that range only. Having flailed around in the source I have the feeling that this is possible, but I haven't quite fathomed out how to do it (I'm using matplotlib for an interactive plot embedded in a tk application). Essentially I want the appropriate magic spell to give me a bounding box in y for the current x axis limits. The things I tried so far always seem to give the bounding box for all the data points, including the ones which are not currently being plotted on the x range. Sorry if I've missed something obvious! Thanks in advance, Jon |
From: John H. <jdh...@ac...> - 2004-08-19 14:56:06
|
>>>>> "Jon" == Jon Wright <wr...@es...> writes: Jon> Hi all, Is there a trick hidden somewhere for autoscaling one Jon> axis only? I am frequently plotting data which has a series Jon> of narrow peaks and a large dynamic range. After zooming on Jon> the x-axis to the region of interest, I'd like to have an Jon> option to make the y axis rescale for the data in that range Just to make sure you know, with the new toolbar2 (matplotlib-0.61) you can selectively scale the yaxis interactively by pressing the pan/zoom button, and clicking and dragging your right mouse button over the y axis while holding down the 'y' key. Ditto for pan with the left button. Jon> only. Having flailed around in the source I have the feeling Jon> that this is possible, but I haven't quite fathomed out how Jon> to do it (I'm using matplotlib for an interactive plot Jon> embedded in a tk application). Essentially I want the Jon> appropriate magic spell to give me a bounding box in y for Jon> the current x axis limits. The things I tried so far always Jon> seem to give the bounding box for all the data points, Jon> including the ones which are not currently being plotted on Jon> the x range. Sorry if I've missed something obvious! No you're not missing anything. I can give you an idea of how to hack this though. The autoscaling is controlled by a tick locator, found in matplotlib.tickers. There are a number of locators which derive from the Locator base class. You can access the major tick locator of a given axis with, for example locator = ax.yaxis.get_major_locator() The locator has a method to compute the view limits vmin, vmax = locator.autoscale() It uses a _transforms.Interval instance under the hood to get the data limits dmin, dmax which gives the min and max range for your data on that axis. Of course, this is the min and max for all the y data, not just the data in the current xrange, which is your problem. In order to solve this, your need to: 1) compute the data limits in the current viewport, 2) set the limited data lim on the axis interval instance, 3) use it to get the new autoscale limits, and 4) reset the old data lim interval instance back to its original setting. Assuming you know the y data lim in the xrange of interest (more on that later) you would do (untested but should work barring an obvious screw up) interval = ax.yaxis.get_data_interval() savemin, savemax = interval.get_bounds() dmin, dmax = # compute the y data limits in this xrange as below interval.set_bounds(dmin, dmax) # the locator has a ref to the interval and so sees your changes ax.set_ylim(locator.autoscale()) # autoscale returns (vmin, vmax) # now reset the original data lim interval.set_bounds(savemin, savemax) The only remaining thing is to get the ydata in xrange. This depends on the kind of data you plotted, but let's assume it is from 'plot' and thus your data are stored in Line2D instances. With a single line (eg returned by the call) 'line, = plot(x,y)' (note the comma for tuple unpacking) you can do import matplotlib.numerix as nx xmin, xmax = ax.get_xlim() xdata = line.get_xdata() ydata = line.get_xdata() ind = nx.nonzero(mx.logical_and(nx.greater_equal(xdata, xmin) nx.less_equal(xdata, xmax))) y = nx.take(ydata, ind) dmin, dmax = min(y), max(y) # and now set the data lim in the interval instance as indicated # above Now that's the process for a single line. For multiple lines, all you need to do is keep a running total of all the data to get the min/max of all the lines. The function ax.get_lines() will return all the data lines matplotlib uses. If you have scatters, pcolors and other kinds of plots which may use collections and other data structures, then more work would be needed still. However, you may have direct access to your data, in which case you can just use that to extract the ydata in the range. BTW, there has been some discussion on the devel list recently about a plugin feature to support easy customization and extension of the toolbar. This kind of thing is a perfect candidate for that, because you could create a plugin for 'autoscale y in the current xrange' and we could place it in a contrib plugin dir that others could add to their toolbar when they want. Hope this helps, JDH |
From: Gregory L. <gre...@ff...> - 2004-08-19 09:47:33
|
On Wed, 2004-08-18 at 21:45, Dominique Orban wrote: > Great, this is doing the job nicely, thanks ! I am not very clear as to > what the 'subs' argument really does. In your example: > > > #full control > > gca().set_xscale('log',base=100,subs=[10,20,50]) > > #Major tick every 16**i, minor tick every subs*16**i > > (16 should be 100 right?). oooouuuups, yes indeed, sorry! > There's a major tick at 100, 100^2, 100^3, > etc. And you're saying there are minor tick marks at 10*100*i ?!? hum, not really, minor tick every array([10,20,50])*100**i (I use array else python (and maybe some reader too familiar with python lists) may think I mean [10,20,50] concatenated 100**i with itself...that could be a very long list indeed ;-) )... So minor ticks at ...0.001,0.002,0.005,0.1,0.2,0.5,10,20,50,1000,2000,5000,... > What if you'd want tick labels [0, 1, 2, 3, 4, ...] instead of (in base > 2, say) [1, 2, 4, 8, 16, ...] ? > Is that easily done? I tried to obtain > it based on the example custom_ticker1.py (in the examples > subdirectory), but haven't been successful so far. You mean tick labels like a linear plot, but with log ticking? (and beware of 0, I doubt you will be able to see the 0 label in a log plot except if you do a *LOT* of paning ;-) ;-P ) If yes, this is not yet possible, because only "major" ticks (the one corresponding to base**i) are labeled, and what you want is labeling of all ticks...this would be feasible when I cleanup minor/major ticking for logscale, in the meantime I added a flag to logformatter to tell "label all ticks" instead of "label only major ticks". Then, to do what you want (or what I believe you want ;-) ), simply do gca().set_xscale('log',base=1000,label_minor=True). the base should be large enough so that your whole xrange is in it, and by default minor tick will be generated every unit. Be aware though that due to log spacing, last labels could be very close to each other and this ain't pretty ;-) That's why I allowed full control on minor ticks with subs, often you do want to carefully choose which ticks you want, because you can end up with a black mes of ticks and labels on the right of your graph if you don't... > Thanks A LOT for the update of axes.py and ticker.py, you're welcome, Greg. |