API details for DashComponentBase, DashFigureFactory, DashComponent and DashApp

imports

DashComponentBase

All classes in the library are derived from DashComponentBase which is a an abstract base class (ABC) that provides:

  • automatic storing of parameters to attributes
  • automatic storing of parameters to a ._stored_params property
  • exporting component to a config dict with .to_config()
  • exporting component to a yaml file with .to_yaml()
  • building component from a config dict with classmethod .from_config()
  • building component from a yaml file with classmethod .from_yaml()

class DashComponentBase[source]

DashComponentBase(no_store=None, no_attr=None, no_config=None, child_depth=3) :: ABC

Base class for all dash_oop_components classes.

Stores parameter of child classes to attributes and ._stored_params. Proved .to_config(), to_yaml(), .from_config() and .from_yaml() methods

DashComponentBase.to_config[source]

DashComponentBase.to_config()

returns a dict with class name, module and params

DashComponentBase.to_yaml[source]

DashComponentBase.to_yaml(filepath=None)

stores a yaml configuration to disk.

If no filepath is given, returns a str of the yaml config.

DashComponentBase.from_config[source]

DashComponentBase.from_config(config, try_pickles=False, force_pickles=False, **update_params)

Loads a dash_oop_component class from a configuration dict.

Args: config (dict): configuration dict, generated from .to_config() try_pickles (bool): when finding a filepath parameter try loading from that file, if it fails, load from config force_pickles (bool): when finding a filepath parameter try loading from that file, if it fails, raise error **update_params: kwargs that override settings in params

Returns: Instance of the class defined in the config.

DashComponentBase.from_config[source]

DashComponentBase.from_config(config, try_pickles=False, force_pickles=False, **update_params)

Loads a dash_oop_component class from a configuration dict.

Args: config (dict): configuration dict, generated from .to_config() try_pickles (bool): when finding a filepath parameter try loading from that file, if it fails, load from config force_pickles (bool): when finding a filepath parameter try loading from that file, if it fails, raise error **update_params: kwargs that override settings in params

Returns: Instance of the class defined in the config.

Example use of DashComponentBase

Define a class T as a childclass of DashComponentBase and initialize an instance t:

class T(DashComponentBase): 
    def __init__(self, a=1, b=2, **kwargs):
        super().__init__(child_depth=2)
        
t = T(a=2, b=3)

Get the configuration of the instance t:

print(t.to_config())
{'dash_component': {'class_name': 'T', 'module': '__main__', 'params': {'a': 2, 'b': 3, 'kwargs': {}}}}

Get the configuration in yaml format:

print(t.to_yaml())
dash_component:
  class_name: T
  module: __main__
  params:
    a: 2
    b: 3
    kwargs: {}

Tests showing parameters have been assigned to attributes and config stores all relevenat data to rebuild the instance from the config:

  • parameters have been assigned to attributes
  • class_name and module have been recorded
  • parameters have been recorded
assert t.a == 2
assert t.b == 3
assert t.to_config()['dash_component']['class_name'] == "T"
assert t.to_config()['dash_component']['module'] == "__main__"
assert t.to_config()['dash_component']['params']['a'] == t.a
assert t.to_config()['dash_component']['params']['b'] == t.b

Store to yaml:

t.to_yaml("T.yaml")

Load from yaml and check that loaded instance t2 is same as t:

t2 = T.from_yaml("T.yaml")

assert t2.to_config()['dash_component']['class_name'] == "T"
assert t2.to_config()['dash_component']['module'] == "__main__"
assert t2.to_config()['dash_component']['params']['a'] == t.a
assert t2.to_config()['dash_component']['params']['b'] == t.b

Override parameters upon loading:

t2 = T.from_yaml("T.yaml", b=4)
assert t2.b == 4

If **kwargs in the class definition than unknown parameters get loads to self.kwargs:

t2 = T.from_yaml("T.yaml", c=5)
assert hasattr(t2, "kwargs")
assert "c" in t2.kwargs
assert t2.kwargs["c"] == 5

Store to file ("pickle", although also works with dill and joblib) and reload from file:

t2.dump("t") # stores to "t.pkl"
t3 = DashComponentBase.from_file("t.pkl")
print(t3.to_yaml())
assert t3.kwargs["c"] == 5
dash_component:
  class_name: T
  module: __main__
  params:
    a: 2
    b: 3
    kwargs:
      c: 5

If suffix is ".pkl" can simply leave it out. And you can load from any DashComponentBase child class:

t4 =  T.from_file("t")
print(t4.to_yaml())
assert t4.kwargs["c"] == 5
dash_component:
  class_name: T
  module: __main__
  params:
    a: 2
    b: 3
    kwargs:
      c: 5

DashFigureFactory

A DashFigureFactory loads data and provides plots, tables, lists, dicts, etc that can be used for building your dashboard.

