📣 Announcing Plotly.py 5.13.0 - Grouped Scatter, New Markers and Marker Angles, Sankey Links with Arrows, Map Clustering

Update: A new post on version 5.15.0 was released since this was posted.

We are happy to announce that Plotly.py 5.13.0 is now available for download via pip and conda! For up-to-date installation and upgrading instructions, please see our Getting Started documentation page and if you run into trouble, check out our Troubleshooting Guide.

To start working with Plotly v5.13.0, using pip:

  • pip install plotly==5.13.0

Or with conda:

  • conda install -c plotly plotly=5.13.0

This is a combined announcement for Plotly.py versions 5.9.0 through 5.13.0 and highlights some of the main updates. See the full changelog

:bar_chart: Grouped Scatter Support

If you’ve ever wanted to overlay scatter points on bars, you can now do it with Plotly.py. In the following example, we use the new attributes scattermode and offsetgroup on scatter to create a figure that shows individual points on a grouped scatter and averages with grouped bars. For the full code for this example, see the multiple chart types page in the Plotly.py docs.

There’s also a new scattergap attribute that you can use to adjust the gap between the different scatter groups. These examples show grouped scatter points with 1) a default gap and with 2) a scattergap of 0.75.

import plotly.express as px

df = px.data.medals_long()

fig = px.scatter(df, y="count", x="nation", color="medal")

import plotly.express as px

df = px.data.medals_long()

fig = px.scatter(df, y="count", x="nation", color="medal")
fig.update_layout(scattermode="group", scattergap=0.75)

This feature was anonymously sponsored. Thank you to our sponsor! :heart_decoration:

:arrow_upper_right: New Markers and Angle Attributes

It’s now easier to build network graphs and other graphs that require arrows and angles to show change or direction. Plotly.py introduces new arrow symbols and the attributes angle, angleref and standoff on marker and backoff on line. This example of a dumbbell plot from the Plotly.py docs uses the new arrow markers. You’ll find further documentation and examples on the marker style page.

:white_square_button: Persistent Selections

If you want to capture information about a user selection when using Plotly.py graphs in a Dash app, the new persistent selections feature offers new possibilities. The Dash 2.6 announcement offers more detail on using selections in a Dash context. In addition to selections now being persistent, you can add selections that display when a graph renders as well as style selection lines and fills in different ways.

import plotly.express as px

df = px.data.iris()

fig = px.scatter(df, x="sepal_width", y="sepal_length")
fig.add_selection(x0=3.0, y0=6.5, x1=3.5, y1=5.5)


import plotly.express as px

df = px.data.iris()

fig = px.scatter(df, x="sepal_width", y="sepal_length")
fig.add_selection(x0=3.0, y0=6.5, x1=3.5, y1=5.5)



:arrow_right: Sankey Links with Arrows

You can now create Sankey diagrams with arrow links. Use arrowlen to set the length (in px) of link arrows.

import plotly.graph_objects as go

