Large axis labels/positioning the axes

Hi folks,

I'm using 'yticks' to set labels on the y axis, unfortunately they're rather long strings occasionally. I was wondering if there's a way to tweak the position of the axes within the plot, or better yet to have it automatically push the axes over so that the entire labels fit (I realize that's a tall order and would be quite happy with a way of tweaking it manually).

I managed to get the 'axesPatch' to move over but unfortunately that didn't take the axes (or the labels) with it.

Another (small, less important) question: is there a way to disable the actual 'ticks' and just have labels present?

Thanks!

David

Hi folks,

I'm using 'yticks' to set labels on the y axis, unfortunately they're
rather long strings occasionally. I was wondering if there's a way to
tweak the position of the axes within the plot, or better yet to have
it automatically push the axes over so that the entire labels fit (I
realize that's a tall order and would be quite happy with a way of
tweaking it manually).

If you are using subplots, you can move them over using

  fig = figure()
  fig.subplots_adjust(left=0.2)

Alternatively, you can manually position your axes using the "axes"
command rather than the "subplot" command, but the above will probably
work for you. We've done some work on auto-layout but w/o much
success. You can however, make 0.2 (or whatever) the default in your
matplotlibrc file using the parameter (see
http://matplotlib.sf.net/matplotlibrc). For example, you can set the
"left" parameter there with::

    figure.subplot.left : 0.125 # the left side of the subplots of the figure

Another (small, less important) question: is there a way to disable
the actual 'ticks' and just have labels present?

The easiest way is to make them invisible::

    ax = subplot(111)
    for line in ax.get_yticklines():
        line.set_visible(False)

JDH

···

On Wed, Jun 18, 2008 at 1:54 PM, David Warde-Farley <dwf@...386...> wrote:

Works like a charm! Thanks.

One more related thing: is there any way to retrieve the size of a textbox in figure coordinates, something like
ax.get_ymajorticklabels[0].get_width()?

Also, I'm kind of wondering why things like set_text() on that doesn't work. In general I haven't had much success with editing the properties of objects like this.

David

···

On 18-Jun-08, at 3:17 PM, John Hunter wrote:

If you are using subplots, you can move them over using

  fig = figure()
  fig.subplots_adjust(left=0.2)

One more related thing: is there any way to retrieve the size of a textbox
in figure coordinates, something like
ax.get_ymajorticklabels[0].get_width()?

This is not very easy since the renderer is not known until the figure
is drawn. After the window is drawn and the text instance knows its
renderer, you can call t.get_window_extent(). So you would likely
want to connect to the "on_draw" method and get the window extent
there, and then do something with it, eg move the left of the canvas
over. Here is a recursive, iterative solution that will gradually
move the left of the subplot over until the label fits w/o going
outside the figure border (requires 0.98)::

    import matplotlib.pyplot as plt

    fig = plt.figure()
    ax = fig.add_subplot(111)
    ax.plot(range(10))
    ax.set_yticks((2,5,7))
    labels = ax.set_yticklabels(('really, really, really', 'long', 'labels'))

    def on_draw(event):
        for label in labels:
            bbox = label.get_window_extent()
            if bbox.xmin<0:
                print 'adjusting left of subplot'
                fig.subplots_adjust(left=1.1*fig.subplotpars.left)
                fig.canvas.draw()
                break

    fig.canvas.mpl_connect('draw_event', on_draw)

    plt.show()

Also, I'm kind of wondering why things like set_text() on that doesn't work.
In general I haven't had much success with editing the properties of objects
like this.

The tick labels are a bit special, since they are generated on the fly
(eg if you are panning and zooming, new ticks must be created and sold
ones destroyed). So you can't set their text directly, but rather
need to create a tick locator and a tick formatter as described in
Users Guide Chapter 6 -
http://matplotlib.sourceforge.net/users_guide_0.98.0.pdf and the
examples

  http://matplotlib.sourceforge.net/examples/pylab/custom_ticker1.py
  http://matplotlib.sourceforge.net/examples/pylab/major_minor_demo1.py

JDH

···

On Wed, Jun 18, 2008 at 2:42 PM, David Warde-Farley <dwf@...386...> wrote:

Hi John, (apologies for sending twice, forgot to CC the list)

Thanks again for the help. I was wondering about the code you posted -- what's the problem with say, using bbox.xmin to adjust left only once? Or else perhaps get_text_width_height from the renderer? Wouldn't that yield the desired effect without the iterative procedure, since you'd immediately know (roughly) how much to push the subplot over?

Thanks,

David

···

On 19-Jun-08, at 11:30 AM, John Hunter wrote:

On Wed, Jun 18, 2008 at 2:42 PM, David Warde-Farley <dwf@...386... > > wrote:

One more related thing: is there any way to retrieve the size of a textbox
in figure coordinates, something like
ax.get_ymajorticklabels[0].get_width()?

This is not very easy since the renderer is not known until the figure
is drawn. After the window is drawn and the text instance knows its
renderer, you can call t.get_window_extent(). So you would likely
want to connect to the "on_draw" method and get the window extent
there, and then do something with it, eg move the left of the canvas
over. Here is a recursive, iterative solution that will gradually
move the left of the subplot over until the label fits w/o going
outside the figure border (requires 0.98)::

   * snip *

Yes, that is a better approach. But you need to do a little work to
get the coordinate system width (going from width in pixels to
fractional width). Here is an example:

mport matplotlib.pyplot as plt
import matplotlib.transforms as mtransforms
fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(range(10))
ax.set_yticks((2,5,7))
labels = ax.set_yticklabels(('really, really, really', 'long', 'labels'))

def on_draw(event):
    bboxes = []
    for label in labels:
        bbox = label.get_window_extent()
        # the figure transform goes from relative coords->pixels and we
        # want the inverse of that
        bboxi = bbox.inverse_transformed(fig.transFigure)
        bboxes.append(bboxi)

    # this is the bbox that bounds all the bboxes, again in relative
    # figure coords
    bbox = mtransforms.Bbox.union(bboxes)
    if fig.subplotpars.left < bbox.width:
        # we need to move it over
        fig.subplots_adjust(left=1.1*bbox.width) # pad a little
        fig.canvas.draw()
    return False

fig.canvas.mpl_connect('draw_event', on_draw)

plt.show()

···

On Fri, Jun 20, 2008 at 9:32 PM, David Warde-Farley <dwf@...386...> wrote:

Thanks again for the help. I was wondering about the code you posted --
what's the problem with say, using bbox.xmin to adjust left only once? Or
else perhaps get_text_width_height from the renderer? Wouldn't that yield
the desired effect without the iterative procedure, since you'd immediately
know (roughly) how much to push the subplot over?