aspect ratio bug ?

Hi there,

I've boiled down a problem and while the following my look useless, I need to understand why matplotlib is behaving like it is.

Below is code showing my issue. I don't believe the issue is with the "bbox_inches='tight'", if you leave that off, my image is indeed, 800x1400, but the last row is a row of transparent pixels(on linux/not mac). It's difficult to see unless you use the imagemagik command display.

The basic problem is that when my data has an aspect ratio very close to 1.75, the image gets changed to one with an aspect of 1.74875.

Correct figure info 8x14@...4246... = 800x1400 => 1.75 Aspect Ratio.
Incorrect figure info => 800x1399 => 1.74875

Data that works aspect ratio: 1.7499999999999998
Data that fails aspect ratio: 1.7499999999999996
---> Srsly?! -------------------------------^

It would be great if someone could explain to me what's happening if this is indeed working as expected. If it's not, it would be great if someone could fix it.

Thanks in advance.
Matt

import matplotlib.pyplot as plt

def create_image():
    # I want an 800x1400 image (aspect = 1400/800 = 1.75.
    fig = plt.figure(1, figsize=(8, 14), frameon=False, dpi=100)

    # Use the whole figure and fill with a patch.
    fig.add_axes([0, 0, 1, 1])
    ax = plt.gca()
    limb = ax.axesPatch
    limb.set_facecolor('#6587ad')

    # Set some bounds with Aspects very close to the desired aspect ratios.
    x1 = 0.0
    y1 = 0.0
    x2 = 16.

    # If you un-comment out this line (and comment the one below). I get an image I expect
    # y2 = 27.999999999999994671 # produces 800 x 1400 image
    # aspect = 1.7499999999999998 works

    # Use this line and I get and image the wrong size (or with transparent pixels.)
    y2 = 27.999999999999994670 # produces (wrong?) 800 x 1399 image
    # aspect = 1.7499999999999996 Fails? wat?

    corners = ((x1, y1), (x2, y2))
    ax.update_datalim(corners)
    ax.set_xlim((x1, x2))
    ax.set_ylim((y1, y2))

    ax.set_aspect('equal', anchor='C')
    ax.set_xticks([])
    ax.set_yticks([])

    plt.savefig('rectangle.png', pad_inches=0.0, bbox_inches='tight')

    # If you use this below, the file size is correct, but there is a single
    # line transparent pixels along the bottom of the image

    # plt.savefig('rectangle.png', pad_inches=0.0)

if __name__ == '__main__':
    create_image()

The original question was raised in a mpl ticket: https://github.com/matplotlib/matplotlib/issues/1513

My original answer there (copied & pasted):

The bbox_inches='tight' option to savefig does some analysis on the artists visible on your plot and figures out the minimum
bounding box needed to fit all of the artists on the plot. In doing so,
it will reduce the size of the outputted image, rather than keeping the size and “zooming” in. A really simple example to show this (not using basemap):

>>> import matplotlib.pyplot as plt
>>> fig = plt.figure(figsize=(3, 4))
>>> ax = plt.axes([0.4, 0.4, 0.2, 0.2])
>>> ax.plot(range(10))
>>> plt.savefig('figsize_no_tight.png')
>>> plt.savefig('figsize_tight.png', bbox_inches='tight')


$> file figsize_* figsize_no_tight.png: PNG image data, 300 x 400, 8-bit/color RGBA, non-interlaced
figsize_tight.png: PNG image data, 98 x 123, 8-bit/color RGBA, non-interlaced

Matt has said that he doesn’t think this addresses the issue so anyone else with any ideas, please chip in!
My suspicion is that what is being described is a combination of bbox_inches=“tight” and a snapping issue relating to the fixed aspect (snapping here could be literally mpl snapping, or could simply be floating point problems).

Hope someone else has some ideas about what is going on.

Cheers,

Phil

···

On 20 November 2012 00:25, <savoie@…4247…> wrote:

Hi there,

I’ve boiled down a problem and while the following my look useless, I need to understand why matplotlib is behaving like it is.

Below is code showing my issue. I don’t believe the issue is with the “bbox_inches=‘tight’”, if you leave that off, my image is indeed, 800x1400, but the last row is a row of transparent pixels(on linux/not mac). It’s difficult to see unless you use the imagemagik command display.

The basic problem is that when my data has an aspect ratio very close to 1.75, the image gets changed to one with an aspect of 1.74875.

Correct figure info 8x14@…4246… = 800x1400 => 1.75 Aspect Ratio.

Incorrect figure info => 800x1399 => 1.74875

Data that works aspect ratio: 1.7499999999999998

Data that fails aspect ratio: 1.7499999999999996

—> Srsly?! -------------------------------^

It would be great if someone could explain to me what’s happening if this is indeed working as expected. If it’s not, it would be great if someone could fix it.

Thanks in advance.

Matt

import matplotlib.pyplot as plt

def create_image():

# I want an 800x1400 image (aspect = 1400/800 = 1.75.

fig = plt.figure(1, figsize=(8, 14), frameon=False, dpi=100)



# Use the whole figure and fill with a patch.

fig.add_axes([0, 0, 1, 1])

ax = plt.gca()

limb = ax.axesPatch

limb.set_facecolor('#6587ad')



# Set some bounds with Aspects very close to the desired aspect ratios.

x1 = 0.0

y1 = 0.0

x2 = 16.



# If you un-comment out this line (and comment the one below). I get an image I expect

# y2 = 27.999999999999994671   # produces 800 x 1400 image

# aspect = 1.7499999999999998 works



# Use this line and I get and image the wrong size (or with transparent pixels.)

y2 = 27.999999999999994670   # produces (wrong?) 800 x 1399 image

# aspect = 1.7499999999999996 Fails? wat?



corners = ((x1, y1), (x2, y2))

ax.update_datalim(corners)

ax.set_xlim((x1, x2))

ax.set_ylim((y1, y2))



ax.set_aspect('equal', anchor='C')

ax.set_xticks([])

ax.set_yticks([])



plt.savefig('rectangle.png', pad_inches=0.0, bbox_inches='tight')



# If you use this below, the file size is correct, but there is a single

# line transparent pixels along the bottom of the image



#  plt.savefig('rectangle.png', pad_inches=0.0)

if name == ‘main’:

create_image()

Monitor your physical, virtual and cloud infrastructure from a single

web console. Get in-depth insight into apps, servers, databases, vmware,

SAP, cloud infrastructure, etc. Download 30-day Free Trial.

Pricing starts from $795 for 25 servers or applications!

http://p.sf.net/sfu/zoho_dev2dev_nov


Matplotlib-users mailing list

Matplotlib-users@lists.sourceforge.net

https://lists.sourceforge.net/lists/listinfo/matplotlib-users