question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Modular callbacks and leverage python's object oriented nature

See original GitHub issue

Chris & Community,

Thanks for the earlier reply.

As I explore this more possibilities come to mind. This kind of mirrors some of the suggestions made earlier by some people about totally pythonic-react and highly reusable components without writing a line of javascript, which I think was your aim to start with.

I have made an attempt here. So I am trying to create an encapsulated panel (div) that has its own bundle of controls. So I am able to replicate the divisions within the app using a “parent” child node and naming convention.

The component is a class called custom_div and on initialization attaches itself to the main app layout. A central callback function tied to a button that then adds a button. This all seems to work.

my_div = custom_div(app, ‘my_div’)

However the key is to encapsulate the callback function within the new division. So that each new division has its own callback. Do you think this is possible?

EXAMPLE CODE

# coding=utf-8
from pprint import pprint

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

app = dash.Dash()
app.config.supress_callback_exceptions = True

class custom_div:
    def __init__(self, dash_app, div_name):
        self.app = dash_app
        self.parent_name = div_name
        self.div = html.Div(id=div_name,
                            style={'background-color': 'yellow',
                                   'resize': 'both',
                                   'width': 500
                                   },
                            children=[
                                dcc.Input(id=self.gen_id('id_width'), value=200, type="number"),
                                html.Button('Set Width', id=self.gen_id('width-butt'), type='submit'),
                                html.P('mint', id=self.gen_id('mint'))
                            ])
        self.app.layout['root'].children.append(self.div)

    def gen_id(self, comp_name):
        return ''.join([self.parent_name, '.', comp_name])

app.layout = html.Div([
    html.Button('Add Div', id='add-div', type='submit'),
    html.Div(id='root', children=[]),
    html.P('INFO', id='info'),
])

@app.callback(
    Output('root', 'children'),
    events=[Event('add-div', 'click')],
)
def add_new_div():
    my_div = custom_div(app, 'new_div')
    return app.layout['root'].children

my_div = custom_div(app, 'my_div')

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

Issue Analytics

  • State:open
  • Created 6 years ago
  • Reactions:1
  • Comments:12 (6 by maintainers)

github_iconTop GitHub Comments

10reactions
ned2commented, Jul 23, 2017

I’ve also been trying to work out the best way to encapsulate callbacks with corresponding component trees to make reusable components. I came up with the following class-based solution.

class BaseBlock:
    def __init__(self, app=None):
        self.app = app

        if self.app is not None and hasattr(self, 'callbacks'):
            self.callbacks(self.app)

class MyBlock(BaseBlock):
    layout = html.Div('layout for this "block".')

    def callbacks(self, app):

        @app.callback(Output('foo', 'figure'), [Input('bar')])
        def do_things(bar):
            return SOME_DATA

        @app.callback(Output('baz', 'figure'), [Input('boop')])
        def do_things(boop):
            return OTHER_DATA

# creating a new MyBlock will register all callbacks
block = MyBlock(app=app)

# now insert this component into the app's layout 
app.layout['slot'] = block.layout

The idea being that supplying a ‘callback’ method is optional if the layout doesn’t require any callbacks. I think the main advantage here is if you also associated some data and corresponding logic with the subclass, otherwise the function-based approach that @chriddyp suggests would do the job fine.

4reactions
jamestwebbercommented, Aug 25, 2017

So is this a working solution right now or in need of a PR? We are having similar questions as we try to refactor an increasingly-complex Dash app into readable components. How to wire up the callbacks and have everything still work is a bit confusing to figure out.

This issue dovetails with #38 in that Flask apps are already pretty modular. If we could have a structure like:

main_site/
     __init__.py  <- main site code, flask initialization
    config.py
    manage.py <- CLI tools for server management
    dash_app/
         __init__.py
        plotting_code.py <- callbacks
        layout_code.py <- Div tree
    some_other_app/
        ...who knows

That would be very nice!

Read more comments on GitHub >

github_iconTop Results From Across the Web

SciPy 1.0: fundamental algorithms for scientific computing in ...
Since its initial release in 2001, SciPy has become a de facto standard for leveraging scientific algorithms in Python, with over 600 unique ......
Read more >
Courses for Python: Python 3 Beginner - Skillsoft
Explore Python, the general purpose high-level programming language focused on code readability and efficiency.
Read more >
Parallel Processing in Python - A Practical Guide with Examples
In this tutorial, you'll understand the procedure to parallelize any typical logic using python's multiprocessing module.
Read more >
Python Stacks, Queues, and Priority Queues in Practice
Even though the LIFO queue above is oriented horizontally, it preserves ... To work around this, you can leverage Python's tuple comparison, ...
Read more >
Python 3 Object-oriented Programming
Python 3 Object Oriented Programming, Packt Publishing, was the first of his ... leverages them. ... the organization of classes into packages and...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found