3

The IPywidgets manual is very helpful for the most part, but is lacking some explanation about how one goes about creating complex dashboards. In particular, I am trying to figure our how to:

  1. Design abstractions to assist in building easily extendable dashboards which contain multiple interdependent widgets, some of which hide/show other widgets.
  2. Do this in a way which would allow me to get and set the state of all the widgets as a dict so I could subsequently implement buttons to save and load the configuration of my dashboard to a JSON file.

To make this question more concrete, I designed a minimal example of my current approach, which based on a design pattern I received from @jasongrout on the Jupyter Widgets channel on Gitter; when answering, please demonstrate your design pattern by reimplementing this example in it, ensuring the two criteria above are clearly fulfilled:

from IPython.display import display
import IPython.display as ipd
import ipywidgets as widgets
import matplotlib.pyplot as plt

class ModelUI:

    def __init__(self):

        self.par = dict()
        self.initUI()

    def initUI(self):

        self.funcPars = widgets.VBox()

        self.initLinear()
        self.initQuadratic()
        self.initFunc()
        self.initButton()
        self.initOutput()    

        self.controls = widgets.HBox([
            self.func, 
            self.funcPars, 
            self.plot
        ])
        self.UI = widgets.VBox([
            self.controls, 
            self.output
        ])

    def initFunc(self):

        self.func = widgets.Dropdown(
            description="Function:", 
            options=[
                "Linear", 
                "Quadratic"
            ])
        self.func.observe(self.updateFunc, "value")

        self.updateFunc(None)

    def initButton(self):

        self.plot = widgets.Button(description="Plot")
        self.plot.on_click(self.plotFunction)

    def updateFunc(self, change):

        if self.func.value == "Linear":
            self.funcPars.children = self.linPars
            self.par['func'] = "Linear"
        elif self.func.value == "Quadratic":
            self.funcPars.children = self.quadPars
            self.par['func'] = "Quadratic"
        else:
            pass

    def initLinear(self):

        self.m = widgets.FloatSlider(
            description="m", 
            min=-10, max=10, value=2)
        self.k = widgets.FloatSlider(
            description="k", 
            min=-10, max=10, value=1)
        self.linPars = [self.m, self.k]

        self.m.observe(self.updateLinear, "value")
        self.k.observe(self.updateLinear, "value")

        self.updateLinear(None)

    def updateLinear(self, change):

        self.par['m'] = self.m.value
        self.par['k'] = self.k.value

    def initQuadratic(self):

        self.a = widgets.FloatSlider(
            description="a", 
            min=-10, max=10, value=1)
        self.b = widgets.FloatSlider(
            description="b", 
            min=-10, max=10, value=2)
        self.c = widgets.FloatSlider(
            description="c", 
            min=-10, max=10, value=3)
        self.quadPars = [self.a, self.b, self.c]

        self.a.observe(self.updateQuadratic, "value")
        self.b.observe(self.updateQuadratic, "value")
        self.c.observe(self.updateQuadratic, "value")

        self.updateQuadratic(None)

    def updateQuadratic(self, change):

        self.par['a'] = self.a.value
        self.par['b'] = self.b.value
        self.par['c'] = self.c.value

    def initOutput(self):

        self.output = widgets.Output()
        self.plotFunction(None)    

    def plotFunction(self, change):

        self.function = {
            "Linear": lambda x: self.par['m']*x + self.par['k'],
            "Quadratic": lambda x: self.par['a']*x**2 + self.par['b']*x + self.par['c']
            }
        with self.output:
            ipd.clear_output()
            xvals = [ i/10 for i in range(-100,100)]
            yvals = list(map(self.function[self.par['func']], xvals))
            plt.plot(xvals,yvals)
            plt.show()

    def _ipython_display_(self):

        display(self.UI)

ModelUI()
Ixxie
  • 1,393
  • 1
  • 9
  • 17
  • I am also extremely interested in having some documentation regarding creating complex GUIs with Jupyter. As anything happened since publication of OP 5 years ago? – Ken Grimes Jan 05 '23 at 10:22
  • Could you provide some explanation on what this design pattern is and some documentation for the code? – Ken Grimes Jan 05 '23 at 10:23
  • 1
    @KenGrimes sorry, but I didn't continue exploring the ecosystem. I've been learning frontend development instead. However, I think I spotted some alternative dashboard projects connected to the newer developments in JupyterLab. I suggest starting from the JupyterLab docs and community forum / chat and trying to find out the best current solutions to this problem, rather than proceeding with this. – Ixxie Jan 09 '23 at 15:11

0 Answers0