diff --git a/seaborn/_oldcore.py b/seaborn/_oldcore.py index 8821a5de3b..8afd10f0bd 100644 --- a/seaborn/_oldcore.py +++ b/seaborn/_oldcore.py @@ -55,6 +55,30 @@ def map(cls, plotter, *args, **kwargs): setattr(plotter, method_name, cls(plotter, *args, **kwargs)) return plotter + def _check_list_length(self, levels, values, variable): + """Input check when values are provided as a list.""" + # Copied from _core/properties; eventually will be replaced for that. + message = "" + if len(levels) > len(values): + message = " ".join([ + f"\nThe {variable} list has fewer values ({len(values)})", + f"than needed ({len(levels)}) and will cycle, which may", + "produce an uninterpretable plot." + ]) + values = [x for _, x in zip(levels, itertools.cycle(values))] + + elif len(values) > len(levels): + message = " ".join([ + f"The {variable} list has more values ({len(values)})", + f"than needed ({len(levels)}), which may not be intended.", + ]) + values = values[:len(levels)] + + if message: + warnings.warn(message, UserWarning, stacklevel=6) + + return values + def _lookup_single(self, key): """Apply the mapping to a single data value.""" return self.lookup_table[key] @@ -212,10 +236,7 @@ def categorical_mapping(self, data, palette, order): else: colors = color_palette("husl", n_colors) elif isinstance(palette, list): - if len(palette) != n_colors: - err = "The palette list has the wrong number of colors." - raise ValueError(err) - colors = palette + colors = self._check_list_length(levels, palette, "palette") else: colors = color_palette(palette, n_colors) @@ -367,10 +388,7 @@ def categorical_mapping(self, data, sizes, order): elif isinstance(sizes, list): # List inputs give size values in the same order as the levels - if len(sizes) != len(levels): - err = "The `sizes` list has the wrong number of values." - raise ValueError(err) - + sizes = self._check_list_length(levels, sizes, "sizes") lookup_table = dict(zip(levels, sizes)) else: @@ -578,9 +596,7 @@ def _map_attributes(self, arg, levels, defaults, attr): raise ValueError(err) lookup_table = arg elif isinstance(arg, Sequence): - if len(levels) != len(arg): - err = f"The `{attr}` argument has the wrong number of values" - raise ValueError(err) + arg = self._check_list_length(levels, arg, attr) lookup_table = dict(zip(levels, arg)) elif arg: err = f"This `{attr}` argument was not understood: {arg}" diff --git a/tests/test_axisgrid.py b/tests/test_axisgrid.py index 398f2d4a76..d0ac268907 100644 --- a/tests/test_axisgrid.py +++ b/tests/test_axisgrid.py @@ -1385,7 +1385,7 @@ def test_pairplot_markers(self): m2 = g._legend.legendHandles[1].get_paths()[0] assert m1 != m2 - with pytest.raises(ValueError): + with pytest.warns(UserWarning): g = ag.pairplot(self.df, hue="a", vars=vars, markers=markers[:-2]) def test_corner_despine(self): diff --git a/tests/test_core.py b/tests/test_core.py index a64d063784..20932de7c1 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -151,7 +151,7 @@ def test_hue_map_categorical(self, wide_df, long_df): # Test list with wrong number of colors palette = colors[:-1] - with pytest.raises(ValueError): + with pytest.warns(UserWarning): HueMapping(p, palette=palette) # Test hue order @@ -296,7 +296,7 @@ def test_hue_map_numeric(self, long_df): assert m.lookup_table == dict(zip(hue_levels, palette)) palette = color_palette("Blues", len(hue_levels) + 1) - with pytest.raises(ValueError): + with pytest.warns(UserWarning): HueMapping(p, palette=palette) # Test dictionary of colors @@ -460,7 +460,7 @@ def test_map_size_categorical(self, long_df): # Test sizes list with wrong length sizes = list(np.random.rand(len(levels) + 1)) - with pytest.raises(ValueError): + with pytest.warns(UserWarning): SizeMapping(p, sizes=sizes) # Test sizes dict with missing levels @@ -578,13 +578,13 @@ def test_map_style(self, long_df): assert_array_equal(m(key, "path").vertices, path.vertices) # Test too many levels with style lists - with pytest.raises(ValueError): + with pytest.warns(UserWarning): StyleMapping(p, markers=["o", "s"], dashes=False) - with pytest.raises(ValueError): + with pytest.warns(UserWarning): StyleMapping(p, markers=False, dashes=[(2, 1)]) - # Test too many levels with style dicts + # Test missing keys with style dicts markers, dashes = {"a": "o", "b": "s"}, False with pytest.raises(ValueError): StyleMapping(p, markers=markers, dashes=dashes)