faq: reducing figure.figsize cuts off labels and tick marks

Hi,

there has been a similar question recently but I couldn't figure out
if or how this is solved:

I'd like to reduce the figure size so that I can add it to a LaTeX
document without scaling (PDF output with LaTeX font rendering). For
that, I need to adapt the font sizes, too.

Unfortunately, the canvas is not properly scaled so that the axis
labels and the possibly the tick marks are cut off.

Is this a bug, feature, design flaw? How can I properly work around
it, i.e. reduce the graph automatically for a given figsize/font size
combination so that everything fits on the figure?

An example follows to demonstrate, thanks in advance,
Daniel

import numpy,pylab,matplotlib.ticker as mtick

x = numpy.linspace(0,10,1000)
y = numpy.exp(x)

pylab.rcdefaults()

fig = pylab.figure()
ax = fig.add_subplot(111)
ax.set_yscale('log')
ax.yaxis.set_major_formatter(mtick.FormatStrFormatter('%d'))
ax.set_xlabel('asdf')
ax.set_ylabel('qwer')
ax.plot(x,y)
fig.savefig('example_mpl-ticker_1')

pylab.rcParams['figure.figsize'] = 5,3
pylab.rcParams['font.size'] = 12

fig = pylab.figure()
ax = fig.add_subplot(111)
ax.set_yscale('log')
ax.yaxis.set_major_formatter(mtick.FormatStrFormatter('%d'))
ax.set_xlabel('asdf')
ax.set_ylabel('qwer')
ax.plot(x,y)
fig.savefig('example_mpl-ticker_2')

2011/2/22 Daniel Mader <danielstefanmader@...982...>:

Hi,

there has been a similar question recently but I couldn't figure out
if or how this is solved:

I'd like to reduce the figure size so that I can add it to a LaTeX
document without scaling (PDF output with LaTeX font rendering). For
that, I need to adapt the font sizes, too.

Unfortunately, the canvas is not properly scaled so that the axis
labels and the possibly the tick marks are cut off.

Is this a bug, feature, design flaw? How can I properly work around
it, i.e. reduce the graph automatically for a given figsize/font size
combination so that everything fits on the figure?

You'll have to understand how dimensions are calculated and then use
stuff like Figure.subplots_adjust.

http://matplotlib.sourceforge.net/api/figure_api.html#matplotlib.figure.Figure.subplots_adjust
http://matplotlib.sourceforge.net/api/figure_api.html#matplotlib.figure.SubplotParams
http://matplotlib.sourceforge.net/faq/howto_faq.html#automatically-make-room-for-tick-labels

As a fast and dirty trick you can pass big numbers to subplots_adjust
and then use bbox_inches='tight' in savefig.

Goyo

I use matplotlib for this purpose pretty frequently. A few tricks:

from http://matplotlib.sourceforge.net/users/customizing.html :
# note that font.size controls default text sizes. To configure
# special text sizes tick labels, axes, labels, title, etc, see the rc
# settings for axes and ticks. Special text sizes can be defined
# relative to font.size, using the following values: xx-small, x-small,
# small, medium, large, x-large, xx-large, larger, or smaller

# specify the figure canvas size, in inches
figure(figsize=(3.4, 4))

# place the axes in the figure window
# specifying (left, bottom, width, height) as fraction of figure size
# adjust those positions to make enough room for tick and axis labels
axes([0.15, 0.12, 0.8, 0.83])

Specify the dpi for you screen, so the figure rendered on your screen
is the correct size. This is figure.dpi, best to set it in
matplotlibrc.

Darren

···

On Tue, Feb 22, 2011 at 4:23 AM, Daniel Mader <danielstefanmader@...982...> wrote:

Hi,

there has been a similar question recently but I couldn't figure out
if or how this is solved:

I'd like to reduce the figure size so that I can add it to a LaTeX
document without scaling (PDF output with LaTeX font rendering). For
that, I need to adapt the font sizes, too.

Unfortunately, the canvas is not properly scaled so that the axis
labels and the possibly the tick marks are cut off.

Is this a bug, feature, design flaw? How can I properly work around
it, i.e. reduce the graph automatically for a given figsize/font size
combination so that everything fits on the figure?

