Dashboards
Julia backend for Plotly Dash
Version 0.2.8 released
- Integration with travis ci
- dash-bootstrap-components added with prefix dbc. Examples of use will be soon
- passchangedprops argument added to
callback!
function. For details see docs ofcallback!
Version 0.2.5 released
Now you can use
PlotlyBase.Plot
to work with thefigure
property of thedcc_graph
component. Examples are: Plot usage in layout, Plot usage in callbackAdded
PreventUpdate
exception andno_update()
function to prevent updates in callback. See PreventUpdate example and no_update() exampleMost of dashboards from Dash Tutorial are implemented using Dashboards.jl. See DashboardsExamples repo
Installation
Julia version >= 1.2 is required. It also works in 1.1 now, but I do not plan testing and support for versions under 1.2
import Pkg; Pkg.add("Dashboards")
Usage
Basic application
julia> import HTTP
julia> using Dashboards
julia> app = Dash("Test app", external_stylesheets = ["https://codepen.io/chriddyp/pen/bWLwgP.css"]) do
html_div() do
html_h1("Hello Dashboards"),
html_div("Dashboards: Julia interface for Dash"),
dcc_graph(
id = "example-graph",
figure = (
data = [
(x = [1, 2, 3], y = [4, 1, 2], type = "bar", name = "SF"),
(x = [1, 2, 3], y = [2, 4, 5], type = "bar", name = "Montréal"),
],
layout = (title = "Dash Data Visualization",)
)
)
end
end
julia> handler = make_handler(app, debug = true)
julia> HTTP.serve(handler, HTTP.Sockets.localhost, 8080)
- The
Dash
struct represent dashboard application. - The constructor for
Dash
struct isDash(layout_maker::Function, name::String; external_stylesheets::Vector{String} = Vector{String}(), url_base_pathname="/", assets_folder::String = "assets")
wherelayout_maker
is a function with signature ()::Component - Unlike the python version where each Dash component is represented as a separate class, all components in Dashboard are represented by struct
Component
. - You can create
Component
specific for concrete Dash component by the set of functions in the formlowercase(<component package>)_lowercase(<component name>)
. For example, in python html<div>
element is represented asHTML.Div
in Dasboards it is created using functionhtml_div
- The list of all supported components is available in docstring for Dasboards module
- All functions for a component creation have the signature
(;kwargs...)::Component
. List of key arguments specific for the concrete component is available in the docstring for each function - Functions for creation components which have
children
property have two additional methods(children::Any; kwargs...)::Component
and(children_maker::Function; kwargs..)::Component
.children
must by string or number or single component or collection of components make_handler(app::Dash; debug::Bool = false)
makes handler function for using in HTTP package
Once you have run the code to create the Dashboard, go to http://127.0.0.1:8080
in your browser to view the Dashboard!
Basic Callback
julia> import HTTP
julia> using Dashboards
julia> app = Dash("Test app", external_stylesheets = ["https://codepen.io/chriddyp/pen/bWLwgP.css"]) do
html_div() do
dcc_input(id = "my-id", value="initial value", type = "text"),
html_div(id = "my-div")
end
end
julia> callback!(app, callid"my-id.value => my-div.children") do input_value
"You've entered $(input_value)"
end
julia> handler = make_handler(app, debug = true)
julia> HTTP.serve(handler, HTTP.Sockets.localhost, 8080)
- You can make your dashboard interactive by register callbacks for changes in frontend with function
callback!(func::Function, app::Dash, id::CallbackId)
- Inputs and outputs (and states, see below) of callback are described by struct
CallbackId
which can easily created by string macrocallid""
callid""
parse string in form"[{state1 [,...]}] input1[,...] => output1[,...]"
where all items is"<element id>.<property name>"
- Callback function must have the signature(states..., inputs...) and return data for output
States and Multiple Outputs
julia> import HTTP
julia> using Dashboards
julia> app = Dash("Test app", external_stylesheets = ["https://codepen.io/chriddyp/pen/bWLwgP.css"]) do
html_div() do
dcc_input(id = "my-id", value="initial value", type = "text"),
html_div(id = "my-div"),
html_div(id = "my-div2")
end
end
julia> callback!(app, callid"{my-id.type} my-id.value => my-div.children, my-div2.children") do state_value, input_value
"You've entered $(input_value) in input with type $(state_value)",
"You've entered $(input_value)"
end
julia> handler = make_handler(app, debug = true)
julia> HTTP.serve(handler, HTTP.Sockets.localhost, 8080)
- For multiple output callback must return any collection with element for each output
Comparation with original python syntax
component naming:
html.Div
=> html_div
, dcc.Graph
=> dcc_graph
and etc
component creation:
Just like in Python, functions for creating components have keywords arguments, which are the same as in Python. html_div(id="my-id", children="Simple text")
. For components that have children
prop, two additional signatures are available. (children; kwargs..)
and (children_maker::Function; kwargs...)
so You can write html_div("Simple text", id="my-id")
for simple elements or avoid the hell of nested brackets with do
syntax for complex elements:
html_div(id="outer-div") do
html_h1("Welcome"),
html_div(id="inner-div") do
......
end
end
application and layout:
- python:
app = dash.Dash("Test", external_stylesheets=external_stylesheets)
app.layout = html.Div(children=[....])
- Dashboards:
app = Dash("Test", external_stylesheets=external_stylesheets) do
html_div() do
......
end
end
callbacks:
- python:
@app.callback(Output('output', 'children'),
[Input('submit-button', 'n_clicks')],
[State('state-1', 'value'),
State('state-2', 'value')])
def update_output(n_clicks, state1, state2):
.....
- Dashboards:
callback!(app, callid"""{state1.value, state2.value}
submit-button.n_clicks
=> output.children""" ) do state1, state2, n_clicks
.....
end
Be careful - in Dashboards states came first in arguments list
json:
I use JSON2 for json serialization/deserialization, so in callbacks all json objects are NamedTuples not Dicts. In component props you can use both Dicts and NamedTuples for json objects. But be careful with single property objects: layout = (title = "Test graph")
is not interpreted as NamedTuple by Julia - you need add comma at the end layout = (title = "Test graph",)