1

I'm using a matplotlib button to create another plot with a button. However, the second button in the second plot does not work. Could anyone take a look at my code and give me some help?

import numpy as np
import matplotlib
import matplotlib.pyplot as plt
import tkinter as tk
from matplotlib.widgets import Button

def next1(event):
    print("you clicked here")

def next0(event):

    # plt.close('all')
    fig, ax = plt.subplots()
    rects = ax.bar(range(10), 20*np.random.rand(10))

    axnext1 = plt.axes([0.11, 0.05, 0.05, 0.0375])
    bnext1 = Button(axnext1, 'Next2')
    print(bnext1.label)
    bnext1.on_clicked(next1)
    plt.show()

fig, ax = plt.subplots()
rects = ax.bar(range(10), 20*np.random.rand(10))

axnext0 = plt.axes([0.11, 0.05, 0.05, 0.0375])
bnext0 = Button(axnext0, 'Next1')
print(bnext0.label)
bnext0.on_clicked(next0)

plt.show()

This figure shows the problem I had. The second figure is created by the button in the first image. While the button in the second figure does not work.

1
  • after clicking first button it shows QCoreApplication::exec: The event loop is already running and this can be the problem. It runs event loop for first window and it can't run event loop for second window at the same time. it may need to run second plot in separated thread. Or it need to check if you can inform matplotlib that it has to run both windows with one event loop. Commented May 31, 2022 at 3:44

1 Answer 1

1

It seems problem is because you assign second button to local variable (inside function) and python deletes this object when it finishes function. Button has to be assigned to global variable - to keep it after finishing function.

def next0(event):
    global bnext1

    # ... code ...

BTW:

After clicking first button it shows me information (not erorr message)

QCoreApplication::exec: The event loop is already running 

because second window tries to create new event loop but event loop already exists - created by first window.

To resolve this problem you can run second window in non-blocking mode.

def next0(event):
    global bnext1

    # ... code ...

    plt.show(block=False)
Sign up to request clarification or add additional context in comments.

4 Comments

Thank you @furas. This definitely answered my question!
"Button has to be assigned to global variable" ---- Addendum to this: it doesn't need to be a global variable -- you just need to keep a reference to it for as long as you need it so it doesn't get garbage-collected See: stackoverflow.com/a/48565037/10046738
@jmdavalos one of the simplest method to keep reference is to assign to global viariable. Even code in your link uses return and button = testfn() to keep button in global viariable (because all variables outside functions and classes are global - event without using keyword global) BTW: code in current question uses on_clicked(next0) to execute code and it can't use return to send reference - so I used global to this.
@furas totally agree with you! it's indeed the simplest and easiest way to keep reference :) added this comment for people in the future who may be viewing your answer and giving them other options to explore and sharing that the underlying principle behind assigning it to a global variable is because it prevents the instance from being garbage-collected

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.