Quantcast
Channel: ЁЯОЫя╕П Dash - Plotly Community Forum
Viewing all articles
Browse latest Browse all 6271
тЖз

Multiple Dash apps - components id collisions

$
0
0

Hello,
IтАЩm trying to leverage Dash to create interactive plots of mathematical functions inside Jupyter Notebook. Therefore, IтАЩve embedded the Dash app logic into MyClass. Whenever I need to plot a mathematical function, I create a Python function which is going to update the traces of the figure, and pass it to the constructor of MyClass.

This is my code:

import numpy as np
import plotly.graph_objects as go
from jupyter_dash import JupyterDash
import dash_core_components as dcc
import dash_html_components as html
import dash_bootstrap_components as dbc
from dash.dependencies import Input, Output, State, ALL
from dash.development.base_component import Component

class MyClass:
    # count how many instances have been created
    currently_open = 0

    def __init__(self, user_func):
        type(self).currently_open += 1

        self.fig = go.Figure()

        childrens = []
        childrens.append(
            dbc.Container([
                self._create_slider(0, "Par a", 1, 5, 2.5),
                self._create_slider(1, "Par b", 0, 1, 0.15),
            ])
        )

        # Add a Plotly Graph Object
        childrens.append(
            dcc.Graph(id="my_plot" + str(type(self).currently_open), figure={})
        )
        
        # create the Dash app applying the specified CSS and JS
        self.app = JupyterDash(
            "IPlot-" + str(type(self).currently_open),
            external_stylesheets=[dbc.themes.SLATE],
        )
        # add the controls
        self.app.layout = html.Div(childrens)

        # Create the callback, specifying the input/output controls
        @self.app.callback(
            [Output("my_plot" + str(type(self).currently_open), "figure"),
             *[Output('value_slider_{}'.format(j), 'children') for j in range(2)]],
            [Input({'type': 'control_', 'index': ALL}, 'value')]
        )
        def func(values):
            user_func(self.fig, values)
            return [self.fig, *values]
        
        # execute the app in the Jupyter environment
        self.app.run_server(mode="inline")

    def _create_slider(self, i, _name, _min, _max, _val):
        return dbc.Row(
                children = [
                    # this shows the label
                    dbc.Col(html.Div(_name), 
                            width=1, style = {"text-align": "right"}),
                    # this will show the actual value of the slider
                    dbc.Col(html.Div(id="value_slider_" + str(i), children={}), 
                            width=1, style = {"text-align": "left"}),
                    dbc.Col(dcc.Slider(
                        id = {
                            "type": "control_",
                            "index": i
                        },
                        min = _min,
                        max = _max,
                        step = (_max - _min) / 50,
                        value = _val,
                    )),
                ]
            )

Now, letтАЩs suppose I want to plot two different mathematical functions. I create a first instance, everything works ok in the first app:

def my_sin_func(fig, values):
    a, b = values
    fig.data = []
    xx = np.linspace(0, 20, 200)
    yy = a * np.sin(xx) * np.exp(-xx * b)
    fig.add_trace(
        go.Scatter(x=xx, y=yy, mode="lines")
    )
    fig.add_trace(
        go.Scatter(x=xx, y=np.sin(xx), mode="lines")
    )

a = MyClass(my_sin_func)

Then. I create the second instance, everything works ok on the second app:

def my_cos_func(fig, values):
    a, b = values
    fig.data = []
    xx = np.linspace(0, 20, 200)
    yy = a * np.cos(xx) * np.exp(-xx * b)
    fig.add_trace(
        go.Scatter(x=xx, y=yy, mode="lines")
    )
    fig.add_trace(
        go.Scatter(x=xx, y=np.cos(xx), mode="lines")
    )

b = MyClass(my_cos_func)

But as soon as I move back to the first app and change a slider, an error happens in the second app:

KeyError: '..my_plot1.figure...value_slider_0.children...value_slider_1.children..'

I thought that different apps would somehow use a local scope, instead it seems the interactive controls of the two apps are colliding. A possible solution would be to generate unique IDs for each control every time an instance is created, so that the controls of the instance a have a different ID than the instance bтАж Is there something else I can try? Is there some option I can change?

Thank you in advance.

2 posts - 2 participants

Read full topic

тЖз

Viewing all articles
Browse latest Browse all 6271

Trending Articles