This provides a clean seperation where all your data preparation and visualisation logic goes into one place (the DashFigureFactory) and all the dashboard layout and interaction logic goes into another (the DashComponents). This means that you only have to change the data representation in one place, and the whole dashboard will adapt.

When used as a parameter to a DashComponent (e.g. parameter figure_factory)the parameter figure_factory gets replaced by the figure factory configuration dict. This means that a DashComponent automatically loads its underlying DashFigureFactory parameters upon load!

In some cases you may perform a lot of costly calculations during the initialization of the DashFigureFactory (e.g. calculate SHAP values). In this case you may want to pickle the DashFigureFactory and reload it from file. If you add a parameter filepath to the parameters and .dump() the DashFigureFactory, then you can automatically reload it from pickle by adding .from_yaml("component.yaml", try_pickles=True).

class DashFigureFactory[source]

DashFigureFactory(no_store=None, no_attr=None, no_config=None) :: DashComponentBase

Helper class to store data for a dashboard and provide e.g. plotting functions.

You should seperate the datastorage/plotting logic from the dashboard logic. All data/plotting logic goes into a DashFigureFactory.

All dashboard logic goes into a DashComponent.

Stores to config under key 'dash_figure_factory'

Example use of DashFigureFactory: ListFactory

A DashFigureFactory that simply stores a list and has a return_list() method:

class ListFactory(DashFigureFactory):
    def __init__(self, list_input, filepath=None):
        super().__init__()
        
    def list_length(self):
        return len(self.list_input)
        
    def return_list(self, first_n_items=None):
        if first_n_items is None: first_n_items = self.list_length()
        if first_n_items <= len(self.list_input):
            return self.list_input[:first_n_items]
        return None
list_factory = ListFactory(["this", "is", "a", "dumb", "example"], filepath="list_factory.pkl")
print(list_factory.return_list())
['this', 'is', 'a', 'dumb', 'example']
print(list_factory.to_yaml())
dash_figure_factory:
  class_name: ListFactory
  module: __main__
  params:
    list_input:
    - this
    - is
    - a
    - dumb
    - example
    filepath: list_factory.pkl

assert list_factory.list_input == ['this', 'is', 'a', 'dumb', 'example']
assert list_factory.return_list() == ['this', 'is', 'a', 'dumb', 'example']
assert list_factory.return_list(2) == ['this', 'is']

Storing and loading from yaml:

list_factory.to_yaml("list_factory.yaml")
list_factory2 = DashFigureFactory.from_yaml("list_factory.yaml")

assert list_factory2.list_input == list_factory.list_input
assert list_factory2.return_list() == list_factory.return_list()
assert list_factory2.return_list(2) == list_factory.return_list(2)
  • If you use force_pickles=True but filepath does not exist, then it will throw a FileNotFoundError.
  • If you use try_pickles=True but filepath does not exist, then it will simply show a warning.
list_factory = ListFactory(["this", "is", "a", "dumb", "example"], filepath="list_factory2.pkl")
list_factory.to_yaml("list_factory2.yaml")
try:
    ListFactory.from_yaml("list_factory2.yaml", force_pickles=True)
except Exception as e:
    assert isinstance(e, FileNotFoundError)
list_factory = ListFactory.from_yaml("list_factory2.yaml", try_pickles=True)
Couldn't find list_factory2.pkl! You could try passing correct filepath as kwarg.Now loading from config instead...

So you have to make sure the file exists by dumping it:

list_factory = ListFactory(["this", "is", "a", "dumb", "example"], filepath="list_factory.pkl")
list_factory.to_yaml("list_factory.yaml")
list_factory.dump()
list_factory2 = ListFactory.from_yaml("list_factory.yaml", force_pickles=True)
assert isinstance(list_factory2, ListFactory)

A DashComponent combines a dash layout with dash callbacks.

It provides:

  • a .layout() method that returns the layout for the component
  • a .register_callbacks(app) method that allow you to register the callbacks of the component to a specific dash app
  • automatic conversion of any DashFigureFactory parameters to it's config (this means that figure factory will be automatically loaded upon load)
  • automatic registration of all DashComponent subcomponents in its attributes (which means that callbacks of all subcomponents will also automatically be registered)
  • a make_hideable staticmethod that makes it easy to hide parts of a layout depending on configuration bools
  • a querystring() method that allows you to store the state of your dashboard in the url querystring, and then load the state of the dashboard back from that url.

It inherits from DashComponentBase so:

  • All parameters are automatically stored to attributes and to ._stored_params
  • Can be exported and loaded from config and yaml
  • Can be dumped to pickle/dill/joblib and loaded .from_file()

IMPORTANT:

  • add +self.name to all the id's in your layout to make sure layout id's are unique.
  • define your callbacks in _register_callbacks(self, app) (note the underscore!)
  • If you're using self.querystring(params)(...), then set the self.name of the component to something definitive and readable, as otherwise each run it gets assigned a new random uuid string everytime you reboot your app, breaking previously generated querystring urls.

class DashComponent[source]

