diff --git a/CHANGELOG.md b/CHANGELOG.md
index b062a6ea359..2ba4903fb63 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,12 @@ This project adheres to [Semantic Versioning](http://semver.org/).
## Dev version
+### Updated
+
+- Updated Plotly.js to version 1.54.0. The main feature of the Plotly.js is the
+ possibility to draw layout shapes, using custom dragmodes and corresponding
+ modebar buttons.
+
### Added
- The `hover_data` parameter of `px` functions can now be a dictionary. This
diff --git a/doc/python/configuration-options.md b/doc/python/configuration-options.md
index b5b174dfc8a..c8f46b7caaa 100644
--- a/doc/python/configuration-options.md
+++ b/doc/python/configuration-options.md
@@ -5,8 +5,8 @@ jupyter:
text_representation:
extension: .md
format_name: markdown
- format_version: '1.1'
- jupytext_version: 1.1.1
+ format_version: '1.2'
+ jupytext_version: 1.3.0
kernelspec:
display_name: Python 3
language: python
@@ -20,7 +20,7 @@ jupyter:
name: python
nbconvert_exporter: python
pygments_lexer: ipython3
- version: 3.7.0
+ version: 3.7.3
plotly:
description: How to set the configuration options of figures using the Plotly
Python graphing library.
@@ -236,6 +236,29 @@ fig.show(config={
})
```
+### Add optional shape-drawing buttons to modebar
+
+Some modebar buttons of Cartesian plots are optional and have to be added explictly, using the `modeBarButtonsToAdd` config attribute. These buttons are used for drawing or erasing shapes. See [the tutorial on shapes and shape drawing](python/shapes#drawing-shapes-on-cartesian-plots) for more details.
+
+```python
+import plotly.graph_objects as go
+import plotly.express as px
+df = px.data.iris()
+fig = px.scatter(df, x='petal_width', y='sepal_length', color='species')
+fig.update_layout(
+ dragmode='drawopenpath',
+ newshape_line_color='cyan',
+ title_text='Draw a path to separate versicolor and virginica'
+)
+fig.show(config={'modeBarButtonsToAdd':['drawline',
+ 'drawopenpath',
+ 'drawclosedpath',
+ 'drawcircle',
+ 'drawrect',
+ 'eraseshape'
+ ]})
+```
+
### Double-Click Delay
Sets the maximum delay between two consecutive clicks to be interpreted as a double-click in milliseconds. This is the time interval between first mousedown and second mouseup. The default timing is 300 ms (less than half a second).
This setting propagates to all on-subplot double clicks (except for `geo` and `mapbox`).
diff --git a/doc/python/images.md b/doc/python/images.md
index 108d88022ad..5d63c0ebb9c 100644
--- a/doc/python/images.md
+++ b/doc/python/images.md
@@ -6,7 +6,7 @@ jupyter:
extension: .md
format_name: markdown
format_version: '1.2'
- jupytext_version: 1.3.2
+ jupytext_version: 1.3.0
kernelspec:
display_name: Python 3
language: python
@@ -305,5 +305,59 @@ fig.update_layout(
fig.show(config={'doubleClick': 'reset'})
```
+### Annotating layout image with shapes
+
+_introduced in plotly 4.7_
+
+It can be useful to add shapes to a layout image, for highlighting an object, drawing bounding boxes as part of a machine learning training set, or identifying seeds for a segmentation algorithm.
+
+In order to enable shape drawing, you need to
+- define a dragmode corresponding to a drawing tool (`'drawline'`,`'drawopenpath'`, `'drawclosedpath'`, `'drawcircle'`, or `'drawrect'`)
+- add [modebar buttons](/python/configuration-options#add-optional-shapedrawing-buttons-to-modebar) corresponding to the drawing tools you wish to use.
+
+The style of new shapes is specified by the `newshape` layout attribute. Shapes can be selected and modified after they have been drawn. More details and examples are given in the [tutorial on shapes](/python/shapes#drawing-shapes-on-cartesian-plots).
+
+Drawing or modifying a shape triggers a `relayout` event, which [can be captured by a callback inside a Dash application](https://dash.plotly.com/interactive-graphing).
+
+```python
+import plotly.graph_objects as go
+fig = go.Figure()
+# Add image
+img_width = 1600
+img_height = 900
+scale_factor = 0.5
+fig.add_layout_image(
+ x=0,
+ sizex=img_width,
+ y=0,
+ sizey=img_height,
+ xref="x",
+ yref="y",
+ opacity=1.0,
+ layer="below",
+ source="https://raw.githubusercontent.com/michaelbabyn/plot_data/master/bridge.jpg"
+)
+fig.update_xaxes(showgrid=False, range=(0, img_width))
+fig.update_yaxes(showgrid=False, scaleanchor='x', range=(img_height, 0))
+# Line shape added programatically
+fig.add_shape(
+ type='line', xref='x', yref='y',
+ x0=650, x1=1080, y0=380, y1=180, line_color='cyan'
+)
+# Set dragmode and newshape properties; add modebar buttons
+fig.update_layout(
+ dragmode='drawrect',
+ newshape=dict(line_color='cyan'),
+ title_text='Drag to add annotations - use modebar to change drawing tool'
+)
+fig.show(config={'modeBarButtonsToAdd':['drawline',
+ 'drawopenpath',
+ 'drawclosedpath',
+ 'drawcircle',
+ 'drawrect',
+ 'eraseshape'
+ ]})
+```
+
#### Reference
See https://plotly.com/python/reference/#layout-images for more information and chart attribute options!
diff --git a/doc/python/imshow.md b/doc/python/imshow.md
index 521b0fa1b12..cfb246d9d07 100644
--- a/doc/python/imshow.md
+++ b/doc/python/imshow.md
@@ -20,7 +20,7 @@ jupyter:
name: python
nbconvert_exporter: python
pygments_lexer: ipython3
- version: 3.7.7
+ version: 3.7.3
plotly:
description: How to display image data in Python with Plotly.
display_as: scientific
@@ -260,6 +260,53 @@ imshow. See the [plotly and datashader tutorial](/python/datashader/) for
examples on how to use plotly and datashader.
+### Annotating image traces with shapes
+
+_introduced in plotly 4.7_
+
+It can be useful to add shapes to an image trace, for highlighting an object, drawing bounding boxes as part of a machine learning training set, or identifying seeds for a segmentation algorithm.
+
+In order to enable shape drawing, you need to
+- define a dragmode corresponding to a drawing tool (`'drawline'`,`'drawopenpath'`, `'drawclosedpath'`, `'drawcircle'`, or `'drawrect'`)
+- add modebar buttons corresponding to the drawing tools you wish to use.
+
+The style of new shapes is specified by the `newshape` layout attribute. Shapes can be selected and modified after they have been drawn. More details and examples are given in the [tutorial on shapes](/python/shapes#drawing-shapes-on-cartesian-plots).
+
+Drawing or modifying a shape triggers a `relayout` event, which [can be captured by a callback inside a Dash application](https://dash.plotly.com/interactive-graphing).
+
+```python
+import plotly.express as px
+from skimage import data
+img = data.chelsea()
+fig = px.imshow(img)
+fig.add_annotation(
+ x=0.5,
+ y=0.9,
+ text="Drag and draw annotations",
+ xref="paper",
+ yref="paper",
+ showarrow=False,
+ font_size=20, font_color='cyan')
+# Shape defined programatically
+fig.add_shape(
+ type='rect',
+ x0=230, x1=290, y0=230, y1=280,
+ xref='x', yref='y',
+ line_color='cyan'
+)
+# Define dragmode, newshape parameters, amd add modebar buttons
+fig.update_layout(
+ dragmode='drawrect',
+ newshape=dict(line_color='cyan'))
+fig.show(config={'modeBarButtonsToAdd':['drawline',
+ 'drawopenpath',
+ 'drawclosedpath',
+ 'drawcircle',
+ 'drawrect',
+ 'eraseshape'
+ ]})
+```
+
#### Reference
See https://plotly.com/python/reference/#image for more information and chart attribute options!
diff --git a/doc/python/shapes.md b/doc/python/shapes.md
index 2b5301b4865..6338506e741 100644
--- a/doc/python/shapes.md
+++ b/doc/python/shapes.md
@@ -6,7 +6,7 @@ jupyter:
extension: .md
format_name: markdown
format_version: '1.2'
- jupytext_version: 1.3.2
+ jupytext_version: 1.3.0
kernelspec:
display_name: Python 3
language: python
@@ -716,5 +716,91 @@ fig.update_layout(
fig.show()
```
+### Drawing shapes on Cartesian plots
+
+_introduced in plotly 4.7_
+
+You can create layout shapes programatically, but you can also draw shapes manually by setting the `dragmode` to one of the shape-drawing modes: `'drawline'`,`'drawopenpath'`, `'drawclosedpath'`, `'drawcircle'`, or `'drawrect'`. If you need to switch between different shape-drawing or other dragmodes (panning, selecting, etc.), [modebar buttons can be added](/python/configuration-options#add-optional-shapedrawing-buttons-to-modebar) in the `config` to select the dragmode. If you switch to a different dragmode such as pan or zoom, you will need to select the drawing tool in the modebar to go back to shape drawing.
+
+This shape-drawing feature is particularly interesting for annotating graphs, in particular [image traces](/python/imshow) or [layout images](/python/images).
+
+Once you have drawn shapes, you can select and modify an existing shape by clicking on its boundary (note the arrow pointer). Its fillcolor turns to pink to highlight the activated shape and then you can
+- drag and resize it for lines, rectangles and circles/ellipses
+- drag and move individual vertices for closed paths
+- move individual vertices for open paths.
+
+An activated shape is deleted by cliking on the `eraseshape` button.
+
+Drawing or modifying a shape triggers a `relayout` event, which [can be captured by a callback inside a Dash application](https://dash.plotly.com/interactive-graphing).
+
+```python
+import plotly.graph_objects as go
+fig = go.Figure()
+text="Click and drag here
to draw a rectangle
or select another shape
in the modebar"
+fig.add_annotation(
+ x=0.5,
+ y=0.5,
+ text=text,
+ xref="paper",
+ yref="paper",
+ showarrow=False,
+ font_size=20
+)
+# shape defined programatically
+fig.add_shape(editable=True,
+ x0=-1, x1=0, y0=2, y1=3,
+ xref='x1', yref='y1')
+# define dragmode and add modebar buttons
+fig.update_layout(dragmode='drawrect')
+fig.show(config={'modeBarButtonsToAdd':['drawline',
+ 'drawopenpath',
+ 'drawclosedpath',
+ 'drawcircle',
+ 'drawrect',
+ 'eraseshape'
+ ]})
+```
+
+### Style of user-drawn shapes
+
+The layout `newshape` attribute controls the visual appearance of new shapes drawn by the user. `newshape` attributes have the same names as layout shapes.
+
+_Note on shape opacity_: having a new shape's opacity > 0.5 makes it possible to activate a shape by clicking inside the shape (for opacity <= 0.5 you have to click on the border of the shape), but you cannot start a new shape within an existing shape (which is possible for an opacity <= 0.5).
+
+```python
+import plotly.graph_objects as go
+fig = go.Figure()
+text="Click and drag
to draw a rectangle
or select another shape
in the modebar"
+fig.add_annotation(
+ x=0.5,
+ y=0.5,
+ text=text,
+ xref="paper",
+ yref="paper",
+ showarrow=False,
+ font_size=20
+)
+# shape defined programatically
+fig.add_shape(line_color='yellow',
+ fillcolor='turquoise',
+ opacity=0.4,
+ editable=True,
+ x0=0, x1=1, y0=2, y1=3,
+ xref='x1', yref='y1'
+)
+fig.update_layout(dragmode='drawrect',
+ # style of new shapes
+ newshape=dict(line_color='yellow',
+ fillcolor='turquoise',
+ opacity=0.5))
+fig.show(config={'modeBarButtonsToAdd':['drawline',
+ 'drawopenpath',
+ 'drawclosedpath',
+ 'drawcircle',
+ 'drawrect',
+ 'eraseshape'
+ ]})
+```
+
### Reference
See https://plotly.com/python/reference/#layout-shapes for more information and chart attribute options!