Skip to content

add_shape, add_layout_image, add_annotation for multiple facets at once, add_hline and add_vline (+add_vrect/add_hrect) #2558

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

Closed
wants to merge 59 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
1fb1888
row='all' col='all' working for add_shape
nicholas-esterer Jun 9, 2020
a84c8b8
Can also assign outer product of list indices
nicholas-esterer Jun 10, 2020
e96138b
range can now also get passed
nicholas-esterer Jun 10, 2020
af9c758
Trying to write some tests.
nicholas-esterer Jun 11, 2020
33c0f30
Added methods to index all or a subset of the subplots
nicholas-esterer Jun 11, 2020
0dea19c
Added tests for _get_subplot_coordinates and _indexing_combinations
nicholas-esterer Jun 12, 2020
366f5ec
wrote tests for _select_subplot_coordinates and _indexing_combinations
nicholas-esterer Jun 12, 2020
7fca7de
Merge branch 'issue-2140-b' into issue-2140
nicholas-esterer Jun 12, 2020
3bb61c1
Removed abandoned old test code
nicholas-esterer Jun 12, 2020
0d63119
Made add_trace recursive so it can address mulitple subplots
nicholas-esterer Jun 12, 2020
08d56c0
BaseFigure.add_trace and _add_annotation_like accept lists now for ro…
nicholas-esterer Jun 12, 2020
76e5d99
Documented row='all' or col='all'
nicholas-esterer Jun 12, 2020
553a056
Documented new row and col syntax in add_trace
nicholas-esterer Jun 15, 2020
571c890
Added _make_paper_spanning_shape
nicholas-esterer Jun 15, 2020
70a5ce2
Added add_vline, add_hline, add_vrect, add_hrect
nicholas-esterer Jun 15, 2020
40dea30
Fixed typo in docs
nicholas-esterer Jun 15, 2020
f472458
add_vline and the like work on single plots made without make_subplots
nicholas-esterer Jun 15, 2020
35ba5a2
Added discussion of how to test vline, hline, etc.
nicholas-esterer Jun 18, 2020
1d74ee7
rm pdb include, revert package-lock, add_vline etc. return self
nicholas-esterer Jun 18, 2020
be05c07
Shape is not added to subplot that contains no trace
nicholas-esterer Jun 18, 2020
c259f1a
Wrote hline etc. tests for subplots
nicholas-esterer Jun 19, 2020
9236eae
Added hline etc. tests for empty subplots and single plot
nicholas-esterer Jun 19, 2020
caff20c
More descriptive error when row or col out-of-bounds
nicholas-esterer Jun 19, 2020
87faec1
For custom-sized subplots, _add_annotation_like works with "all"
nicholas-esterer Jun 19, 2020
776123c
Changed exclude_subplots_without_data to exclude_empty_subplots
nicholas-esterer Jun 19, 2020
38ef1d1
Merge branch 'master' into issue-2140
nicholas-esterer Jun 19, 2020
09eea88
vline etc. can be added to single plot now
nicholas-esterer Jun 19, 2020
28f5212
Can't have multiple ** expansions in python 2 function calls
nicholas-esterer Jun 19, 2020
e942e68
Added domain to xref and yref validators
nicholas-esterer Jul 23, 2020
040dd5b
Domain referenced shapes, images and annotations are working
nicholas-esterer Sep 8, 2020
9dd6349
Use Plotly.js's domain referenced shapes for hline, vline etc.
nicholas-esterer Sep 8, 2020
cd01db0
Merge branch 'master' into issue-2140
nicholas-esterer Sep 8, 2020
f900521
Fixed some test_paper_span_shapes.py tests
nicholas-esterer Sep 8, 2020
f6c131a
BaseFigure._make_axis_spanning_shape works for single plots
nicholas-esterer Sep 9, 2020
73455fa
paper span shapes tests are passing again
nicholas-esterer Sep 9, 2020
197bc32
Added example with axis domain referencing shape
nicholas-esterer Sep 11, 2020
bf7581a
Trying to build my docs
nicholas-esterer Sep 11, 2020
84a39d4
Adding documentation on domain referencing stuff
nicholas-esterer Sep 14, 2020
4b58de0
Clarified when we're talking about axis data or axis domains
nicholas-esterer Sep 14, 2020
229f65d
Described axis domain reference in figure structure docs
nicholas-esterer Sep 14, 2020
bf71c81
Added doc page for add_hline, add_vline, add_hrect, add_vrect
nicholas-esterer Sep 15, 2020
cd49147
Docs on addressing multiple facet rows and columns for adding shapes
nicholas-esterer Sep 15, 2020
e4b44c6
Put ' domain' in new shapes with domain reference
nicholas-esterer Sep 24, 2020
3a52321
Starting to add annotation shape positions
nicholas-esterer Sep 29, 2020
f80e2a0
Position of annotation on lines and rects
nicholas-esterer Sep 30, 2020
9d90f39
Annotations can be added to hline, vline, hrect, vrect
nicholas-esterer Oct 1, 2020
8a62ba7
Skeleton of annotated shapes test
nicholas-esterer Oct 2, 2020
3a440c8
Moved tests to test_autoshapes
nicholas-esterer Oct 2, 2020
ef5f6e8
Annotation tests for automatic shapes completed
nicholas-esterer Oct 5, 2020
7f34a1b
Autoshapes documentation, don't add annotation if not specified
nicholas-esterer Oct 5, 2020
5e67c43
codegen
nicholas-esterer Oct 5, 2020
2379c54
If no annotations or shapes added in _process_multiple_axis_spanning_…
nicholas-esterer Oct 5, 2020
f2c9dfd
EnumeratedValidator now compatible with domain suffix
nicholas-esterer Oct 6, 2020
80e213f
Sort JSON keys for tests in Python3.5
nicholas-esterer Oct 6, 2020
da3e452
Codegen off of plotly.js master
nicholas-esterer Oct 6, 2020
f0d4f34
add_hline, add_vline, add_hrect, add_vrect add to all subplots
nicholas-esterer Oct 6, 2020
0ba4721
Arbitrary annotation position description word order
nicholas-esterer Oct 7, 2020
31d68fd
Documented annotation_* kwargs for add_hline etc.
nicholas-esterer Oct 8, 2020
4cfed3c
Removed accidentally added apidoc stuff
nicholas-esterer Oct 16, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ node_modules/

