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 3 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
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,5 @@ temp-plot.html
doc/python/.ipynb_checkpoints
doc/python/.mapbox_token
doc/.ipynb_checkpoints

tags
122 changes: 93 additions & 29 deletions packages/python/plotly/plotly/basedatatypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import warnings
from contextlib import contextmanager
from copy import deepcopy, copy
import itertools

from _plotly_utils.utils import _natural_sort_strings
from .optional_imports import get_module
Expand All @@ -18,6 +19,60 @@
Undefined = object()


def _rcindex_type(d):
all_flag = False
if type(d) == type(tuple()):
d, f = d
if f == "all":
all_flag = True
if type(d) == type(range(1)):
d = list(d)
if type(d) == type(int()):
return (d, "i", all_flag)
elif type(d) == type(list()):
return (d, "l", all_flag)
elif d == "all":
return (d, "a", all_flag)
else:
raise TypeError(
"argument must be 'all', int or list, got {d_type}".format(
d_type=str(type(d))
)
)


def _rcsingle_index_to_list(d):
if type(d) == type(int()):
return [d]
return d


def _row_col_index_combinations(rows, cols, max_n_rows, max_n_cols):
all_flag = False
rows, rtype, f = _rcindex_type(rows)
all_flag |= f
cols, ctype, f = _rcindex_type(cols)
all_flag |= f
rows = _rcsingle_index_to_list(rows)
cols = _rcsingle_index_to_list(cols)
ptype = (rtype, ctype)
all_rows = range(1, max_n_rows + 1)
all_cols = range(1, max_n_cols + 1)
if ptype == ("a", "a"):
return list(itertools.product(all_rows, all_cols))
elif ptype == ("l", "a") or ptype == ("i", "a"):
return list(itertools.product(rows, all_cols))
elif ptype == ("a", "l") or ptype == ("a", "i"):
return list(itertools.product(all_rows, cols))
elif ptype == ("l", "l"):
if len(rows) == len(cols) and not all_flag:
return list(zip(rows, cols))
else:
return list(itertools.product(rows, cols))
elif ptype == ("l", "i") or ptype == ("i", "i") or ptype == ("i", "l"):
return list(itertools.product(rows, cols))


class BaseFigure(object):
"""
Base class for all figure types (both widget and non-widget)
Expand Down Expand Up @@ -1090,42 +1145,51 @@ def _add_annotation_like(
"Received col parameter but not row.\n"
"row and col must be specified together"
)
grid_ref = self._validate_get_grid_ref()

# Get grid_ref if specific row or column requested
if row is not None:
grid_ref = self._validate_get_grid_ref()
refs = grid_ref[row - 1][col - 1]
# TODO It is assumed that grid_ref has an equal number of columns in
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this can be not-true, you can have really odd layouts: https://plotly.com/python/subplots/#multiple-custom-sized-subplots

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey so I checked this out and it turns out even in this case grid_ref is still a rectangle, just some of the entries are None. So we could still easily iterate through the grid_ref using something like

for r in range(1,len(grid_ref)+1):
    for c in range(1,len(grid_ref[0])+1):
        sub_plot=fig.get_subplot(row=r,col=c)
        if sub_plot is not None:
            ....

We just check if it is not None before doing anything to it 🔧

# each row. Is this ever not true?
rows_cols = _row_col_index_combinations(
row, col, len(grid_ref), len(grid_ref[0])
)

if not refs:
raise ValueError(
"No subplot found at position ({r}, {c})".format(r=row, c=col)
)
for r, c in rows_cols:
refs = grid_ref[r - 1][c - 1]

if refs[0].subplot_type != "xy":
raise ValueError(
"""
Cannot add {prop_singular} to subplot at position ({r}, {c}) because subplot
is of type {subplot_type}.""".format(
prop_singular=prop_singular,
r=row,
c=col,
subplot_type=refs[0].subplot_type,
if not refs:
raise ValueError(
"No subplot found at position ({r}, {c})".format(r=r, c=c)
)
)
if len(refs) == 1 and secondary_y:
raise ValueError(
"""
Cannot add {prop_singular} to secondary y-axis of subplot at position ({r}, {c})
because subplot does not have a secondary y-axis"""
)
if secondary_y:
xaxis, yaxis = refs[1].layout_keys
else:
xaxis, yaxis = refs[0].layout_keys
xref, yref = xaxis.replace("axis", ""), yaxis.replace("axis", "")
new_obj.update(xref=xref, yref=yref)

self.layout[prop_plural] += (new_obj,)
if refs[0].subplot_type != "xy":
raise ValueError(
"""
Cannot add {prop_singular} to subplot at position ({r}, {c}) because subplot
is of type {subplot_type}.""".format(
prop_singular=prop_singular,
r=r,
c=c,
subplot_type=refs[0].subplot_type,
)
)
if len(refs) == 1 and secondary_y:
raise ValueError(
"""
Cannot add {prop_singular} to secondary y-axis of subplot at position ({r}, {c})
because subplot does not have a secondary y-axis""".format(
prop_singular=prop_singular, r=r, c=c
)
)
if secondary_y:
xaxis, yaxis = refs[1].layout_keys
else:
xaxis, yaxis = refs[0].layout_keys
xref, yref = xaxis.replace("axis", ""), yaxis.replace("axis", "")
new_obj.update(xref=xref, yref=yref)

self.layout[prop_plural] += (new_obj,)

return self

Expand Down