From 6627d3ee45384b06d3ca745a338b2b18ff2510d0 Mon Sep 17 00:00:00 2001 From: Nicholas Esterer Date: Wed, 11 Nov 2020 14:41:37 -0500 Subject: [PATCH 01/11] Select annotation-like objects with string or int If selector is string, transformed to dict(type=selector), if selector is int, indexes the resulting list of objects filtered down by row, col and secondary y. --- .../python/plotly/plotly/basedatatypes.py | 59 +++++++++++++------ 1 file changed, 41 insertions(+), 18 deletions(-) diff --git a/packages/python/plotly/plotly/basedatatypes.py b/packages/python/plotly/plotly/basedatatypes.py index 7e089eeb3c1..185aaa00f64 100644 --- a/packages/python/plotly/plotly/basedatatypes.py +++ b/packages/python/plotly/plotly/basedatatypes.py @@ -1194,6 +1194,10 @@ def _perform_select_traces(self, filter_by_subplot, grid_subplot_refs, selector) def _selector_matches(obj, selector): if selector is None: return True + # If selector is a string then put it at the 'type' key of a dictionary + # to select objects where "type":selector + if type(selector) == type(str()): + selector = dict(type=selector) # If selector is a dict, compare the fields if (type(selector) == type(dict())) or isinstance(selector, BasePlotlyType): # This returns True if selector is an empty dict @@ -1450,27 +1454,46 @@ def _select_annotations_like( yref_to_row[yref] = r + 1 yref_to_secondary_y[yref] = is_secondary_y - for obj in self.layout[prop]: - # Filter by row - if col is not None and xref_to_col.get(obj.xref, None) != col: - continue - - # Filter by col - if row is not None and yref_to_row.get(obj.yref, None) != row: - continue + # filter down (select) which graph objects, by applying the filters + # successively + def _filter_row(obj): + """ Filter objects in rows by column """ + return (col is None) or (xref_to_col.get(obj.xref, None) == col) - # Filter by secondary y - if ( - secondary_y is not None - and yref_to_secondary_y.get(obj.yref, None) != secondary_y - ): - continue + def _filter_col(obj): + """ Filter objects in columns by row """ + return (row is None) or (yref_to_row.get(obj.yref, None) == row) - # Filter by selector - if not self._selector_matches(obj, selector): - continue + def _filter_sec_y(obj): + """ Filter objects on secondary y axes """ + return (secondary_y is None) or ( + yref_to_secondary_y.get(obj.yref, None) == secondary_y + ) - yield obj + def _filter_selector_matches(obj): + """ Filter objects for which selector matches """ + return self._selector_matches(obj, selector) + + funcs = [_filter_row, _filter_col, _filter_sec_y] + # If selector is not an int, we use the _filter_selector_matches to + # filter out items + if type(selector) != type(int()): + # append selector as filter function + funcs += [_filter_selector_matches] + + def _reducer(last, f): + # takes list of objects that has been filtered down up to now (last) + # and applies the next filter function (f) to filter it down further. + return filter(lambda o: f(o), last) + + # filtered_objs is a sequence of objects filtered by the above functions + filtered_objs = reduce(_reducer, funcs, self.layout[prop]) + # If selector is an integer, use it as an index into the sequence of + # filtered objects. Note in this case we do not call _filter_selector_matches. + if type(selector) == type(int()): + # wrap in iter because this function should always return an iterator + return iter([list(filtered_objs)[selector]]) + return filtered_objs def _add_annotation_like( self, From 9762086bf4fbbbe1360bd63ba305c46e9a077436 Mon Sep 17 00:00:00 2001 From: Nicholas Esterer Date: Wed, 11 Nov 2020 16:25:18 -0500 Subject: [PATCH 02/11] traces can be selected with index or string if selector is string, it is converted to dict(type=selector) --- .../python/plotly/plotly/basedatatypes.py | 75 ++++++++++--------- 1 file changed, 40 insertions(+), 35 deletions(-) diff --git a/packages/python/plotly/plotly/basedatatypes.py b/packages/python/plotly/plotly/basedatatypes.py index 185aaa00f64..27ac2e7378d 100644 --- a/packages/python/plotly/plotly/basedatatypes.py +++ b/packages/python/plotly/plotly/basedatatypes.py @@ -1177,18 +1177,16 @@ def select_traces(self, selector=None, row=None, col=None, secondary_y=None): def _perform_select_traces(self, filter_by_subplot, grid_subplot_refs, selector): from plotly.subplots import _get_subplot_ref_for_trace - for trace in self.data: - # Filter by subplot - if filter_by_subplot: - trace_subplot_ref = _get_subplot_ref_for_trace(trace) - if trace_subplot_ref not in grid_subplot_refs: - continue + # functions for filtering + def _filter_by_subplot_ref(trace): + trace_subplot_ref = _get_subplot_ref_for_trace(trace) + return trace_subplot_ref in grid_subplot_refs - # Filter by selector - if not self._selector_matches(trace, selector): - continue + funcs = [] + if filter_by_subplot: + funcs.append(_filter_by_subplot_ref) - yield trace + return self._filter_by_selector(self.data, funcs, selector) @staticmethod def _selector_matches(obj, selector): @@ -1214,8 +1212,8 @@ def _selector_matches(obj, selector): if isinstance(selector_val, BasePlotlyType): selector_val = selector_val.to_plotly_json() - if obj_val != selector_val: - return False + return obj_val == selector_val + return True # If selector is a function, call it with the obj as the argument elif type(selector) == type(lambda x: True): @@ -1226,6 +1224,34 @@ def _selector_matches(obj, selector): "accepting a graph object returning a boolean." ) + def _filter_by_selector(self, objects, funcs, selector): + """ + objects is a sequence of objects, funcs a list of functions that + return True if the object should be included in the selection and False + otherwise and selector is an argument to the self._selector_matches + function. + If selector is an integer, the resulting sequence obtained after + sucessively filtering by each function in funcs is indexed by this + integer. + Otherwise selector is used as the selector argument to + self._selector_matches which is used to filter down the sequence. + The function returns the sequence (an iterator). + """ + + # if selector is not an int, we call it on each trace to test it for selection + if type(selector) != type(int()): + funcs.append(lambda obj: self._selector_matches(obj, selector)) + + def _filt(last, f): + return filter(f, last) + + filtered_objects = reduce(_filt, funcs, objects) + + if type(selector) == type(int()): + return iter([list(filtered_objects)[selector]]) + + return filtered_objects + def for_each_trace(self, fn, selector=None, row=None, col=None, secondary_y=None): """ Apply a function to all traces that satisfy the specified selection @@ -1470,30 +1496,9 @@ def _filter_sec_y(obj): yref_to_secondary_y.get(obj.yref, None) == secondary_y ) - def _filter_selector_matches(obj): - """ Filter objects for which selector matches """ - return self._selector_matches(obj, selector) - funcs = [_filter_row, _filter_col, _filter_sec_y] - # If selector is not an int, we use the _filter_selector_matches to - # filter out items - if type(selector) != type(int()): - # append selector as filter function - funcs += [_filter_selector_matches] - - def _reducer(last, f): - # takes list of objects that has been filtered down up to now (last) - # and applies the next filter function (f) to filter it down further. - return filter(lambda o: f(o), last) - - # filtered_objs is a sequence of objects filtered by the above functions - filtered_objs = reduce(_reducer, funcs, self.layout[prop]) - # If selector is an integer, use it as an index into the sequence of - # filtered objects. Note in this case we do not call _filter_selector_matches. - if type(selector) == type(int()): - # wrap in iter because this function should always return an iterator - return iter([list(filtered_objs)[selector]]) - return filtered_objs + + return self._filter_by_selector(self.layout[prop], funcs, selector) def _add_annotation_like( self, From 00bf9ac99b294e88924570761598d7f27f096f3d Mon Sep 17 00:00:00 2001 From: Nicholas Esterer Date: Wed, 11 Nov 2020 17:05:20 -0500 Subject: [PATCH 03/11] select_* methods now accept integer or string selector e.g., select_xaxes uses this selector note: need to test new selector argument that is integer or string --- .../python/plotly/plotly/basedatatypes.py | 50 +++++++------------ 1 file changed, 19 insertions(+), 31 deletions(-) diff --git a/packages/python/plotly/plotly/basedatatypes.py b/packages/python/plotly/plotly/basedatatypes.py index 27ac2e7378d..ac64d3a55cb 100644 --- a/packages/python/plotly/plotly/basedatatypes.py +++ b/packages/python/plotly/plotly/basedatatypes.py @@ -1421,37 +1421,25 @@ def _select_layout_subplots_by_prefix( else: container_to_row_col = None - # Natural sort keys so that xaxis20 is after xaxis3 - layout_keys = _natural_sort_strings(list(self.layout)) - - for k in layout_keys: - if k.startswith(prefix) and self.layout[k] is not None: - - # Filter by row/col - if ( - row is not None - and container_to_row_col.get(k, (None, None, None))[0] != row - ): - # row specified and this is not a match - continue - elif ( - col is not None - and container_to_row_col.get(k, (None, None, None))[1] != col - ): - # col specified and this is not a match - continue - elif ( - secondary_y is not None - and container_to_row_col.get(k, (None, None, None))[2] - != secondary_y - ): - continue - - # Filter by selector - if not self._selector_matches(self.layout[k], selector): - continue - - yield self.layout[k] + layout_keys_filters = [ + lambda k: k.startswith(prefix) and self.layout[k] is not None, + lambda k: row is None + or container_to_row_col.get(k, (None, None, None))[0] == row, + lambda k: col is None + or container_to_row_col.get(k, (None, None, None))[1] == col, + lambda k: ( + secondary_y is None + or container_to_row_col.get(k, (None, None, None))[2] == secondary_y + ), + ] + layout_keys = reduce( + lambda last, f: filter(f, last), + layout_keys_filters, + # Natural sort keys so that xaxis20 is after xaxis3 + _natural_sort_strings(list(self.layout)), + ) + layout_objs = [self.layout[k] for k in layout_keys] + return self._filter_by_selector(layout_objs, [], selector) def _select_annotations_like( self, prop, selector=None, row=None, col=None, secondary_y=None From 4d199945acd01050f3ed47e2b2f34fd4d9e9e044 Mon Sep 17 00:00:00 2001 From: Nicholas Esterer Date: Wed, 11 Nov 2020 17:29:56 -0500 Subject: [PATCH 04/11] Mistake returning early from BaseFigure._selector_matches --- packages/python/plotly/plotly/basedatatypes.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/python/plotly/plotly/basedatatypes.py b/packages/python/plotly/plotly/basedatatypes.py index ac64d3a55cb..50105c2c1cf 100644 --- a/packages/python/plotly/plotly/basedatatypes.py +++ b/packages/python/plotly/plotly/basedatatypes.py @@ -1212,8 +1212,8 @@ def _selector_matches(obj, selector): if isinstance(selector_val, BasePlotlyType): selector_val = selector_val.to_plotly_json() - return obj_val == selector_val - + if obj_val != selector_val: + return False return True # If selector is a function, call it with the obj as the argument elif type(selector) == type(lambda x: True): From 8ca6ee3d5fbe8c6ba3682539077907e41e9debdd Mon Sep 17 00:00:00 2001 From: Nicholas Esterer Date: Wed, 11 Nov 2020 17:59:09 -0500 Subject: [PATCH 05/11] Cast the returned iterators to generators --- packages/python/plotly/plotly/basedatatypes.py | 12 +++++++++--- .../test_update_objects/test_selector_matches.py | 5 +++++ .../test_update_objects/test_update_traces.py | 2 +- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/packages/python/plotly/plotly/basedatatypes.py b/packages/python/plotly/plotly/basedatatypes.py index 50105c2c1cf..aa5d980cb42 100644 --- a/packages/python/plotly/plotly/basedatatypes.py +++ b/packages/python/plotly/plotly/basedatatypes.py @@ -382,6 +382,12 @@ def _axis_spanning_shapes_docstr(shape_type): return docstr +def _generator(i): + """ "cast" an iterator to a generator """ + while True: + yield next(i) + + class BaseFigure(object): """ Base class for all figure types (both widget and non-widget) @@ -1186,7 +1192,7 @@ def _filter_by_subplot_ref(trace): if filter_by_subplot: funcs.append(_filter_by_subplot_ref) - return self._filter_by_selector(self.data, funcs, selector) + return _generator(self._filter_by_selector(self.data, funcs, selector)) @staticmethod def _selector_matches(obj, selector): @@ -1439,7 +1445,7 @@ def _select_layout_subplots_by_prefix( _natural_sort_strings(list(self.layout)), ) layout_objs = [self.layout[k] for k in layout_keys] - return self._filter_by_selector(layout_objs, [], selector) + return _generator(self._filter_by_selector(layout_objs, [], selector)) def _select_annotations_like( self, prop, selector=None, row=None, col=None, secondary_y=None @@ -1486,7 +1492,7 @@ def _filter_sec_y(obj): funcs = [_filter_row, _filter_col, _filter_sec_y] - return self._filter_by_selector(self.layout[prop], funcs, selector) + return _generator(self._filter_by_selector(self.layout[prop], funcs, selector)) def _add_annotation_like( self, diff --git a/packages/python/plotly/plotly/tests/test_core/test_update_objects/test_selector_matches.py b/packages/python/plotly/plotly/tests/test_core/test_update_objects/test_selector_matches.py index 138d0b48921..d04d13cf987 100644 --- a/packages/python/plotly/plotly/tests/test_core/test_update_objects/test_selector_matches.py +++ b/packages/python/plotly/plotly/tests/test_core/test_update_objects/test_selector_matches.py @@ -89,3 +89,8 @@ def _sel(d): return d["x"] == 1 and d["y"] == 3 and d["text"] == "pat metheny" assert BaseFigure._selector_matches(obj, _sel) == False + + +def test_string_selector_matches_type_key(): + assert BaseFigure._selector_matches(dict(type="bar"), "bar") + assert BaseFigure._selector_matches(dict(type="scatter"), "bar") == False diff --git a/packages/python/plotly/plotly/tests/test_core/test_update_objects/test_update_traces.py b/packages/python/plotly/plotly/tests/test_core/test_update_objects/test_update_traces.py index ccfe50382e0..f3d6b80185d 100644 --- a/packages/python/plotly/plotly/tests/test_core/test_update_objects/test_update_traces.py +++ b/packages/python/plotly/plotly/tests/test_core/test_update_objects/test_update_traces.py @@ -260,7 +260,7 @@ def f(t): def test_select_traces_type_error(self): with self.assertRaises(TypeError): - self.assert_select_traces([0], selector=123, row=1, col=1) + self.assert_select_traces([0], selector=123.456, row=1, col=1) def test_for_each_trace_lowercase_names(self): # Names are all uppercase to start From 08e29a07a02187f4ab8986e89d0f92104de131d1 Mon Sep 17 00:00:00 2001 From: Nicholas Esterer Date: Wed, 11 Nov 2020 18:24:27 -0500 Subject: [PATCH 06/11] added tests for selecting traces using string or index --- .../test_update_objects/test_update_traces.py | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/packages/python/plotly/plotly/tests/test_core/test_update_objects/test_update_traces.py b/packages/python/plotly/plotly/tests/test_core/test_update_objects/test_update_traces.py index f3d6b80185d..1e6c64df44f 100644 --- a/packages/python/plotly/plotly/tests/test_core/test_update_objects/test_update_traces.py +++ b/packages/python/plotly/plotly/tests/test_core/test_update_objects/test_update_traces.py @@ -2,9 +2,11 @@ from unittest import TestCase import inspect import copy +import pytest import plotly.graph_objs as go from plotly.subplots import make_subplots +from functools import reduce class TestSelectForEachUpdateTraces(TestCase): @@ -414,3 +416,60 @@ def test_update_traces_overwrite(self): {"type": "bar", "marker": {"line": {"width": 10}}}, ], ) + + +@pytest.fixture +def select_traces_fixture(): + fig = make_subplots(2, 3) + for n in range(3): + fig.add_trace(go.Scatter(x=[1, 2], y=[3, n]), row=2, col=3) + for n, ty in zip(range(3), [go.Scatter, go.Bar, go.Bar]): + fig.add_trace(ty(x=[1, 2], y=[3, 10 * n]), row=1, col=3) + return fig + + +def test_select_traces_integer(select_traces_fixture): + fig = select_traces_fixture + # check we can index last trace selected + tr = list(fig.select_traces(selector=-1))[0] + assert tr.y[1] == 20 + # check we can index last trace selected in a row and column + tr = list(fig.select_traces(selector=-1, row=2, col=3))[0] + assert tr.y[1] == 2 + # check that indexing out of bounds raises IndexError + with pytest.raises(IndexError): + tr = list(fig.select_traces(selector=6))[0] + + +def test_select_traces_string(select_traces_fixture): + fig = select_traces_fixture + # check we can select traces by type simply by passing a string to selector + trs = list(fig.select_traces(selector="bar")) + assert len(trs) == 2 and reduce( + lambda last, cur: last + and (cur[0]["type"] == "bar") + and (cur[0]["y"][1] == cur[1]), + zip(trs, [10, 20]), + True, + ) + # check we can select traces by type regardless of the subplots they are on + trs = list(fig.select_traces(selector="scatter")) + assert len(trs) == 4 and reduce( + lambda last, cur: last + and (cur[0]["type"] == "scatter") + and (cur[0]["y"][1] == cur[1]), + zip(trs, [0, 1, 2, 0]), + True, + ) + # check that we can select traces by type but only on a specific subplot + trs = list(fig.select_traces(row=2, col=3, selector="scatter")) + assert len(trs) == 3 and reduce( + lambda last, cur: last + and (cur[0]["type"] == "scatter") + and (cur[0]["y"][1] == cur[1]), + zip(trs, [0, 1, 2]), + True, + ) + # check that if selector matches no trace types then no traces are returned + trs = list(fig.select_traces(selector="bogus")) + assert len(trs) == 0 From d4302cc8de0f4ccd8575a2a3d2eea53b9e744d78 Mon Sep 17 00:00:00 2001 From: Nicholas Esterer Date: Thu, 12 Nov 2020 11:55:48 -0500 Subject: [PATCH 07/11] better cast to generator --- packages/python/plotly/plotly/basedatatypes.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/python/plotly/plotly/basedatatypes.py b/packages/python/plotly/plotly/basedatatypes.py index aa5d980cb42..275903200f5 100644 --- a/packages/python/plotly/plotly/basedatatypes.py +++ b/packages/python/plotly/plotly/basedatatypes.py @@ -384,8 +384,8 @@ def _axis_spanning_shapes_docstr(shape_type): def _generator(i): """ "cast" an iterator to a generator """ - while True: - yield next(i) + for x in i: + yield x class BaseFigure(object): From 9fae7a46a44c6b1007273a454790380d36732aee Mon Sep 17 00:00:00 2001 From: Nicholas Esterer Date: Thu, 12 Nov 2020 12:24:13 -0500 Subject: [PATCH 08/11] tests for selecting annotation-like objects with integer string doesn't make sense in this case as they don't have a "type" key. --- .../test_update_annotations.py | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/packages/python/plotly/plotly/tests/test_core/test_update_objects/test_update_annotations.py b/packages/python/plotly/plotly/tests/test_core/test_update_objects/test_update_annotations.py index e7ac974d68a..bd3cd59878d 100644 --- a/packages/python/plotly/plotly/tests/test_core/test_update_objects/test_update_annotations.py +++ b/packages/python/plotly/plotly/tests/test_core/test_update_objects/test_update_annotations.py @@ -5,6 +5,7 @@ import plotly.graph_objs as go from plotly.subplots import make_subplots +import pytest class TestSelectForEachUpdateAnnotations(TestCase): @@ -348,3 +349,26 @@ def test_no_exclude_empty_subplots(): assert fig.layout[k][1]["xref"] == "x2" and fig.layout[k][1]["yref"] == "y2" assert fig.layout[k][2]["xref"] == "x3" and fig.layout[k][2]["yref"] == "y3" assert fig.layout[k][3]["xref"] == "x4" and fig.layout[k][3]["yref"] == "y4" + + +@pytest.fixture +def select_annotations_integer(): + fig = make_subplots(2, 3) + fig.add_annotation(row=1, col=2, text="B") + fig.add_annotation(row=2, col=2, text="A") + fig.add_annotation(row=2, col=2, text="B") + fig.add_annotation(row=2, col=2, text="AB") + fig.add_annotation(text="hello") + return fig + + +def test_select_annotations_integer(select_annotations_integer): + fig = select_annotations_integer + anns = list(fig.select_annotations(selector=-1)) + assert (len(anns) == 1) and (anns[0]["text"] == "hello") + anns = list(fig.select_annotations(row=2, col=2, selector=-1)) + assert (len(anns) == 1) and anns[0]["text"] == "AB" + anns = list(fig.select_annotations(row=1, col=2, selector=-1)) + assert (len(anns) == 1) and anns[0]["text"] == "B" + with pytest.raises(IndexError): + fig.select_annotations(row=2, col=2, selector=3) From a802f9d17b4b226a044b04629f31431b6b26f812 Mon Sep 17 00:00:00 2001 From: Nicholas Esterer Date: Thu, 12 Nov 2020 12:58:42 -0500 Subject: [PATCH 09/11] Integer selector tested on select_* elements over subplots e.g., select_xaxes --- .../test_update_subplots.py | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/packages/python/plotly/plotly/tests/test_core/test_update_objects/test_update_subplots.py b/packages/python/plotly/plotly/tests/test_core/test_update_objects/test_update_subplots.py index 14a4758b102..8fd76120f6f 100644 --- a/packages/python/plotly/plotly/tests/test_core/test_update_objects/test_update_subplots.py +++ b/packages/python/plotly/plotly/tests/test_core/test_update_objects/test_update_subplots.py @@ -152,6 +152,10 @@ def test_select_by_type_and_selector(self): "xaxis", "xaxes", [], selector={"title.text": "C"}, test_no_grid=True ) + self.assert_select_subplots( + "xaxis", "xaxes", [4], selector=-1, test_no_grid=True + ) + # yaxis self.assert_select_subplots( "yaxis", "yaxes", [1, 3], selector={"title.text": "A"}, test_no_grid=True @@ -165,6 +169,14 @@ def test_select_by_type_and_selector(self): "yaxis", "yaxes", [], selector={"title.text": "C"}, test_no_grid=True ) + self.assert_select_subplots( + "yaxis", "yaxes", [5], selector=-1, test_no_grid=True + ) + + self.assert_select_subplots( + "yaxis", "yaxes", [2], selector=1, test_no_grid=True + ) + # scene self.assert_select_subplots( "scene", @@ -190,6 +202,10 @@ def test_select_by_type_and_selector(self): test_no_grid=True, ) + self.assert_select_subplots( + "scene", "scenes", [1], selector=0, test_no_grid=True + ) + # polar self.assert_select_subplots( "polar", @@ -215,6 +231,10 @@ def test_select_by_type_and_selector(self): test_no_grid=True, ) + self.assert_select_subplots( + "polar", "polars", [2], selector=-1, test_no_grid=True + ) + # ternary self.assert_select_subplots( "ternary", @@ -240,6 +260,10 @@ def test_select_by_type_and_selector(self): test_no_grid=True, ) + self.assert_select_subplots( + "ternary", "ternaries", [1], selector=-1, test_no_grid=True + ) + # No 'geo' or 'mapbox' subplots initialized, but the first subplot # object is always present self.assert_select_subplots( @@ -272,6 +296,8 @@ def test_select_by_type_and_grid_and_selector(self): "xaxis", "xaxes", [3, 4], col=1, selector={"title.text": "B"} ) + self.assert_select_subplots("xaxis", "xaxes", [4], col=1, selector=-1) + self.assert_select_subplots( "xaxis", "xaxes", [3], row=2, selector={"title.text": "B"} ) @@ -285,6 +311,10 @@ def test_select_by_type_and_grid_and_selector(self): "yaxis", "yaxes", [1, 3], col=1, selector={"title.text": "A"} ) + self.assert_select_subplots("yaxis", "yaxes", [5], col=1, selector=-1) + + self.assert_select_subplots("yaxis", "yaxes", [1], col=1, selector=0) + self.assert_select_subplots( "yaxis", "yaxes", [4], col=1, selector={"title.text": "B"} ) @@ -294,6 +324,8 @@ def test_select_by_type_and_grid_and_selector(self): "polar", "polars", [1, 2], row=2, selector={"angularaxis.rotation": 45} ) + self.assert_select_subplots("polar", "polars", [2], row=2, selector=-1) + self.assert_select_subplots( "polar", "polars", [1], col=2, selector={"angularaxis.rotation": 45} ) From e33e10b0ead08d57840182dd9d5d122dd7b42e8d Mon Sep 17 00:00:00 2001 From: Nicolas Kruchten Date: Wed, 18 Nov 2020 15:23:28 -0500 Subject: [PATCH 10/11] docstring --- packages/python/plotly/codegen/figure.py | 34 +++--- .../python/plotly/plotly/basedatatypes.py | 18 ++- .../plotly/plotly/graph_objs/_figure.py | 106 ++++++++++-------- .../plotly/plotly/graph_objs/_figurewidget.py | 106 ++++++++++-------- 4 files changed, 156 insertions(+), 108 deletions(-) diff --git a/packages/python/plotly/codegen/figure.py b/packages/python/plotly/codegen/figure.py index 42a964d2ec9..e94ac554449 100644 --- a/packages/python/plotly/codegen/figure.py +++ b/packages/python/plotly/codegen/figure.py @@ -89,18 +89,18 @@ def __init__(self, data=None, layout=None, frames=None, skip_invalid=False, **kwargs): \"\"\" Create a new :class:{fig_classname} instance - + Parameters ---------- data {data_description} - + layout {layout_description} - + frames {frames_description} - + skip_invalid: bool If True, invalid properties in the figure specification will be skipped silently. If False (default) invalid properties in the @@ -233,8 +233,8 @@ def add_{trace_node.plotly_name}(self""" * If False, only select yaxis objects associated with the primary y-axis of the subplot. * If None (the default), do not filter yaxis objects based on - a secondary y-axis condition. - + a secondary y-axis condition. + To select yaxis objects by secondary y-axis, the Figure must have been created using plotly.subplots.make_subplots. See the docstring for the specs argument to make_subplots for more @@ -287,7 +287,7 @@ def for_each_{singular_name}( \"\"\" Apply a function to all {singular_name} objects that satisfy the specified selection criteria - + Parameters ---------- fn: @@ -329,7 +329,7 @@ def update_{plural_name}( \"\"\" Perform a property update operation on all {singular_name} objects that satisfy the specified selection criteria - + Parameters ---------- patch: dict @@ -395,7 +395,7 @@ def select_{method_prefix}{plural_name}( Parameters ---------- - selector: dict, function, or None (default None) + selector: dict, function, int, str, or None (default None) Dict to use as selection criteria. Annotations will be selected if they contain properties corresponding to all of the dictionary's keys, with values that exactly match @@ -403,7 +403,9 @@ def select_{method_prefix}{plural_name}( selected. If a function, it must be a function accepting a single argument and returning a boolean. The function will be called on each {singular_name} and those for which the function returned True - will be in the selection. + will be in the selection. If an int N, the Nth {singular_name} matching row + and col will be selected (N can be negative). If a string S, the selector + is equivalent to dict(type=S). row, col: int or None (default None) Subplot row and column index of {plural_name} to select. To select {plural_name} by row and column, the Figure must have been @@ -443,7 +445,7 @@ def for_each_{method_prefix}{singular_name}( ---------- fn: Function that inputs a single {singular_name} object. - selector: dict, function, or None (default None) + selector: dict, function, int, str or None (default None) Dict to use as selection criteria. Traces will be selected if they contain properties corresponding to all of the dictionary's keys, with values that exactly match @@ -451,7 +453,9 @@ def for_each_{method_prefix}{singular_name}( selected. If a function, it must be a function accepting a single argument and returning a boolean. The function will be called on each {singular_name} and those for which the function returned True - will be in the selection. + will be in the selection. If an int N, the Nth {singular_name} matching row + and col will be selected (N can be negative). If a string S, the selector + is equivalent to dict(type=S). row, col: int or None (default None) Subplot row and column index of {plural_name} to select. To select {plural_name} by row and column, the Figure must have been @@ -504,7 +508,7 @@ def update_{method_prefix}{plural_name}( patch: dict or None (default None) Dictionary of property updates to be applied to all {plural_name} that satisfy the selection criteria. - selector: dict, function, or None (default None) + selector: dict, function, int, str or None (default None) Dict to use as selection criteria. Traces will be selected if they contain properties corresponding to all of the dictionary's keys, with values that exactly match @@ -512,7 +516,9 @@ def update_{method_prefix}{plural_name}( selected. If a function, it must be a function accepting a single argument and returning a boolean. The function will be called on each {singular_name} and those for which the function returned True - will be in the selection. + will be in the selection. If an int N, the Nth {singular_name} matching row + and col will be selected (N can be negative). If a string S, the selector + is equivalent to dict(type=S). row, col: int or None (default None) Subplot row and column index of {plural_name} to select. To select {plural_name} by row and column, the Figure must have been diff --git a/packages/python/plotly/plotly/basedatatypes.py b/packages/python/plotly/plotly/basedatatypes.py index 275903200f5..f9112a9e916 100644 --- a/packages/python/plotly/plotly/basedatatypes.py +++ b/packages/python/plotly/plotly/basedatatypes.py @@ -1107,7 +1107,7 @@ def select_traces(self, selector=None, row=None, col=None, secondary_y=None): Parameters ---------- - selector: dict, function, or None (default None) + selector: dict, function, int, str or None (default None) Dict to use as selection criteria. Traces will be selected if they contain properties corresponding to all of the dictionary's keys, with values that exactly match @@ -1115,7 +1115,9 @@ def select_traces(self, selector=None, row=None, col=None, secondary_y=None): selected. If a function, it must be a function accepting a single argument and returning a boolean. The function will be called on each trace and those for which the function returned True - will be in the selection. + will be in the selection. If an int N, the Nth trace matching row + and col will be selected (N can be negative). If a string S, the selector + is equivalent to dict(type=S). row, col: int or None (default None) Subplot row and column index of traces to select. To select traces by row and column, the Figure must have been @@ -1267,7 +1269,7 @@ def for_each_trace(self, fn, selector=None, row=None, col=None, secondary_y=None ---------- fn: Function that inputs a single trace object. - selector: dict, function, or None (default None) + selector: dict, function, int, str or None (default None) Dict to use as selection criteria. Traces will be selected if they contain properties corresponding to all of the dictionary's keys, with values that exactly match @@ -1275,7 +1277,9 @@ def for_each_trace(self, fn, selector=None, row=None, col=None, secondary_y=None selected. If a function, it must be a function accepting a single argument and returning a boolean. The function will be called on each trace and those for which the function returned True - will be in the selection. + will be in the selection. If an int N, the Nth trace matching row + and col will be selected (N can be negative). If a string S, the selector + is equivalent to dict(type=S). row, col: int or None (default None) Subplot row and column index of traces to select. To select traces by row and column, the Figure must have been @@ -1324,7 +1328,7 @@ def update_traces( patch: dict or None (default None) Dictionary of property updates to be applied to all traces that satisfy the selection criteria. - selector: dict, function, or None (default None) + selector: dict, function, int, str or None (default None) Dict to use as selection criteria. Traces will be selected if they contain properties corresponding to all of the dictionary's keys, with values that exactly match @@ -1332,7 +1336,9 @@ def update_traces( selected. If a function, it must be a function accepting a single argument and returning a boolean. The function will be called on each trace and those for which the function returned True - will be in the selection. + will be in the selection. If an int N, the Nth trace matching row + and col will be selected (N can be negative). If a string S, the selector + is equivalent to dict(type=S). row, col: int or None (default None) Subplot row and column index of traces to select. To select traces by row and column, the Figure must have been diff --git a/packages/python/plotly/plotly/graph_objs/_figure.py b/packages/python/plotly/plotly/graph_objs/_figure.py index d9cf48be670..eda51ca99ed 100644 --- a/packages/python/plotly/plotly/graph_objs/_figure.py +++ b/packages/python/plotly/plotly/graph_objs/_figure.py @@ -7,7 +7,7 @@ def __init__( ): """ Create a new :class:Figure instance - + Parameters ---------- data @@ -39,7 +39,7 @@ def __init__( the specified trace type (e.g. [{'type': 'scatter', ...}, {'type': 'bar, ...}]) - + layout The 'layout' property is an instance of Layout that may be specified as: @@ -540,7 +540,7 @@ def __init__( yaxis :class:`plotly.graph_objects.layout.YAxis` instance or dict with compatible properties - + frames The 'frames' property is a tuple of instances of Frame that may be specified as: @@ -573,7 +573,7 @@ def __init__( traces A list of trace indices that identify the respective traces in the data attribute - + skip_invalid: bool If True, invalid properties in the figure specification will be skipped silently. If False (default) invalid properties in the @@ -17506,7 +17506,7 @@ def for_each_coloraxis(self, fn, selector=None, row=None, col=None): """ Apply a function to all coloraxis objects that satisfy the specified selection criteria - + Parameters ---------- fn: @@ -17542,7 +17542,7 @@ def update_coloraxes( """ Perform a property update operation on all coloraxis objects that satisfy the specified selection criteria - + Parameters ---------- patch: dict @@ -17618,7 +17618,7 @@ def for_each_geo(self, fn, selector=None, row=None, col=None): """ Apply a function to all geo objects that satisfy the specified selection criteria - + Parameters ---------- fn: @@ -17654,7 +17654,7 @@ def update_geos( """ Perform a property update operation on all geo objects that satisfy the specified selection criteria - + Parameters ---------- patch: dict @@ -17730,7 +17730,7 @@ def for_each_mapbox(self, fn, selector=None, row=None, col=None): """ Apply a function to all mapbox objects that satisfy the specified selection criteria - + Parameters ---------- fn: @@ -17766,7 +17766,7 @@ def update_mapboxes( """ Perform a property update operation on all mapbox objects that satisfy the specified selection criteria - + Parameters ---------- patch: dict @@ -17842,7 +17842,7 @@ def for_each_polar(self, fn, selector=None, row=None, col=None): """ Apply a function to all polar objects that satisfy the specified selection criteria - + Parameters ---------- fn: @@ -17878,7 +17878,7 @@ def update_polars( """ Perform a property update operation on all polar objects that satisfy the specified selection criteria - + Parameters ---------- patch: dict @@ -17954,7 +17954,7 @@ def for_each_scene(self, fn, selector=None, row=None, col=None): """ Apply a function to all scene objects that satisfy the specified selection criteria - + Parameters ---------- fn: @@ -17990,7 +17990,7 @@ def update_scenes( """ Perform a property update operation on all scene objects that satisfy the specified selection criteria - + Parameters ---------- patch: dict @@ -18066,7 +18066,7 @@ def for_each_ternary(self, fn, selector=None, row=None, col=None): """ Apply a function to all ternary objects that satisfy the specified selection criteria - + Parameters ---------- fn: @@ -18102,7 +18102,7 @@ def update_ternaries( """ Perform a property update operation on all ternary objects that satisfy the specified selection criteria - + Parameters ---------- patch: dict @@ -18178,7 +18178,7 @@ def for_each_xaxis(self, fn, selector=None, row=None, col=None): """ Apply a function to all xaxis objects that satisfy the specified selection criteria - + Parameters ---------- fn: @@ -18214,7 +18214,7 @@ def update_xaxes( """ Perform a property update operation on all xaxis objects that satisfy the specified selection criteria - + Parameters ---------- patch: dict @@ -18283,8 +18283,8 @@ def select_yaxes(self, selector=None, row=None, col=None, secondary_y=None): * If False, only select yaxis objects associated with the primary y-axis of the subplot. * If None (the default), do not filter yaxis objects based on - a secondary y-axis condition. - + a secondary y-axis condition. + To select yaxis objects by secondary y-axis, the Figure must have been created using plotly.subplots.make_subplots. See the docstring for the specs argument to make_subplots for more @@ -18304,7 +18304,7 @@ def for_each_yaxis(self, fn, selector=None, row=None, col=None, secondary_y=None """ Apply a function to all yaxis objects that satisfy the specified selection criteria - + Parameters ---------- fn: @@ -18330,8 +18330,8 @@ def for_each_yaxis(self, fn, selector=None, row=None, col=None, secondary_y=None * If False, only select yaxis objects associated with the primary y-axis of the subplot. * If None (the default), do not filter yaxis objects based on - a secondary y-axis condition. - + a secondary y-axis condition. + To select yaxis objects by secondary y-axis, the Figure must have been created using plotly.subplots.make_subplots. See the docstring for the specs argument to make_subplots for more @@ -18361,7 +18361,7 @@ def update_yaxes( """ Perform a property update operation on all yaxis objects that satisfy the specified selection criteria - + Parameters ---------- patch: dict @@ -18392,8 +18392,8 @@ def update_yaxes( * If False, only select yaxis objects associated with the primary y-axis of the subplot. * If None (the default), do not filter yaxis objects based on - a secondary y-axis condition. - + a secondary y-axis condition. + To select yaxis objects by secondary y-axis, the Figure must have been created using plotly.subplots.make_subplots. See the docstring for the specs argument to make_subplots for more @@ -18422,7 +18422,7 @@ def select_annotations(self, selector=None, row=None, col=None, secondary_y=None Parameters ---------- - selector: dict, function, or None (default None) + selector: dict, function, int, str, or None (default None) Dict to use as selection criteria. Annotations will be selected if they contain properties corresponding to all of the dictionary's keys, with values that exactly match @@ -18430,7 +18430,9 @@ def select_annotations(self, selector=None, row=None, col=None, secondary_y=None selected. If a function, it must be a function accepting a single argument and returning a boolean. The function will be called on each annotation and those for which the function returned True - will be in the selection. + will be in the selection. If an int N, the Nth annotation matching row + and col will be selected (N can be negative). If a string S, the selector + is equivalent to dict(type=S). row, col: int or None (default None) Subplot row and column index of annotations to select. To select annotations by row and column, the Figure must have been @@ -18470,7 +18472,7 @@ def for_each_annotation( ---------- fn: Function that inputs a single annotation object. - selector: dict, function, or None (default None) + selector: dict, function, int, str or None (default None) Dict to use as selection criteria. Traces will be selected if they contain properties corresponding to all of the dictionary's keys, with values that exactly match @@ -18478,7 +18480,9 @@ def for_each_annotation( selected. If a function, it must be a function accepting a single argument and returning a boolean. The function will be called on each annotation and those for which the function returned True - will be in the selection. + will be in the selection. If an int N, the Nth annotation matching row + and col will be selected (N can be negative). If a string S, the selector + is equivalent to dict(type=S). row, col: int or None (default None) Subplot row and column index of annotations to select. To select annotations by row and column, the Figure must have been @@ -18525,7 +18529,7 @@ def update_annotations( patch: dict or None (default None) Dictionary of property updates to be applied to all annotations that satisfy the selection criteria. - selector: dict, function, or None (default None) + selector: dict, function, int, str or None (default None) Dict to use as selection criteria. Traces will be selected if they contain properties corresponding to all of the dictionary's keys, with values that exactly match @@ -18533,7 +18537,9 @@ def update_annotations( selected. If a function, it must be a function accepting a single argument and returning a boolean. The function will be called on each annotation and those for which the function returned True - will be in the selection. + will be in the selection. If an int N, the Nth annotation matching row + and col will be selected (N can be negative). If a string S, the selector + is equivalent to dict(type=S). row, col: int or None (default None) Subplot row and column index of annotations to select. To select annotations by row and column, the Figure must have been @@ -18993,7 +18999,7 @@ def select_layout_images(self, selector=None, row=None, col=None, secondary_y=No Parameters ---------- - selector: dict, function, or None (default None) + selector: dict, function, int, str, or None (default None) Dict to use as selection criteria. Annotations will be selected if they contain properties corresponding to all of the dictionary's keys, with values that exactly match @@ -19001,7 +19007,9 @@ def select_layout_images(self, selector=None, row=None, col=None, secondary_y=No selected. If a function, it must be a function accepting a single argument and returning a boolean. The function will be called on each image and those for which the function returned True - will be in the selection. + will be in the selection. If an int N, the Nth image matching row + and col will be selected (N can be negative). If a string S, the selector + is equivalent to dict(type=S). row, col: int or None (default None) Subplot row and column index of images to select. To select images by row and column, the Figure must have been @@ -19041,7 +19049,7 @@ def for_each_layout_image( ---------- fn: Function that inputs a single image object. - selector: dict, function, or None (default None) + selector: dict, function, int, str or None (default None) Dict to use as selection criteria. Traces will be selected if they contain properties corresponding to all of the dictionary's keys, with values that exactly match @@ -19049,7 +19057,9 @@ def for_each_layout_image( selected. If a function, it must be a function accepting a single argument and returning a boolean. The function will be called on each image and those for which the function returned True - will be in the selection. + will be in the selection. If an int N, the Nth image matching row + and col will be selected (N can be negative). If a string S, the selector + is equivalent to dict(type=S). row, col: int or None (default None) Subplot row and column index of images to select. To select images by row and column, the Figure must have been @@ -19092,7 +19102,7 @@ def update_layout_images( patch: dict or None (default None) Dictionary of property updates to be applied to all images that satisfy the selection criteria. - selector: dict, function, or None (default None) + selector: dict, function, int, str or None (default None) Dict to use as selection criteria. Traces will be selected if they contain properties corresponding to all of the dictionary's keys, with values that exactly match @@ -19100,7 +19110,9 @@ def update_layout_images( selected. If a function, it must be a function accepting a single argument and returning a boolean. The function will be called on each image and those for which the function returned True - will be in the selection. + will be in the selection. If an int N, the Nth image matching row + and col will be selected (N can be negative). If a string S, the selector + is equivalent to dict(type=S). row, col: int or None (default None) Subplot row and column index of images to select. To select images by row and column, the Figure must have been @@ -19306,7 +19318,7 @@ def select_shapes(self, selector=None, row=None, col=None, secondary_y=None): Parameters ---------- - selector: dict, function, or None (default None) + selector: dict, function, int, str, or None (default None) Dict to use as selection criteria. Annotations will be selected if they contain properties corresponding to all of the dictionary's keys, with values that exactly match @@ -19314,7 +19326,9 @@ def select_shapes(self, selector=None, row=None, col=None, secondary_y=None): selected. If a function, it must be a function accepting a single argument and returning a boolean. The function will be called on each shape and those for which the function returned True - will be in the selection. + will be in the selection. If an int N, the Nth shape matching row + and col will be selected (N can be negative). If a string S, the selector + is equivalent to dict(type=S). row, col: int or None (default None) Subplot row and column index of shapes to select. To select shapes by row and column, the Figure must have been @@ -19352,7 +19366,7 @@ def for_each_shape(self, fn, selector=None, row=None, col=None, secondary_y=None ---------- fn: Function that inputs a single shape object. - selector: dict, function, or None (default None) + selector: dict, function, int, str or None (default None) Dict to use as selection criteria. Traces will be selected if they contain properties corresponding to all of the dictionary's keys, with values that exactly match @@ -19360,7 +19374,9 @@ def for_each_shape(self, fn, selector=None, row=None, col=None, secondary_y=None selected. If a function, it must be a function accepting a single argument and returning a boolean. The function will be called on each shape and those for which the function returned True - will be in the selection. + will be in the selection. If an int N, the Nth shape matching row + and col will be selected (N can be negative). If a string S, the selector + is equivalent to dict(type=S). row, col: int or None (default None) Subplot row and column index of shapes to select. To select shapes by row and column, the Figure must have been @@ -19403,7 +19419,7 @@ def update_shapes( patch: dict or None (default None) Dictionary of property updates to be applied to all shapes that satisfy the selection criteria. - selector: dict, function, or None (default None) + selector: dict, function, int, str or None (default None) Dict to use as selection criteria. Traces will be selected if they contain properties corresponding to all of the dictionary's keys, with values that exactly match @@ -19411,7 +19427,9 @@ def update_shapes( selected. If a function, it must be a function accepting a single argument and returning a boolean. The function will be called on each shape and those for which the function returned True - will be in the selection. + will be in the selection. If an int N, the Nth shape matching row + and col will be selected (N can be negative). If a string S, the selector + is equivalent to dict(type=S). row, col: int or None (default None) Subplot row and column index of shapes to select. To select shapes by row and column, the Figure must have been diff --git a/packages/python/plotly/plotly/graph_objs/_figurewidget.py b/packages/python/plotly/plotly/graph_objs/_figurewidget.py index d32e8b36e38..0004e72598d 100644 --- a/packages/python/plotly/plotly/graph_objs/_figurewidget.py +++ b/packages/python/plotly/plotly/graph_objs/_figurewidget.py @@ -7,7 +7,7 @@ def __init__( ): """ Create a new :class:FigureWidget instance - + Parameters ---------- data @@ -39,7 +39,7 @@ def __init__( the specified trace type (e.g. [{'type': 'scatter', ...}, {'type': 'bar, ...}]) - + layout The 'layout' property is an instance of Layout that may be specified as: @@ -540,7 +540,7 @@ def __init__( yaxis :class:`plotly.graph_objects.layout.YAxis` instance or dict with compatible properties - + frames The 'frames' property is a tuple of instances of Frame that may be specified as: @@ -573,7 +573,7 @@ def __init__( traces A list of trace indices that identify the respective traces in the data attribute - + skip_invalid: bool If True, invalid properties in the figure specification will be skipped silently. If False (default) invalid properties in the @@ -17506,7 +17506,7 @@ def for_each_coloraxis(self, fn, selector=None, row=None, col=None): """ Apply a function to all coloraxis objects that satisfy the specified selection criteria - + Parameters ---------- fn: @@ -17542,7 +17542,7 @@ def update_coloraxes( """ Perform a property update operation on all coloraxis objects that satisfy the specified selection criteria - + Parameters ---------- patch: dict @@ -17618,7 +17618,7 @@ def for_each_geo(self, fn, selector=None, row=None, col=None): """ Apply a function to all geo objects that satisfy the specified selection criteria - + Parameters ---------- fn: @@ -17654,7 +17654,7 @@ def update_geos( """ Perform a property update operation on all geo objects that satisfy the specified selection criteria - + Parameters ---------- patch: dict @@ -17730,7 +17730,7 @@ def for_each_mapbox(self, fn, selector=None, row=None, col=None): """ Apply a function to all mapbox objects that satisfy the specified selection criteria - + Parameters ---------- fn: @@ -17766,7 +17766,7 @@ def update_mapboxes( """ Perform a property update operation on all mapbox objects that satisfy the specified selection criteria - + Parameters ---------- patch: dict @@ -17842,7 +17842,7 @@ def for_each_polar(self, fn, selector=None, row=None, col=None): """ Apply a function to all polar objects that satisfy the specified selection criteria - + Parameters ---------- fn: @@ -17878,7 +17878,7 @@ def update_polars( """ Perform a property update operation on all polar objects that satisfy the specified selection criteria - + Parameters ---------- patch: dict @@ -17954,7 +17954,7 @@ def for_each_scene(self, fn, selector=None, row=None, col=None): """ Apply a function to all scene objects that satisfy the specified selection criteria - + Parameters ---------- fn: @@ -17990,7 +17990,7 @@ def update_scenes( """ Perform a property update operation on all scene objects that satisfy the specified selection criteria - + Parameters ---------- patch: dict @@ -18066,7 +18066,7 @@ def for_each_ternary(self, fn, selector=None, row=None, col=None): """ Apply a function to all ternary objects that satisfy the specified selection criteria - + Parameters ---------- fn: @@ -18102,7 +18102,7 @@ def update_ternaries( """ Perform a property update operation on all ternary objects that satisfy the specified selection criteria - + Parameters ---------- patch: dict @@ -18178,7 +18178,7 @@ def for_each_xaxis(self, fn, selector=None, row=None, col=None): """ Apply a function to all xaxis objects that satisfy the specified selection criteria - + Parameters ---------- fn: @@ -18214,7 +18214,7 @@ def update_xaxes( """ Perform a property update operation on all xaxis objects that satisfy the specified selection criteria - + Parameters ---------- patch: dict @@ -18283,8 +18283,8 @@ def select_yaxes(self, selector=None, row=None, col=None, secondary_y=None): * If False, only select yaxis objects associated with the primary y-axis of the subplot. * If None (the default), do not filter yaxis objects based on - a secondary y-axis condition. - + a secondary y-axis condition. + To select yaxis objects by secondary y-axis, the Figure must have been created using plotly.subplots.make_subplots. See the docstring for the specs argument to make_subplots for more @@ -18304,7 +18304,7 @@ def for_each_yaxis(self, fn, selector=None, row=None, col=None, secondary_y=None """ Apply a function to all yaxis objects that satisfy the specified selection criteria - + Parameters ---------- fn: @@ -18330,8 +18330,8 @@ def for_each_yaxis(self, fn, selector=None, row=None, col=None, secondary_y=None * If False, only select yaxis objects associated with the primary y-axis of the subplot. * If None (the default), do not filter yaxis objects based on - a secondary y-axis condition. - + a secondary y-axis condition. + To select yaxis objects by secondary y-axis, the Figure must have been created using plotly.subplots.make_subplots. See the docstring for the specs argument to make_subplots for more @@ -18361,7 +18361,7 @@ def update_yaxes( """ Perform a property update operation on all yaxis objects that satisfy the specified selection criteria - + Parameters ---------- patch: dict @@ -18392,8 +18392,8 @@ def update_yaxes( * If False, only select yaxis objects associated with the primary y-axis of the subplot. * If None (the default), do not filter yaxis objects based on - a secondary y-axis condition. - + a secondary y-axis condition. + To select yaxis objects by secondary y-axis, the Figure must have been created using plotly.subplots.make_subplots. See the docstring for the specs argument to make_subplots for more @@ -18422,7 +18422,7 @@ def select_annotations(self, selector=None, row=None, col=None, secondary_y=None Parameters ---------- - selector: dict, function, or None (default None) + selector: dict, function, int, str, or None (default None) Dict to use as selection criteria. Annotations will be selected if they contain properties corresponding to all of the dictionary's keys, with values that exactly match @@ -18430,7 +18430,9 @@ def select_annotations(self, selector=None, row=None, col=None, secondary_y=None selected. If a function, it must be a function accepting a single argument and returning a boolean. The function will be called on each annotation and those for which the function returned True - will be in the selection. + will be in the selection. If an int N, the Nth annotation matching row + and col will be selected (N can be negative). If a string S, the selector + is equivalent to dict(type=S). row, col: int or None (default None) Subplot row and column index of annotations to select. To select annotations by row and column, the Figure must have been @@ -18470,7 +18472,7 @@ def for_each_annotation( ---------- fn: Function that inputs a single annotation object. - selector: dict, function, or None (default None) + selector: dict, function, int, str or None (default None) Dict to use as selection criteria. Traces will be selected if they contain properties corresponding to all of the dictionary's keys, with values that exactly match @@ -18478,7 +18480,9 @@ def for_each_annotation( selected. If a function, it must be a function accepting a single argument and returning a boolean. The function will be called on each annotation and those for which the function returned True - will be in the selection. + will be in the selection. If an int N, the Nth annotation matching row + and col will be selected (N can be negative). If a string S, the selector + is equivalent to dict(type=S). row, col: int or None (default None) Subplot row and column index of annotations to select. To select annotations by row and column, the Figure must have been @@ -18525,7 +18529,7 @@ def update_annotations( patch: dict or None (default None) Dictionary of property updates to be applied to all annotations that satisfy the selection criteria. - selector: dict, function, or None (default None) + selector: dict, function, int, str or None (default None) Dict to use as selection criteria. Traces will be selected if they contain properties corresponding to all of the dictionary's keys, with values that exactly match @@ -18533,7 +18537,9 @@ def update_annotations( selected. If a function, it must be a function accepting a single argument and returning a boolean. The function will be called on each annotation and those for which the function returned True - will be in the selection. + will be in the selection. If an int N, the Nth annotation matching row + and col will be selected (N can be negative). If a string S, the selector + is equivalent to dict(type=S). row, col: int or None (default None) Subplot row and column index of annotations to select. To select annotations by row and column, the Figure must have been @@ -18993,7 +18999,7 @@ def select_layout_images(self, selector=None, row=None, col=None, secondary_y=No Parameters ---------- - selector: dict, function, or None (default None) + selector: dict, function, int, str, or None (default None) Dict to use as selection criteria. Annotations will be selected if they contain properties corresponding to all of the dictionary's keys, with values that exactly match @@ -19001,7 +19007,9 @@ def select_layout_images(self, selector=None, row=None, col=None, secondary_y=No selected. If a function, it must be a function accepting a single argument and returning a boolean. The function will be called on each image and those for which the function returned True - will be in the selection. + will be in the selection. If an int N, the Nth image matching row + and col will be selected (N can be negative). If a string S, the selector + is equivalent to dict(type=S). row, col: int or None (default None) Subplot row and column index of images to select. To select images by row and column, the Figure must have been @@ -19041,7 +19049,7 @@ def for_each_layout_image( ---------- fn: Function that inputs a single image object. - selector: dict, function, or None (default None) + selector: dict, function, int, str or None (default None) Dict to use as selection criteria. Traces will be selected if they contain properties corresponding to all of the dictionary's keys, with values that exactly match @@ -19049,7 +19057,9 @@ def for_each_layout_image( selected. If a function, it must be a function accepting a single argument and returning a boolean. The function will be called on each image and those for which the function returned True - will be in the selection. + will be in the selection. If an int N, the Nth image matching row + and col will be selected (N can be negative). If a string S, the selector + is equivalent to dict(type=S). row, col: int or None (default None) Subplot row and column index of images to select. To select images by row and column, the Figure must have been @@ -19092,7 +19102,7 @@ def update_layout_images( patch: dict or None (default None) Dictionary of property updates to be applied to all images that satisfy the selection criteria. - selector: dict, function, or None (default None) + selector: dict, function, int, str or None (default None) Dict to use as selection criteria. Traces will be selected if they contain properties corresponding to all of the dictionary's keys, with values that exactly match @@ -19100,7 +19110,9 @@ def update_layout_images( selected. If a function, it must be a function accepting a single argument and returning a boolean. The function will be called on each image and those for which the function returned True - will be in the selection. + will be in the selection. If an int N, the Nth image matching row + and col will be selected (N can be negative). If a string S, the selector + is equivalent to dict(type=S). row, col: int or None (default None) Subplot row and column index of images to select. To select images by row and column, the Figure must have been @@ -19306,7 +19318,7 @@ def select_shapes(self, selector=None, row=None, col=None, secondary_y=None): Parameters ---------- - selector: dict, function, or None (default None) + selector: dict, function, int, str, or None (default None) Dict to use as selection criteria. Annotations will be selected if they contain properties corresponding to all of the dictionary's keys, with values that exactly match @@ -19314,7 +19326,9 @@ def select_shapes(self, selector=None, row=None, col=None, secondary_y=None): selected. If a function, it must be a function accepting a single argument and returning a boolean. The function will be called on each shape and those for which the function returned True - will be in the selection. + will be in the selection. If an int N, the Nth shape matching row + and col will be selected (N can be negative). If a string S, the selector + is equivalent to dict(type=S). row, col: int or None (default None) Subplot row and column index of shapes to select. To select shapes by row and column, the Figure must have been @@ -19352,7 +19366,7 @@ def for_each_shape(self, fn, selector=None, row=None, col=None, secondary_y=None ---------- fn: Function that inputs a single shape object. - selector: dict, function, or None (default None) + selector: dict, function, int, str or None (default None) Dict to use as selection criteria. Traces will be selected if they contain properties corresponding to all of the dictionary's keys, with values that exactly match @@ -19360,7 +19374,9 @@ def for_each_shape(self, fn, selector=None, row=None, col=None, secondary_y=None selected. If a function, it must be a function accepting a single argument and returning a boolean. The function will be called on each shape and those for which the function returned True - will be in the selection. + will be in the selection. If an int N, the Nth shape matching row + and col will be selected (N can be negative). If a string S, the selector + is equivalent to dict(type=S). row, col: int or None (default None) Subplot row and column index of shapes to select. To select shapes by row and column, the Figure must have been @@ -19403,7 +19419,7 @@ def update_shapes( patch: dict or None (default None) Dictionary of property updates to be applied to all shapes that satisfy the selection criteria. - selector: dict, function, or None (default None) + selector: dict, function, int, str or None (default None) Dict to use as selection criteria. Traces will be selected if they contain properties corresponding to all of the dictionary's keys, with values that exactly match @@ -19411,7 +19427,9 @@ def update_shapes( selected. If a function, it must be a function accepting a single argument and returning a boolean. The function will be called on each shape and those for which the function returned True - will be in the selection. + will be in the selection. If an int N, the Nth shape matching row + and col will be selected (N can be negative). If a string S, the selector + is equivalent to dict(type=S). row, col: int or None (default None) Subplot row and column index of shapes to select. To select shapes by row and column, the Figure must have been From 9985b30d1bfaa1b7d5ebec1bf2d6a973f95b10eb Mon Sep 17 00:00:00 2001 From: Nicolas Kruchten Date: Wed, 18 Nov 2020 21:08:43 -0500 Subject: [PATCH 11/11] clean up flake8 errors --- .../python/plotly/plotly/basedatatypes.py | 29 ++++++++----------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/packages/python/plotly/plotly/basedatatypes.py b/packages/python/plotly/plotly/basedatatypes.py index f9112a9e916..5de2e4c23e5 100644 --- a/packages/python/plotly/plotly/basedatatypes.py +++ b/packages/python/plotly/plotly/basedatatypes.py @@ -177,7 +177,7 @@ def _check_path_in_prop_tree(obj, path, error_cast=None): an Exception object or None. The caller can raise this exception to see where the lookup error occurred. """ - if type(path) == type(tuple()): + if isinstance(path, tuple): path = _remake_path_from_tuple(path) prop, prop_idcs = _str_to_dict_path_full(path) prev_objs = [] @@ -242,7 +242,7 @@ def _check_path_in_prop_tree(obj, path, error_cast=None): # Make KeyError more pretty by changing it to a PlotlyKeyError, # because the Python interpreter has a special way of printing # KeyError - if type(e) == type(KeyError()): + if isinstance(e, KeyError): e = PlotlyKeyError() if error_cast is not None: e = error_cast() @@ -282,7 +282,7 @@ def _indexing_combinations(dims, alls, product=False): for d, a in zip(dims, alls): if d == "all": d = a - elif type(d) != type(list()): + elif not isinstance(d, list): d = [d] r.append(d) if product: @@ -293,7 +293,7 @@ def _indexing_combinations(dims, alls, product=False): def _is_select_subplot_coordinates_arg(*args): """ Returns true if any args are lists or the string 'all' """ - return any((a == "all") or (type(a) == type(list())) for a in args) + return any((a == "all") or isinstance(a, list) for a in args) def _axis_spanning_shapes_docstr(shape_type): @@ -1202,10 +1202,10 @@ def _selector_matches(obj, selector): return True # If selector is a string then put it at the 'type' key of a dictionary # to select objects where "type":selector - if type(selector) == type(str()): + if isinstance(selector, six.string_types): selector = dict(type=selector) # If selector is a dict, compare the fields - if (type(selector) == type(dict())) or isinstance(selector, BasePlotlyType): + if isinstance(selector, dict) or isinstance(selector, BasePlotlyType): # This returns True if selector is an empty dict for k in selector: if k not in obj: @@ -1224,7 +1224,7 @@ def _selector_matches(obj, selector): return False return True # If selector is a function, call it with the obj as the argument - elif type(selector) == type(lambda x: True): + elif six.callable(selector): return selector(obj) else: raise TypeError( @@ -1247,7 +1247,7 @@ def _filter_by_selector(self, objects, funcs, selector): """ # if selector is not an int, we call it on each trace to test it for selection - if type(selector) != type(int()): + if not isinstance(selector, int): funcs.append(lambda obj: self._selector_matches(obj, selector)) def _filt(last, f): @@ -1255,7 +1255,7 @@ def _filt(last, f): filtered_objects = reduce(_filt, funcs, objects) - if type(selector) == type(int()): + if isinstance(selector, int): return iter([list(filtered_objects)[selector]]) return filtered_objects @@ -3941,14 +3941,10 @@ def _make_axis_spanning_layout_object(self, direction, shape): """ if direction == "vertical": # fix y points to top and bottom of subplot - axis = "y" ref = "yref" - axis_layout_key_template = "yaxis%s" elif direction == "horizontal": # fix x points to left and right of subplot - axis = "x" ref = "xref" - axis_layout_key_template = "xaxis%s" else: raise ValueError( "Bad direction: %s. Permissible values are 'vertical' and 'horizontal'." @@ -4019,7 +4015,7 @@ def _process_multiple_axis_spanning_shapes( ): n_layout_objs_after = len(self.layout[layout_obj]) if (n_layout_objs_after > n_layout_objs_before) and ( - row == None and col == None + row is None and col is None ): # this was called intending to add to a single plot (and # self.add_{layout_obj} succeeded) @@ -4132,7 +4128,7 @@ def _subplot_not_empty(self, xref, yref, selector="all"): if not selector: # If nothing to select was specified then a subplot is always deemed non-empty return True - if selector == True: + if selector is True: selector = "all" if selector == "all": selector = ["traces", "shapes", "annotations", "images"] @@ -4302,7 +4298,6 @@ def _process_kwargs(self, **kwargs): """ Process any extra kwargs that are not predefined as constructor params """ - invalid_kwargs = {} for k, v in kwargs.items(): err = _check_path_in_prop_tree(self, k, error_cast=ValueError) if err is None: @@ -6277,7 +6272,7 @@ def _get_child_props(self, child): # ------------------------------------- try: trace_index = BaseFigure._index_is(self.data, child) - except ValueError as _: + except ValueError: trace_index = None # Child is a trace