Streamlit vs. Dash and Beyond: An introduction to web dashboard development frameworks for Python
By: Alireza Ghasemi
Tags: Dashboard, Dash, Streamlit

Streamlit vs. Dash and Beyond: An introduction to web dashboard development frameworks for Python Alireza Ghasemi Jun 21·11 min read

A lot of data scientists do not have a computer science/software engineering background. Those who do, do not necessarily enjoy writing a web application, or any sort of front-end UI to present their work to the outside world. And even those who indeed enjoy some “pure” software engineering from time to time, may not be very fond of spending too much data science budget on adjusting CSS directives to make buttons and charts look decent on multiple devices. After all, a data science project is obviously targeted around a data-driven question, and it is always encouraged to minimise the extracurricular costs, at least at early stages and for demos, proofs of concepts, etc…

That is the raison d’etre of a family of software frameworks very close to web application frameworks, but distinct enough to merit a separate category. These frameworks work like web application frameworks in that they enable developing web UIs and full-stack web applications, but differ in the sense that they are very much optimised and tailored for specific use cases involving data visualisation, AI, and machine learning. They also differ from more “classic” BI solutions such as PowerBI and Tableau, in that they really aren’t “No-Code” like the latter, nor do they claim so. We will refer to these kinds of frameworks as web dashboarding solutions in the rest of this article, although other names may also have been used for them in the industry.

Our goal in this article is to have a look at two major frameworks in this category, the recently introduced Streamlit, and the older and more established Dash from Plotly. We believe these two frameworks represent the two ends of the spectrum of simplicity-flexibility, and can hence cover the vast majority of use cases appearing in data science projects. We also mention a few other contenders in this space, mostly for the curious reader to follow up later. We focus on Python, as it is by far the most common programming language in the data science community. Both Streamlit and Dash are native in Python, while at least Dash supports R and Julia as well.

Streamlit

Streamlit was introduced in October 2019 by a team of developers led by former Google X lab members. There was a lot of enthusiasm in the data science community around Streamlit which continues today. This is mostly owing to its promise of simplicity, which is to a large extent fulfilled, and its continuous improvement with new features since its early days.

Streamlit: Introduction and Widgets

Streamlit is interesting for its simplicity, providing a decent-looking web application on top of a data science or machine learning backend (or anything else for that matter), in literally a few lines of code. This is achieved by its very unique UI model which avoids explicit event handling or functionalness, as is common in other Ui frameworks. Instead, Streamlit introduces a linear-flow, imperative execution model for the UI code, where each UI widget corresponds to a variable in the Python code and a change in the state or the value of the widget causes, roughly speaking, the re-execution of the code from the point where the widget is defined. With this linear execution model, it becomes very easy to add a web UI on top of a computation backend, possibly as simple as changing parameter definitions with Streamlit widget definitions (text, date range, radio and checkboxes for categorical variables etc…) and then running the script via the streamlit command instead of the Python interpreter. The following figures, taken from the Streamlit gallery depict this: You see the Python code assigning variables to the outcomes of a few checkboxes and radio buttons, and the resulting UI. This example can be found on the awesome-streamlit website.

Plotting in Streamlit

Obviously, the major part of a data dashboard is occupied by charts, plots, and data visualisations. The richness of the plotting API and support for various types of charts is a distinguishing factor for dashboard development solutions. Streamlit has native support for most of the popular Python plotting libraries, including Matplotlib as the simplest one (where a plot is simply a static image), going all the way up to interactive plots created with Plotly, Bokeh, and Altair. This wide choice allows us to continue using our own preferred plotting library exact same way we did before, except the last step where we draw the plot object using Streamlit. The two figures below show an example code using Plotly Express and the resulting interactive plot, from an example dashboard in the awesome-streamlit website:

Sidebars, tabs, and containers

Recently, as a major feature, Streamlit extended the linear execution in a still controlled way. This is achieved by making it possible to group certain widgets into containers, which can then exhibit different behaviour, depending on the type of the container.

