Skip to content

Shape drawing doc #2407

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
May 2, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
29 changes: 26 additions & 3 deletions doc/python/configuration-options.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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.
Expand Down Expand Up @@ -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`).
Expand Down
56 changes: 55 additions & 1 deletion doc/python/images.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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!
49 changes: 48 additions & 1 deletion doc/python/imshow.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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!

88 changes: 87 additions & 1 deletion doc/python/shapes.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 <br> to draw a rectangle <br><br> or select another shape <br>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<br> to draw a rectangle <br><br> or select another shape <br>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!