|
From: Christoph G. <cw...@fa...> - 2013-10-17 12:20:37
|
Hello, I'm stuck trying to find a solution to the following problem. I'd like to show an array using imshow preserving the 1:1 aspect ratio of its pixels. At the same time, I would like the axes to fit around the image tightly. Is there some way to, for example, choose a certain figure width, and have the height chosen automatically to the optimal value? Thanks, Christoph |
|
From: Benjamin R. <ben...@ou...> - 2013-10-17 13:28:32
|
On Thu, Oct 17, 2013 at 8:20 AM, Christoph Groth <cw...@fa...> wrote: > Hello, > > I'm stuck trying to find a solution to the following problem. > > I'd like to show an array using imshow preserving the 1:1 aspect ratio > of its pixels. At the same time, I would like the axes to fit around > the image tightly. > > Is there some way to, for example, choose a certain figure width, and > have the height chosen automatically to the optimal value? > > Thanks, > Christoph > > I particularly like using the figaspect() function: http://matplotlib.org/api/figure_api.html?highlight=figaspect#matplotlib.figure.figaspect The example usage there needs to be updated (it assumes the pylab mode which imports everything in pyplot into the global namespace). But it should be accessible like so: import matplotlib.pyplot as plt w, h = plt.figaspect(2) It isn't perfect, but for its simplicity, it gets it mostly right. Cheers! Ben Root |
|
From: Christoph G. <chr...@gr...> - 2013-10-17 14:45:12
|
Benjamin Root writes: > I particularly like using the figaspect() function: > > (...) > > It isn't perfect, but for its simplicity, it gets it mostly right. Thanks, Benjamin, for your quick reply. Unfortunately, figaspect is only an approximate solution, as it simply uses the aspect ration of the image for the whole figure (with axes and labels). I wonder how difficult it would be to teach matplotlib to tightly fit the axes around an image, and, ideally, output the figure cropped. |
|
From: Joe K. <jof...@gm...> - 2013-10-17 15:46:00
|
<snip>
>
> Unfortunately, figaspect is only an approximate solution, as it simply
> uses the aspect ration of the image for the whole figure (with axes and
> labels).
>
> I wonder how difficult it would be to teach matplotlib to tightly fit
> the axes around an image, and, ideally, output the figure cropped.
>
So, you're wanting the image to be displayed pixel-to-pixel, but still have
(tight) room for the axes, etc?
If so, you can use the "bbox_inches" kwarg to crop "out" and capture the
extent of the labels, etc, and just set the figure size to exactly the size
of the image.
For example:
import numpy as np
import matplotlib.pyplot as plt
dpi = 80
data = np.random.random((100, 100))
height, width = np.array(data.shape, dtype=float) / dpi
fig, ax = plt.subplots(figsize=(width, height), dpi=dpi)
ax.imshow(data, interpolation='none')
fig.savefig('test.png', bbox_inches='tight')
If show the figure (i.e. "plt.show()"), the ticklabels, etc will be outside
the figure and not shown, but they will be properly saved, regardless.
Hope that helps,
-Joe
>
>
>
> ------------------------------------------------------------------------------
> October Webinars: Code for Performance
> Free Intel webinars can help you accelerate application performance.
> Explore tips for MPI, OpenMP, advanced profiling, and more. Get the most
> from
> the latest Intel processors and coprocessors. See abstracts and register >
> http://pubads.g.doubleclick.net/gampad/clk?id=60135031&iu=/4140/ostg.clktrk
> _______________________________________________
> Matplotlib-users mailing list
> Mat...@li...
> https://lists.sourceforge.net/lists/listinfo/matplotlib-users
>
|
|
From: Nicolas R. <Nic...@in...> - 2013-10-17 15:50:34
|
Would something like this suit your needs ?
import matplotlib.pyplot as plt
# Image size
width,height = 640,480
# Pixel border around image
border = 1
dpi = 72.0
figsize= (width+2*border)/float(dpi), (height+2*border)/float(dpi)
fig = plt.figure(figsize=figsize, dpi=dpi, facecolor="white")
hpixel = 1.0/(width+2*border)
vpixel = 1.0/(height+2*border)
ax = fig.add_axes([border*hpixel, border*vpixel,
1-2*border*hpixel, 1-2*border*vpixel])
ax.set_xlim(0, width)
ax.set_ylim(0, height)
plt.show()
Nicolas
On Oct 17, 2013, at 4:16 PM, Christoph Groth <chr...@gr...> wrote:
> Benjamin Root writes:
>
>> I particularly like using the figaspect() function:
>>
>> (...)
>>
>> It isn't perfect, but for its simplicity, it gets it mostly right.
>
> Thanks, Benjamin, for your quick reply.
>
> Unfortunately, figaspect is only an approximate solution, as it simply
> uses the aspect ration of the image for the whole figure (with axes and
> labels).
>
> I wonder how difficult it would be to teach matplotlib to tightly fit
> the axes around an image, and, ideally, output the figure cropped.
>
>
> ------------------------------------------------------------------------------
> October Webinars: Code for Performance
> Free Intel webinars can help you accelerate application performance.
> Explore tips for MPI, OpenMP, advanced profiling, and more. Get the most from
> the latest Intel processors and coprocessors. See abstracts and register >
> http://pubads.g.doubleclick.net/gampad/clk?id=60135031&iu=/4140/ostg.clktrk
> _______________________________________________
> Matplotlib-users mailing list
> Mat...@li...
> https://lists.sourceforge.net/lists/listinfo/matplotlib-users
|
|
From: Christoph G. <chr...@gr...> - 2013-10-18 12:10:13
|
Joe, thank you very much for your reply. So the "figsize" of a matplotlib plot is the physical size of the region between the axes where the data is shown? If this is indeed the case, as it seems, then achieving (almost) what I wanted is as easy as setting a figsize with the proper aspect ratio, like in your example. Before your reply, I believed that "figure size" in matplotlib refers to the size of the whole figure (including axes, axis labels, and borders), as "figure" in matplotlib seems to be a name for instances of matplotlib.figure.Figure which are the whole thing. I said "almost" in the first paragraph as it would be nice if there was a way to create figures that have a given total width (after cropping) at a given font size. The reason is this: In many scientific journals (for example Physical Review), figures are scaled to have the same width as a column of text. If I prepare a bunch of figures with the same width "within the axes" and consistent font sizes and line widths, the resulting figures will typically have somewhat different total widths. After scaling the figures to the same width, the font sizes and line widths will differ slightly from figure to figure. Christoph |
|
From: Christoph G. <chr...@gr...> - 2013-10-18 12:19:56
|
Nicolas Rougier writes: > Would something like this suit your needs ? > > (...) Thanks. Setting figsize is indeed the way to achieve (almost) what I wanted. My other followup in this thread describes the remaining issue. |
|
From: Joe K. <jof...@gm...> - 2013-10-21 14:21:08
|
I just realized that I replied to this off-list. Sending back out to the
entire list. (Sorry for the duplicate e-mail Christoph!)
On Oct 18, 2013 6:11 AM, "Christoph Groth" <chr...@gr...> wrote:
> Joe, thank you very much for your reply. So the "figsize" of a
> matplotlib plot is the physical size of the region between the axes
> where the data is shown?
No, your first assumption was correct. "figsize" refers to the size of the
whole figure.
What I meant to do in that example was abuse the fact that matplotlib will
happily add things beyond the figure boundaries. You can then abuse the
"bbox_inches" kwarg to savefig to show everything, while keeping the size
of the "data area" between the axes boundaries the same as the figsize.
My example there is actually completely wrong. I meant to do this:
import numpy as np
import matplotlib.pyplot as plt
dpi = 80
data = np.random.random((100, 100))
height, width = np.array(data.shape, dtype=float) / dpi
fig = plt.figure(figsize=(width, height), dpi=dpi)
ax = fig.add_axes([0, 0, 1, 1])
ax.imshow(data, interpolation='none')
fig.savefig('test.png', bbox_inches='tight')
At any rate, I'm not quite sure if that's actually what you wanted, but
it's a useful trick in cases like this.
|