Learn how to implement interactive behavior in Dash applications using Python decorators and callbacks. This article explains how to dynamically update visualizations based on user input by connecting dropdown selections to graph outputs.
Key Insights
- Dash uses the @app.callback decorator to enable interactivity by linking input components (like dropdowns) to output components (such as graphs), triggering updates only when user events occur.
- Each interactive element must be assigned a unique ID to allow the callback to identify which component to monitor and update, such as "manufacturer dropdown" for input and "fuel efficiency versus horsepower graph" for output.
- Noble Desktop’s explanation highlights that the callback function is automatically executed on page load when an initial value is present, eliminating the need for a separately declared starting figure.
Note: These materials offer prospective students a preview of how our classes are structured. Students enrolled in this course will receive access to the full set of materials, including video lectures, project-based assignments, and instructor feedback.
Our next step is to use something called a decorator. And if you're not familiar with Python decorators, learning decorators is outside the scope of this class, but you can think of them as a function you're usually given, you usually don't make them yourself, a function you're given that will modify the function after it. So in our case, we're going to use the app, a method on the app variable, the dash gives us, and we'll be using this at the layout and run the server, as you can see here and here, right? That's our app variable.
And it has a method on it called callback. And a callback is a term in programming for, I want you to run this function at a certain time, call it back at a certain time, don't run it right away, only run it at a certain time. And that's really how we implement interactivity.
We don't want it, for example, to filter these scatter plot points to only the Acura ones, right when everything loads, or BMW right away, or Cadillac right away. One thing, those are all mutually exclusive. We want it to only run that function, hey, filter it down when our user asks for it.
And we don't know in our program, unlike most of the time we run functions, we don't know when it's going to run. It depends on the user. There's no set time in the life cycle of this to do that.
Right, we're not saying like, hey, every 10 seconds, run a function to filter by a different car manufacturer. Right, instead it's like, oh, do that when the user clicks, and we just don't know if that'll be 10 seconds in, 20 seconds in, maybe they'll never change this. Maybe they'll change it constantly, we just don't know.
So that's why we use a callback, the callback paradigm. So what we're going to do is probably after our layout is a good place for this code, but definitely before app.run. App.run, remember, always needs to be the last thing. Now run the server with all the stuff we gave you.
What we'll do is we'll use a decorator, and the Python syntax for that is use the at symbol. At app.callback, and we give it what to take as input for our callback, and what to output for our callback, or where to output the results of our callback. So what this is going to do, let me add a little comment here.
We're going to say, when the input event happens, create a new element at the output point. Our input event will be when they choose a different dropdown option. The place we want to output is the graph here.
We're going to say output here, a certain something. Output out here, our new graph with its filtered data. We have this input element, the dropdown, and the output element here.
Now, to set these, we need names for them. And typically the way we do that is we give an ID. And this is a very, you know, web technologies, HTML elements can have IDs, where we can then have like a hook, a name by which to call it within our code.
So for our DCC.dropdown, we'll give it an ID. Don't forget to comma after the ID. And maybe we'll call it manufacturer dropdown.
That seems like a good name for it. So that's our input. Our output is this scatter figure, or more accurately the graph that encapsulates it.
We're going to say for DCC.graph, we're going to give it instead of a figure, we're going to give it an ID. Maybe fuel efficiency versus horsepower graph. Okay, so we have a name for where we're going to output what changes, and a name for our input, our dropdown.
We're going to use the input and output that we imported from Dash. And the first thing you always do, and I've definitely put these in the wrong order, is the output. Where does it output to? And that's a function where we can give it the name of the thing to output to.
And the second thing we give it is what part of that thing is going to change. And it's going to be the figure. Remember, that's originally what we had here.
You know, figure equals our fig, right? What element is going to change within this graph? So that's what we'll output. Our input is our manufacturer dropdown. That's why we have to give them these names, so we can, you know, tell it what elements we're doing this interactivity on.
And every dropdown, this is just something you know if you've worked with web interfaces, dropdowns store what it is that's currently selected as their value property. So that's what we give for the second thing here. So the way we can read this is when the manufacturer dropdown changes, look at its value property.
And when that happens, when the below changes, use our code to replace the graph. Yeah, I hope those comments are helpful. All right, so after this call to app.callback, the way decorators work, this callback is going to modify our function.
It's going to tell it when to run, right? So our callback decorator modifies when our below function runs. And the answer is it'll run when this changes. And its output will be output to here.
So here now we define a function. We can call it whatever we want. It doesn't actually matter if there's lots of space here or no space.
Typically it's written with no space. But it also doesn't matter what its name is, but there can't be something in between. We can't do a print here.
And we're going to call our function update graph. That seems like a good name for it. Now the first argument our function will get, because we said the input is from the manufacturer dropdown when the value changes, this value, again, meaning the thing that's selected in this dropdown, will be passed in as an argument.
We'll call that selected manufacturer. Okay, for now, what we're going to do is print out selected manufacturer. Let's make sure that's what we think it is.
And then output, and for the function your output is defined by what you return within the function. Let's output a new figure. And again, that's because what's it expecting, it's going to put our whatever we return in the FE versus HP graph as the figure property.
So actually before, I think it might be nice to define it as a variable. We'll say the updated figure is px.scatter. And for now, actually, we'll copy and paste. It's this.
Copy and paste that. And then we're, yeah, we're not really updating this. It's just currently a copy of the previous one.
And we'll return it. Okay, so what are we doing here with this function? We're saying when this input happens, give us that value. It will come in as a selected manufacturer, and we're going to print it now just for confirmation.
And then to make sure our output is working right, we're declaring an updated figure, which is the exact same figure. And we're returning that. So two things should happen when we save this and go back.
One, we should get our selected manufacturer printed out in the terminal. And nothing should break. When we change the value, it should just print out the selected manufacturer and output the unchanged, currently unchanged scatterplot.
Let's try it. Give this a shot. All right, first, let's see what's happening here in the terminal.
So it printed out Acura, and that's our default value. Let's change it to BMW. Nothing should change.
It's doing a sort of silent update where it's replacing the figure with the figure. But we got BMW printed out. Cadillac, nothing changed, but Cadillac was printed out.
We've managed to not break anything, which is always good when you're adding a lot of code. And we now know we have access to this string, this selected manufacturer. What we'll do is use this to filter down our cars to only the ones that have that selected manufacturer and then update our plot.
And before we go any further and start doing that, let's do one more thing and hope it doesn't change anything. That is, we can actually get rid of this scatterplot here. That's because this callback happens immediately as well.
As soon as the page loads, it says, okay, the value is, it hasn't changed, but it's got a value for the first time, the manufacturer dropdown. And so it will run update graph. So as soon as the page loads, this function will run and it will return our updated figure or really the starting figure and put it on the page.
We don't need this duplicated figure here. So let's double check that. We're going to delete that, save it.
Yup, it reloaded. Acura is the first choice. And here we've got our graph.
It displayed just fine. And we should have Acura printed out. So yes, again, the graph does get this update graph function does get called on page loads.
We don't need to declare a figure. This will be our starting figure. Of course, it's not really the Acura figure.
It's all still all manufacturers. We'll fix that in our next step.