Published in


Plotly & Dash 500

Written by: Daniel Anton Suchy

Hello, world! My name is Daniel Anton Suchy, and I am a data scientist at Plotly. Today, I’d like to share some information about the Plotly and Dash 500 (P&D500) app I recently created.

From real-world problems to Dash

The idea of the “P&D500” was born from Dave Gibbon’s strong initiative to create a project that would showcase the practical abilities of Dash and Plotly. Over the years, Dave has been engaging with app authors, collecting and promoting the best Dash apps he has seen, all the while slowly building this amazing dataset of real-world Dash applications.

A year ago, Dave created a web app that displays the apps he curated, with a cross-filter ability that allows exploring the data.

P&D500 predecessor, created by Dave Gibbon using Dashboard Engine.

Dave doesn’t have formal programming training, but he was able to use Plotly’s simple drag-and-drop Dash Enterprise Dashboard Engine interface to build an impressive app. He received an immense amount of positive feedback, so he asked me to help him expand on it. That’s how the current iteration of the “Plotly and Dash 500” project was born!

The main view in the P&D500 app.

The dataset currently stands at over 1,200 hand-picked apps. Here’s a quick overview of Dave’s process:

  • The data collection process consisted of extensive repeated manual searches over a long period (GitHub, google, LinkedIn, research periodical search tools, etc.)
  • The data curation process was manual (eye test, GitHub stars, the sophistication of workflow, the sophistication of visualizations, uniqueness, geographic/country of origin, the language of the app, etc.)
  • For app ranking, part of it was qualitative, while the other part was quantitative

The first time I saw this dataset, I was blown away. Even as a data scientist, I had never seen such a clean dataset filled with such rich information! It was incredibly easy to work with: well-organized, clearly-defined data fields, followed good etiquette with the locations data which made it very simple to geocode, and the data itself is very rich. I was excited to see what we could do with it.

The Art of Possible

Are you interested in a specific topic? Simply type it into the search bar, and you will be presented with a list of related apps.

Want a wider range of apps related to your industry? Select the sector, and you will be presented with a selection of relevant applications to explore and take inspiration from.

Are you looking for an application for a particular region? You can choose from a list of over 20 languages!

Over 850 applications have their source code available on GitHub. Looking at existing code is a great way to learn and get inspiration, helping developers to further improve their skills and build better apps suited to their needs.

For 600+ apps, you will also be able to find a link to the live app, which is an easy way to see how the app looks and functions, without having to run the code locally.

Technical bit

So, how does the app work?

The simple answer is that 4 main callbacks enable the following:

  1. Data filtering based on 16 filters
  2. Snapshot saving and sharing
  3. Modal displays when map/scatter/marquee is clicked
  4. Sunburst chart transformation into an interactive medium

Now to the details.

  1. Data filtering

Currently, 16 different filters can be used simultaneously to filter the data. That translates to a lot of visualization possibilities, but if managed incorrectly, applying all filters every time a user selects a new filter could slow down the app considerably.

This is remedied by two simple solutions:

  • Add a simple “If” statement so that when a filter is not selected, code skips creating a mask for the Pandas df.
  • Where possible, use the Redis cache.

The main example of the Redis cache is the free text search:

mask = df[[“title”, “organization”]].apply(lambda row: 
row.str.contains(type_filter, case=False).any(), axis=1)

This expression can be computationally heavy since it loops through the whole DataFrame to find the apps that mention the text the user wishes to see.

We simply make a function out of it and use the @cache.memoize() decorator that will cache the results of the user’s search.

def text_filter(text):
mask = df.apply(lambda row: row.str.contains(text, case=False).any(), axis=1)
return mask

You might think, “How does this speed things up if the user searches for a different expression”? In that case, the cache does not exist yet, and the Pandas mask will be calculated normally. However, once the user is satisfied after having narrowed the data down, and uses a different filter, the cache for text_filter() will be used, and the expensive Pandas operation will be skipped.

Using Redis cache is a great way to speed up your app and make it more responsive. By adding a couple of lines of code, the response time of a large SQL call/data operation/function becomes milliseconds instead of seconds for subsequent queries.

Any Redis database can be used, however, if you have a Dash Enterprise license, it can be simply added via the App Manager. You can read more in the Redis documentation.

Another trick to speed up loading times is the Dash Ag-Grid table. While Ag-Grid has many great features, the main feature I utilized was pagination.

When pagination is enabled, the data passed into the table won’t be fully loaded when initialized. The data is subsequently loaded as the user scrolls through the table. This behavior can be modified to suit the needs, however, you can expect response time in milliseconds.

How does this help? The data of the DataFrame you want to display has to be sent to the user and then processed by the browser. If you try to send a DataFrame that has 1MB, 10, 100… it will take a long time, and the experience can be varied among users with different computer specs, behavior that you have no control over. Pagination mitigates all of that, as well as the initial callback wait, and makes it virtually instantaneous.

2. Snapshot saving and sharing

