margins, locator_params, formatter offset

During the last few days I have added some convenience methods and pyplot functions. Please review them to see whether names, APIs, or functionality should be changed. The general motivation is that formatters and locators are a bit obscure and hidden in the object hierarchy, so I wanted to make it easier for people to make simple changes. In addition, in autoscaling, one might want an option that is almost "tight" but leaves a little margin, so symbols at the edge don't get sliced off, for example.

At the Axes and pyplot levels, the changes made so far include expanding ticklabel_format() and adding two new methods/functions, locator_params() and margins(). The change to ticklabel_format is the addition of a new kwarg:

           *useOffset* [True | False | offset]; if True,
                          the offset will be calculated as needed;
                          if False, no offset will be used; if a
                          numeric offset is specified, it will be
                          used.

This involved changing the underlying ScalarFormatter to accept a numeric offset as an alternative to calculating it automatically.

The docstrings for the new methods are:

     def locator_params(self, axis='both', tight=False, **kwargs):
         """
         Convenience method for controlling tick locators.

         Keyword arguments:

         *axis*
             ['x' | 'y' | 'both'] Axis on which to operate;
             default is 'both'.

         *tight*
             [True | False] Parameter passed to :meth:`autoscale_view`.

         Remaining keyword arguments are passed to directly to the
         :meth:`~matplotlib.ticker.MaxNLocator.set_params` method.

         Typically one might want to reduce the maximum number
         of ticks and use tight bounds when plotting small
         subplots, for example::

             ax.locator_params(tight=True, nbins=4)

         Because the locator is involved in autoscaling,
         :meth:`autoscale_view` is called automatically after
         the parameters are changed.

         This presently works only for the
         :class:`~matplotlib.ticker.MaxNLocator` used
         by default on linear axes, but it may be generalized.
         """

and

     def margins(self, *args, **kw):
         """
         Convenience method to set or retrieve autoscaling margins.

         signatures::

             margins()

         returns xmargin, ymargin

         ::

             margins(margin, tight=True)

             margins(xmargin, ymargin, tight=True)

             margins(x=xmargin, y=ymargin, tight=True)

         All three forms above set the xmargin and ymargin parameters.
         All keyword parameters are optional. A single argument
         specifies both xmargin and ymargin. The *tight* parameter
         is passed to :meth:`autoscale_view`, which is executed after
         a margin is changed.

         Specifying any margin changes only the autoscaling; for example,
         if *xmargin* is not zero, then *xmargin* times the X data
         interval will be added to each end of that interval before
         it is used in autoscaling.

         """

Eric

No comments other than these seem like really good changes to reduce
the barrier for the users.

Nice work!

Ryan

···

On Tue, Apr 20, 2010 at 2:46 PM, Eric Firing <efiring@...229...> wrote:

During the last few days I have added some convenience methods and
pyplot functions. Please review them to see whether names, APIs, or
functionality should be changed. The general motivation is that
formatters and locators are a bit obscure and hidden in the object
hierarchy, so I wanted to make it easier for people to make simple
changes. In addition, in autoscaling, one might want an option that is
almost "tight" but leaves a little margin, so symbols at the edge don't
get sliced off, for example.

--
Ryan May
Graduate Research Assistant
School of Meteorology
University of Oklahoma

Eric,

Just a minor concern about "locator_params" implicitly calling "autoscale_view".
For example,

ax1 = subplot(121)
ax1.plot([1,2,3])
ax1.locator_params("x", nbins=5)
ax1.margins(0.1, tight=True)

ax2 = subplot(122)
ax2.plot([1,2,3])
ax2.margins(0.1, tight=True)
ax2.locator_params("x", nbins=5)

Same commands are applied to each subplot but with different order,
and the results are different.
"ax.2locator_params("x", bnins=5)" implicitly calls
"ax2.autoscale_view(tight=False)", overriding tight=True in margins
call.

And I think this is a bit confusing.

I understand that autoscale_view depends on locator. Still at least
some option to prevent calling "autoscale_view" may be needed?

Regards,

-JJ

Jae-Joon Lee wrote:

Eric,

Just a minor concern about "locator_params" implicitly calling "autoscale_view".
For example,

ax1 = subplot(121)
ax1.plot([1,2,3])
ax1.locator_params("x", nbins=5)
ax1.margins(0.1, tight=True)

ax2 = subplot(122)
ax2.plot([1,2,3])
ax2.margins(0.1, tight=True)
ax2.locator_params("x", nbins=5)

Same commands are applied to each subplot but with different order,
and the results are different.
"ax.2locator_params("x", bnins=5)" implicitly calls
"ax2.autoscale_view(tight=False)", overriding tight=True in margins
call.

And I think this is a bit confusing.

I agree, and I was aware of this problem. It arises from the fact that the "tight" state is not saved, as I think it should be. I will look into fixing that.

I understand that autoscale_view depends on locator. Still at least
some option to prevent calling "autoscale_view" may be needed?

That seems to me like a more complex and confusing solution than saving the "tight" setting, and keeping it until it is explicitly changed by its own setter, by autoscale_view, or by margins. The default for autoscale_view will then be to change "tight" only if the kwarg is provided and is not None.

Eric

···

Regards,

-JJ