diff --git a/ultraplot/constructor.py b/ultraplot/constructor.py index de7874c2f..3be503589 100644 --- a/ultraplot/constructor.py +++ b/ultraplot/constructor.py @@ -881,10 +881,10 @@ def _parse_basic_properties(self, kwargs): def _handle_empty_args(self, props, kwargs): """Handle case when no positional arguments are provided.""" - props.setdefault("color", "black") + props.setdefault("color", ["black"]) if kwargs: warnings._warn_ultraplot(f"Ignoring Cycle() keyword arg(s) {kwargs}.") - self._build_cycler(()) + self._build_cycler((props,)) def _handle_cycler_args(self, args, props, kwargs): """Handle case when arguments are cycler objects.""" @@ -928,13 +928,17 @@ def _build_cycler(self, dicts): props.setdefault(key, []).extend(value) # Build cycler with matching property lengths # Ensure at least a default color property exists - if not props: - props = {"color": ["black"]} - # Build cycler with matching property lengths lengths = [len(value) for value in props.values()] maxlen = np.lcm.reduce(lengths) - props = {key: value * (maxlen // len(value)) for key, value in props.items()} + props = { + key: value * (maxlen // len(value)) + for key, value in props.items() + if len(value) + } + # Set default color property if not present + if "color" not in props or not props: + props = {"color": ["black"]} mcycler = cycler.cycler(**props) super().__init__(mcycler) diff --git a/ultraplot/tests/test_constructor.py b/ultraplot/tests/test_constructor.py index 912437614..e017c0a9f 100644 --- a/ultraplot/tests/test_constructor.py +++ b/ultraplot/tests/test_constructor.py @@ -65,6 +65,10 @@ def test_not_allowed_keyword(): def test_cycler_edge_cases(): """Test edge cases and error conditions""" # Test with empty lists + cycle = uplt.Cycle() + assert cycle.get_next() == dict(color="black") # default fallback + cycle = uplt.Cycle(color=[]) + assert cycle.get_next() == dict(color="black") # default fallback cycle = uplt.Cycle(colors=[]) assert cycle.get_next() == dict(color="black") # default fallback @@ -74,6 +78,7 @@ def test_cycler_edge_cases(): props1 = cycle.get_next() props2 = cycle.get_next() assert props1["marker"] == props2["marker"] # marker should stay same + assert props1["color"] == "red" assert props1["color"] != props2["color"] # color should cycle @@ -108,3 +113,12 @@ def test_pass_on_cycle(): for color in colors: assert color == active_cycle.get_next()["color"] assert color == cycle.get_next()["color"] + + colors = ["red", "green", "black"] + cycle = uplt.Cycle(color=colors) + fig, ax = uplt.subplots() + ax.set_prop_cycle(cycle) + active_cycle = ax.axes._active_cycle + for color in colors: + assert color == active_cycle.get_next()["color"] + assert color == cycle.get_next()["color"]