Skip to content

Commit abd8609

Browse files
Merge pull request #2840 from plotly/hline-vline-multifacets-rebase
`add_{hline,vline,hrect,vrect}` and `add_{shape,image,annotation}` to multiple facets, squashed
2 parents 1ca15e9 + e2f18b1 commit abd8609

20 files changed

+3052
-589
lines changed

.gitignore

+2-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ node_modules/
3131

3232
# virtual envs
3333
vv
34-
venv
34+
venv*
3535

3636
# dist files
3737
build
@@ -46,4 +46,5 @@ temp-plot.html
4646
doc/python/.ipynb_checkpoints
4747
doc/python/.mapbox_token
4848
doc/.ipynb_checkpoints
49+
tags
4950
doc/check-or-enforce-order.py

doc/python/figure-structure.md

+15-2
Original file line numberDiff line numberDiff line change
@@ -95,18 +95,31 @@ The third of the three top-level attributes of a figure is `frames`, whose value
9595

9696
### The `config` Object
9797

98-
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.
98+
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.
9999

100-
### Positioning With Paper or Container Coordinates
100+
### Positioning With Paper, Container Coordinates, or Axis Domain Coordinates
101101

102102
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`.
103103

104104
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.
105105

106+
To position an object in "paper" coordinates, the corresponding axis reference
107+
is set to `"paper"`. For instance a shape's `xref` attribute would be set to
108+
`"paper"` so that the `x` value of the shape refers to its position in paper
109+
coordinates.
110+
106111
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.
107112

108113
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.
109114

115+
Furthermore, shapes, annotations, and images can be placed relative to an axis's
116+
domain so that, for instance, an `x` value of `0.5` would place the object
117+
halfway along the x-axis, regardless of the domain as specified in the
118+
`layout.xaxis.domain` attribute. This behavior can be specified by adding
119+
`' domain'` to the axis reference in the axis referencing attribute of the object.
120+
For example, setting `yref = 'y2 domain'` for a shape will refer to the length
121+
and position of the axis named `y2`.
122+
110123
### 2D Cartesian Trace Types and Subplots
111124

112125
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.
+121
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
---
2+
jupyter:
3+
jupytext:
4+
notebook_metadata_filter: all
5+
text_representation:
6+
extension: .md
7+
format_name: markdown
8+
format_version: '1.2'
9+
jupytext_version: 1.3.0
10+
kernelspec:
11+
display_name: Python 3
12+
language: python
13+
name: python3
14+
language_info:
15+
codemirror_mode:
16+
name: ipython
17+
version: 3
18+
file_extension: .py
19+
mimetype: text/x-python
20+
name: python
21+
nbconvert_exporter: python
22+
pygments_lexer: ipython3
23+
version: 3.7.3
24+
plotly:
25+
description: How to add annotated horizontal and vertical lines in Python.
26+
display_as: file_settings
27+
language: python
28+
layout: base
29+
name: Shapes
30+
order: 37
31+
permalink: python/horizontal-vertical-shapes/
32+
thumbnail: thumbnail/horizontal-vertical-shapes.jpg
33+
---
34+
35+
### Horizontal and Vertical Lines and Boxes (Autoshapes) in Plotly.py
36+
37+
*introduced in plotly 4.12*
38+
39+
Horizontal and vertical lines and rectangles (autoshapes) that span an entire
40+
plot can be added via the `add_hline`, `add_vline`, `add_hrect`, and `add_vrect`
41+
methods of `plotly.graph_objects.Figure`. Shapes added with these methods are
42+
added as [layout shapes](/python/shapes) (as shown when doing `print(fig)`, for
43+
example). These shapes are fixed to the endpoints of one axis, regardless of the
44+
range of the plot, and fixed to data coordinates on the other axis. The
45+
following shows some possibilities, try panning and zooming the resulting figure
46+
to see how the shapes stick to some axes:
47+
48+
49+
```python
50+
import plotly.express as px
51+
52+
df = px.data.iris()
53+
fig = px.scatter(df, x="sepal_length", y="sepal_width")
54+
55+
# Add a vertical line that spans the entire y axis
56+
# intersecting the x axis at x=5
57+
fig.add_vline(x=5, line_color="red")
58+
# Add a horizontal line that spans the entire x axis
59+
# intersecting the y axis at y=3
60+
fig.add_hline(y=3, line_color="blue")
61+
# Add a vertical rectangle that spans the entire y axis
62+
# intersecting the x axis at 5.5 and 6.5
63+
fig.add_vrect(x0=5.5, x1=6.5, line_color="purple")
64+
# Add a horizontal rectangle that spans the entire x axis
65+
# intersecting the y axis at 2.5 and 4
66+
fig.add_hrect(y0=2.5, y1=4, line_color="orange")
67+
# (try panning and zooming the plot)
68+
fig.show()
69+
```
70+
71+
#### Adding Autoshapes to Multiple Facets / Subplots
72+
73+
The same line or box can be added to multiple facets by using the `'all'`
74+
keyword in the `row` and `col` arguments like with `Figure.add_shape`. For
75+
example
76+
```python
77+
import plotly.express as px
78+
79+
df = px.data.tips()
80+
fig = px.scatter(df, x="total_bill", y="tip", facet_row="smoker", facet_col="sex")
81+
# Adds a vertical line to all facets
82+
fig.add_vline(x=30, row="all", col="all", line_color="purple")
83+
# Adds a horizontal line to all the rows of the second column
84+
fig.add_hline(y=6, row="all", col=2, line_color="yellow")
85+
# Adds a vertical rectangle to all the columns of the first row
86+
fig.add_vrect(x0=20, x1=40, row=1, col="all", line_color="green")
87+
fig.show()
88+
```
89+
The default `row` and `col` values are `"all"` so
90+
`fig.add_vline(x=30, line_color="purple")` is equivalent
91+
to `fig.add_vline(x=30, row="all", col="all", line_color="purple")` in the above
92+
example.
93+
94+
#### Adding Text Annotations to Autoshapes
95+
96+
Text [annotations](/python/text-and-annotations) can be added to an autoshape
97+
using the `annotation` keyword. Using the above example:
98+
```python
99+
import plotly.express as px
100+
import plotly.graph_objects as go
101+
102+
df = px.data.tips()
103+
fig = px.scatter(df, x="total_bill", y="tip", facet_row="smoker", facet_col="sex")
104+
# Add annotations anchored to the top right corner of the resulting lines
105+
fig.add_vline(x=30, line_color="purple", annotation=go.layout.Annotation(text="A"))
106+
# Another way to add annotations when we are only interested in specifying text
107+
fig.add_hline(y=6, row="all", col=2, line_color="yellow", annotation_text="B")
108+
# Specify the position of the resulting annotations
109+
fig.add_vrect(
110+
x0=20,
111+
x1=40,
112+
row=1,
113+
col="all",
114+
line_color="green",
115+
annotation_text="C",
116+
annotation_position="bottom inside left",
117+
)
118+
fig.show()
119+
```
120+
Call `help` on any of the autoshape functions in the Python interpreter to learn
121+
more (e.g., `help(fig.add_vline)`).

doc/python/images.md

+41-4
Original file line numberDiff line numberDiff line change
@@ -309,15 +309,15 @@ fig.show(config={'doubleClick': 'reset'})
309309

310310
_introduced in plotly 4.7_
311311

312-
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.
312+
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.
313313

314314
In order to enable shape drawing, you need to
315315
- define a dragmode corresponding to a drawing tool (`'drawline'`,`'drawopenpath'`, `'drawclosedpath'`, `'drawcircle'`, or `'drawrect'`)
316316
- add [modebar buttons](/python/configuration-options#add-optional-shapedrawing-buttons-to-modebar) corresponding to the drawing tools you wish to use.
317317

318318
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).
319319

320-
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).
320+
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).
321321

322322
```python
323323
import plotly.graph_objects as go
@@ -339,7 +339,7 @@ fig.add_layout_image(
339339
)
340340
fig.update_xaxes(showgrid=False, range=(0, img_width))
341341
fig.update_yaxes(showgrid=False, scaleanchor='x', range=(img_height, 0))
342-
# Line shape added programatically
342+
# Line shape added programatically
343343
fig.add_shape(
344344
type='line', xref='x', yref='y',
345345
x0=650, x1=1080, y0=380, y1=180, line_color='cyan'
@@ -359,5 +359,42 @@ fig.show(config={'modeBarButtonsToAdd':['drawline',
359359
]})
360360
```
361361

362+
363+
### Images Placed Relative to Axes
364+
365+
Using `xref='x domain'` or `yref='y domain'`, images can be placed relative to
366+
axes. As an example, the following shows how to put an image in the top corner
367+
of a subplot (try panning and zooming the resulting figure):
368+
369+
```python
370+
import plotly.express as px
371+
372+
df = px.data.iris()
373+
fig = px.scatter(df, x="sepal_length", y="sepal_width", facet_col="species")
374+
# sources of images
375+
sources = [
376+
"https://upload.wikimedia.org/wikipedia/commons/thumb/f/fe/Iris_setosa_var._setosa_%282595031014%29.jpg/360px-Iris_setosa_var._setosa_%282595031014%29.jpg",
377+
"https://upload.wikimedia.org/wikipedia/commons/thumb/3/38/Iris_versicolor_quebec_1.jpg/320px-Iris_versicolor_quebec_1.jpg",
378+
"https://upload.wikimedia.org/wikipedia/commons/thumb/f/f8/Iris_virginica_2.jpg/480px-Iris_virginica_2.jpg",
379+
]
380+
# add images
381+
for col, src in enumerate(sources):
382+
fig.add_layout_image(
383+
row=1,
384+
col=col + 1,
385+
source=src,
386+
xref="x domain",
387+
yref="y domain",
388+
x=1,
389+
y=1,
390+
xanchor="right",
391+
yanchor="top",
392+
sizex=0.2,
393+
sizey=0.2,
394+
)
395+
396+
fig.show()
397+
```
398+
362399
#### Reference
363-
See https://plotly.com/python/reference/layout/images/ for more information and chart attribute options!
400+
See https://plotly.com/python/reference/layout/images/ for more information and chart attribute options!

0 commit comments

Comments
 (0)