0

I want to create figure callbacks in a loop, with different additional input arguments to the callback for each figure. In the below code snippet the function prints "B" regardless of which figure I click in.

import matplotlib.pyplot as plt
import numpy as np

def onclick(event, key):
    print(key)

for k in ["A", "B"]:
    x = np.arange(1,10)
    y = x**2
    fig = plt.figure()
    ax = fig.add_subplot(111)
    ax.set_title(k)
    ax.plot(x,y)
    cid = fig.canvas.mpl_connect('button_press_event', lambda tmp: onclick(tmp, k))
HaMo
  • 130
  • 1
  • 2
  • 8

1 Answers1

1

Replace

lambda tmp: onclick(tmp, k)

with

functools.partial(onclick, key=k)

Full example:

from functools import partial
import numpy as np
import matplotlib.pyplot as plt

def onclick(event, key):
    print(key)

for k in ["A", "B"]:
    x = np.arange(1,10)
    y = x**2
    fig = plt.figure()
    ax = fig.add_subplot(111)
    ax.set_title(k)
    ax.plot(x,y)
    cid = fig.canvas.mpl_connect('button_press_event', partial(onclick, key=k))

plt.show()
Paul Brodersen
  • 11,221
  • 21
  • 38
  • Thank you! Works like a charm. I am probably stuck in Matlab thinking when it comes to callback functions, but does anyone know a resource which explains why this does not work in Python I'd be happy to read – HaMo Nov 05 '21 at 11:54
  • 1
    Your issue has nothing to do with the callback and everything to do with lambda functions, and at what point the value of `k` gets evaluated ("early versus late binding"). As a starting point, I suggest this [SO answer](https://stackoverflow.com/a/3252364/2912349). – Paul Brodersen Nov 05 '21 at 12:21