📣 New Releases: Plotly.js 3.0, Plotly.py6.0, Dash 3.0.0rc1

:rocket: We’re excited to announce the release of Plotly.js v3.0, Plotly.py v6.0, and Dash v3.0.0rc1

Official Changelog :arrow_forward: Plotly.js 3.0.0

Official Changelog :arrow_forward: Plotly.py 6.0.0

Official Changelog :arrow_forward: Dash 3.0.0rc1

In these releases we put emphasis on performance, better integrations with other Python libraries like Narwhals and Anywidget, and removal of deprecated features. To read the full summary of the recent releases and their impact, check out @nathandrezner 's blog post on Plotly.

:stop_sign: Dash 3.0 includes changes that break certain functionalities of community component libraries such as Dash Mantine Components (dmc), Dash Bootstrap Components (dbc), Dash AG Grid (dag), Dash Leaflet.
Dash Core Components (dcc), Dash HTML Components (html) and Dash DataTable have already been updated.

If you are an author of a community component, please test it out with Dash 3, and if you spot a bug please let us know in the topic thread below. People using the aforementioned community components in their apps should pin to Dash 2.18.2 until these components are updated.

Important Docs :arrow_down_small:

Highlights :arrow_down_small:

Plotly:

Faster performance for common dataframe types, including Polars and PyArrow:

  • Improves on existing support via dataframe interchange protocol
  • Up to 10x better performance for Polars, and increased performance in Pandas thanks to general optimizations
  • More native dataframe support in the pipeline, including DuckDB

Plotly’s chart widgets are now powered by anywidget:

  • Support for widgets in more notebook editors, like Marimo
  • Plotly charts play great inside of apps built with anywidget or Jupyter Widgets.
  • Note: Support for JupyterLab < 7 has been dropped in favor of modern versions.

Kaleido rebuild:

  • Enables support for the latest Chrome
  • Simplifies long-term maintenance
  • Plans to default to the new Kaleido in a future version of Plotly.py

Dash:

Added support for a new system for hooks and plugins:

  • Setup, layout, routing, callback, error, and index hooks will be available
  • Flask extensions, extra actions, error handling, and other sophisticated functionality is easier to add

Additional refinements and improvements:

  • Default to React 18 in Dash: Dash is bumping the default version of React for compatibility with new component libraries.
  • Component prop typing in Dash: Explicit typing can be added directly to callback signatures.
  • Better render performance in Dash: Apps with many Dash components will see improved render performance.

Previous Releases

:mega: Dash 2.17.0 Released - Callback updates with set_props, No Output Callbacks, Layout as List, dcc.Loading, Trace Zorder
:mega: Dash 2.15.0 Released - Slider Tooltip Styling, Setting Allowed Axes Range, More Page Routing Inputs
:mega: Dash 2.13.0 Released - Coupling with Plotly.py, Shapes in Legends, and Broader DataFrame Support
:mega: Dash 2.11.0 Released - Dash in Jupyter, Locked Flask versions, and dcc.Graph Updates

10 Likes

Awesome work! Thank you to the plotly team, you are doing an amazing work. :clap:

Do you have more info to share about the “better render performance in Dash” ? (e.g. what are the expected improvements?)
I’m a bit surprised about the change for app.run_server, this is going to break all the examples and tutorials online.

Really excited to try building Dash plugins!

Hello @spriteware,

There should be some documentation about how the render performance was adjusted.

But, essentially, components are now rerendered in place, vs the whole tree being rerendered.

This has a major impact on the ability for adjusting individual components via callbacks as the whole page doesn’t rerender.

2 Likes

@spriteware
I created a page with with 100 mantine graphs (they mostly work, so good enough for testing) which get updated every seconds with animations. While in debug mode there where definitely lags but scrolling still smooth af. With debug mode turned off the lag is moderate for 100 graphs with animations. 50 in debug and 80 without debug run absolutely smooth.

Like you said, many thanks to the plotly team for this great update! <3

