plotly / plotly/dash

add callbacks dynamically

Aperta
#787 4 commenti 5 reazioni 0 assegnatari Vedi su GitHub

Nessuno ha ancora preso questa issue.

feature P3
Lingua principale
Python
Stelle
24.4k
Fork
2.3k
Merge medio
2g 7h
PR unite (30g)
13

Descrizione

Hi!

this is somewhat of a mixture of a feature request and a bug report. here is my example:

import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output, State
import json
import os

external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
app.config.suppress_callback_exceptions=True

try:
    os.remove('cities.json')
except OSError:
    pass


def make_cb(city):
    @app.callback(Output('%s-pushed' % city, 'children'),
                  [Input('%s-but' % city, 'n_clicks')],
                  [State('%s-but' % city, 'children')])
    def fing(nc,cval):
        if nc:
            return cval
        return ''


def get_layout():
    
    try:
        cities = json.load(open('cities.json'))
    except FileNotFoundError:
        cities = []
    
    return html.Div([
                dcc.Input(id='input-1', type='text', value='Montréal'),
                html.Button(id='submit-button', n_clicks=0, children='Submit'),
                html.Div(id='pushed-city'),
                html.Div([html.Div([html.Button(c,id='%s-but' % c),
                                    html.Div(id='%s-pushed' % c)])
                          for c in cities],id='output-state')
            ])


app.layout = get_layout


@app.callback(Output('output-state', 'children'),
              [Input('submit-button', 'n_clicks')],
              [State('input-1', 'value')])
def update_output(n_clicks, input1):
    try:
        cities = set(json.load(open('cities.json')))
    except FileNotFoundError:
        cities = set()
    
    if input1 not in cities and input1 is not None:
        cities.add(input1)
        cities = list(cities)
        json.dump(cities,open('cities.json','w'))
        make_cb(input1)
    print(app.callback_map)
    return [html.Div([html.Button(c,id='%s-but' % c),
                                    html.Div(id='%s-pushed' % c)])
                          for c in cities]


if __name__ == '__main__':
    app.run_server(debug=True)

this is a simple app based on the documentation, that allows the user to add interactive elements, with some caching. There are two issues. The first one I don't understand, the second one I do.

  1. If I click the submit button, to add a city, everything appears fine, the print(app.callback_map) line shows me that the callback has been registered, i can see everything in the browser, however the callback does not become active, until I refresh the browser.

  2. If I use a proper server like gunicorn not the flask development server, with parallel processes, the callback_map dictionary is not shared, so the whole thing breaks down, and the callbacks basically don't work.

Now, I'm quite sure that 1, has some easy explanation that I'm just a little too tired to figure out, I wrote this whole thing because of 2,

I also hacked together a solution for myself for the second one, that allows for declaring the callback map as a shared key-value store, using redis. If anyone's interested, I can post a PR. As far as i can see, only __iter__, __getitem__, __setitem__ and items() are utilized from the callback_map.

I looked through #577 #475 #373 this and this. Based on these, creating a shared key-value store for the callbacks is a well isolated issue that fits the main arch of these topics.

Guida per i contributori

Apri la guida per i contributori

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Direzione di ricerca

Inizia tracciando come Dash registra e utilizza app.callback_map durante la distribuzione dei callback, usando come riproduzione l’esempio dynamic-callback nell’issue. Analizza le implicazioni della memorizzazione dei metadati dei callback in un archivio chiave-valore condiviso basato su Redis tra più processi worker. Il lavoro è completato quando i callback aggiunti dinamicamente funzionano senza aggiornare il browser e rimangono disponibili con più processi server.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Valutazione

Stack tecnologico
python, redis
Ambito
backend, distributed-systems
Tipo di issue
Funzionalità
Difficoltà
5/5
Tempo stimato
Più di una settimana
Stato di attività
Ferma
Chiarezza
Abbastanza chiara
Idoneità per principianti
25/100

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.