Using Plotly DASH in Python, one can produce cutting-edge data-visualization web apps in a few lines of code (like these). However, this elegance can be confusing if you aren’t fluent in Python.
Here’s what I wish I knew before I started learning DASH.
QUICK DASH TIPS
- You should be comfortable with the Pythonic way of working with dictionaries, lists and the Pandas library especially.
- DASH’s tutorials favor a layout-first approach to app building which embeds data functions. DASH provides mechanisms for you to take a data-first approach (which I go into below) but it can be a struggle.
Styling Or Data?
In most DASH tutorials the app.layer is taught first, since the layout object is created first. The problem with this approach is that many DASH tutorials embed data in the layout object. For me, that’s immediately confusing.
I immediately set out to redo all the DASH tutorials by separating data from layout.
For my first app, I want a dropdown component where the user selects a manager of exchange traded funds (ETFs). Then, the selection should populate a table with the funds for that manager. Additionally, it should graph the relationship of each ETF’s assets and expense ratio.
Most DASH tutorials show how to populate the dropdown in the layout layer, as below:
That to me isn’t a real-world approach programming a dropdown. The database should drive all the data shown in the app. After fiddling around I came up with the following. (Excuse me for the messy coding; I know, seems I’m hypocritical here!).
First, I pull my data into a panda dataframe.
Again, whatever you do, don’t start learning DASH without first learning the pandas library. Second, you must understand the difference between Python dictionaries and lists.
Next, I create a layout. Unlike many of the DASH examples I’ve studied, I want all data handled outside the layout. This will make it easier for me to maintain the app.
In the above, I create an input component (that I hide), but use to trigger an “output” event that fills the dropdown with values from my database which I created above.
This admitted kludge was inspired by DASH’s documentation, which states:
“When the Dash app starts, it automatically calls all of the callbacks with the initial values of the input components in order to populate the initial state of the output components”
After a bit of work. I was able to create a mini DASH app that contains a dropdown list, data table and graph, all in the same layout with all the data work separated out:
Next, the layout and then the callbacks which run the data functions as the user interacts with the app.
That I could fully separate my data away from the layout shows that DASH, for all its compactness, is quite flexible!
Here are some other DASH practices that confused me.
“Decorators” are a sick Python joke along the lines of throwing a knife at your friend and telling him or her to catch the “nice shiny thing”!
Callback decorations allow the @app.callback() function to pass data from the browser Input()s (there can be many) to the Python functions immediately following the callback.
Semantically, from my data-first approach I realized that DASH’s callback OUTPUT is my INPUT into the graph component. DASH’s input was simply what fired by data functions (so and output to me). Thinking that way helped me in my data-first approach.
Decorators (the @ sign), wrap functions around functions for reasons that still make my head hurt.
When I first began learning DASH I got stuck on the above “input_value” I hunted all over the place for where “input_value” is created.
My feeling is that in the tutorials the argument should be given a name like “_dash_callback_arg1”. The coder should be tipped off that the variable passed into the callback function is neither property nor variable.
Now that I understand it, I agree it makes life easier for me, to name it what I want going forward.
In any case, the callbacks pass arguments into the functions they wrap and you can name them anything you want. The writer of the code above named it “input_value”. Seems reasonable to me now!
In my effort to further abstract the data functions I couldn’t get this to work.
Once I had my head right, I was able to continue abstracting the data with the following.
In the above, I expand the Python data objects into what I expect become JSON strings. Dataframe.tolist(), replaces the dataframe object with a string.
I’m hoping this is just the beginning of my DASH journey! I hope I’ll have more to report later!
You can find the above code in the github project here. Sorry for the mess!