# virtual envs
vv
venv
venv*

# dist files
build
Expand All @@ -46,4 +46,5 @@ temp-plot.html
doc/python/.ipynb_checkpoints
doc/python/.mapbox_token
doc/.ipynb_checkpoints
tags
doc/check-or-enforce-order.py
17 changes: 15 additions & 2 deletions doc/python/figure-structure.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,18 +95,31 @@ The third of the three top-level attributes of a figure is `frames`, whose value

### The `config` Object

At [render-time](/python/renderers/), it is also possible to control certain figure behaviors which are not considered part of the figure proper i.e. the behaviour of the "modebar" and how the figure relates to mouse actions like scrolling etc. The object that contains these options is called the [`config`, and has its own documentation page](/python/configuration-options/). It is exposed in Python as the `config` keyword argument of the `.show()` method on `plotly.graph_objects.Figure` objects.
At [render-time](/python/renderers/), it is also possible to control certain figure behaviors which are not considered part of the figure proper i.e. the behavior of the "modebar" and how the figure relates to mouse actions like scrolling etc. The object that contains these options is called the [`config`, and has its own documentation page](/python/configuration-options/). It is exposed in Python as the `config` keyword argument of the `.show()` method on `plotly.graph_objects.Figure` objects.

### Positioning With Paper or Container Coordinates
### Positioning With Paper, Container Coordinates, or Axis Domain Coordinates

