July 24 🚢 Chart the future of dynamic data + AI with the newest Plotly product launch. Get Your Pass!

author photo

Chris Parmer

May 12, 2023 - 15 min read

Partial Property Updates: Extending Full-Stack Development with Python

Our intention with Dash is to make it as simple as possible for developers to go as far as possible making rich, web-based data apps using only Python. Dash simplifies full-stack development by eliminating the need to write JavaScript.

Simplicity often comes at the expense of customizability. With Dash, we want there to be an entry point that’s easy to learn and easy to understand. But we also want to deliver solutions that have escape hatches — functionality that allows you to customize behavior on a deeper level progressively. Escape hatches let you start with a simple use case and then fine-tune what you’ve built over time to make it more performant and user-friendly.

Partial Property Updates is a great example of this principle. Partial Property Updates make it easier to change individual aspects of a property of the UI without sending the entire property’s data back and forth across the network. This improves the performance of an application by reducing network payloads and by providing a programming pattern to remove unnecessary computations.

What’s Unique About Partial Property Updates

Partial Property Updates allow Dash users to leverage the Patch() object to make changes to a component of a property without manipulating the entire property. The Patch() object is defined in Python and describes the change to the property that should occur in the browser client in JavaScript. For example, this lets you update a figure (e.g. changing the color of a graph) without “redrawing” it entirely, i.e. without moving the entire visualization’s data over the server.

The Partial Properties Update feature improves the performance of a particular set of common UI interactions, like highlighting part of a chart in a different color to make data stand out, altering what’s shown on the x- or y-axis of a graph, or appending data to a table as new real-time data comes in.

App performance matters. Data apps that feel snappy and responsive are more likely to be used by stakeholders to make business decisions. Partial Property Updates extend the full-stack development capabilities of Dash, enabling users to write highly functional and performant UI interactions in the backend with Python. It also vastly reduces the amount of data that’s sent over the network. This lets you create dynamic apps that respond in real time without needing to write trivial actions using JavaScript or leverage unnecessary network bandwidth to deal with more granular UI interactions.

Dash bridges the gap between data analytics and modern web app UIs. Partial Properties Updates enables developers to take their apps to the next level of efficiency and user-friendliness.

A Brief History of Full-Stack Development Frameworks

The first websites (and many still, today!) involved a static document that was passed from the web server to the user's client for every user interaction. Typically, these pages were entirely HTML. Any time a user made a request or change — for example filling out a form or performing a data query — they’d be redirected to an entirely different page with the results. Developers work within an entire page rather than of elements within that page, which doesn’t offer the level of granularity users may need when interacting with the UI. You can still build websites like this (and many do!) with Flask or Django in Python without touching JavaScript.

JavaScript and AJAX web development techniques changed that framework in the early 2000s. This innovative technique enabled developers to build apps that could asynchronously pass data between servers without changing the way that the client-side page behaved. This made it possible for users to make changes to content dynamically without having to reload or be redirected to a new page. The catch, of course, is that AJAX requires a combination of different programming languages and data structures including HTML, CSS, JSON or XML, and JavaScript, which brings all of these data structures together.

Today, APIs have made the conversation between frontend requests and backend data retrieval a little more streamlined. Now, each level of the stack has its own specialization: the API layer (JSON, GraphQL, REST, AJAX, etc), the front end UI layer (CSS, JavaScript, HTML), and the back end layer (web servers written in any language, including Python)—not to mention the actual data analytics code behind your data app.

Building a modern web app requires knowing multiple programming languages or coordinating a team of people who can tackle the different parts of the app. This creates barriers to velocity.

The Next Evolution of Full-Stack Capabilities

Our vision with Dash was to enable a single data analyst to build a modern web application with Python. Instead of redirecting users to different pages upon form completion like the early websites, Dash enables developers to update components on the same page without resorting to JavaScript. Partial Property Updates takes this even further by providing an even more granular way to make updates on the page. It allows the developer to describe sets of operations that should be performed within the UI layer, like appending data or merging data structures, within their Python code.

In a nutshell, Partial Property Updates enables the apps you create to behave like they’re built with multiple languages as the JavaScript functionality is abstracted internally by Dash. Partial Property Updates expands how developers are able to build apps—taking app development into its next logical evolution.

Updating Point Colors

Patch is Among Many Escape Hatches