You might have noticed a share button in the header of the app. When you click on it, your current app view (including all the filters) will be saved, and you will be given a shareable link.

Share your current view of the application by clicking a single button.

There are two components to this functionality:

  • Saving the state of the app — done with the usage of dash_snapshots Dash Enterprise package that simply allows us to run a one-line function snapshot_save(content_to_save) that will do the magic and store the content in the Redis database. This can then be retrieved whenever the unique link is later opened.
  • Copying the link to the clipboard — is done through the following client-side callback:
function copyShareableLinkToClipboard (text) {
var el = document.createElement('textarea');
el.value = text;
el.setAttribute('readonly', ''); = {position: 'absolute', left: '-9999px'};
Output("copy-to-clipboard-output-confirmation", "children"),
Input("share-clipboard-trigger-text", "storage"),

Where share-clipboard-trigger-text is a unique link created by snapshot_save(content_to_save).

Updating the user with a notification.

3. Modal displays

This modal contains more information about the app & author. It is triggered by the clickData callback when map/scatter/marquee is clicked.

When the figures are created, we store the index of the DataFrame inside the figure so that we can use it later to retrieve the data about that particular app when it is clicked on. An example of how to store additional data in figures can be found in the Plotly graphing library documentation, in our case we pass custom data as follows: custom_data=[df.index].

To determine which component was clicked dash.callback_context.triggered is used, and then depending on the source clicked, the appropriate data is retrieved:

ctx = dash.callback_context.triggered_id
if "fig-map" == ctx:
index = clickData["points"][0]["customdata"][0]
elif "fig-fico-rating" == ctx:
index = scatter_clickData["points"][0]["customdata"][0]
else: # ( marquee click)
index = marquee_clickData["points"][0]["customdata"][0]
df_temp = df[df.index == index]

Plotly has a thorough explanation of how to use dash.callback_context.triggered in the Dash documentation, I would highly recommend trying it out, as it is a very powerful tool that lets you implement complex logic in your callbacks.

Once we have the data, we can populate the modal with it. The modal component is created using dmc.Modal() component and is populated in such a way that only the data (author LinkedIn, code, live app…) that is available for the application is displayed.

I decided to use the Mantine modal because of the synergy with dmc.Timeline() component which is a great way to display the data in an informative and visually appealing way!

Modal with more information about the clicked user app, created using Dash Mantine Components.

4. Sunburst chart

A sunburst chart is a great way to see how the data is distributed and what are the most popular topics.

To take this amazing figure type to the next level, we will utilize Input("sunburst", "clickData") callback to enhance the figure, and transform it into a filter that will allow us to filter the data based on the topic we are interested in.

Sunburst figure modified to act as a selector that cross-filters the data.

This is achieved by exploring the clicked data through pie_click["points"][0]["currentPath"] and pie_click["points"][0]["entry"], and then comparing it to previously selected topics which are stored between callbacks in


Once the selection is made, we also alert the user that the data has been filtered by displaying a notification.

Notification at the bottom right of the user’s screen, updating the user about the action taken.

A few tips

When you are designing your app, keep the user experience top of mind!

  • Figure legend/axes titles
  • Does it need to be shown? If yes, name and position them properly.
  • Make sure the colors used remain consistent between the figures and the app itself.
  • Control panel
  • Figure controls are intuitive enough so that the user does not need to use the control panel, so consider removing it — it looks better when the never-used control buttons don’t phase in and out on hover!
  • If you require the user to take a screenshot of the figure, remove the other controls and just keep the screenshot button!
  • Hover Information Take your time to write your custom hover template and don’t forget to use bold, italic, underline, or even color!
  • Notifications and overlays
  • If you have a callback that re-plots a figure, use a loading overlay over the figure, to let the user know “look, this figure is now being changed because of the button you clicked!” at a single glance. The overlay will also remove the worry we all have on some pages where nothing seemingly happens and you start wondering if you really did click that button or not.
  • Consider using notifications/tooltips to inform the user!
  • Custom CSS
  • Small things like changing the border color on hover can inform the user “look, this is intractable”.
  • You can easily create custom behavior for components (see marquee components in the P&D500 app).
  • Also, make sure the fonts and colors are consistent throughout the app!

Thank you!

Whether you have found your app inside P&D500, or whether you just intend to use it, we want to thank you for taking part in this journey, and we hope you will find it helpful.

We will be adding more features to the whole experience and creating walkthrough videos too, so look forward to it!

You can submit your application at the top-right of the page.

If you have an app that you would like to be featured, you are welcome to submit it via the application’s submission menu, found under a dropdown on the top right of the page. We are so excited to see what you will create!

For technical questions, please reach out to me on LinkedIn.
For other questions/suggestions, please reach out to Dave.



Plotly is a data visualization company that makes it easy to build, test, and deploy beautiful interactive web apps, charts and graphs—in any programming language.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store

The low-code framework for rapidly building interactive, scalable data apps in Python.