DashComponent(title='Dash', name=None, no_store=None, no_attr=None, no_config=None) :: DashComponentBase

DashComponent is a bundle of a dash layout and callbacks that can make use of DashFigureFactory objects.

A DashComponent can have DashComponent subcomponents, that you register with register_components().

DashComponents allow you to:

  1. Write clean, re-usable, composable code for your dashboard
  2. Store your dashboard to config files
  3. Load your dashboard from config files

Each DashComponent should have a unique .name so that dash id's don't clash. If no name is given, DashComponent generates a unique uuid name. This allows for multiple instance of the same component type in a single layout. But remember to add +self.name to all id's.

Important: define your callbacks in _register_callbacks() (note underscore!) and DashComponent will register callbacks of subcomponents in addition to _register_callbacks() when calling register_callbacks()

DashComponent.make_hideable[source]

DashComponent.make_hideable(element, hide=False)

helper function to optionally not display an element in a layout.

Example: make_hideable(dbc.Col([cutoff.layout()]), hide=hide_cutoff)

Args: hide(bool): wrap the element inside a hidden html.div. If the element is a dbc.Col or a dbc.FormGroup, wrap element.children in a hidden html.Div instead. Defaults to False.

DashComponent.querystring[source]

DashComponent.querystring(params, *attrs)

wrapper function that applies params loaded from querystrings to the underlying dash layout function's attributes attrs. By default it only applies to the "value" attribute.

Use: To only track the value attribute: self.querystring(params)(dcc.Input)(id="input-"+self.name, value=1)

To track specific attribute(s):

    self.querystring(params, "value", "min", "max")(dcc.Slider)(id="input-"+self.name)

if params=='_store_querystring_params': stores a list of tuple(id, attribute) to be tracked in the querystring to self._querystring_params. All (nested) querystring parameters can be accessed with .get_querystring_params()

DashComponent.get_querystring_params[source]

DashComponent.get_querystring_params()

Returns a list of tuple(id, attribute) of all element attributes in all (sub-)components that have been wrapped by self.querystring() and should be tracked in the url querystring.

DashComponent.get_unreachable_querystring_params[source]

DashComponent.get_unreachable_querystring_params()

returns all element (id, attr) querystring parameters that have a self.querystring() wrapper but because params has not been passed correctly down to subcomponents .layout() function, will not actually get updated.

DashComponent.layout[source]

DashComponent.layout(params=None)

layout to be defined by the particular ExplainerComponent instance. All element id's should append +self.name to make sure they are unique.

DashComponent.component_callbacks[source]

DashComponent.component_callbacks(app)

register callbacks specific to this ExplainerComponent.

DashComponent.register_callbacks[source]

DashComponent.register_callbacks(app)

First register callbacks of all subcomponents, then call _register_callbacks(app)

Tracking every single parameter in a big multi tab dashboard can result in extremely long querystring urls. However often you would only want to share the analysis on a single tab anyway, so we can shorten the url by only keeping track of the parameters of the tab that you are on at the moment. To make this possible we define a drop-in replacement for dcc.Tabs called DashComponentTabs.

When you pass an id and a list of DashComponents, this generates automatically a

dcc.Tabs(id=id, children = [dcc.Tab(tab.layout(), label=tab.title) for tab in tabs])

When you pass a component parameter and do not set single_tab_querystrings=False, then DashComponentTabs stores the querystring parameter for each tab in component._tab_params. This will get used by DashApp to exclude all parameters that are not on the current tab from being stored in the querystring url.

Example usage:

self.querystring(params)(DashComponentTabs)(
                component=self, id="tabs", tabs=[self.list1, self.list2], params=params)

class DashComponentTabs[source]

DashComponentTabs(id=None, tabs=None, params=None, value=None, component=None, single_tab_querystrings=True, **kwargs) :: Tabs

A Tabs component. A Dash component that lets you render pages with tabs - the Tabs component's children can be dcc.Tab components, which can hold a label that will be displayed as a tab, and can in turn hold children components that will be that tab's content.

