In case anyone else runs into this, it seems to be related to widgets not being disconnected properly, in this case specifically the Textboxes. See for example this comment on GitHub.
I ended up just completely replacing the Figure and redisplaying it, which works fine. In my case, since I was waiting for the window to close in the main script, this required a little additional work to relink the callback, e.g.:
closed = Base.Event()
selection = Observable(...) # this triggers and controls figure (re)construction
window_open_callback = Ref{Any}(nothing)
on(selection) do selected
# filter data etc...
figure = build_figure(data; selection)
isnothing(window_open_callback[]) || off(window_open_callback[])
display(figure)
window_open_callback[] = on(events(figure).window_open) do is_open
!is_open && notify(closed)
end
end
notify(selection)
wait(closed)