📣 Dash 2.2.0 Released

Update : version 2.3 has been released since this was posted.

Hi Everyone,

:tada: It’s my pleasure to announce that Dash 2.2.0 has been released.

pip install dash==2.2.0

Official Changelog :arrow_forward: Dash v2.2.0

Highlights :arrow_down_small:

1. Added dash.get_asset_url, dash.get_relative_path, dash.strip_relative_path

In previous Dash versions we had app.get_asset_url , app.get_relative_path and app.strip_relative path.
As of Dash v2.2.0 there are versions of these functions that do not need the app object.

:sparkling_heart: #1923 - Thank you to @AnnMarieW for the Pull Request that led to the updated functions:

  • dash.get_asset_url ,
  • dash.get_relative_path
  • dash.strip_relative path

Use these versions when building multi-page Dash apps, especially on Dash Enterprise or any environment that uses requests_pathname_prefix or proxying. Since these methods don’t use the app object, you won’t run into the notorious circular app imports issue.

In particular use:

  • get_asset_url with images: html.Img(src=dash.get_asset_url('logo.png'))
  • get_relative_path when setting relative href links: dcc.Link(href=dash.get_relative_path('/historical-data'))
  • strip_relative_path in dcc.Location callbacks: page_id = dash.strip_relative_path(href)

Apps deployed on Dash Enterprise are hosted on a single domain with a shared TLS cert but with different relative URLs ( https://<your-dash-enterprise-domain>.com/<your-dash-app-name> e.g. https://dash.acme.com/weekly-analytics ).

These helper methods handle constructing the correct URLs when deployed and when working locally. For more information see below:

:point_right: get_relative_path

get_relative_path returns a path with requests_pathname_prefix prefixed before it. Use this function when specifying local URL paths that will work in environments regardless of what requests_pathname_prefix is.

In some deployment environments, like Dash Enterprise, requests_pathname_prefix is set to the application name, e.g. my-dash-app. When working locally, requests_pathname_prefix might be unset and so a relative URL like /page-2 can just be /page-2. However, when the app is deployed to a URL like /my-dash-app, then app.get_relative_path('/page-2') will return /my-dash-app/page-2.

This can be used as an alternative to get_asset_url as well with app.get_relative_path('/assets/logo.png').

Use this function with app.strip_relative_path in callbacks that deal with dcc.Location pathname routing. That is, your usage may look like:

import dash
app = dash.Dash(__name__)

app.layout = html.Div([
    # Header links for all pages
    html.Div([
            dcc.Link(href=dash.get_relative_path('/page-1')),
            dcc.Link(href=dash.get_relative_path('/page-2')),
    ]),

    dcc.Location(id='url'),
    html.Div(id='content')

])

@dash.callback(Output('content', 'children'), [Input('url', 'pathname')])
def display_content(path):
    page_name = dash.strip_relative_path(path)
    if not page_name:  # None or ''
        return chapters.home_page
    elif page_name == 'page-1':
        return chapters.page_1
    elif page_name == "page-2":
        return chapters.page_2

:point_right: strip_relative_path

strip_relative_path(path) returns a path with requests_pathname_prefix and leading and trailing slashes stripped from it. Also, if None is passed in, None is returned. Use this function with get_relative_path in callbacks that deal with dcc.Location pathname routing.

Note that chapters.page_1 will be served if the user visits /page-1 or /page-1/ since strip_relative_path removes the trailing slash.

Also note that strip_relative_path is compatible with get_relative_path in environments where requests_pathname_prefix set. In some deployment environments, like Dash Enterprise, requests_pathname_prefix is set to the application name, e.g. my-dash-app.

When working locally, requests_pathname_prefix might be unset and so a relative URL like /page-2 can just be /page-2. However, when the app is deployed to a URL like /my-dash-app, then app.get_relative_path('/page-2') will return /my-dash-app/page-2. The pathname property of dcc.Location will return ‘/my-dash-app/page-2’ to the callback. In this case, app.strip_relative_path('/my-dash-app/page-2') will return 'page-2'

For nested URLs, slashes are still included: app.strip_relative_path('/page-1/sub-page-1/') will return
page-1/sub-page-1


2. Updates:

Upgraded Plotly.js to v2.9.0 (from v2.8.3):

  1. :point_right: ticklabelstep - Adds ticklabelstep to axes to reduce number of tick labels while still showing all ticks. Requires Plotly v5.6.0 or higher. This feature development was sponsored by one of our customers. Many thanks :pray:

Before:

import plotly.express as px
df = px.data.gapminder().query("country=='Canada'")
fig = px.line(df, x="year", y="lifeExp", title='Life expectancy in Canada') 
fig.show()

As you can see from the image, all x-axis ticks and their respective labels are present.

After:

import plotly.express as px
df = px.data.gapminder().query("country=='Canada'")
fig = px.line(df, x="year", y="lifeExp", title='Life expectancy in Canada')
fig.update_xaxes(ticklabelstep=2)
# the initial example with all tick labels would be equivalent to fig.update_xaxes(ticklabelstep=1)
fig.show()

As you can see from the image below, all x-axis ticks are still present but only 3 tick labels are showing, since we chose to show every 2nd label with ticklabelstep=2.


  1. :point_right: Displays the plotly.js version when hovering on the modebar.

Plotly.js is the JavaScript graphing library used under the hood by the Python plotly graphing library Plotly.py (https://plotly.com/python) and Dash. Dash, Plotly.py, and some other libraries like Dash Enterprise Design Kit and the vscode-python / vscode-jupyter extension all bundle their own versions of plotly.js in their own releases. So if you create a graph with plotly in a Jupyter notebook you may be using a different version of plotly.js than in your Dash app. This means that newer features might be available in one environment and not in the other.

By displaying the version number in the graph, you can determine which versions of plotly.js are actually being used in each environment which can be helpful if you’re using cutting-edge features.You can usually determine which versions of plotly.js are available in which Python packages by inspecting those package’s changelogs or release announcements. For example, in this announcement we upgraded Dash to plotly.js 2.9.0 which is the same version of plotly.js that is used by the plotly.py library in version 5.6.0.

If you want to use a specific version of plotly.js in your Dash app without upgrading or downgrading dash , then you can download the plotly.js javascript bundle from the plotly.js releases page and place it in your app’s assets/ folder


3. Notable Fixes:

  • #1932 Fixes several bugs:
    • Restores compatibility with IE11 #1925
    • Restores style_header text alignment in Dash Table #1914 - Thanks for reporting @geneblandjr & @bernarducs
    • Clears the unneeded webdriver-manager requirement from dash[testing] #1919

4. Previous Releases:

:mega: Dash 2.1.0 Release
:mega: Dash 2.0 Prerelease Candidate Available!
:mega: Dash v1.21.0 - Plotly.js 2.0, Icicle Charts, Bar Chart Patterns, Clipboard Component, Bug Fixes

10 Likes

This is great! Thanks for sharing @adamschroeder