📣 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")
fig.update_traces(marker_size=10)
fig.update_layout(scattermode="group")
fig.show()

import plotly.express as px

df = px.data.medals_long()

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

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)

fig.show()

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)

fig.update_layout(dragmode='select',
                  activeselection=dict(fillcolor='yellow'))

fig.show()

: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(
    arrangement='snap',
    node=dict(
        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],
        pad=10  
    ),
    link=dict(
        arrowlen=15,
        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]  
    )
))

fig.show()

: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"]
)
fig.update_traces(marker=dict(cornerradius=5))
fig.show()

: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(
    "https://raw.githubusercontent.com/plotly/datasets/master/us-cities-top-1k.csv"
)

fig = px.scatter_mapbox(
    us_cities,
    lat="lat",
    lon="lon",
    hover_name="City",
    hover_data=["State", "Population"],
    color_discrete_sequence=["fuchsia"],
    zoom=3,
    height=300,
)
fig.update_layout(mapbox_style="open-street-map")
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})
fig.show()

: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

px.set_mapbox_access_token(open(".mapbox_token").read())
df = pd.read_csv(
    "https://raw.githubusercontent.com/plotly/datasets/master/2011_february_us_airport_traffic.csv"
)
fig = px.scatter_mapbox(df, lat="lat", lon="long", size="cnt", zoom=3)
fig.update_traces(cluster=dict(enabled=True))
fig.show()

: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
17 Likes

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 Like

+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
dash==2.8.1
plotly==5.13.0

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"]
)
fig.update_traces(marker=dict(cornerradius=1))
fig.show()

image

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(
    data_frame=df[:1000],
    lat="LATITUDE",
    lon="LONGITUDE",
    size="size",
    mapbox_style='carto-positron',
    
)
fig.update_traces(cluster=dict(enabled=True))

# 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__":
    app.run_server(debug=True)

1 Like

Hi @adamschroeder
I have the same issue like @Slava, using plotly==6.0.0 (I tried also 5.20.0 and 5.13.0) generated by
fig.update_traces(marker=dict(cornerradius=5)) . Same code works for one of my colleagues using plotly==5.20.0.

The error output is:
“ValueError: Invalid property specified for object of type plotly.graph_objs.treemap.Marker: ‘cornerradius’ Did you mean “coloraxis”? Valid properties: autocolorscale Determines whether the colorscale is a default palette (autocolorscale: true) or the palette determined by marker.colorscale. Has an effect only if colors is set to a numerical array. In case colorscale is unspecified or autocolorscale is true, the default palette will be chosen according to whether numbers in the color array are all positive, all negative or mixed. cauto Determines whether or not the color domain is computed with respect to the input data (here colors) or the bounds set in marker.cmin and marker.cmax Has an effect only if colors is set to a numerical array. Defaults to false when marker.cmin and marker.cmax are set by the user. cmax Sets the upper bound of the color domain. Has an effect only if colors is set to a numerical array. Value should have the same units as colors and if set, marker.cmin must be set as well. cmid Sets the mid-point of the color domain by scaling marker.cmin and/or marker.cmax to be equidistant to this point. Has an effect only if colors is set to a numerical array. Value should have the same units as colors. Has no effect when marker.cauto is false. cmin Sets the lower bound of the color domain. Has an effect only if colors is set to a numerical array. Value should have the same units as colors and if set, marker.cmax must be set as well. coloraxis Sets a reference to a shared color axis. References to these shared color axes are “coloraxis”, “coloraxis2”, “coloraxis3”, etc. Settings for these shared color axes are set in the layout, under layout.coloraxis, layout.coloraxis2, etc. Note that multiple color scales can be linked to the same color axis. colorbar :class:plotly.graph_objects.treemap.marker.ColorBar instance or dict with compatible properties colors Sets the color of each sector of this trace. If not specified, the default trace color set is used to pick the sector colors. colorscale Sets the colorscale. Has an effect only if colors is set to a numerical array. The colorscale must be an array containing arrays mapping a normalized value to an rgb, rgba, hex, hsl, hsv, or named color string. At minimum, a mapping for the lowest (0) and highest (1) values are required. For example, [[0, 'rgb(0,0,255)'], [1, 'rgb(255,0,0)']]. To control the bounds of the colorscale in color space, use marker.cmin and marker.cmax. Alternatively, colorscale may be a palette name string of the following list: Blackbody,Bluered,Blues,Cividis,Earth,E lectric,Greens,Greys,Hot,Jet,Picnic,Portland,Rainbow,Rd Bu,Reds,Viridis,YlGnBu,YlOrRd. colorssrc Sets the source reference on Chart Studio Cloud for colors. depthfade Determines if the sector colors are faded towards the background from the leaves up to the headers. This option is unavailable when a colorscale is present, defaults to false when marker.colors is set, but otherwise defaults to true. When set to “reversed”, the fading direction is inverted, that is the top elements within hierarchy are drawn with fully saturated colors while the leaves are faded towards the background color. line :class:plotly.graph_objects.treemap.marker.Line instance or dict with compatible properties pad :class:plotly.graph_objects.treemap.marker.Pad instance or dict with compatible properties reversescale Reverses the color mapping if true. Has an effect only if colors is set to a numerical array. If true, marker.cmin will correspond to the last color in the array and marker.cmax will correspond to the first color. showscale Determines whether or not a colorbar is displayed for this trace. Has an effect only if colors is set to a numerical array. Did you mean “coloraxis”? Bad property path: cornerradius ^^^^^^^^^^^^”

@silviupsf
Thanks for reporting this. Can you please share a minimal reproducible example so we can replicate your error on our computer?

Hi @adamschroeder.
I’m not so experienced with Python environments - when I ran the “streamlit run appHome.py” command in the Terminal, I thought it was using the current project environment (packages), but it was using the system one (=older that I’m using in the project). When I realised this and changed the plotly version from 5.9.0 to a newer one, it started working. :slight_smile:

Because during this experience I did some tests, I will write some conclusions, maybe it will help someone else.:

  1. fig.update_traces(marker=dict(cornerradius=5)) started to work from plotly 5.12.0 and above (I tested all the versions to the current one from 5.9.0 to 6.0.0rc);
  2. from the version 6.0.0, even if the code was the same, some colors were changed and the right bar with the values is not shown any more (see attached captures).
    The code used for the tests was:
import streamlit as slit
from st_pages import Page, show_pages
import pandas as pd
import plotly.express as px

show_pages([Page("appHome.py", "Home")])
data = {'Sys': ['Sy1','Sy2'], 'Chg': ['8', '3']}
df = pd.DataFrame(data)
fig = px.treemap(df, path=[px.Constant("JM"), 'Sys'], values='Chg', color='Chg')
fig.update_layout(margin=dict(t=20, l=5, r=10, b=10))
fig.update_traces(marker=dict(cornerradius=5))
slit.plotly_chart(fig, theme="streamlit", use_container_width=True, config={'displaylogo': False})


1 Like