1 Like

I assume you did this experiment with dash 3.0, did you try the same with dash 2.x? If yes what are the results?

Would you mind sharing the code of this experiment? :smiley:

Yes exactly - sure:

I made the example to only update every second graph. If you then go the the profile tab in the dev settings and turn on Highlight updates when components render under settings, you can see how Dash 2.* renders every graph even if they dont receive an update. But I think you will see the difference pretty quick - I recommend first testing with 2.* :smiley:

The examples are just random stuff from that docs.

app.py:

from random import randint

import dash_mantine_components as dmc
from dash import ALL, Dash, Input, Output, State, _dash_renderer, callback, dcc

from appshell import create_appshell
# from cards import test_card
from figure import bar_graphs, create_bar_data, radar_graphs

_dash_renderer._set_react_version("18.2.0")

app = Dash(__name__)

app.layout = create_appshell(
    dmc.Stack(
        [
            # dmc.Group([test_card, test_card]),
            dmc.Flex("Hello", id="output"),
            dmc.Button("Click me", id="click"),
            dcc.Store(id="lacy-store"),
            dcc.Interval(id="interval"),
            *bar_graphs,
            *radar_graphs,
        ]
    )
)


@callback(
    Output({"type": "graph", "index": ALL}, "data"), Input("interval", "n_intervals")
)
def update_graph(_):
    data = create_bar_data()
    return [data] * (len(bar_graphs) // 2)


@callback(
    Output("appshell", "navbar"),
    Input("mobile-burger", "opened"),
    Input("desktop-burger", "opened"),
    State("appshell", "navbar"),
)
def toggle_navbar(mobile_opened, desktop_opened, navbar):
    navbar["collapsed"] = {
        "mobile": not mobile_opened,
        "desktop": not desktop_opened,
    }
    return navbar


@callback(
    Output({"type": "radar", "index": ALL}, "data"),
    Input("interval", "n_intervals"),
)
def update(_):
    data = [
        {"product": "Apples", "sales": randint(20, 100)},
        {"product": "Oranges", "sales": randint(20, 100)},
        {"product": "Tomatoes", "sales": randint(20, 100)},
        {"product": "Grapes", "sales": randint(20, 100)},
        {"product": "Bananas", "sales": randint(20, 100)},
        {"product": "Lemons", "sales": randint(20, 100)},
    ]
    return [data] * len(radar_graphs)


if __name__ == "__main__":
    app.run(debug=False)

figures.py

import random

import dash_mantine_components as dmc


def create_radar_chart(n):
    return dmc.RadarChart(
        id={"type": "radar", "index": str(n)},
        h=300,
        data=[{}],
        dataKey="product",
        withPolarRadiusAxis=True,
        radarProps={
            "isAnimationActive": True,
        },
        series=[{"name": "sales", "color": "blue.4", "opacity": 0.2}],
    )


def create_bar_data():
    return [
        {
            "month": "January",
            "Smartphones": random.randint(100, 1000),
            "Laptops": 900,
            "Tablets": 200,
        },
        {
            "month": "February",
            "Smartphones": 1900,
            "Laptops": 1200,
            "Tablets": random.randint(100, 1000),
        },
        {
            "month": "March",
            "Smartphones": random.randint(100, 1000),
            "Laptops": 1000,
            "Tablets": 200,
        },
        {
            "month": "April",
            "Smartphones": random.randint(100, 1000),
            "Laptops": 200,
            "Tablets": 800,
        },
        {
            "month": "May",
            "Smartphones": 800,
            "Laptops": random.randint(100, 1000),
            "Tablets": random.randint(100, 1000),
        },
        {
            "month": "June",
            "Smartphones": 750,
            "Laptops": random.randint(100, 1000),
            "Tablets": 1000,
        },
    ]


def create_bargraph(n):
    if n % 2 == 0:
        return dmc.BarChart(
            h=300,
            dataKey="month",
            data=create_bar_data(),
            barProps={"isAnimationActive": True},
            series=[
                {"name": "Smartphones", "color": "violet.6"},
                {"name": "Laptops", "color": "blue.6"},
                {"name": "Tablets", "color": "teal.6"},
            ],
            tickLine="y",
            gridAxis="y",
            withXAxis=True,
            withYAxis=True,
        )

    return dmc.BarChart(
        h=300,
        dataKey="month",
        id={"type": "graph", "index": str(n)},
        data=create_bar_data(),
        barProps={"isAnimationActive": True},
        series=[
            {"name": "Smartphones", "color": "violet.6"},
            {"name": "Laptops", "color": "blue.6"},
            {"name": "Tablets", "color": "teal.6"},
        ],
        tickLine="y",
        gridAxis="y",
        withXAxis=True,
        withYAxis=True,
    )


bar_graphs = [create_bargraph(i) for i in range(40)]
radar_graphs = [create_radar_chart(i) for i in range(40)]

appshell.py

import dash_mantine_components as dmc


def create_appshell(content):
    return dmc.MantineProvider(
        forceColorScheme="dark",
        children=dmc.AppShell(
            [
                dmc.AppShellHeader(
                    dmc.Group(
                        [
                            dmc.Burger(
                                id="mobile-burger",
                                size="sm",
                                hiddenFrom="sm",
                                opened=False,
                            ),
                            dmc.Burger(
                                id="desktop-burger",
                                size="sm",
                                visibleFrom="sm",
                                opened=True,
                            ),
                            dmc.Title("Demo App", c="blue"),
                        ],
                        h="100%",
                        px="md",
                    )
                ),
                dmc.AppShellNavbar(
                    id="navbar",
                    children=[
                        dmc.NavLink(href="/page-1", label="Page 1"),
                        dmc.NavLink(href="/page-2", label="Page 2"),
                        dmc.NavLink(href="/page-3", label="Page 3"),
                        dmc.NavLink(href="/page-4", label="Page 4"),
                    ],
                    p="md",
                ),
                dmc.AppShellMain(content),
            ],
            header={"height": 60},
            navbar={
                "width": 230,
                "breakpoint": "sm",
                "collapsed": {"mobile": True, "desktop": False},
            },
            padding="md",
            id="appshell",
        ),
    )

2 Likes

@spriteware

You can see more details in this PR

And this issue:

1 Like

Looking at the migration guide, I don’t understand the point behind the section on typing. What exactly has changed in Dash 3.0 regarding type hints? I already use type hints all the time in my Dash applications. For the callbacks that I write, this works fine. What am I missing here?

Otherwise, great update, looking forward to see all the improvements in action.

:tada: dash-mantine-components 1.0.0rc1 is Now Available!

:rocket: Pre-release Highlights

  • This release ensures dash-mantine-components V1 is fully compatible with both Dash 2 and Dash 3.
  • If you’re using dmc >= 0.15.0, there are no known breaking changes.
  • If you’re using dmc < 0.15.0, please refer to our migration guide.
  • :warning: Important: Apps running dmc < 1.0.0 must pin dash < 3 to prevent compatibility issues.

We’d love for you to take dmc 1.0.0rc1 for a spin! If you encounter any issues, please report them on our GitHub.

Currently, the dmc docs site is running 1.0.0rc1 with Dash 2.18.2. Next week, we’ll be testing it with Dash 3.0.0rc1—stay tuned!

1 Like

:art: dash-bootstrap-templates 2.0.0 is available!

The dash-bootstrap-templates library provides 52 Bootstrap themed Plotly figure templates making it easy to style your Plotly figures in both light and dark mode theme. See the Dash Bootstrap Theme Explorer for more details.

:sparkles: What’s New?

  • Full compatibility with Plotly 6.0.0—bringing you the latest features and improvements.
  • For apps that require Plotly < 6, please pin to dash-bootstrap-templates 1.3.0 to maintain compatibility.
1 Like