Various figure components configured within the layout of the figure support positioning attributes named `x` or `y`, whose values may be specified in "paper coordinates" (sometimes referred to as "plot fractions" or "normalized coordinates"). Examples include `layout.xaxis.domain` or `layout.legend.x` or `layout.annotation[].x`.

Positioning in paper coordinates is *not* done in absolute pixel terms, but rather in terms relative to a coordinate system defined with an origin `(0,0)` at `(layout.margin.l, layout.margin.b)` and a point `(1,1)` at `(layout.width-layout.margin.r, layout.height-layout.margin.t)` (note: `layout.margin` values are pixel values, as are `layout.width` and `layout.height`). Paper coordinate values less than 0 or greater than 1 are permitted, and refer to areas within the plot margins.

To position an object in "paper" coordinates, the corresponding axis reference
is set to `"paper"`. For instance a shape's `xref` attribute would be set to
`"paper"` so that the `x` value of the shape refers to its position in paper
coordinates.

Note that the contents of the `layout.margin` attribute are by default computed based on the position and dimensions of certain items like the title or legend, and may be made dependent on the position and dimensions of tick labels as well when setting the `layout.xaxis.automargin` attribute to `True`. This has the effect of automatically increasing the margin values and therefore shrinking the physical area defined between the `(0,0)` and `(1,1)` points. Positioning certain items at paper coordinates less than 0 or greater than 1 will also trigger this behavior. The `layout.width` and `layout.height`, however, are taken as givens, so a figure will never grow or shrink based on its contents.

The figure title may be positioned using "container coordinates" which have `(0,0)` and `(1,1)` anchored at the bottom-left and top-right of the figure, respectively, and therefore are independent of the values of layout.margin.

Furthermore, shapes, annotations, and images can be placed relative to an axis's
domain so that, for instance, an `x` value of `0.5` would place the object
halfway along the x-axis, regardless of the domain as specified in the
`layout.xaxis.domain` attribute. This behavior can be specified by adding
`' domain'` to the axis reference in the axis referencing attribute of the object.
For example, setting `yref = 'y2 domain'` for a shape will refer to the length
and position of the axis named `y2`.

### 2D Cartesian Trace Types and Subplots

The most commonly-used kind of subplot is a [two-dimensional Cartesian subplot](/python/axes/). Traces compatible with these subplots support `xaxis` and `yaxis` attributes whose values must refer to corresponding objects in the layout portion of the figure. For example, if `xaxis="x"`, and `yaxis="y"` (which is the default) then this trace is drawn on the subplot at the intersection of the axes configured under `layout.xaxis` and `layout.yaxis`, but if `xaxis="x2"` and `yaxis="y3"` then the trace is drawn at the intersection of the axes configured under `layout.xaxis2` and `layout.yaxis3`. Note that attributes such as `layout.xaxis` and `layout.xaxis2` etc do not have to be explicitly defined, in which case default values will be inferred. Multiple traces of different types can be drawn on the same subplot.
Expand Down
116 changes: 116 additions & 0 deletions doc/python/horizontal-vertical-shapes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
---
jupyter:
jupytext:
notebook_metadata_filter: all
text_representation:
extension: .md
format_name: markdown
format_version: '1.2'
jupytext_version: 1.3.0
kernelspec:
display_name: Python 3
language: python
name: python3
language_info:
codemirror_mode:
name: ipython
version: 3
file_extension: .py
mimetype: text/x-python
name: python
nbconvert_exporter: python
pygments_lexer: ipython3
version: 3.7.3
plotly:
description: How to add annotated horizontal and vertical lines in Python.
display_as: file_settings
language: python
layout: base
name: Shapes
order: 37
permalink: python/horizontal-vertical-shapes/
thumbnail: thumbnail/horizontal-vertical-shapes.jpg
---

### Horizontal and Vertical Lines and Boxes (Autoshapes) in Plotly.py

