Search code examples
pythonflaskcallbackdashboardplotly-dash

What is the best way for allowing for dynamic object creation and removal in a Plotly Dash dashboard?


Currently, I have a class which stores a dictionary of Card elements, each of which is unique. The class can also generate these cards and append them to the dictionary or remove a card from a dictionary. However, I am not sure how to best allow for this action through a callback function since the ID for a card doesn't exist until the card is made, and the functionality isn't directly within the Dash framework since a dictionary object acts as an intermediary where the objects are stored.

Basically, I am wondering what the best way to dynamically create and destroy objects with a callback is?

Thank you!


Solution

  • Assuming you want to avoid extra computation for building cards you wont use, I'd suggest create a which creates each card and store those functions in a dictionary. (You can also create a universal function with params that allow specificity)

    my_card_functions = {
      'id_1': make_id_1,
      'id_2': make_id_2,
    }
    

    Creating a card could be done as such:

    my_id = 'id_1'
    f = my_card_functions[my_id] # will break if id isn't registered
    my_card = f()
    

    You can store the cards you want to create in a dcc.store object. Here's an example of some code you might consider:

    # Pretend these are structured properly
    dcc.Store(id='cards_data')
    html.Div(id='my_cards',children=[])
    
    @app.callback(
      Output('my_cards','children'),
      [Input('cards_data','data')],
      [State('my_cards','children')]
    )
    def make_cards(data, children):
      """Makes cards for each id"""
      if not data:
        raise PreventUpdate
    
      # The following code is not correct but serves as a demonstrative example
      # Some data structure manipulation is necessary to access 
      # the ids from the children elements
      children_ids = [x['id'] for x in children]
    
      # Assuming your data looks something like this:
      # {'add':['id_1','id_2']}
    
      for x in data['add']:
        if x not in children_ids:
          f = my_card_functions[my_id]
          my_card = f()
    
          # Store values
          children.append(my_card)
    
      return children
    

    Note, this approach does not resolve removal of cards. That could easily be done but would probably require a more dynamic use of caching.