-1

The following code behaves absolutely ununderstandable for me:

import matplotlib.pyplot as plt
import matplotlib.image as mpimg
import numpy as np

img=mpimg.imread('stinkbug.png')

imgplot = plt.imshow(img)
circle = plt.Circle((0, 0), radius=100, fc='y')

plt.figure(0)
#plt.show(imgplot)
plt.show(circle)

It displays two figures, although no only one show() function called.

It displays stinkbug in figure, although imgplot was never shown.

It does not display circle, although circle was shown.

Dims
  • 47,675
  • 117
  • 331
  • 600
  • 4
    To answer the title, yes. It is generally very predictable, but can seem random if you don't read the docs and assume what a method does based only on the name. (real answer coming soon). – Mad Physicist Feb 09 '16 at 18:55
  • 1
    Possible duplicate of [plot a circle with pyplot](http://stackoverflow.com/questions/9215658/plot-a-circle-with-pyplot) – Mad Physicist Feb 09 '16 at 19:20

1 Answers1

7

You are telling matplotlib to do the following:

  1. Load an image (... so far so good)
  2. Create a figure displaying the image (Figure 1 by default) (... so far so good)
  3. Create a patch object that represents a circle. This is not associated with any axes or anything where it could be drawn.
  4. Create an empty Figure 0. Why? We may never know.
  5. Call plt.show() with a patch as an argument. Because matplotlib is being nice, it ignores this argument and just displays the two figures as predicted.

Some Notes

  1. Patch objects are just representations of a shape. You have to plot them somewhere for them to work.
  2. plt.show() just displays all the figures if you are not in interactive mode.

A Solution

Given all that, here is what I think you were trying to do:

import matplotlib.pyplot as plt
import matplotlib.image as mpimg
import numpy as np

img = mpimg.imread('stinkbug.png')
circle = plt.Circle((0, 0), radius=100, fc='y')

fig, ax = plt.subplots()
ax.imshow(img)
ax.add_artist(circle)
fig.show()

subplots creates both a figure and axes for you. You can then use ax.imshow to display the image and ax.add_artist to display the circle. fig.show() and plt.show() are identical in this case.

Mad Physicist
  • 107,652
  • 25
  • 181
  • 264
  • 1
    Sorry, that was a copy-and-paste error. I fixed it. `fig.show(circle)` is just `fig.show()` with matplotlib forgiving the extra argument. `ax.add_artist(circle)` is what adds the circle to the axes and therefore gets it displayed. – Mad Physicist Feb 09 '16 at 19:46
  • Is it correct to think, that axes belong to figure? Is this relationship is one-to-many (one figure, many axes)? – Dims Feb 09 '16 at 20:08
  • One figure many axes is correct. I do not think that you can add an axes object to more than one figure. A figure can have as many subplots (each an axes object) as your heart desires. – Mad Physicist Feb 09 '16 at 20:10
  • 1
    After I issue `fig.show()`, then figure appears in separate window with both circle and insect. Then, if I close this window and issue `fig.show()` again, the following error occurs: `TclError: this isn't a Tk application`. Why? – Dims Feb 10 '16 at 08:37
  • 1
    Funny you should mention that. See this Q: http://stackoverflow.com/questions/35300855/matplotlib-figure-does-not-close-after-being-resurrected?noredirect=1#comment58328896_35300855. Basically, once you close the figure, it's gone forever. The resources are deallocated. – Mad Physicist Feb 10 '16 at 18:05
  • Which resources are deallocated? For `fig`? For `ax`? Can I check `fig` or `ax` to see if resources were deallocated? Predictable program means result is 100% defined by operation and state variables. If it also depends on some hidden parameters, it become "unpredictable" :) – Dims Feb 11 '16 at 04:51
  • @Dims. Nothing in this world is deterministic in the sense that you mean. Everything is an abstraction that *may* fail at any time, including our most basic model of reality. However, `matplotlib` is pretty deterministic in the sense that you can look at the documentation, and if necessary the code, to know what it is supposed to do. It is a mature software so there are not a lot of bugs (although those are deterministic too). In general, do not expect figures to work after closing them. – Mad Physicist Feb 11 '16 at 13:47
  • I understand that and my goal is to understand not only PURPOSE, but also an ACTUAL EFFECT. I think I have a right for that :) – Dims Feb 11 '16 at 18:14
  • So, is it possible to know, what resources are deallocated when I close a window? – Dims Feb 11 '16 at 18:15
  • Absolutely. If I am not mistaken, the matplotlib docs should provide at least a good starting point. I couldn't tell you the answer off hand because it depends on your backend and your platform. For example, I favor the QtAgg backend on an Arch Linux system running gnome, but I couldn't tell you exactly how Qt interacts with gnome and x. That being said, I would recommend asking a separate question. I would be interested in learning what the real matplotlib gurus have to say. – Mad Physicist Feb 11 '16 at 21:36
  • From your earlier comment, I would guess that you are using the TkAgg backend. You would want to read up on that, as well as Tk for the platform you are using. – Mad Physicist Feb 11 '16 at 21:42
  • Also, in reference to the Tk error, you may want to try opening two figures, then closing one. You will probably still be able to reopen it. Tk, like Qt, uses a separate thread to run the GUI. My guess is that matplotlib does not let the thread die until all figures are closed, but I could be wrong about that. – Mad Physicist Feb 11 '16 at 21:48