Horizontal and vertical lines and rectangles (autoshapes) that span an entire
plot can be added via the `add_hline`, `add_vline`, `add_hrect`, and `add_vrect`
methods of `plotly.graph_objects.Figure`. These shapes are fixed to the
endpoints of one axis, regardless of the range of the plot, and fixed to data
coordinates on the other axis. For example


```python
import plotly.express as px

df = px.data.iris()
fig = px.scatter(df, x="sepal_length", y="sepal_width")

# Add a vertical line that spans the entire y axis
# intersecting the x axis at x=5
fig.add_vline(x=5, line_color="red")
# Add a horizontal line that spans the entire x axis
# intersecting the y axis at y=3
fig.add_hline(y=3, line_color="blue")
# Add a vertical rectangle that spans the entire y axis
# intersecting the x axis at 5.5 and 6.5
fig.add_vrect(x0=5.5, x1=6.5, line_color="purple")
# Add a horizontal rectangle that spans the entire x axis
# intersecting the y axis at 2.5 and 4
fig.add_hrect(y0=2.5, y1=4, line_color="orange")
# (try dragging the plot around)
fig.show()
```

#### Adding Autoshapes to Multiple Facets / Subplots

The same line or box can be added to multiple facets by using the `'all'`
keyword in the `row` and `col` arguments like with `Figure.add_shape`. For
example
```python
import plotly.express as px

df = px.data.tips()
fig = px.scatter(df, x="total_bill", y="tip", facet_row="smoker", facet_col="sex")
# Adds a vertical line to all facets
fig.add_vline(x=30, row="all", col="all", line_color="purple")
# Adds a horizontal line to all the rows of the second column
fig.add_hline(y=6, row="all", col=2, line_color="yellow")
# Adds a vertical rectangle to all the columns of the first row
fig.add_vrect(x0=20, x1=40, row=1, col="all", line_color="green")
fig.show()
```
The default `row` and `col` values are `"all"` so
`fig.add_vline(x=30, line_color="purple")` is equivalent
to `fig.add_vline(x=30, row="all", col="all", line_color="purple")` in the above
example.

#### Adding Text Annotations to Autoshapes

Text can be added to an autoshape using the `annotation` keyword. Using the
above example:
```python
import plotly.express as px
import plotly.graph_objects as go

df = px.data.tips()
fig = px.scatter(df, x="total_bill", y="tip", facet_row="smoker", facet_col="sex")
# Add annotations anchored to the top right corner of the resulting lines
fig.add_vline(x=30, line_color="purple", annotation=go.layout.Annotation(text="A"))
# Another way to add annotations when we are only interested in specifying text
fig.add_hline(y=6, row="all", col=2, line_color="yellow", annotation_text="B")
# Specify the position of the resulting annotations
fig.add_vrect(
x0=20,
x1=40,
row=1,
col="all",
line_color="green",
annotation_text="C",
annotation_position="bottom inside left",
)
fig.show()
```
Call `help` on any of the autoshape functions in the Python interpreter to learn
more (e.g., `help(fig.add_vline)`).
11 changes: 7 additions & 4 deletions doc/python/images.md
Original file line number Diff line number Diff line change
Expand Up @@ -309,15 +309,15 @@ fig.show(config={'doubleClick': 'reset'})

_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.
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).
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
Expand All @@ -339,7 +339,7 @@ fig.add_layout_image(
)
fig.update_xaxes(showgrid=False, range=(0, img_width))
fig.update_yaxes(showgrid=False, scaleanchor='x', range=(img_height, 0))
# Line shape added programatically
# Line shape added programatically
fig.add_shape(
type='line', xref='x', yref='y',
x0=650, x1=1080, y0=380, y1=180, line_color='cyan'
Expand All @@ -359,5 +359,8 @@ fig.show(config={'modeBarButtonsToAdd':['drawline',
]})
```


### Images Placed Relative to the Axes

#### Reference
See https://plotly.com/python/reference/layout/images/ for more information and chart attribute options!
See https://plotly.com/python/reference/layout/images/ for more information and chart attribute options!
Loading