The most straightforward type of containers is a horizontal layout, which lays widgets horizontally on the screen instead of vertically. This comes especially useful for widget groups that are naturally and semantically correlated to each other, such as radio buttons and semantically-related checkboxes.

Expanders. or accordions in some other UI frameworks allow hiding certain widgets and plots in a cluttered screen and let the user show them per will. This is obviously useful in a screen that can be divided into multiple sections of related widgets. With expanders, the user has the ability to focus only on a subset of visualisations at the same time.

Finally, in the past few months, Streamlit introduced forms as a way to circumvent its traditional execution model. Forms allow to “trigger” the execution of the Python code for a group of widgets, not by modifying any of them, but only through the press of a special submit button, hence avoiding unnecessary and possibly time-consuming re-runs. This way of “binding” a group of variables together also solves a major limitation of Streamlit’s execution model, where for example one cannot read the same variable using two widgets (e.g. a Date be entered either as text or through a special Date field, based on users’ convenience). The figure below shows an example of using expanders and horizontal layouts.

Developing custom components

In cases where the original set of widgets and visualisation possibilities of Streamlit are not enough for a certain use case, they introduced the possibility of developing custom components, which are mixtures of Python and Javascript/Typescript code. Annotations and parsing tree visualisers for NLP, graph visualisation, and some popular web components such as the Ace editor are currently among the custom components that are available. Please see https://streamlit.io/gallery?type=components&category=featured for further information.

Custom customs allow ideally infinitely extending Streamlit, without compromising its basic promise of simplicity and its model. Still, however, there may be certain use cases for which there is an explicit need to access and modify underlying web-specific elements or have the flexibility to mix client-side JavaScript code with Python. In such cases, Plotly Dash, which we introduce below, is a great choice.

Plotly Dash

Plotly Inc., the developers of the very popular plotting library of the same name, launched Dash in 2017, partially inspired by the R package Shiny. It was marketed as a “low-code” solution for creating web applications for data visualisation, and went further to be widely used for creating UI for ML apps and arguably become the “industry leader” in this space​.

Dash works on top of the Python web framework Flask, the web UI library React.js and the Javascript plotting library Plotly.js​. It is available for Python and R​.

​Dash follows a dual business model, where the open-source software is available via pip without any limitations with an MIT license, while an enterprise edition is also offered to customers who need features such as authentication, CI/CD, and technical support. Anyways, Dash open source is not a “light” version in any sense and contains everything that is required for creating a web-based dashboard.

Widgets and plots

Dash is different from Streamlit in the sense that it is more loyal to the event-based nature of UI development, whereas Streamlit completely hides this from the user. The structure of a Dash app is composed of a layout, where various components, such as input widgets and plots, are positioned, and callbacks, where the changes in the input widgets trigger interactivity and change in the output. As we mentioned above, Streamlit replaces the whole idea of callbacks with a much simpler, and also more limited, concept of persistent state.

The components that are positioned in a layout can be chosen from the standard component library of Dash, or a variety of other component libraries provided by third parties. These third-party libraries usually provide support for well-known web widget libraries, making a Dash app “look and feel” more like a typical web one. Dash Bootstrap Components is the most famous one, wrapping around the famous Bootstrap framework.

Regarding plotting, Dash natively only supports Plotly graphs, which cover a lot of common plotting needs of data-driven apps, from simple charts to machine-learning-specific plots such ROC curves. For the specific use cases where another plotting framework has to be used, Dash supports it by accepting a Graph object to plot. Graph objects can be constructed and returned by a lot of other Python plotting frameworks.

Embedding Javascript and CSS

A lot of Dash core components accept a style property that can be filled with arbitrary CSS styling. This allows a lot of flexibility in modifying the appearance of apps, making the look and feel follow a company-wide guideline or best practices in frontend programming. This is a feature that makes Dash stand out against Streamlit, where it is still very difficult, if not impossible, to apply arbitrary styling to an app.

Javascript code can be embedded into a Dash app too, enabling for example LaTeX rendering and collecting page analytics. This is again impossible in Streamlit. In general, the static assets of a web application such as CSS directives, Javascript code, and images, can be collected into a specific assets folder, and later be used in the Python code. Even event handlers can be written completely in Javascript, in which case they will be executed client-side. This helps in avoiding heavy computation loads on the server. See https://dash.plotly.com/clientside-callbacks for more information.

