Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #79411 > unrolled thread

Matplotlib: getting a figure to show without plt.show()

Started byPeter Pearson <pkpearson@nowhere.invalid>
First post2014-10-22 04:57 +0000
Last post2014-10-22 16:38 +0000
Articles 3 — 2 participants

Back to article view | Back to comp.lang.python


Contents

  Matplotlib: getting a figure to show without plt.show() Peter Pearson <pkpearson@nowhere.invalid> - 2014-10-22 04:57 +0000
    Re: Matplotlib: getting a figure to show without plt.show() Peter Otten <__peter__@web.de> - 2014-10-22 12:38 +0200
      Re: Matplotlib: getting a figure to show without plt.show() Peter Pearson <pkpearson@nowhere.invalid> - 2014-10-22 16:38 +0000

#79411 — Matplotlib: getting a figure to show without plt.show()

FromPeter Pearson <pkpearson@nowhere.invalid>
Date2014-10-22 04:57 +0000
SubjectMatplotlib: getting a figure to show without plt.show()
Message-ID<caorpjFo1amU1@mid.individual.net>
I'm using Matplotlib to present a "control" window with clickable
buttons, and to plot things in another window when you click buttons,
in the style of the code below.  I'm ashamed of the stinky way I
use "first" to call plt.show the first time data are plotted but then
to call fig.canvas.draw for subsequent data plots.  Can someone tell
me the right way?

If I call plt.show every time, then after about 40 plots I get
"RuntimeError: maximum recursion depth exceeded while calling a Python
object", which makes sense because I'm getting one layer deeper in
callbacks with every plot (plt.show doesn't return).  But if I call
fig.canvas.draw every time, the window for the data plot never appears
on my screen.

Thanks for any suggestions.

##############################
import matplotlib.pyplot as plt
from matplotlib.widgets import Button

def callback(event):
    global n, first
    fig = plt.figure(2)
    fig.clear()
    plt.plot([0,1],[0,n])
    n += 1  # (Pretending something changes from one plot to the next.)
    if first:
        first = False
        plt.show()
    else:
        fig.canvas.draw()

global n, first
n = 0
first = True
fig = plt.figure(1)
quit_button = Button(plt.axes([.1,.3,.4,.2]), "Quit")
quit_button.on_clicked(lambda x: plt.close("all"))
plot_button = Button(plt.axes([.1,.1,.4,.2]), "Plot")
plot_button.on_clicked(callback)
plt.show()
##############################

-- 
To email me, substitute nowhere->runbox, invalid->com.

[toc] | [next] | [standalone]


#79427

FromPeter Otten <__peter__@web.de>
Date2014-10-22 12:38 +0200
Message-ID<mailman.15064.1413974302.18130.python-list@python.org>
In reply to#79411
Peter Pearson wrote:

> I'm using Matplotlib to present a "control" window with clickable
> buttons, and to plot things in another window when you click buttons,
> in the style of the code below.  I'm ashamed of the stinky way I
> use "first" to call plt.show the first time data are plotted but then
> to call fig.canvas.draw for subsequent data plots.  

> def callback(event):
>     global n, first
>     fig = plt.figure(2)
>     fig.clear()
>     plt.plot([0,1],[0,n])
>     n += 1  # (Pretending something changes from one plot to the next.)
>     if first:
>         first = False
>         plt.show()
>     else:
>         fig.canvas.draw()

> Can someone tell me the right way?

I don't see what's wrong with doing something different the first time 
around.

> If I call plt.show every time, then after about 40 plots I get
> "RuntimeError: maximum recursion depth exceeded while calling a Python
> object", which makes sense because I'm getting one layer deeper in
> callbacks with every plot (plt.show doesn't return).  But if I call
> fig.canvas.draw every time, the window for the data plot never appears
> on my screen.

If your backend uses tkinter, then the problem may be that plt.show() starts 
a new mainloop. Over here this causes the script to hang on termination. 
Through try-and-error I came up with

import matplotlib.pyplot as plt
from matplotlib.widgets import Button

def callback(event):
    global n, fig2

    if fig2 is None:
        fig2 = plt.figure(2)

    fig2.clear()
    fig2.gca().plot([0, .5, 1], [0, 1/n, 1])
    fig2.show()

    n += 1 

n = 1
fig2 = None

plt.figure(1)

quit_button = Button(plt.axes([.1, .3, .4, .2]), "Quit")
quit_button.on_clicked(lambda x: plt.close("all"))

plot_button = Button(plt.axes([.1, .1, .4, .2]), "Plot")
plot_button.on_clicked(callback)

plt.show()

If you don't mind that the second window shows up immediately you can modify 
that to

import matplotlib.pyplot as plt
from matplotlib.widgets import Button

def callback(event):
    global n

    fig2.clear()
    fig2.gca().plot([0, .5, 1], [0, 1/n, 1])
    fig2.show()

    n += 1 

n = 1

plt.figure(1)

quit_button = Button(plt.axes([.1, .3, .4, .2]), "Quit")
quit_button.on_clicked(lambda x: plt.close("all"))

plot_button = Button(plt.axes([.1, .1, .4, .2]), "Plot")
plot_button.on_clicked(callback)

fig2 = plt.figure(2)

plt.show()

and thus avoid the special case. 

As I'm not an expert for matplotlib you might also post your question on the 
matplotlib mailing list.

[toc] | [prev] | [next] | [standalone]


#79456

FromPeter Pearson <pkpearson@nowhere.invalid>
Date2014-10-22 16:38 +0000
Message-ID<caq4rpF3vveU1@mid.individual.net>
In reply to#79427
On Wed, 22 Oct 2014 12:38:02 +0200, Peter Otten wrote:
> Peter Pearson wrote:
[snip]
>> def callback(event):
>>     global n, first
>>     fig = plt.figure(2)
>>     fig.clear()
>>     plt.plot([0,1],[0,n])
>>     n += 1  # (Pretending something changes from one plot to the next.)
>>     if first:
>>         first = False
>>         plt.show()
>>     else:
>>         fig.canvas.draw()
>>
>> Can someone tell me the right way?
[snip]

> def callback(event):
>     global n, fig2
>
>     if fig2 is None:
>         fig2 = plt.figure(2)
>
>     fig2.clear()
>     fig2.gca().plot([0, .5, 1], [0, 1/n, 1])
>     fig2.show()

Thank you for pointing out two useful things:

 * I like fig2.gca().plot better than plt.plot, since it makes it
   clear that I'm talking about fig2 and not some other part of the
   vast and inscrutable plt kingdom.

 * fig2.show is different from plt.show, and in fact this solves my
   problem exactly, since fig2.show returns immediately.

By the way, I will dispense with your "if fig2 is None" test.  In real
life, I say something like fig2 = plt.figure("Packet Sizes").  If a
figure named "Packet Sizes" doesn't exist, plt.figure creates it,
otherwise it returns a pointer to the existing figure -- *and* it titles
the figure's window with "Packet Sizes" rather than "2".

[snip]
> As I'm not an expert for matplotlib you might also post your question on the 
> matplotlib mailing list.

Sound advice.  Next time.  Thanks again.


-- 
To email me, substitute nowhere->runbox, invalid->com.

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.python


csiph-web