Basemap white space

Hello list

I’ve trying for a while a “python only” solution to remove white spaces that Basemap generate to keep the aspect ratio. I found these two threads that explain the issue better:

http://www.mail-archive.com/matplotlib-users@lists.sourceforge.net/msg14430.html
http://www.mail-archive.com/matplotlib-users@…1753…forge.net/msg14262.html

In the past I relied on ImageMagick’s “convert” command with the “-trim white” option for the job. However, just recently I came across with this other list and a PIL solution:

http://mail.python.org/pipermail/image-sig/2008-July/005092.html

Here is how I’m doing:

savefig(‘mapa.png’, dpi=300)

from PIL import Image

im = Image.open(“mapa.png”)

def trim(im, border):

from PIL import ImageChops

bg = Image.new(im.mode, im.size, border)

diff = ImageChops.difference(im, bg)

bbox = diff.getbbox()

if bbox:

return im.crop(bbox)

else:

found no content

raise ValueError(“cannot trim; image was empty”)

im2=trim(im,‘white’)

im2.show()

This works and the aspect ratio is preserved, but as you can see, it is not a very smart implementation. I save and then reload it again… any suggestions to improve this are welcome.

Also, I have not tried this on figures with labels and annotations.

Thanks for any input.

···

Filipe Pires Alvarenga Fernandes

University of Massachusetts Dartmouth
200 Mill Road - Fairhaven, MA
Tel: (508) 910-6381
Email: falvarengafernandes@…1874…
ocefpaf@…1361…

      ocefpaf@...287...

http://ocefpaf.tiddlyspot.com/


2010/3/28 Filipe Pires Alvarenga Fernandes <ocefpaf@...287...>:

Hello list
I've trying for a while a "python only" solution to remove white spaces that
Basemap generate to keep the aspect ratio. I found these two threads that
explain the issue better:

I think maybe you can make use of the Agg Backend to achieve a
Python-only solution to obtain a PIL Image from a figure without
bypassing over the HDD:

Furthemore, if this doesn't work, maybe you can use a StringIO as
"file", then seek() the StringIO and reread with PIL from the
"file-like" StringIO, or something like that?

···

#
# Render the Figure to a PIL Image ...
#

# Prepare figure to be of pixel extent *shape* ...

dpi = figure.dpi
figure.set_size_inches(float(shape[0]) / dpi, float(shape[1]) / dpi)

# Create the rendering Canvas ...
#
# We also convert the picture to an RGB string.

canvas = matplotlib.backends.backend_agg.FigureCanvasAgg(figure)
canvas.draw()
image_string = canvas.tostring_rgb()

# Create a PIL Image from RGB string ...

image = Image.fromstring("RGB", shape, image_string)

# Now do whatever you want with the Image.

Friedrich

Thanks Friedrich,

However, my knowledge of python is very limited, even though I think I
understood what you suggested I do not know how to get the shape (of
the figure?) for this part:

fig.set_size_inches(float(shape[0]) / dpi, float(shape[1]) / dpi)

error is:

Traceback (most recent call last):
File "blueearth-map.py", line 108, in <module>
fig.set_size_inches(float(shape[0]) / dpi, float(shape[1]) / dpi)
TypeError: 'function' object is unsubscriptable

It seems that it ended up calling a function shape instead of a variable shape.

I'm sending attached the script if you are interested in looking at it.

Thanks again. Filipe.

blueearth-map.py (3.4 KB)

···

On Sun, Mar 28, 2010 at 3:35 PM, Friedrich Romstedt <friedrichromstedt@...287...> wrote:

2010/3/28 Filipe Pires Alvarenga Fernandes <ocefpaf@...287...>:
> Hello list
> I've trying for a while a "python only" solution to remove white spaces that
> Basemap generate to keep the aspect ratio. I found these two threads that
> explain the issue better:

I think maybe you can make use of the Agg Backend to achieve a
Python-only solution to obtain a PIL Image from a figure without
bypassing over the HDD:

Furthemore, if this doesn't work, maybe you can use a StringIO as
"file", then seek() the StringIO and reread with PIL from the
"file-like" StringIO, or something like that?

#
# Render the Figure to a PIL Image ...
#

# Prepare figure to be of pixel extent *shape* ...

dpi = figure.dpi
figure.set_size_inches(float(shape[0]) / dpi, float(shape[1]) / dpi)

# Create the rendering Canvas ...
#
# We also convert the picture to an RGB string.

canvas = matplotlib.backends.backend_agg.FigureCanvasAgg(figure)
canvas.draw()
image_string = canvas.tostring_rgb()

# Create a PIL Image from RGB string ...

image = Image.fromstring("RGB", shape, image_string)

# Now do whatever you want with the Image.

Friedrich

2010/3/30 Filipe Pires Alvarenga Fernandes <ocefpaf@...287...>:

However, my knowledge of python is very limited, even though I think I
understood what you suggested I do not know how to get the shape (of
the figure?) for this part:

fig.set_size_inches(float(shape[0]) / dpi, float(shape[1]) / dpi)

error is:

Traceback (most recent call last):
File "blueearth-map.py", line 108, in <module>
fig.set_size_inches(float(shape[0]) / dpi, float(shape[1]) / dpi)
TypeError: 'function' object is unsubscriptable

It seems that it ended up calling a function shape instead of a variable shape.

You're completely right, I assumed that you fill in some 2-element
vector in *shape*, it was intended as an /argument/. The function
attemted to be indexed is imported from numpy by matplotlib.pyplot:
There is a code line "from numpy import *".

So, simply put some line somewhere like:

shape = [500, 500] .

You have to set or have to calculate the figure's shape in pixels
somewhere, because you need it to convert the rgb string back into a
PIL image. It's not that nice, I know, for your problem?

Friedrich