Package: simpledash
Simple DashSimple Dash is a library that simplifies building applications withPlotly Dashby allowing you to attach data directly to the layout and creating all the necessary callback functions under the hood.InstallationpipinstallsimpledashTutorialSimplest example - using Input object in the layoutLet's create an app with singleInputcomponent, that renders back whatever the user has typed in.fromsimpledash.callbacksimportsetup_callbacksapp.layout=html.Div([dash_core_components.Input(id='data-input',className='row'),# with Simple Dash you can use a dash dependency object directly in the layout# it will be replaced by actual `data-input.value` and updated every time it changeshtml.Div(dash.dependencies.Input('data-input','value'),className='row',id='output-div')])setup_callbacks(app)# this will scan the layout and create all necessary callback functionsAs you can see, no callbacks were explicitly defined and the code is clean and simple.What happened? Thesetup_callbacksmethod has scanned the app's layout, found all occurrences ofdash.dependencies.Inputand created a callback functions for them.More complex example - data functions withdata_providerdecoratorWe would like to have two Inputs (named A and B) and let user decide which one is going to be used
for rendering the output value. This choice will be done via dropdown.importdash_core_componentsasdccfromdash.dependenciesimportInputfromsimpledash.data.data_providersimportdata_providerinput_a=dcc.Input(id='data-input-a',value="")input_b=dcc.Input(id='data-input-b',value="")input_chooser=dcc.Dropdown(id='input-chooser',options=options_from(['A','B']))# use a `data_provider` annotation to indicate, that the method provides data based on inputs# inputs used by function are declared as arguments to the decorator# and are later on passed to the function as arguments@data_provider(Input('data-input-a','value'),Input('data-input-b','value'),Input('input-chooser','value'))defoutput_value(input_a_value,input_b_value,input_chooser_value):ifinput_chooser_value=="A":returninput_a_valueifinput_chooser_value=="B":returninput_b_valuereturn""app.layout=html.Div([html.Div(["A: ",input_a],className='row'),html.Div(["B: ",input_b],className='row'),html.Div(["Which one to show? ",input_chooser],className='row'),html.Br(),# you simply use `data_provider` instance in the layout (as in previous example)html.Div(["Here's the output: ",output_value],className='row',id='output'),# but you can also run some simple operations on `data_provider`, like `upper()`html.Div(["Also in uppercase!: ",output_value.upper()],className='row',id='output-upper')])setup_callbacks(app)This time we have useddata_providerdecorator to declare the function that is able to provide data based on inputs. Note, that this is a plain python function, so you should be able to do any operation on inputs, regardless of the complexity.Interesting thing we see in the example isoutput_value.upper(). This is just a syntax sugar
that Simple Dash gives you - instead of writing anotherdata_providerto do the uppercasing,
we can call the method directly onoutput_value(and this will create newdata_providerunder the hood for you).Please note that the set of operations you are able to do ondata_providerinstance are limited to:accessing the property (output_value.xyz)accessing the item by index (output_value['xyz'])calling the method (output_value.xyz("param"))Nestingdata_providersLet's say you'd like to replicate theoutput_value.upper()behavior from previous example, but without syntax sugar, i.e. by defining newdata_providerdirectly.The first option is to create adata_providerthat takes the same inputs asoutput_valueand passes values of those inputs tooutput_value. Here's how it looks like:@data_provider(Input('data-input-a','value'),Input('data-input-b','value'),Input('input-chooser','value'))defuppercase_output_value_1(input_a_value,input_b_value,input_chooser_value):v=output_value(input_a_value,input_b_value,input_chooser_value)returnv.upper()The second option has much less boilerplate, because the wholedata_provideris specified as an input:@data_provider(output_value)defuppercase_output_value_2(v):returnv.upper()What's next?To see more advanced examples go toexamplessection of the repo.FAQIs there a usage fordata_providerwith no inputs?Usedata_providerwith no inputs when you've got a static, but time-consuming-to-calculate data.data_providerwill ensure laziness - i.e. that the function is called only if the component using it is being displayed to the user.What is the performance of Simple Dash vs plain dash?Performance hasn't been priority so far, so it's reasonable to expect Simple Dash to be slower. That being said - there's a room for improvement (for example - cachingdata_provider's output) and we expect to tackle this issue in later releases.What are the limitations when compared to plain dash?Validators like to fail ondata_providers, so in many cases you need to just stop using them.To give you an example - this will not work:dcc.Graph(figure={'data':[graph_objects.Scattermapbox(lat=some_data_provider,...)]})but this will:dcc.Graph(figure={'data':[dict(lat=some_data_provider,...)]})Can I test it?Absolutely. Any testing methods that worked for plain dash apps will work with this approach too.Testing data providers is also pretty easy - they behave just like a methods, so you can call them in your test code.