Since Dash was released in 2017, we've released feature after feature that "raises the ceiling" in what's possible within a pure Python data app framework. Other notable features beyond Patch and Partial Properties include:

  • Custom Components - Writing custom JavaScript or React components that extend the built-in capabilities of the Dash component system
  • Pattern Matching Callbacks - Enabling dynamically created inputs and outputs on a page
  • Clientside Callbacks - Enabling callbacks to be written in JavaScript instead of Python
  • Background Callbacks - Running long-running callbacks in a background job queue
  • Caching - Caching callbacks in a shared memory store
  • Loading States - Enabling custom loading states while updates are taking place
  • Multi-Page Applications and Custom Query Parameters
  • Persistence - Saving the values for certain input controls in local storage, session storage, or memory so they can be preset when the user returns to the application

Why Partial Property Updates Matter for Developers and Organizations

At Plotly, we see significant opportunities for organizations that put full-stack data app development into the hands of individual data analysts and data scientists. Building an internal data app in a traditional software stack often requires an expensive team of developers with different specializations (front end, back end, API, DevOps, etc.). Dash allows you to significantly simplify the team requirements for app projects — for example, enabling a single data scientist or data analyst to execute on an app idea for an ad hoc use case.

Using Partial Property Updates in Dash eliminates the gap between what’s possible to build in a traditional full-stack software environment and what’s easy to build in Python with Dash. When more individuals with varying skill sets are empowered to build the data apps their businesses need, they can drive outcomes much quicker than if those development efforts were spread across slow moving teams. Innovation can happen faster and so can data-driven decision-making processes.

from dash import Dash, dcc, html, Input, Output, Patch
import plotly.express as px
app = Dash(__name__)
# Getting our data
df = px.data.gapminder()
df = df.loc[df.year == 2002].reset_index()
# Creating our figure
fig = px.scatter(x=df.lifeExp, y=df.gdpPercap, hover_name=df.country)
fig.update_traces(marker=dict(color="blue"))
app.layout = html.Div(
[
html.H4("Updating Point Colors"),
dcc.Dropdown(id="dropdown", options=df.country.unique(), multi=True),
dcc.Graph(id="graph-update-example", figure=fig),
]
)
@app.callback(
Output("graph-update-example", "figure"), Input("dropdown", "value"), prevent_initial_call=True
)
def update_markers(countries):
country_count = list(df[df.country.isin(countries)].index)
patched_figure = Patch()
updated_markers = [
"red" if i in country_count else "blue" for i in range(len(df) + 1)
]
patched_figure['data'][0]['marker']['color'] = updated_markers
return patched_figure
app.run_server(debug=True)

The above example illustrates how to use assignment with the Patch() object. When we define the assignment change — in this case, altering the color of specific points — we tell Dash that we want that part of the chart to be the value in updated_markers. Once the callback returns the Patch() object, Dash assigns the value in updated_markers to ['data'][0]['marker']['color'] in the chart.

If you’re already familiar with Python, the actions you can create with Patch() are similar to common actions you’d build into the backend. In addition to using assignment with the Patch() object, you can also define the following changes:

  • Append: Works the same as appending lists in Python. It’s useful for adding to a component's children and adding data to axes on a visualization.
  • Prepend: Allows you to add a new value at the beginning of a list. You can use this to add historical data to a chart before more recent data, for example.
  • Extend: This also works the same as extending a list in Python and can be used to provide an iterable whose values will be added to the end of the list. You could use it to add rows from a dataframe to a Datatable's data — for example, as a user requests more data to be added to a table.
  • Insert: Enables you to add to a list at a specific index.
  • Reverse: Makes it possible to reverse data in a list, enabling your users to flip between prioritizing different data in a visualization for better analysis.
  • Clear: Lets you remove all items from a list. This comes in handy when users want to show or remove elements of a visualization to increase or decrease the complexity of the data they’re looking at.
  • Update: Allows you to merge another dictionary into a property attribute that is a dictionary, enabling you to easily update multiple properties like the style of a Plotly figure.
  • Delete: Allows you to provide the option to delete parts of a property's data that matches a specific index. This enables users to delete rows from a table.
  • Remove: Similar to Delete(), you can remove parts of a property's data that matches a given value.

Patch() also supports math operations to increment, decrement, multiply, and divide values. Additionally, you can combine Patch() methods and use multiple Patch() objects within a callback. The latter gives you the chance to make adjustments to multiple figures at once.

With Patch() you can address a wide variety of use cases with creative solutions you can tailor as you go. We’re excited for you to try out Partial Property Updates for yourself. Check out our Partial Property Updates documentation for more details about getting started or tune into the on-demand webinar! We also recommend you check out the Plotly forum post on Partial Property Updates to see more examples . We’d love to see how you’re using this new feature, so be sure to join us in the Plotly Community to share what you’re working on.

Products & Services

COMPANY

  • WE ARE HIRING

© 2024
Plotly. All rights reserved.
Cookie Preferences