diff --git a/ultraplot/axes/plot.py b/ultraplot/axes/plot.py index ae387927f..612405a5c 100644 --- a/ultraplot/axes/plot.py +++ b/ultraplot/axes/plot.py @@ -4120,8 +4120,10 @@ def _parse_cmap( # Parse keyword args cmap_kw = cmap_kw or {} norm_kw = norm_kw or {} - # If norm is given we use it to set vmin and vmax - if (vmin is not None or vmax is not None) and norm is not None: + # If norm is an already-instantiated Normalize, extract vmin/vmax from it. + # When norm is a string or tuple it will be constructed later with the + # supplied vmin/vmax, so we must not reject them here. + if (vmin is not None or vmax is not None) and isinstance(norm, mcolors.Normalize): raise ValueError("If 'norm' is given, 'vmin' and 'vmax' must not be set.") if isinstance(norm, mcolors.Normalize): vmin = norm.vmin diff --git a/ultraplot/tests/test_plot.py b/ultraplot/tests/test_plot.py index 652f71856..7b3971232 100644 --- a/ultraplot/tests/test_plot.py +++ b/ultraplot/tests/test_plot.py @@ -612,6 +612,19 @@ def test_pie_labeled_series_in_dataframes(): uplt.close(fig) +def test_string_norm_with_vmin_vmax(rng): + """ + When norm is a string (e.g. 'log'), vmin and vmax should be forwarded + to the normalizer constructor instead of raising ValueError. + Regression test for https://github.com/Ultraplot/UltraPlot/issues/689 + """ + data = 11 ** (0.25 * np.cumsum(rng.random((20, 20)), axis=0)) + fig, ax = uplt.subplots() + m = ax.pcolormesh(data, cmap="magma", norm="log", vmin=1e-2) + assert m.norm.vmin == pytest.approx(1e-2) + uplt.close(fig) + + def test_color_parsing_for_none(): """ Ensure that none is not parsed to white