1

I have a function fun() that binds a callback callback() when a matplotlib figure is clicked. I want this callback to be able to access the variable space of fun() to make changes. How can I go about this?

import numpy as np
import matplotlib.pyplot as plt

def callback(event):
    data = event.xdata

def fun():
    data = 0

    fig, ax = plt.subplots()
    ax.plot(np.random.rand(12), np.random.rand(12), 'go')
    fig.canvas.mpl_connect('button_release_event', callback)

    plt.show()
    return data

print fun()

Putting data in the global scope is not an acceptable solution. The function should be self-contained. The answer here would allow me to pass variables to callback(), but would not let me edit them.

SkyNT
  • 718
  • 1
  • 8
  • 19
  • Use a nested function (define your callback in the body of fun). But notice that the fun function would already have terminated when your callback will be called. – S. de Melo Oct 06 '16 at 14:43
  • I've already tried a nested function within ```fun()```: it does not work. A nested ```callback()``` can access the scope of ```fun()```, but it cannot modify it. Try it for yourself. Also, normally the function does not terminate until ```plt.show()``` is resolved (i.e. after canvas interaction). I have no issues with premature termination in the script above. – SkyNT Oct 06 '16 at 15:23
  • In fact you can by using a litte trick. See http://stackoverflow.com/questions/6198709/how-do-i-change-nesting-functions-variable-in-the-nested-function. You can use a dict, like d = dict(data=0) and then modify d["data"] in the nested function. – S. de Melo Oct 07 '16 at 05:58

1 Answers1

4

I understand you would like to have some state, that can be changed during runtime. One option might be to use a callable object, that is not a function (I have not tested it):

class Callback(object):
     def __init__(self, data):
         self.data = data
     def __call__(self, event):
         # Manipulate the data
         self.data += 1
...
datacallback = Callback(0)
fig.canvas.mpl_connect('button_release_event', datacallback)
print datacallback.data

That way we would have a counter how often the event is raised. But it works with any kind of data, also more complex than an integer.

oekopez
  • 1,080
  • 1
  • 11
  • 19