Source code for dasher.api
from collections.abc import Mapping
from collections.abc import Sequence
from dash.dependencies import Input
from dash.dependencies import Output
from dasher.base import BaseLayout
[docs]class Api(object):
""" Dasher api.
The api allows generation of widgets and dash dependencies (for
instances of ``DasherCallback``). It is used by ``Dasher`` to generate interactive
apps.
Parameters
----------
title: str, optional
Title of the app.
layout: str or DasherLayout subclass, optional
Name of a built-in layout or custom layout (DasherLayout subclass)
layout_kw: dict, optional
Dictionary of keyword arguments passed to the `layout` class.
"""
def __init__(self, title=None, layout="bootstrap", layout_kw=None):
if layout_kw is None:
layout_kw = {}
self.layout = self._load_layout(layout)(title, **layout_kw)
@staticmethod
def _load_layout(layout):
if layout == "bootstrap":
from dasher.layout.bootstrap import BootstrapLayout
return BootstrapLayout
elif issubclass(layout, BaseLayout):
return layout
else:
msg = "layout must be either a named layout or a subclass of DasherLayout"
raise ValueError(msg)
[docs] def generate_widget(self, name, x, label=None):
""" Generate a dasher widget, which is a styled and labeled interactive
component.
The type of the interactive component is determined
based on the type of `x` using the selected widget specification of the layout.
Parameters
----------
name: str
Name of the widget.
x: object of supported type
Object used to determine which interactive component is returned.
label: str or None, optional
Label of the component.
Returns
-------
dasher.base.BaseWidget
Generated dasher widget.
See Also
--------
get_widget: Generates widget and returns the ``layout`` of the widget.
get_component: Generates widget and returns the widgets' ``component``.
"""
for type_spec, component_cls in self.layout.widget_spec.items():
if isinstance(x, type_spec):
return component_cls(name, x, label)
raise NotImplementedError(
f"No layout specification found for {name} of type {type(x)}"
)
[docs] def get_component(self, name, x):
""" Generate an interactive dash component.
This is a convenience method, which first calls the ``generate_widget`` method
and then directly returns the un-styled and un-labeled ``component`` of the
widget.
Parameters
----------
name: str
Name of the component.
x: object of supported type
Object used to determine which interactive component is returned.
Returns
-------
dash.development.base_component.Component
Generated dash component.
"""
return self.generate_widget(name, x, None).component
[docs] def get_widget(self, name, x, label=None):
""" Generate a styled and labeled interactive dash component.
This is a convenience method, which first calls the ``generate_widget`` method
and then directly returns the ``layout`` of the widget.
Parameters
----------
name: str
Name of the component.
x: object of supported type
Object used to determine which interactive component is returned.
label: str or None, optional
Label of the component.
Returns
-------
dash.development.base_component.Component
Generated dash component.
"""
return self.generate_widget(name, x, label).layout
@staticmethod
def _create_labels_dict(labels, kw):
if labels is None:
return {k: k for k in kw.keys()}
elif isinstance(labels, Sequence):
if len(labels) != len(kw):
raise ValueError("labels must be of same length as kw")
return {k: l for k, l in zip(kw.keys(), labels)}
elif isinstance(labels, Mapping):
return {k: labels.get(k, k) for k in kw.keys()}
else:
raise TypeError("labels must be list-like, dict-like or None")
[docs] def generate_widgets(self, kw, labels=None, group=None):
""" Generate dasher widgets based on a dictionary.
Parameters
----------
kw: dict
The keys of the dictionary define the names of the widgets and the type of
the values is used to determine the type of the interactive widgets based on
the selected component specification.
labels: list or dict, optional
Labels for the widgets. May be either a list of labels for `kw` in the order
of appearance or a dictionary mapping the keys of `kw` to the desired
labels. If ``None``, the keys of `kw` are used for the labels directly.
group: str, optional
If not ``None``, `group` will be used as a suffix for each
component / widget name in order to group widgets.
Returns
-------
list of dasher.base.BaseWidget
List of generated dasher widgets.
See Also
--------
get_widgets: Generates widgets and returns the ``layout`` of the widgets.
get_components: Generates widgets and returns the ``component`` of the widgets.
"""
labels = self._create_labels_dict(labels, kw)
return [
self.generate_widget(
name if group is None else f"{name}-{group}", x, labels[name]
)
for name, x in kw.items()
]
[docs] def get_widgets(self, kw, labels=None, group=None):
""" Generate interactive widgets based on a dictionary.
This is a convenience method, which first calls the ``generate_widgets`` method
and then directly returns a list containing the ``layout`` of the widgets.
Parameters
----------
kw: dict
The keys of the dictionary define the names of the widgets and the type of
the values is used to determine the type of the interactive widgets based on
the selected component specification.
labels: list or dict, optional
Labels for the widgets. May be either a list of labels for `kw` in the order
of appearance or a dictionary mapping the keys of `kw` to the desired
labels. If ``None``, the keys of `kw` are used for the labels directly.
group: str, optional
If not ``None``, `group` will be used as a suffix for each
component / widget name in order to group widgets.
Returns
-------
list of dash.development.base_component.Component
List of generated interactive components.
"""
widgets = self.generate_widgets(kw, labels, group)
return [w.layout for w in widgets]
[docs] def get_components(self, kw, labels=None, group=None):
""" Generate interactive components based on a dictionary.
This is a convenience method, which first calls the ``generate_widgets`` method
and then directly returns a list containing the un-styled and un-labeled
``component`` of the widgets.
Parameters
----------
kw: dict
The keys of the dictionary define the names of the widgets and the type of
the values is used to determine the type of the interactive widgets based on
the selected component specification.
labels: list or dict, optional
Labels for the widgets. May be either a list of labels for `kw` in the order
of appearance or a dictionary mapping the keys of `kw` to the desired
labels. If ``None``, the keys of `kw` are used for the labels directly.
group: str, optional
If not ``None``, `group` will be used as a suffix for each
component / widget name in order to group widgets.
Returns
-------
list of dash.development.base_component.Component
List of generated interactive components.
"""
widgets = self.generate_widgets(kw, labels, group)
return [w.component for w in widgets]
[docs] @staticmethod
def generate_dependencies(widgets, output_id, output_dependency="children"):
""" Generate input and output dependencies for a list of widgets.
It generates an ``dash.dependencies.Input`` for each widgets' underlying dash
component using the ``value`` property. An ``dash.dependencies.Output`` is
generated for `output_id` using the ``children`` property.
Parameters
----------
widgets: list of BaseWidget
List of dasher widgets to generate dependencies for.
output_id: str
Id of the output.
output_dependency: str, optional
Property for the output dependency.
Returns
-------
output: dash.dependencies.Output
Generated output dependency.
input_list: list of dash.dependencies.Input
List of generated input dependencies.
"""
input_list = [Input(w.name, w.dependency) for w in widgets]
output = Output(output_id, output_dependency)
return output, input_list
[docs] @staticmethod
def register_callback(app, callback):
""" Register a dasher callback with dependencies in the dash app.
Parameters
----------
app: dash.Dash
The dash app
callback: DasherCallback
The dasher callback to register
"""
return app.callback(callback.outputs, callback.inputs)(callback.f)