Accessing the underlying Server

As we already mentioned, Dash is built on top of the Flask web server in the backend, with Plotly.js and React.js in the front-end. Although no knowledge of these frameworks is necessary to use Dash, they are still available for the advanced user and can be customised to match very specialised use cases. As an example, the underlying React components corresponding to Dash components can be accessed and filtered directly, instead of relying on what is exposed via the Dash wrapper.

A much more important use of this feature, and something that is again absent in Streamlit, is to access the underlying Flask server object. The server object can later be arbitrarily optimised, for example, to match certain deployment criteria, or one can write REST endpoints served by the same server object, hence serving both the REST API of a service and its web UI by the same service. This is extremely useful when the API is supposed to be accessible from outside the Dash UI app, for example by other software or mobile applications.

Other Python Dashboarding Solution

With the steady success of Dash and the enthusiasm over Streamlit, a few other frameworks were introduced in recent years, mostly by the development team of another famous data science product (similar to Plotly for Dash). Here we just briefly mention them, leaving more investigations to the curious user to see whether one can find a unique feature in these other frameworks which is lacking in Dash and Streamlit.

The most worthy to mention among these is probably Voila from Jupyter. The target of the Voila framework is the seamless (and painless) deployment of a Jupyter notebook as a normal-looking web application. In that sense, it can become indispensable in a certain target market: When one has to, for other reasons, develop a notebook, they can also deploy the notebook as a web application at a very low cost. Voila uses a series of convenient defaults, such as hiding code cells, and works with major notebook interactivity solutions such as ipywidgets, although some other third-party notebook add-ons are not fully supported. Still, it serves well for at least non-complicated use cases of serving a notebook as a web application. More information can be found at https://voila.readthedocs.io/en/stable/.

Finally, we would like to close the discussion by mentioning two other solutions, each backed by the vendors of a well-known data science package. Wave is a web application framework recently introduced by H2O, vendors of the well-known distributed machine learning framework of the same name. It features collaborative contents as a unique capability compared to the other frameworks mentioned in this article. Apart from this, Wave enjoys, quite predictably, perfect harmony with the rest of the H2O framework and ecosystem, and is, therefore, a viable options especially for teams who already use H2O in their pipeline.

Another dashboarding solution is Panel from HoloViz. With HoloViz itself being specialised in the data visualisation industry, Panel enjoys being part of a rich ecosystem of packages for visualising and analysing diverse modalities of data, from geospatial point clouds to medical image stacks. This allows users who work on such modalities to integrate their workflow in a more seamless manner and develop custom dashboards in a fraction of time, compared to more general frameworks. More information can be found at https://holoviz.org/.

Dash vs. Streamlit: When to use which one?

As mentioned above, Dash and Streamlit lie on two opposing ends of an imaginary spectrum between simplicity and flexibility. We believe together they can cover most if not all of the use cases arising in data-driven app prototyping.

In order to decide between these two solutions, the following table may help. Depending on the specific criteria and requirement, one solution may be a better match.

(Very) minimal overhead effort​: Streamlit

Need for CSS customisation​: Dash

Effortless responsiveness​: Streamlit(?)

REST Endpoints​: Dash

Rapid Multiple Tabs / Sidebar​: Streamlit

Low-latency UI​: Dash

Regarding responsiveness, although Streamlit makes some effort to render widgets consistently across multiple devices, it still fails in some corner cases, especially with the newer container features. A Dash app on the other hand can become perfectly responsive like any other web application, but that requires significant work from the developer to implement responsiveness, as nothing is guaranteed out of the box.

This is actually the case in almost all rows of the table: There is almost no limitation on what can be done with Dash; it’s just a matter of implementing provided one has the corresponding web development knowledge. In almost all cases, Dash can be considered a superset of Streamlit in functionality. That means everything that can be implemented in Streamlit, can also be implemented in Dash, but not necessarily as fast and with the same effort.

References