An example follows to demonstrate, thanks in advance

Hi Goyo and Darren,

thanks for pointing out the rcParams solution! For the time being,
this seems an OK approach. I'd like to use the automatic solution,
though, but this does not seem to work:

import matplotlib.pyplot as plt
import matplotlib.transforms as mtransforms
import numpy,pylab,matplotlib.ticker as mtick

x = numpy.linspace(0,10,1000)
y = numpy.exp(x)

pylab.rcdefaults()

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 = pylab.figure(figsize=(5,3))
ax = fig.add_subplot(111)
ax.set_yscale('log')
ax.yaxis.set_major_formatter(mtick.FormatStrFormatter('%d'))
ax.set_xlabel('asdf')
ax.set_ylabel('qwer')
ax.plot(x,y)
labels = ax.get_yticklabels()
fig.canvas.mpl_connect('draw_event', on_draw)
fig.savefig('example_mpl-ticker_2')

2011/2/25 Darren Dale <dsdale24@...287...>:

···

On Tue, Feb 22, 2011 at 4:23 AM, Daniel Mader > <danielstefanmader@...982...> wrote:

Hi,

there has been a similar question recently but I couldn't figure out
if or how this is solved:

I'd like to reduce the figure size so that I can add it to a LaTeX
document without scaling (PDF output with LaTeX font rendering). For
that, I need to adapt the font sizes, too.

Unfortunately, the canvas is not properly scaled so that the axis
labels and the possibly the tick marks are cut off.

Is this a bug, feature, design flaw? How can I properly work around
it, i.e. reduce the graph automatically for a given figsize/font size
combination so that everything fits on the figure?

An example follows to demonstrate, thanks in advance

I use matplotlib for this purpose pretty frequently. A few tricks:

from http://matplotlib.sourceforge.net/users/customizing.html :
# note that font.size controls default text sizes. To configure
# special text sizes tick labels, axes, labels, title, etc, see the rc
# settings for axes and ticks. Special text sizes can be defined
# relative to font.size, using the following values: xx-small, x-small,
# small, medium, large, x-large, xx-large, larger, or smaller

# specify the figure canvas size, in inches
figure(figsize=(3.4, 4))

# place the axes in the figure window
# specifying (left, bottom, width, height) as fraction of figure size
# adjust those positions to make enough room for tick and axis labels
axes([0.15, 0.12, 0.8, 0.83])

Specify the dpi for you screen, so the figure rendered on your screen
is the correct size. This is figure.dpi, best to set it in
matplotlibrc.

Darren

--
Zugallistr. 11/14
5020 Salzburg
M_at +43 699 10 54 54 53
T_at +43 662 841635
M_de +49 179 2300317
E danielstefanmader@...982...

There isn't one.

···

On Fri, Feb 25, 2011 at 6:03 AM, Daniel Mader <danielstefanmader@...982...> wrote:

Hi Goyo and Darren,

thanks for pointing out the rcParams solution! For the time being,
this seems an OK approach. I'd like to use the automatic solution,
though

There is the one in the code, as suggested on the FAQ site :slight_smile:

···

thanks for pointing out the rcParams solution! For the time being,
this seems an OK approach. I'd like to use the automatic solution,
though

There isn't one.

I have slightly modified the example from
http://matplotlib.sourceforge.net/faq/howto_faq.html#automatically-make-room-for-tick-labels
in order to demonstrate what I mean.

It works with the manual string tick labels but not with regular
auto-generated numerical ones.

Maybe someone knows how to fix this? And I *really* think this should
work automatically. As a compromise, maybe an rcParam would help in
order to keep the current dumb behavior...

Thanks in advance,
Daniel

import matplotlib.pyplot as plt
import matplotlib.transforms as mtransforms

fig = plt.figure(figsize=(5,3))
ax = fig.add_subplot(111)

#ax.plot(range(10))
#ax.set_yticks((2,5,7))
#labels = ax.set_yticklabels(('really, really, really', 'long', 'labels'))
ax.plot(range(100),[100000]*100)
labels = ax.get_yticklabels()

def on_draw(event):
   bboxes = []
   for label in labels:
       bbox = label.get_window_extent()
       print bbox
       # 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()