<div dir="ltr"><div>One way to do this would be to instead of requiring the notebook user to understand everything, expose important bits as traitlets, and then change/traitlet.link all of them together. In your example, if:<br>
<ul><li><span style="font-family:courier new,monospace">Plotting</span> knows to redraw itself when its <span style="font-family:courier new,monospace">data</span> changes</li><li><span style="font-family:courier new,monospace">Filtering</span> , updates its <span style="font-family:courier new,monospace">windowtype,</span> to be, instead of <span style="font-family:courier new,monospace">"hamming"</span>,  <span style="font-family:courier new,monospace">scipy.filter.hamming</span></li>
</ul><p>then suddenly your code is now:</p><blockquote style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex" class="gmail_quote"><p><span style="font-family:courier new,monospace">def change_windowtype(name, old_value, new_value):<br>
    plot_ui.data = filtering_ui.windowtype(data)<br></span><span style="font-family:courier new,monospace">filtering_ui.</span><span style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">on_trait_change</span>("windowtype", </span><span style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">change_windowtype</span>)</span><br>
</p></blockquote><p>(I don't think your usage of on_trait_changed as a decorator is legit, but that would be awesome!)<br></p><p>That moves a lot of the event stuff into the internal structure of each of your GUI components. This pattern would also be much easier to wrap up later into a "higher order" GUI. Then, if you want to "hoist" a property, you would just use traitlet.link:</p>
<blockquote style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex" class="gmail_quote"><p><span style="font-family:courier new,monospace">class GUI(widgets.ContainerWidget)<br>    windowtype = traitlets.Any(sync=True)<br>
    plot_data = traitlets.Any(sync=True)<br>    data = traitlets.Any(sync=True)<br><br>    def __init__(self, **kwargs)<br>        super(GUI, self).__init__(**kwargs)<br><br>        self.filtering_ui = Filtering()<br>        self.plot_ui = Plotting()<br>
        <br>        self.children = [self.filtering_ui, self.plot_ui]</span></p><p><span style="font-family:courier new,monospace">        </span><span style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">traitlets.link</span>(self, "plot_data"), (self.plot_ui, "data"),<br>
        </span><span style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">traitlets.link</span>(self, "windowtype"), (self.filtering_ui, "windowtype"),<br>        <br>
    def _windowtype_changed(self, name, old_value, new_value):<br>        self.plot_data = self.windowtype(self.data)<br></span></p></blockquote><p>And now the notebook user would still be able to inspect and change the important parts of even deeply nested settings with simple assignment.</p>
</div></div>