@@ -1194,6 +1194,10 @@ def _perform_select_traces(self, filter_by_subplot, grid_subplot_refs, selector)
11941194 def _selector_matches (obj , selector ):
11951195 if selector is None :
11961196 return True
1197+ # If selector is a string then put it at the 'type' key of a dictionary
1198+ # to select objects where "type":selector
1199+ if type (selector ) == type (str ()):
1200+ selector = dict (type = selector )
11971201 # If selector is a dict, compare the fields
11981202 if (type (selector ) == type (dict ())) or isinstance (selector , BasePlotlyType ):
11991203 # This returns True if selector is an empty dict
@@ -1450,27 +1454,46 @@ def _select_annotations_like(
14501454 yref_to_row [yref ] = r + 1
14511455 yref_to_secondary_y [yref ] = is_secondary_y
14521456
1453- for obj in self .layout [prop ]:
1454- # Filter by row
1455- if col is not None and xref_to_col .get (obj .xref , None ) != col :
1456- continue
1457-
1458- # Filter by col
1459- if row is not None and yref_to_row .get (obj .yref , None ) != row :
1460- continue
1457+ # filter down (select) which graph objects, by applying the filters
1458+ # successively
1459+ def _filter_row (obj ):
1460+ """ Filter objects in rows by column """
1461+ return (col is None ) or (xref_to_col .get (obj .xref , None ) == col )
14611462
1462- # Filter by secondary y
1463- if (
1464- secondary_y is not None
1465- and yref_to_secondary_y .get (obj .yref , None ) != secondary_y
1466- ):
1467- continue
1463+ def _filter_col (obj ):
1464+ """ Filter objects in columns by row """
1465+ return (row is None ) or (yref_to_row .get (obj .yref , None ) == row )
14681466
1469- # Filter by selector
1470- if not self ._selector_matches (obj , selector ):
1471- continue
1467+ def _filter_sec_y (obj ):
1468+ """ Filter objects on secondary y axes """
1469+ return (secondary_y is None ) or (
1470+ yref_to_secondary_y .get (obj .yref , None ) == secondary_y
1471+ )
14721472
1473- yield obj
1473+ def _filter_selector_matches (obj ):
1474+ """ Filter objects for which selector matches """
1475+ return self ._selector_matches (obj , selector )
1476+
1477+ funcs = [_filter_row , _filter_col , _filter_sec_y ]
1478+ # If selector is not an int, we use the _filter_selector_matches to
1479+ # filter out items
1480+ if type (selector ) != type (int ()):
1481+ # append selector as filter function
1482+ funcs += [_filter_selector_matches ]
1483+
1484+ def _reducer (last , f ):
1485+ # takes list of objects that has been filtered down up to now (last)
1486+ # and applies the next filter function (f) to filter it down further.
1487+ return filter (lambda o : f (o ), last )
1488+
1489+ # filtered_objs is a sequence of objects filtered by the above functions
1490+ filtered_objs = reduce (_reducer , funcs , self .layout [prop ])
1491+ # If selector is an integer, use it as an index into the sequence of
1492+ # filtered objects. Note in this case we do not call _filter_selector_matches.
1493+ if type (selector ) == type (int ()):
1494+ # wrap in iter because this function should always return an iterator
1495+ return iter ([list (filtered_objs )[selector ]])
1496+ return filtered_objs
14741497
14751498 def _add_annotation_like (
14761499 self ,
0 commit comments