11

Given an image of 500x500 pixels I want to show that image 1:1 on my screen. Additionally I want to have an x and y axes.

  • plt.imshow() automatically adds axes to my image and centers the image in the window, but the image is scaled and not shown as 500x500 pixels on my screen.
  • fig.figimage() shows the image 1:1 on my screen but adds no axes and displays the image in the bottom left corner of the window. Especially maximizing the window / resizing the windows does not change the size of image.

Now what I need, is a combination of both – diplay the image 1:1 like fig.figshow does, add the axes that plt.imshow() adds and display the image centered like plt.imshow() does.

How can I do that? Or in other terms: How to tell plt.imshow() to display im image unscaled like fig.figimage() does?

Sample code demonstrating the problem:

import matplotlib.pyplot as plt
import numpy as np

width=500;
height=500;

# using plt.imshow()
dummyImage = np.zeros((width, height))
plt.imshow(dummyImage)
plt.show()

# using fig.figimage()
fig = plt.figure(figsize=(width, height))
fig.figimage(dummyImage)
plt.show()

Result:

using plt.imshow(): not exactly 500x500 pixels and actual size depends on size of the window. enter image description here

using fig.figimage(): exactly 500x500 pixels, independent of window size

enter image description here

stefan.at.kotlin
  • 15,347
  • 38
  • 147
  • 270

1 Answers1

4

You will need to do a little bit of calculation yourself. Say, you want 50 pixel margin on all sides, and you have a dpi of 100, you can then calculate the figure size to be figsize=((width+2*margin)/dpi, (height+2*margin)/dpi) inches. You would then need to calculate the borders, e.g. the left border will be margin divided by dpi divided by figure width. You can set the calculated figure size (figsize argument of plt.figure()) and borders (using subplots_adjust) to your figure.

import matplotlib.pyplot as plt
import numpy as np

width=500 # pixels
height=150
margin=50 # pixels
dpi=100. # dots per inch

figsize=((width+2*margin)/dpi, (height+2*margin)/dpi) # inches
left = margin/dpi/figsize[0] #axes ratio
bottom = margin/dpi/figsize[1]

fig = plt.figure(figsize=figsize, dpi=dpi)
fig.subplots_adjust(left=left, bottom=bottom, right=1.-left, top=1.-bottom)

dummyImage = np.zeros((height, width))
plt.imshow(dummyImage)
plt.show()

enter image description here

Note that to have an image of dimensions width width and height height, you need an array np.zeros((height, width)), not the inverse.

In order to make sure the figure keeps its original size, one may add the following code, which resizes the figure back to its original size on every attempt to change the figure size:

def update(event=None):
    fig.set_size_inches(figsize)

update()
ci = fig.canvas.mpl_connect("resize_event", update)
plt.show()
ImportanceOfBeingErnest
  • 321,279
  • 53
  • 665
  • 712
  • Thank you for your detailed reply! That's already close, but the widht seems to be 500 including the tiks (the markings on the y axis). I would require 500 just for the image itself. Do you know a way to make sure the figure does not resize when maximizing the window? – stefan.at.kotlin Jun 03 '17 at 16:54
  • The width should be the width without the ticks. One can see that this is correct when exporting the figure using `savefig`. Now there seems indeed to be a problem, which is that the Window might resize the figure upon creation. This seems to be the case here, using QtAgg backend. It does not occur using TkAgg backend. Would you be happy to use Tk? – ImportanceOfBeingErnest Jun 03 '17 at 17:20
  • I added `import matplotlib matplotlib.use('TkAgg')` but then the image is far away from 500 px. Any idea what could cause this? I tried your code addition to keep the figure to it's original size. This works when using TkAgg in terms of same size as when opening the window, but the image size is still larger than 500 px. – stefan.at.kotlin Jun 03 '17 at 17:39
  • Tried changing the dpi variable, but even setting it to 200 changes nothing - my image is about 750 px wide instead of 500 px. I am on a 4k display and the axes are large and a little bit washed out. Seems like TkAgg has problems with high DPI. I just have no idea how to fix that. – stefan.at.kotlin Jun 03 '17 at 17:41
  • 1
    Update: Changing DPI affects only the axes, not the image size itself which stays at roughly 750 px instead of 500 px ): And I figured out why: Windows DPI scaling is set to 150%. Changing the figsize line to `figsize=((width/1.5+2*margin)/dpi, (height/1.5+2*margin)/dpi)`helps :-) Thank you! – stefan.at.kotlin Jun 03 '17 at 17:47
  • The code above makes sure the figure is always the same size, independent on the dpi; thus far it's expected that changing dpi only scales the axis spines and labels. Concerning the figure size of 750px, I cannot reproduce this issue. Could it be a systems setting (I know that sometimes Windows10 likes to ship with 125% dpi scaling). – ImportanceOfBeingErnest Jun 03 '17 at 17:48
  • As the QtAgg has less problems with high DPI: Do you have any idea how one could prevent resizing here? Our latest comments were overlapping - yes, windows DPI scaling is the problems on TkAgg. – stefan.at.kotlin Jun 03 '17 at 17:49
  • Right click on python.exe - compatability - behaviour by dpi scaling set to application keeps windows frm scaling at TkAgg :-) I noted one more thing: When maximizing the window, the background next to the figure is grey instead of white. Any idea how to fix that? Any any idea how to center the figure in the window? Anyway, you already helped me a lot and with great effort, so I already not select your reply as answer :-) – stefan.at.kotlin Jun 03 '17 at 17:53
  • The gray background comes from the Tk application, you cannot easily change that. One option, which would give you anyways much more control would of course be to embed the figure into a custom Tk or PyQt GUI (This would also allow you to use PyQt and prevent the small resize in PyQt itself.) Then changing the background would be easily possible. As an example for PyQt, you may look at [this question](https://stackoverflow.com/questions/42622146/scrollbar-on-matplotlib-showing-page)'s answer. – ImportanceOfBeingErnest Jun 03 '17 at 18:01