diff --git a/lib/matplotlib/axes/_axes.py b/lib/matplotlib/axes/_axes.py index d6e4f50a2d7e..b93f8aec3142 100644 --- a/lib/matplotlib/axes/_axes.py +++ b/lib/matplotlib/axes/_axes.py @@ -64,11 +64,11 @@ def _plot_args_replacer(args, data): except ValueError: pass else: - warnings.warn( + cbook._warn_external( "Second argument {!r} is ambiguous: could be a color spec but " "is in data; using as data. Either rename the entry in data " "or use three arguments to plot.".format(args[1]), - RuntimeWarning, stacklevel=3) + RuntimeWarning) return ["x", "y"] elif len(args) == 3: return ["x", "y", "c"] diff --git a/lib/matplotlib/cbook/__init__.py b/lib/matplotlib/cbook/__init__.py index cd2177e75f6b..395ade0f649f 100644 --- a/lib/matplotlib/cbook/__init__.py +++ b/lib/matplotlib/cbook/__init__.py @@ -14,7 +14,7 @@ import glob import gzip import io -from itertools import repeat +import itertools import locale import numbers import operator @@ -1254,7 +1254,7 @@ def _compute_conf_interval(data, med, iqr, bootstrap): ncols = len(X) if labels is None: - labels = repeat(None) + labels = itertools.repeat(None) elif len(labels) != ncols: raise ValueError("Dimensions of labels and X must be compatible") @@ -2032,3 +2032,21 @@ def _setattr_cm(obj, **kwargs): delattr(obj, attr) else: setattr(obj, attr, orig) + + +def _warn_external(message, category=None): + """ + `warnings.warn` wrapper that sets *stacklevel* to "outside Matplotlib". + + The original emitter of the warning can be obtained by patching this + function back to `warnings.warn`, i.e. ``cbook._warn_external = + warnings.warn`` (or ``functools.partial(warnings.warn, stacklevel=2)``, + etc.). + """ + frame = sys._getframe() + for stacklevel in itertools.count(1): + if not re.match(r"\A(matplotlib|mpl_toolkits)(\Z|\.)", + frame.f_globals["__name__"]): + break + frame = frame.f_back + warnings.warn(message, category, stacklevel)