Keyword arguments:

  • children (list of a list of or a singular dash component, string or numbers | a list of or a singular dash component, string or number; optional): Array that holds Tab components
  • id (string; optional): The ID of this component, used to identify dash components in callbacks. The ID needs to be unique across all of the components in an app.
  • value (string; optional): The value of the currently selected Tab
  • className (string; optional): Appends a class to the Tabs container holding the individual Tab components.
  • content_className (string; optional): Appends a class to the Tab content container holding the children of the Tab that is selected.
  • parent_className (string; optional): Appends a class to the top-level parent container holding both the Tabs container and the content container.
  • style (dict; optional): Appends (inline) styles to the Tabs container holding the individual Tab components.
  • parent_style (dict; optional): Appends (inline) styles to the top-level parent container holding both the Tabs container and the content container.
  • content_style (dict; optional): Appends (inline) styles to the tab content container holding the children of the Tab that is selected.
  • vertical (boolean; default False): Renders the tabs vertically (on the side)
  • mobile_breakpoint (number; default 800): Breakpoint at which tabs are rendered full width (can be 0 if you don't want full width tabs on mobile)
  • colors (dict; default { border: '#d6d6d6', primary: '#1975FA', background: '#f9f9f9', }): Holds the colors used by the Tabs and Tab components. If you set these, you should specify colors for all properties, so: colors: { border: '#d6d6d6', primary: '#1975FA', background: '#f9f9f9' }. colors has the following type: dict containing keys 'border', 'primary', 'background'. Those keys have the following types:
    • border (string; optional)
    • primary (string; optional)
    • background (string; optional)
  • loading_state (dict; optional): Object that holds the loading state object coming from dash-renderer. loading_state has the following type: dict containing keys 'is_loading', 'prop_name', 'component_name'. Those keys have the following types:
    • is_loading (boolean; optional): Determines if the component is loading or not
    • prop_name (string; optional): Holds which property is loading
    • component_name (string; optional): Holds the name of the component that is loading
  • persistence (boolean | string | number; optional): Used to allow user interactions in this component to be persisted when the component - or the page - is refreshed. If persisted is truthy and hasn't changed from its previous value, a value that the user has changed while using the app will keep that change, as long as the new value also matches what was given originally. Used in conjunction with persistence_type.
  • persisted_props (list of a value equal to: 'value's; default ['value']): Properties whose user interactions will persist after refreshing the component or the page. Since only value is allowed this prop can normally be ignored.
  • persistence_type (a value equal to: 'local', 'session', 'memory'; default 'local'): Where persisted user changes will be stored: memory: only kept in memory, reset on page refresh. local: window.localStorage, data is kept after the browser quit. session: window.sessionStorage, data is cleared once the browser quit.

class DashConnector[source]

DashConnector(title='Dash', name=None, no_store=None, no_attr=None, no_config=None) :: DashComponent

DashComponent is a bundle of a dash layout and callbacks that can make use of DashFigureFactory objects.

A DashComponent can have DashComponent subcomponents, that you register with register_components().

DashComponents allow you to:

  1. Write clean, re-usable, composable code for your dashboard
  2. Store your dashboard to config files
  3. Load your dashboard from config files

Each DashComponent should have a unique .name so that dash id's don't clash. If no name is given, DashComponent generates a unique uuid name. This allows for multiple instance of the same component type in a single layout. But remember to add +self.name to all id's.

Important: define your callbacks in _register_callbacks() (note underscore!) and DashComponent will register callbacks of subcomponents in addition to _register_callbacks() when calling register_callbacks()

Example use of DashComponent:

import dash_html_components as html
import dash_core_components as dcc

Single DashComponent

  • You can pass a name to a DashComponent to be used as a unique suffix for all the layout id's. If you don't pass a name, a random uuid identifier self.name gets generated instead. However if you are going to track querystrings, it's best to pass a specific, short and readable name.
  • You can store the state of your dashboard to the url querystring by wrapping the elements that you would like to track in a self.querystrings(params)(...) wrapper.
    • The state of the querystring will be passed down to the layout function as params.
    • You pass these params to self.querystring, and indicate which elements of the layour function you would like to track and reload from state.
    • If no attributes are listed, by default "value" gets tracked
  • callbacks should be defined in _register_callbacks(app) (note the underscore!)
    • the register_callbacks(app) will then first register all callbacks of subcomponents and then call this _register_callbacks(app) method.
class T(DashComponent):
    def __init__(self, name=None):
        super().__init__()
    
    def layout(self, params=None):
        return html.Div([
            self.querystring(params)(dcc.Input)(id=self.id("input1")),
            self.querystring(params, "min", "max")(dcc.Input)(id=self.id("input2")),
            self.querystring(params, "min", "max", "value")(dcc.Input)(id=self.id("input3"))
        ])
            
t= T(name="0")
t.get_querystring_params()
[('input1-0', 'value'),
 ('input2-0', 'min'),
 ('input2-0', 'max'),
 ('input3-0', 'value'),
 ('input3-0', 'min'),
 ('input3-0', 'max')]
t= T(name="0")
t.get_querystring_params()
input1_attributes = [qs[1] for qs in t.get_querystring_params() if qs[0]=="input1-0"]
input2_attributes = [qs[1] for qs in t.get_querystring_params() if qs[0]=="input2-0"]
input3_attributes = [qs[1] for qs in t.get_querystring_params() if qs[0]=="input3-0"]

assert input1_attributes == ['value'], "if no attributes explicitly listen, default to track 'value'"
assert not 'value' in input2_attributes, "value should not be in attributes if other attributes are explicitly listed"
assert input3_attributes[0] == 'value', "value should always be the first attributes in the list!"

DashComponent example: ListComponent

class ListComponent(DashComponent):
    def __init__(self, list_factory, first_n=2, name=None):
        super().__init__()
        
    def layout(self, params=None):
        return html.Div([
            self.querystring(params)(dcc.Input)(
                id=self.id("input-first-n"), 
                type="number", 
                value=self.first_n,
                min=0,
                max=self.list_factory.list_length()),
            html.Div(id=self.id("output-div"), 
                     children=" ".join(self.list_factory.return_list(self.first_n))),
        ])
    
    def component_callbacks(self, app):
        @app.callback(
            self.Output("output-div", "children"),
            self.Input("input-first-n", "value")
        )
        def update_div(first_n):
            if first_n is not None:
                return " ".join(self.list_factory.return_list(first_n))
            raise PreventUpdate
list_component = ListComponent(list_factory, name="1")
list_component.get_querystring_params()
[('input-first-n-1', 'value')]
assert list_component.list_factory.return_list() == ['this', 'is', 'a', 'dumb', 'example']
assert isinstance(list_component.layout(), html.Div)
assert list_component.get_querystring_params()[0][1] == 'value'
print(list_component.to_yaml())
dash_component:
  class_name: ListComponent
  module: __main__
  params:
    list_factory:
      dash_figure_factory:
        class_name: ListFactory
        module: __main__
        params:
          list_input:
          - this
          - is
          - a
          - dumb
          - example
          filepath: file_factory.pkl
    first_n: 2
    name: '1'

Store and reload the component (with the figure factory automatically getting reloaded as well!):

list_component.to_yaml("list_component.yaml")
list_component2 = ListComponent.from_yaml("list_component.yaml")
assert isinstance(list_component2, ListComponent)
list_component.dump()
list_component2 = ListComponent.from_yaml("list_component.yaml", try_pickles=True)
assert isinstance(list_component2, ListComponent)
Couldn't find file_factory.pkl! So loading from config instead...
assert list_component2.list_factory.return_list() == list_component.list_factory.return_list()
list_factory.to_config()['dash_figure_factory']['params']['filepath']
'file_factory.pkl'

See that force_pickle=True fails when the DashFigureFactory's filepath is non-existent, but that try_pickles=True simply reload the DashFigureFactory from config:

list_factory._stored_params['filepath'] = "non_existing_file.pkl"
list_component = ListComponent(list_factory)
list_component.to_yaml("list_component.yaml")
try:
    list_component.from_yaml("list_component.yaml", force_pickles=True)
except Exception as e:
    assert isinstance(e, FileNotFoundError)
list_factory._stored_params['filepath'] = "file_factory.pkl"
list_component.to_yaml("list_component.yaml")

Composite DashComponent Example: ListComposite

A ListComposite if a combination of two ListComponents, both with different initial settings for first_n.

  • the subcomponents get defined in the init with self.list1 = ... and self.list2 = ...
  • the subcomponents get included in the layout by including self.list1.layout() and self.list2.layout()
  • callbacks can be written that include elements from the ListComposite and the subcomponents
    • you need to add the .name from the subcomponents to properly identify the element id's
    • in this case the reset button resets the two inputs of the subcomponents:
      @app.callback(
            Output("input-first-n-"+self.list1.name, "value"),
            Output("input-first-n-"+self.list2.name, "value"),
            Input("reset-button-"+self.name, "n_clicks")
        )
      
  • additional callbacks should be defined under _register_callbacks(self, app)! (note the underscore!)
  • callbacks of the subcomponents also get automatically registered, and included when DashApp calls register_components(app) (note the lack of underscore here!)
class ListComposite(DashComponent):
    def __init__(self, list_factory, first_n1=2, first_n2=3, name=None):
        super().__init__()
        self.list1 = ListComponent(list_factory, first_n=first_n1, name="1")
        self.list2 = ListComponent(list_factory, first_n=first_n2, name="2")
        
    def layout(self, params=None):
        return html.Div([
            html.Button("Reset", id=self.id("reset-button")),
            self.querystring(params)(DashComponentTabs)(
                component=self, id="tabs", tabs=[self.list1, self.list2], params=params)
        ])
    
    def component_callbacks(self, app):
        @app.callback(
            self.list1.Output("input-first-n", "value"),
            self.list2.Output("input-first-n", "value"),
            self.Input("reset-button", "n_clicks")
        )
        def reset_inpus(n_clicks):
            if n_clicks:
                return self.first_n1, self.first_n2
            raise PreventUpdate
list_composite = ListComposite(list_factory, name="main")
list_composite.get_querystring_params()
[('input-first-n-1', 'value'), ('input-first-n-2', 'value')]
list_composite.layout()
Div([Button(children='Reset', id='reset-button-main'), Tabs(children=[Tab(children=Div([Input(id='input-first-n-1', value=2, type='number', max=5, min=0), Div(children='this is', id='output-div-1')]), id='tabs-1', label='Dash', value='1'), Tab(children=Div([Input(id='input-first-n-2', value=3, type='number', max=5, min=0), Div(children='this is a', id='output-div-2')]), id='tabs-2', label='Dash', value='2')], id='tabs', value='1')])
list_composite._tab_params
{'tabs': {'1': [('input-first-n-1', 'value')],
  '2': [('input-first-n-2', 'value')]}}
print(list_composite._querystring_params)
print(list_composite.list1._querystring_params)
print(list_composite.list2._querystring_params)
[]
[('input-first-n-1', 'value')]
[('input-first-n-2', 'value')]
list_composite.compute_querystring_params()
querystring_params = list_composite.get_querystring_params()
assert len(querystring_params) == 3, \
 "should be three querystring params, one from each subcomponent plus 'tabs'!"
querystring_params
[('tabs', 'value'), ('input-first-n-1', 'value'), ('input-first-n-2', 'value')]
unreachable_querystring_params = list_composite.get_unreachable_querystring_params()
assert len(unreachable_querystring_params) == 0, \
    "should be no unreachable params in this component!"
unreachable_querystring_params
[]
print(list_composite.to_yaml())
dash_component:
  class_name: ListComposite
  module: __main__
  params:
    list_factory:
      dash_figure_factory:
        class_name: ListFactory
        module: __main__
        params:
          list_input:
          - this
          - is
          - a
          - dumb
          - example
          filepath: file_factory.pkl
    first_n1: 2
    first_n2: 3
    name: main

subcomponents are automatically registerd to a _components list when calling register_components().

(this gets called initially in register_callbacks())

list_composite.register_components()
list_composite._components
assert len(list_composite._components) == 2

When we build a dash app from this list_composite, we can check that all three callbacks (one for the composite, and one each for each subcomponent) have indeed been registered:

app = dash.Dash()
app.layout = list_composite.layout()
list_composite.register_callbacks(app)
assert len(app.callback_map) == 3, \
    ("Should be three callbacks (one for the composite, and one each for each "
     "subcomponent) have indeed been registered)")

Using DashConnectors between DashComponents:

You can define DashConnectors that connect the inputs and outputs of multiple DashComponents. You can do this because you have access to the .name property of each subcomponent.

DashConnectors never register callbacks from any of its subcomponents.

Using DashConnectors can help clean up your code, especially if you can re-use them.

class ResetConnector(DashConnector):
    def __init__(self, list_composite, list_component1, list_component2):
        super().__init__()
        
    def component_callbacks(self, app):
        @app.callback(
            [self.list_component1.Output("input-first-n", "value"),
             self.list_component2.Output("input-first-n", "value")],
             self.list_composite.Input("reset-button", "n_clicks")
        )
        def reset_inpus(n_clicks):
            if n_clicks:
                return self.list_composite.first_n1, self.list_composite.first_n2
            raise PreventUpdate
            
class ListComposite(DashComponent):
    def __init__(self, list_factory, first_n1=2, first_n2=3, name=None):
        super().__init__()
        self.list1 = ListComponent(self.list_factory, first_n=first_n1, name="1")
        self.list2 = ListComponent(self.list_factory, first_n=first_n2, name="2")
        self.connector = ResetConnector(self, self.list1, self.list2)
        
    def layout(self, params=None):
        return html.Div([
            html.Button("Reset", id="reset-button-"+self.name),
            self.querystring(params)(DashComponentTabs)(
                component=self, id="tabs", tabs=[self.list1, self.list2], params=params)
        ])
        
list_composite = ListComposite(list_factory)
print(list_composite.to_yaml())
dash_component:
  class_name: ListComposite
  module: __main__
  params:
    list_factory:
      dash_figure_factory:
        class_name: ListFactory
        module: __main__
        params:
          list_input:
          - this
          - is
          - a
          - dumb
          - example
          filepath: file_factory.pkl
    first_n1: 2
    first_n2: 3
    name: GmrYyUT7T8

concat_docstring[source]

concat_docstring(source=None)

Decorator: __doc__ from source to doc

parse_url_to_params[source]

parse_url_to_params(url)

Returns a dict that summarizes the state of the app at the time that the querystring url was generated. Lists are (somewhat hackily) detected by the first char=='['), get evaluated using ast. Numbers are appropriately cast as either int or float.

