How do I determine the origin (caller) of an on_submit / on_text_change event?

How do I determine the origin (caller) of an on_submit / on_text_change event?

Here is my code:

  fig, ax = plt.subplots()
  plot(x, y, 'bo', label='data points')
...
  ax_xc = fig.add_axes([0.675, 0.8, 0.08, 0.05], visible=False)
  ax_yc = fig.add_axes([0.675, 0.7, 0.08, 0.05], visible=False)
  st_xc = TextBox(ax_xc, '', initial=tempMin)
  st_yc = TextBox(ax_yc, '', initial=tempMin)
...
 def changeText(val):
    # now I want to do a caller specific task
...  
  st_xc.on_submit(changeText)
  st_yc.on_submit(changeText)

Something like the following:

def changeText(val, origin):
    print(origin, val)

st_xc.on_submit(lambda val: changeText(val, st_xc))
st_yc.on_submit(lambda val: changeText(val, st_yc))
1 Like

Thank you very much, that works. I was sick so I couldn’t reply earlier, sorry.

Binding the origin in via a default value of a parameter to the lambda is marginally more like:

st_xy.on_submit(lambda val, origin=st_xc: changeText(val, origin))

Due to Python’s late binding if you were to do

# THIS IS BROKEN
for t in list_of_textbox:
    t.on_submit(lambda val: changeText(val, t))

You will end up with every call pointing at the last text box (because at call time Python sorts out what object t refers to). In contrast

for t in list_of_textbox:
    t.on_submit(lambda val, origin=t: changeText(val, origin))

will sort out what object t refers to at lambda definition time and bind that object as the default value of the lambda. See Python lambda closure scoping - Stack Overflow for more details.

1 Like

Thanks for explanation.

If I understand you right, the first version:

is pointing in all cases to the last ot the text box listing,

while the other version takes the actual value of t for the binding:

To make it a little more complex I would not point to the origin caller but (if lambda makes it possible) to the corresponding slider element (that is what I want to change while editing the text box) so my code would look like:

...
  ax_xc = fig.add_axes([0.675, 0.8, 0.08, 0.05], visible=False)
  sl_xc = Slider(ax_xc, label=r'$x_c=\ $', valmin=tempMin, valinit=tempMin, valmax=tempMax, valstep=0.001)
  sl_xc.valtext.set_visible(False)
  ax_txc = fig.add_axes([0.675, 0.78, 0.08, 0.02], visible=False)
  st_xc = TextBox(ax_txc, '', initial=tempMin)
  st_xc.on_submit(lambda val, origin=sl_xc: changeText(val, origin))
...
  ax_yc = fig.add_axes([0.675, 0.7, 0.08, 0.05], visible=False)
  sl_yc = Slider(ax_yc, label=r'$y_c=\ $', valmin=tempMin, valinit=tempMin, valmax=tempMax, valstep=0.001)
  sl_yc.valtext.set_visible(False)
  ax_tyc = fig.add_axes([0.675, 0.68, 0.08, 0.02], visible=False)
  st_yc = TextBox(ax_tyc, '', initial=tempMin)
  st_yc.on_submit(lambda val, origin=sl_yc: changeText(val, origin))
...

Is that working?
I want to access the corresponding slider in order to synchronize the value of the slider with the textbox.

I extended the events and it works:

def changeSlider(val, slider, textbox, parameter):
...
def changeText(val, slider, textbox):

...
  ax_xc = fig.add_axes([0.675, 0.8, 0.08, 0.05], visible=False)
  ax_txc = fig.add_axes([0.675, 0.78, 0.08, 0.02], visible=False)
  sl_xc = Slider(ax_xc, label=r'$x_c=\ $', valmin=tempMin, valinit=tempMin, valmax=tempMax, valstep=span/200.0)
  #sl_xc.valtext.set_visible(False)
  st_xc = TextBox(ax_txc, '', initial=tempMin)
  sl_xc.on_changed(lambda val, slider=sl_xc, textbox=st_xc, parameter=ec.actXc: changeSlider(val, slider, textbox, parameter))
  st_xc.on_text_change(lambda val, slider=sl_xc, textbox=st_xc: changeText(val, slider, textbox))
...
  ax_yc = fig.add_axes([0.675, 0.7, 0.08, 0.05], visible=False)
  ax_tyc = fig.add_axes([0.675, 0.68, 0.08, 0.02], visible=False)
  sl_yc = Slider(ax_yc, label=r'$y_c=\ $', valmin=tempMin, valinit=tempMin, valmax=tempMax, valstep=span/200)
  #sl_yc.valtext.set_visible(False)
  st_yc = TextBox(ax_tyc, '', initial=tempMin)
  sl_yc.on_changed(lambda val, slider=sl_yc, textbox=st_yc, parameter=ec.actYc: changeSlider(val, slider, textbox, parameter))
  st_yc.on_text_change(lambda val, slider=sl_yc, textbox=st_yc: changeText(val, slider, textbox))

Thank you very much for your help!