Elegant Dashboards for Python ML Apps using Taipy GUI
Exploring a low code Python library for data science projects.
Table of Contents
Why Use Dashboards?
Can’t I just use my Jupyter Notebook and Altair? Well, that’s what I used to do too, until I had a need to switch back and forth between many different parameters of a plot. I could either:
- Change those parameters and rerun the cell repeatedly to see the updated plot; or
- Generate all the plots immediately, but end up having to scroll through a long list of plots.
Furthermore, in my use case, the code in the notebook was just polluting what I actually wanted to see — the plots and metrics that I was interested in.
There’s a much more intelligent way of doing this with dashboards. By creating a dashboard, I’m able to:
- Modify the parameters of my problem with on-screen widgets, quickly exploring the search space with immediate visual feedback; and
- Allow non-technical stakeholders to use the same intuitive platform to appreciate what they’re paying for.
Building Dashboards Using Taipy GUI
If your first thought is “but who has the time to be developing dashboards”, worry not. Developing dashboards is actually pleasantly trivial with Taipy, a low-code data science library.
Install Taipy with Pip.
pip install taipy
Taipy comes with two main components:
- Taipy Core, a framework for efficient scheduling of tasks and scenario management; and
- Taipy GUI, a frontend component and the subject of this article.
Although the developers of Taipy advocate the synergy of using Taipy Core and Taipy GUI together, I was primarily interested in creating a dashboard, and so I focused exclusively on Taipy GUI.
With absolutely no knowledge of frontend languages (HTML, CSS, etc), I was able to build a fully functioning web application.
Taipy GUI — A Bare-bones Example
To demonstrate the simplicity and elegance of Taipy, let’s take a look at the following code snippet:
In just a few lines of intuitive code, Taipy has created a webpage and serves it for us via a web server running on the local machine. Taipy also opened our default browser and navigated to localhost:5000
, where we now see the following:
The content of the GUI is stored in the variable md
, a multi-line string. The text is formatted with Markdown, as you may recognise by the familiar syntax used for the header, bold text and italicized text in the example above.
Interpolation of the website
variable was done using the <|…|>
syntax specified in Taipy — a recurring construct as part of Taipy GUI’s augmented Markdown, which will be explained further in the next section.
Exploring Penguins
To further explore the capabilities of Taipy GUI and what it can do for us, let’s create a dashboard to explore the palmerpenguins dataset. Specifically, in this example, we will use the following features of Taipy GUI:
- Selectors
- Buttons
- Charts
- Tables
- Pop-up dialog boxes
The final dashboard will look like this:
You can find the complete code for the dashboard above at the end of this article.
1. Load the Dataset
We begin by loading the DataFrame from the palmerpenguins GitHub repository. The following table shows the data stored, whose columns are quite self-explanatory:
2. Visual Elements
Visual elements such as buttons, selectors and charts are created in Taipy by introducing a new syntax into the Markdown. Substrings with the pattern <|…|…|>
(angle brackets with properties bordered with pipes) in the string passed to the taipy.gui.Gui
object are parsed into different types of visual elements.
3. Selector
Let’s begin by building the penguin species selector on the left panel of the dashboard.
As a reminder, Taipy GUI parses the string as Markdown, so the ###
simply defines a level-3 header. The more interesting part however is the Taipy selector definition.
This construct has 5 components (bordered by the pipes). Here’s what they do:
- {species} : The variable which holds the initial value of the selector — “Adelie” in this case.
- selector : The name of the Taipy visual element.
- lov={target_names} : The list of values (lov) that the species may be be selected from.
- dropdown=True : Indicates that we want the selector to use a dropdown menu.
- width=100% : Sets the width of the selector to the full size of its parent container.
Refer to the Taipy selectors documentation for more information.
4. Indicator
The next control we used is the indicator which displays a value of interest on a number line — in this case, the number of selected penguins out of all the penguins in the dataset.
As can be inferred from this example, Taipy evaluates the expression inside curly braces and uses its result — just like an f-string.
Notice that the “value” property is separate from the first component. The first component (aptly named “display”) determines the displayed label, whereas the ”value” property determines its position on the number line. For example, the code <|{“Fail”}|indicator|value=20|max=100|>
would generate the following indicator:
Refer to the Taipy indicators documentation for more information.
5. Chart
Under the hood, Taipy uses the Plotly graphing library to generate its charts. If you’re already familiar with Plotly, you can probably figure out the type of chart the following code in this section would produce. For the uninitiated however (like me), this probably looks like mumbo jumbo.
Thankfully, the Taipy chart documentation provides ample examples which serve as an excellent primer for crafting several types of commonly used graphs.
Here’s the code for our chart:
And the resulting chart:
The variable df
, which is the DataFrame of the selected penguin species, is fed directly to the chart visual element construct. Then, additional properties are configured to style the chart as we like.
Putting properties such as “height” and “width” in the chart_properties
dictionary and then passing it to “properties” in the Taipy visual element construct is a cleaner way of doing
<|{df}|chart|…|height=35vh|width=40vw|…|>
which would have resulted in a very long line.
Refer to the Taipy chart documentation for more information.
6. Layout
Creating the panel on the left is extremely simple to do. The layout element can be used to create columns. Remember that in our example, we created three columns: one for the left panel and two for the charts.
The basic syntax for creating a layout is as follows:
Here, I created a layout with two columns, with the size ratio of 1:6. Notice that the content section was wrapped in <|
and |>
on new lines. This is known as a part in Taipy. We needed this for the content section because the layout expects two columns — one to render on the left, and one on the right. The standalone text for the left panel gets put in the first column, while the entirety of the part block gets put in the second column.
Optionally, a part can also be defined by starting with <|part.start|>
on a line and ending with <|part.end|>
on another line. Any lines between the start and end constructs will belong to the part. We will use this slightly more verbose syntax in the final code as it is more readable.
Running the script above gives us this:
Refer to the Taipy blocks documentation for more information on layouts and parts.
7. Button, Dialog Box and Table
The last feature we’ll add to our dashboard is a table to display the penguin_df
DataFrame. Better yet, we’re going to put this table in a dialog page, which gets displayed when we click a button.
Let’s take a minute to digest this code which is a little bit more complex than the previous sections.
Aside from the penguin_df
variable which is a DataFrame that we imported earlier, we’re using two other names to create this section:
- show_table_dialog : A boolean which determines if the dialog is shown or hidden; and
- toggle_table_dialog : A function which toggles the Taipy GUI State application variable for the show_table_dialog variable.
But what is this State? Effectively, each variable that we have included in our Taipy application is actually copied into a taipy.gui.State
object. In other words, they exist separately in memory from the initial variables we defined in the local namespace. Opening two different tabs of this Taipy application in your web browser actually creates two different State instances — meaning they can be used independently as they have separate state.
Returning to our code, the toggle_table_dialog
function we declared receives one parameter, which we named state
. In our Markdown, the button and dialog constructs both defined an on_action property which we assigned our toggle_table_dialog
, otherwise known as a callback function. Now, whenever the button or the dialog is interacted with (the latter by clicking the “x” or “Cancel” controls), the toggle_table_dialog
callback function is called, which toggles the state variable of show_table_dialog
.
Refer to the Taipy documentation on buttons, dialogs and tables for more information.
8. Global Callback Function
Finally, we need to add one last component to complete this dashboard: a global callback function. Unlike the previous section where we defined a specific callback function to toggle the dialog, Taipy GUI also offers the use of a global callback function, i.e., a function which gets called whenever any application variable is modified.
In this section, we will use the global callback function to modify the application’s df
state variable. To recap, penguin_df
is the full imported dataset, while df
is a subset based on the selected penguin species.
Let’s define on_change
, our global callback function:
This function takes 3 parameters:
- state : The
taipy.gui.State
object; - var_name : The name of the application variable that was modified; and
- var_value : The value of the application variable that was modified.
In other words, because of our print statement, if we were to change the penguin species from “Adelie” to “Gentoo”, we would see the following text printed out in our terminal:
species <class 'str'> Gentoo
As previously mentioned, the global callback function is called whenever any application state variable is modified, whether by interacting with the GUI, or programatically. This is a handy feature which I use a lot to implement functionality that needs to run whenever any visual element is modified.
Taipy automatically uses any function with the name on_change
in the local namespace as the global callback function — but in the next section I will also show you how you can explicitly configure Taipy to use a function with some other name.
9. Putting It All Together
Putting together all the components that we built in the previous sections, we get the simple but complete dashboard which we saw at the beginning of this article:
As mentioned earlier, notice the (optional) explicit assignment of the global callback function which we defined, by assigning it to the on_change
member of the Gui
object. This isn’t strictly necessary because Taipy would use the function specifically named on_change
in the local namespace, but explicit assignment would have been required otherwise.
Try installing Taipy on your machine and running this script! You will be running the very same dashboard on your local machine. Check out the Taipy controls documentation and try adding sliders or toggles to the dashboard which are just as easy (or easier!) to use.
Final Thoughts
Before discovering Taipy, my go-to dashboarding library in Python was Streamlit — an established library which I also found to be very easy to use. Although my experience with simple mock-ups and prototyping was pleasant, developing a larger application with multiple pages and state management was quite frustrating — as these more complex applications seem to lay outside of the scope that Streamlit excels in.
Taipy offers a lot of customisability which caters to developers that wish to design a very specific user experience — but also reasonable defaults for developers that want to quickly create simple applications. Creating multi-page applications, managing shared state between different pages and styling with CSS are just a few of the many things you can do with Taipy GUI.
Give Taipy a try, and let me know if you liked it as much as I did!