Params: url (str): url to be parsed. The querystring parameters should come in pairs e.g.:?input-id=value&binput-id=1

Returns: dict: dictionary with the component_id as key and a list of (param, value) pairs (e.g. {'input-id': [('value', 1)]}

parse_url_to_qs_and_vals[source]

parse_url_to_qs_and_vals(url)

Returns a dict that summarizes the state of the app at the time that the querystring url was generated. Lists are (somewhat hackily) detected by the first char=='['), get evaluated using ast. Numbers are appropriately cast as either int or float.

Params: url (str): url to be parsed. The querystring parameters should come in pairs e.g.:?input-id=value&binput-id=1

Returns: dict: dictionary with the component_id as key and a list of (param, value) pairs (e.g. {'input-id': [('value', 1)]}

encode_querystring_params_to_url[source]

encode_querystring_params_to_url(querystring_params, values)

encodes a list of querystring_params and a list of values to a url.

Params: querystring_params (list[tuples]): format e.g. [('input-id', 'value'), ('input-id', 'type')] values (list): list of values to be encoded, e.g. [1, 'number']

Returns: str: url of format ?input-id=value&binput-id=1&input-id=type&binput-id='number'

update_url_with_new_params[source]

update_url_with_new_params(old_url, qs_params, vals)

DashApp

In order to run your DashboardComponent dashboard you can pass it to a DashApp and run it:

DashApp(dashboard_component).run()

Args:

  • dashboard_component (DashComponent): component to be run
  • port (int): port to run the server
  • mode ({'dash', 'external', 'inline', 'jupyterlab'}): type of dash server to start
  • querystrings (bool): save state to url querystring and load from querystring
  • kwargs: all kwargs will be passed down to dash.Dash. See below the docstring of dash.Dash

class DashApp[source]

DashApp(dashboard_component, port=8050, mode='dash', querystrings=False, bootstrap=False, **kwargs) :: DashComponentBase

Wrapper class for dash apps. Assigns layout and callbacks from a DashComponent to a Dash app, and runs it.

Can run both Dash and JupyterDash apps.

DashApp.__init__[source]

DashApp.__init__(dashboard_component, port=8050, mode='dash', querystrings=False, bootstrap=False, **kwargs)

    Args:
        dashboard_component (DashComponent): component to be run
        port (int): port to run the server
        mode ({'dash', 'external', 'inline', 'jupyterlab'}): type of dash server to start
        querystrings (bool): save state to querystring and load from querystring
        bootstrap: include default bootstrap css
        kwargs: all kwargs will be passed down to dash.Dash. See below the docstring of dash.Dash

    Returns:
        DashApp: simply start .run() to start the dashboard


"Docstring from Dash

Dash is a framework for building analytical web applications. No JavaScript required.

If a parameter can be set by an environment variable, that is listed as:
    env: ``DASH_****``
Values provided here take precedence over environment variables.

:param name: The name Flask should use for your app. Even if you provide
    your own ``server``, ``name`` will be used to help find assets.
    Typically ``__name__`` (the magic global var, not a string) is the
    best value to use. Default ``'__main__'``, env: ``DASH_APP_NAME``
:type name: string

:param server: Sets the Flask server for your app. There are three options:
    ``True`` (default): Dash will create a new server
    ``False``: The server will be added later via ``app.init_app(server)``
        where ``server`` is a ``flask.Flask`` instance.
    ``flask.Flask``: use this pre-existing Flask server.
:type server: boolean or flask.Flask

:param assets_folder: a path, relative to the current working directory,
    for extra files to be used in the browser. Default ``'assets'``.
    All .js and .css files will be loaded immediately unless excluded by
    ``assets_ignore``, and other files such as images will be served if
    requested.
:type assets_folder: string

:param assets_url_path: The local urls for assets will be:
    ``requests_pathname_prefix + assets_url_path + '/' + asset_path``
    where ``asset_path`` is the path to a file inside ``assets_folder``.
    Default ``'assets'``.
:type asset_url_path: string

:param assets_ignore: A regex, as a string to pass to ``re.compile``, for
    assets to omit from immediate loading. Ignored files will still be
    served if specifically requested. You cannot use this to prevent access
    to sensitive files.
:type assets_ignore: string

:param assets_external_path: an absolute URL from which to load assets.
    Use with ``serve_locally=False``. Dash can still find js and css to
    automatically load if you also keep local copies in your assets
    folder that Dash can index, but external serving can improve
    performance and reduce load on the Dash server.
    env: ``DASH_ASSETS_EXTERNAL_PATH``
:type assets_external_path: string

:param include_assets_files: Default ``True``, set to ``False`` to prevent
    immediate loading of any assets. Assets will still be served if
    specifically requested. You cannot use this to prevent access
    to sensitive files. env: ``DASH_INCLUDE_ASSETS_FILES``
:type include_assets_files: boolean

:param url_base_pathname: A local URL prefix to use app-wide.
    Default ``'/'``. Both `requests_pathname_prefix` and
    `routes_pathname_prefix` default to `url_base_pathname`.
    env: ``DASH_URL_BASE_PATHNAME``
:type url_base_pathname: string

:param requests_pathname_prefix: A local URL prefix for file requests.
    Defaults to `url_base_pathname`, and must end with
    `routes_pathname_prefix`. env: ``DASH_REQUESTS_PATHNAME_PREFIX``
:type requests_pathname_prefix: string

:param routes_pathname_prefix: A local URL prefix for JSON requests.
    Defaults to ``url_base_pathname``, and must start and end
    with ``'/'``. env: ``DASH_ROUTES_PATHNAME_PREFIX``
:type routes_pathname_prefix: string

:param serve_locally: If ``True`` (default), assets and dependencies
    (Dash and Component js and css) will be served from local URLs.
    If ``False`` we will use CDN links where available.
:type serve_locally: boolean

:param compress: Use gzip to compress files and data served by Flask.
    Default ``True``
:type compress: boolean

:param meta_tags: html <meta> tags to be added to the index page.
    Each dict should have the attributes and values for one tag, eg:
    ``{'name': 'description', 'content': 'My App'}``
:type meta_tags: list of dicts

:param index_string: Override the standard Dash index page.
    Must contain the correct insertion markers to interpolate various
    content into it depending on the app config and components used.
    See https://dash.plotly.com/external-resources for details.
:type index_string: string

:param external_scripts: Additional JS files to load with the page.
    Each entry can be a string (the URL) or a dict with ``src`` (the URL)
    and optionally other ``<script>`` tag attributes such as ``integrity``
    and ``crossorigin``.
:type external_scripts: list of strings or dicts

:param external_stylesheets: Additional CSS files to load with the page.
    Each entry can be a string (the URL) or a dict with ``href`` (the URL)
    and optionally other ``<link>`` tag attributes such as ``rel``,
    ``integrity`` and ``crossorigin``.
:type external_stylesheets: list of strings or dicts

:param suppress_callback_exceptions: Default ``False``: check callbacks to
    ensure referenced IDs exist and props are valid. Set to ``True``
    if your layout is dynamic, to bypass these checks.
    env: ``DASH_SUPPRESS_CALLBACK_EXCEPTIONS``
:type suppress_callback_exceptions: boolean

:param prevent_initial_callbacks: Default ``False``: Sets the default value
    of ``prevent_initial_call`` for all callbacks added to the app.
    Normally all callbacks are fired when the associated outputs are first
    added to the page. You can disable this for individual callbacks by
    setting ``prevent_initial_call`` in their definitions, or set it
    ``True`` here in which case you must explicitly set it ``False`` for
    those callbacks you wish to have an initial call. This setting has no
    effect on triggering callbacks when their inputs change later on.

:param show_undo_redo: Default ``False``, set to ``True`` to enable undo
    and redo buttons for stepping through the history of the app state.
:type show_undo_redo: boolean

:param plugins: Extend Dash functionality by passing a list of objects
    with a ``plug`` method, taking a single argument: this app, which will
    be called after the Flask server is attached.
:type plugins: list of objects

:param title: Default ``Dash``. Configures the document.title
(the text that appears in a browser tab).

:param update_title: Default ``Updating...``. Configures the document.title
(the text that appears in a browser tab) text when a callback is being run.
Set to None or '' if you don't want the document.title to change or if you
want to control the document.title through a separate component or
clientside callback.

DashApp.flask_server[source]

DashApp.flask_server()

returns flask server inside self.app, for building wsgi apps

DashApp.run[source]

DashApp.run(port=None)

Run the dash app

Example use of DashApp

You can build and run dash app by simply passing a DashComposite to DashApp and then running it:

db = DashApp(list_composite, mode='external', port=9000, querystrings=True, bootstrap=dbc.themes.FLATLY)
Warning: the use of _register_callbacks() will be deprecated! Use component_callbacks() from now on.
  • You can set the port with port=8051
  • You can run the dashboard inline in a notebook by pasing mode='inline'
    • or mode='external' or mode='jupyterlab'
    • default is mode='dash'
  • Track parameters in the url querystring with querystrings=True
  • Any additional parameters will be passed on the to dash.Dash() constructor
if run_app:
    db.run()

You can also store and reload an entire dashboard:

print(db.to_yaml())
dash_app:
  class_name: DashApp
  module: __main__
  params:
    dashboard_component:
      dash_component:
        class_name: ListComposite
        module: __main__
        params:
          list_factory:
            dash_figure_factory:
              class_name: ListFactory
              module: __main__
              params:
                list_input:
                - this
                - is
                - a
                - dumb
                - example
                filepath: file_factory.pkl
          first_n1: 2
          first_n2: 3
          name: GmrYyUT7T8
    port: 9000
    mode: external
    querystrings: true
    bootstrap: https://stackpath.bootstrapcdn.com/bootswatch/4.5.0/flatly/bootstrap.min.css
    kwargs:
      external_stylesheets:
      - https://stackpath.bootstrapcdn.com/bootswatch/4.5.0/flatly/bootstrap.min.css
      suppress_callback_exceptions: true

db.to_yaml("dashboard.yaml")
db2 = DashApp.from_yaml("dashboard.yaml", force_pickles=True)
Warning: the use of _register_callbacks() will be deprecated! Use component_callbacks() from now on.
if run_app:
    db2.run()
from nbdev.export import *
notebook2script()
Converted 00_core.ipynb.
Converted 01_cli.ipynb.
Converted 02_Example.ipynb.
Converted 03_querystrings.ipynb.
Converted 04_GunicornDeployment.ipynb.
Converted index.ipynb.