Product1 publisher2 min readPublished
Upgrading Python's plotly to 7.0 changes what Dash apps draw in the browser
Chris Parmer says plotly.js 4.0 took a major version number because the chart defaults changed. Because plotly.py 7.0 carries that renderer, a Dash team inherits the new defaults with a routine package bump.
The Product Desk · Product desk
What happened
- Plotly.js 4.0.0 arrived in August 2026, and Plotly announced it together with plotly.py 7.0 in a post published on September 18.
- The release adds a new chart type, adds chart sharing to Plotly Cloud, changes some chart defaults, and removes a few long-deprecated attributes.
- Dash renders with the plotly.js bundled inside plotly.py, so upgrading the `plotly` package swaps the charting library inside an existing Dash app.
- The new trace type is quiver, contributed by @degzhaus in PR 7710; it draws a vector field as arrows with a position and a direction, colorable by any value with a colorscale.
- Plotly.js now parses colors with culori instead of TinyColor, so every CSS Color 4 string works, including oklch(), lab(), hwb() and four- and eight-digit hex.
Compiled by The Product DeskSomething wrong?How this is made
Why it matters
- decision A Dash team that wants anything else in plotly.py 7.0 takes the new chart defaults in the same package upgrade, so the only open decision is when to run the visual check.
- cost The bill lands on whoever maintains image-diff baselines and fixed-layout report templates: better defaults still produce different output, and someone has to re-approve it.
- exposure Code still passing long-deprecated attributes is newly exposed, and those attributes usually survive in figure JSON and dashboard configs written years before anyone read a changelog.
- capability A design system that defines brand colors in oklch() or lab() can hand those strings straight to a chart now, without a conversion step to hex.
A developer bumps `plotly` in requirements.txt on Monday to pick up something on the Python side, and the suite passes, because nothing in it compares rendered images. The figures in the Dash app are now being drawn by a renderer version that arrived with the package bump [8].
Chris Parmer, who wrote the announcement, is plain about what earned the major number. "So the changes to defaults are very minor, and we believe they are strictly better defaults," he wrote, and said the default changes are the main reason the major version went up [5][4]. He also wrote that "Plotly.js is an extraordinarily stable library; we take backwards compatibility and browser support very seriously" [6].
The major number means less than it looks. Plotly.js 4.0.0 was the 275th release of a library Plotly has maintained in the open since 2015, an average of about 25 a year across those eleven years [2][16]. Parmer promises the post contains "all (and I mean all!) of the changes in this release" [14]; its summary paragraph describes both the removals and the default changes as "a few" without putting a number on either [18].
Two of the detailed changes are Sankey attributes. A new `direction` accepts "reversed", with "forward" as the default [10]. A new `sort` accepts "input", which keeps the node and link order you passed instead of moving nodes to reduce crossings, and came from community contributor @adamreeve, who also upgraded d3-sankey to 0.12.3 [11]. On the color side, the post shows twelve strings TinyColor could not read now working as shape fills [13].
Which leaves the practical question of who has to look at anything. A chart a person reads is safe here; a default that shifts a tick label needs no re-approval. A chart consumed by an image-diff test, or pasted into a fixed-layout PDF template, or approved once by a client who kept the PNG, is a work item.
The second question is who controls the timing. For a Dash shop the pin point is the `plotly` package itself, so an upgrade taken for a Python API reason is also a renderer upgrade in the browser [8]. A team with no pinned visual output can take 7.0 the way it takes any minor release. A team with baselines is looking at a branch, a render of the handful of figures something downstream compares, and a human approving the diff before the pin reaches main.
What to watch
- Whether Plotly publishes a table naming each changed default and each removed attribute, so teams can grep their figure code instead of eyeballing charts.
- Whether Dash sets a plotly.py 7 floor in its own requirements, which would move the renderer for teams that had not picked the timing.
- Whether issues filed against 4.0 show a removed attribute breaking figure JSON that was saved years ago.