fig = go.Figure(go.Sankey(
        label=['A', 'B', 'C', 'D', 'E', 'F'],
        x=[0.2, 0.1, 0.5, 0.7, 0.3, 0.5],
        y=[0.7, 0.5, 0.2, 0.4, 0.2, 0.3],
        source=[0, 0, 1, 2, 5, 4, 3, 5],
        target=[5, 3, 4, 3, 0, 2, 2, 3],
        value=[1, 2, 1, 1, 1, 1, 1, 2]  


:deciduous_tree: Rounded Corners on Treemaps

Plotly.py now supports creating treemaps with rounded corners by setting cornerradius on marker:

import plotly.express as px
fig = px.treemap(
    names = ["Eve","Cain", "Seth", "Enos", "Noam", "Abel", "Awan", "Enoch", "Azura"],
    parents = ["", "Eve", "Eve", "Seth", "Seth", "Eve", "Eve", "Awan", "Eve"]

:chart_with_upwards_trend: Syncing Axes Ticks

With overlayed axes, each axis by default has its own number of ticks. This can lead to graphs like this with odd spacing on ticks and gridlines (see how the axes on both sides don’t align)

You can now sync the number of ticks on overlayed axes, by setting "tickmode=sync" on an axis that is overlaying another:

The full code for this example is available on the multiple axes page.

:chart_with_upwards_trend: Avoiding Overlapping Y Axes

If you’ve ever encountered issues with axes with the same overlaying value overlapping, there are now two new attributes to help. To automatically reposition axes to avoid overlap with other axes with the same overlaying value, set autoshift=True.

You can also set a shift value on an axis to shift an axis by that number of pixels.

For the code for these examples see the multiple axes page.

Thanks to Gamma Technologies for sponsoring the related development! :heart_decoration:

:world_map: Setting Map Bounds

If you want to restrict a map to one area, outside which a user interacting with the map can’t pan or zoom, this is now possible on Mapbox scatter plots by using map bounds . Here we set a maximum longitude of -180, a minimum longitude of -50, a maximum latitude of 90, and a minimum latitude of 20.

import plotly.express as px
import pandas as pd

us_cities = pd.read_csv(

fig = px.scatter_mapbox(
    hover_data=["State", "Population"],
fig.update_layout(margin={"r": 0, "t": 0, "l": 0, "b": 0})
fig.update_layout(mapbox_bounds={"west": -180, "east": -50, "south": 20, "north": 90})

:earth_americas: Clusters

It is now possible to display clusters of data points on Mapbox scatter plots. Here, we enable clusters with enabled=True. You can also enable clusters by setting other cluster properties. See the reference docs for more details on available properties.

import plotly.express as px
import pandas as pd

df = pd.read_csv(
fig = px.scatter_mapbox(df, lat="lat", lon="long", size="cnt", zoom=3)

:heart: Powered by Plotly.js 2.18.0 and perfect for Dash 2.8.1

The version of Plotly.js that Plotly.py 5.13.0 is built on is the same one that’s bundled with the just-released Dash 2.8.1, so we recommend that if you’re a Dash user you upgrade to Dash 2.8.1, to get the full benefit of all of these libraries working together.

:package: Get it now!

To sum up: Plotly.py 5.13.0 is out and if you’re excited about any of the above features, head on over to our Getting Started documentation page for full installation instructions!

:reminder_ribbon: In Case You Missed It: Previous Announcements

  • Plotly.py 5.8
    • Better Autocompletions with Type Hints
    • Minor Ticks
  • Plotly.py 5.7
    • Patterns on areas
    • Tick label steps (Plotly 5.6)
    • Text on histograms and heatmaps (Plotly 5.5)
    • Smith charts (Plotly 5.4)
    • Legend group click (Plotly 5.3)
  • Plotly.py 5.2 and 5.1
    • Trendlines
    • ECDF Plots
    • Markers on Lines
    • Sharper WebGL
    • Legend Group Titles
  • Plotly.py 5.0
    • A combined, federated JupyterLab Extension
    • Bar Chart Patterns (aka Hatching or Textures)
    • Icicle and Flame Charts
    • Explicit Legend-Item Ordering
    • Faster JSON serialization with orjson

Thanks @liamc . The Syncing Axes ticks feature is welcome, no need to use workarounds for that anymore :smiley:

Do you know whether there will be some changes regarding the fine tuning of the legend item sizes in the near future? I’m thinking of the bubble charts; currently when the bubble area or diameter is not defined by a constant “marker_size”, (i.e if the area/diam is is dependant of a value) we can either chose to keep the marker size as constant (in such case it has a “default size” which is relatively small) or set it as variable. In the latter case, the legend item size might be too small.
Would the possibility of “scaling” the legend item size make sense?. This way proportions would be kept, but legends would be more readable.
Also, on scatter plot, if the marker_size is manually set to something larger, then the marker on the chart and in the legend get larger. It makes sense, but again, if we could “scale” the marker size in the legend, wouldn’t it help to fix the issues described there : Increase the size of legend symbol in plotly - #2 by empet or here: How to resize legend items - #10 by David22 or r - Change legend size in plotly chart - Stack Overflow ?

This caused a horrible downgrade of Dash to 0.39.0
( I previously had Dash 2.7.1 and plotly 5.11.0)

“conda update dash” seems to straighten things out

+1 concerning syncing axes; that was a definite niggle!

However… my right axis now ends up with 2 decimal places of cruft.

Without sync I have temperatures 13 to 18 on left ticks and humidity 56 to 66 on right ticks. Values are whole numbers against all ticks.
With sync, the right ticks have values 56.06, 58.25, … 66.98.
That rather spoils what is otherwise a more elegant graph.

I should add that it isn’t just decimals; an alternative plot with CO2 levels (in ppm) on the right exis shows the same “spurious significant figures” problem: 997ppm, 1159 ppm, 1341ppm (vs a LHS with 5 ticks at invervals of 100 for VOX Index).

cornerradius for treemap doesn’t work for the latest release of dash

some very useful stuff here! +1 for showing directionality

1 Like

Hi @Slava
Thank you for reporting. What version of Dash did this not work for you?

Hi @adamschroeder

that’s weird. It seems to be working for me. I used the code from above with Dash==2.8.1 and Plotly==5.13.0

import plotly.express as px
fig = px.treemap(
    names = ["Eve","Cain", "Seth", "Enos", "Noam", "Abel", "Awan", "Enoch", "Azura"],
    parents = ["", "Eve", "Eve", "Seth", "Seth", "Eve", "Eve", "Awan", "Eve"]


Can you show us an image of the figure you get?

Hi. I tried a similar example as the one provided under the cluster section but rendering the map in a dash app (wrapped in dcc.Graph). The clusters render well but the label for the number of data points in the cluster is not showing. Any idea as to why?

# dash version 2.9.3 
# plotly version 5.14.1 
import plotly.express as px
import dash
import pandas as pd
from dash import html, dcc

df = pd.read_csv(data_path)
df['size'] = 10
fig = px.scatter_mapbox(

# Create Dash app
app = dash.Dash()

# Define the layout of the app
app.layout = html.Div(
        dcc.Graph(id="example-graph", figure=fig)
if __name__ == "__main__":

1 Like