diff --git a/doc/api/next_api_changes/deprecations/27786-TH.rst b/doc/api/next_api_changes/deprecations/27786-TH.rst new file mode 100644 index 000000000000..6b66e0dba963 --- /dev/null +++ b/doc/api/next_api_changes/deprecations/27786-TH.rst @@ -0,0 +1,7 @@ +Positional parameters in plotting functions +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Many plotting functions will restrict positional arguments to the first few parameters +in the future. All further configuration parameters will have to be passed as keyword +arguments. This is to enforce better code and and allow for future changes with reduced +risk of breaking existing code. diff --git a/galleries/examples/lines_bars_and_markers/cohere.py b/galleries/examples/lines_bars_and_markers/cohere.py index 64124e37645e..917188292311 100644 --- a/galleries/examples/lines_bars_and_markers/cohere.py +++ b/galleries/examples/lines_bars_and_markers/cohere.py @@ -27,7 +27,7 @@ axs[0].set_ylabel('s1 and s2') axs[0].grid(True) -cxy, f = axs[1].cohere(s1, s2, 256, 1. / dt) +cxy, f = axs[1].cohere(s1, s2, NFFT=256, Fs=1. / dt) axs[1].set_ylabel('Coherence') plt.show() diff --git a/galleries/examples/lines_bars_and_markers/csd_demo.py b/galleries/examples/lines_bars_and_markers/csd_demo.py index b2d903ae0885..6d7a9746e88e 100644 --- a/galleries/examples/lines_bars_and_markers/csd_demo.py +++ b/galleries/examples/lines_bars_and_markers/csd_demo.py @@ -34,7 +34,7 @@ ax1.set_ylabel('s1 and s2') ax1.grid(True) -cxy, f = ax2.csd(s1, s2, 256, 1. / dt) +cxy, f = ax2.csd(s1, s2, NFFT=256, Fs=1. / dt) ax2.set_ylabel('CSD (dB)') plt.show() diff --git a/galleries/examples/lines_bars_and_markers/psd_demo.py b/galleries/examples/lines_bars_and_markers/psd_demo.py index 52587fd6d7bf..fa0a8565b6ff 100644 --- a/galleries/examples/lines_bars_and_markers/psd_demo.py +++ b/galleries/examples/lines_bars_and_markers/psd_demo.py @@ -30,7 +30,7 @@ ax0.plot(t, s) ax0.set_xlabel('Time (s)') ax0.set_ylabel('Signal') -ax1.psd(s, 512, 1 / dt) +ax1.psd(s, NFFT=512, Fs=1 / dt) plt.show() diff --git a/galleries/examples/statistics/boxplot_demo.py b/galleries/examples/statistics/boxplot_demo.py index eca0e152078e..f7f1078b2d27 100644 --- a/galleries/examples/statistics/boxplot_demo.py +++ b/galleries/examples/statistics/boxplot_demo.py @@ -34,23 +34,23 @@ axs[0, 0].set_title('basic plot') # notched plot -axs[0, 1].boxplot(data, 1) +axs[0, 1].boxplot(data, notch=True) axs[0, 1].set_title('notched plot') # change outlier point symbols -axs[0, 2].boxplot(data, 0, 'gD') +axs[0, 2].boxplot(data, sym='gD') axs[0, 2].set_title('change outlier\npoint symbols') # don't show outlier points -axs[1, 0].boxplot(data, 0, '') +axs[1, 0].boxplot(data, sym='') axs[1, 0].set_title("don't show\noutlier points") # horizontal boxes -axs[1, 1].boxplot(data, 0, 'rs', 0) +axs[1, 1].boxplot(data, sym='rs', vert=False) axs[1, 1].set_title('horizontal boxes') # change whisker length -axs[1, 2].boxplot(data, 0, 'rs', 0, 0.75) +axs[1, 2].boxplot(data, sym='rs', vert=False, whis=0.75) axs[1, 2].set_title('change whisker length') fig.subplots_adjust(left=0.08, right=0.98, bottom=0.05, top=0.9, diff --git a/lib/matplotlib/_api/deprecation.py b/lib/matplotlib/_api/deprecation.py index 283a55f1beb0..e9722f5d26c4 100644 --- a/lib/matplotlib/_api/deprecation.py +++ b/lib/matplotlib/_api/deprecation.py @@ -437,7 +437,8 @@ def make_keyword_only(since, name, func=None): assert (name in signature.parameters and signature.parameters[name].kind == POK), ( f"Matplotlib internal error: {name!r} must be a positional-or-keyword " - f"parameter for {func.__name__}()") + f"parameter for {func.__name__}(). If this error happens on a function with a " + f"pyplot wrapper, make sure make_keyword_only() is the outermost decorator.") names = [*signature.parameters] name_idx = names.index(name) kwonly = [name for name in names[name_idx:] diff --git a/lib/matplotlib/axes/_axes.py b/lib/matplotlib/axes/_axes.py index b65004b8c272..7a022104cfa1 100644 --- a/lib/matplotlib/axes/_axes.py +++ b/lib/matplotlib/axes/_axes.py @@ -1100,6 +1100,7 @@ def axvspan(self, xmin, xmax, ymin=0, ymax=1, **kwargs): self._request_autoscale_view("x") return p + @_api.make_keyword_only("3.9", "label") @_preprocess_data(replace_names=["y", "xmin", "xmax", "colors"], label_namer="y") def hlines(self, y, xmin, xmax, colors=None, linestyles='solid', @@ -1191,6 +1192,7 @@ def hlines(self, y, xmin, xmax, colors=None, linestyles='solid', self._request_autoscale_view() return lines + @_api.make_keyword_only("3.9", "label") @_preprocess_data(replace_names=["x", "ymin", "ymax", "colors"], label_namer="x") def vlines(self, x, ymin, ymax, colors=None, linestyles='solid', @@ -1282,6 +1284,7 @@ def vlines(self, x, ymin, ymax, colors=None, linestyles='solid', self._request_autoscale_view() return lines + @_api.make_keyword_only("3.9", "orientation") @_preprocess_data(replace_names=["positions", "lineoffsets", "linelengths", "linewidths", "colors", "linestyles"]) @@ -2088,6 +2091,7 @@ def acorr(self, x, **kwargs): """ return self.xcorr(x, x, **kwargs) + @_api.make_keyword_only("3.9", "normed") @_preprocess_data(replace_names=["x", "y"], label_namer="y") def xcorr(self, x, y, normed=True, detrend=mlab.detrend_none, usevlines=True, maxlags=10, **kwargs): @@ -3155,6 +3159,7 @@ def stem(self, *args, linefmt=None, markerfmt=None, basefmt=None, bottom=0, self.add_container(stem_container) return stem_container + @_api.make_keyword_only("3.9", "explode") @_preprocess_data(replace_names=["x", "explode", "labels", "colors"]) def pie(self, x, explode=None, labels=None, colors=None, autopct=None, pctdistance=0.6, shadow=False, labeldistance=1.1, @@ -3434,6 +3439,7 @@ def _errorevery_to_mask(x, errorevery): everymask[errorevery] = True return everymask + @_api.make_keyword_only("3.9", "ecolor") @_preprocess_data(replace_names=["x", "y", "xerr", "yerr"], label_namer="y") @_docstring.dedent_interpd @@ -3810,6 +3816,7 @@ def apply_mask(arrays, mask): return errorbar_container # (l0, caplines, barcols) + @_api.make_keyword_only("3.9", "notch") @_preprocess_data() @_api.rename_parameter("3.9", "labels", "tick_labels") def boxplot(self, x, notch=None, sym=None, vert=None, whis=None, @@ -4144,6 +4151,7 @@ def boxplot(self, x, notch=None, sym=None, vert=None, whis=None, capwidths=capwidths, label=label) return artists + @_api.make_keyword_only("3.9", "widths") def bxp(self, bxpstats, positions=None, widths=None, vert=True, patch_artist=False, shownotches=False, showmeans=False, showcaps=True, showbox=True, showfliers=True, @@ -4636,6 +4644,7 @@ def invalid_shape_exception(csize, xsize): colors = None # use cmap, norm after collection is created return c, colors, edgecolors + @_api.make_keyword_only("3.9", "marker") @_preprocess_data(replace_names=["x", "y", "s", "linewidths", "edgecolors", "c", "facecolor", "facecolors", "color"], @@ -4916,6 +4925,7 @@ def scatter(self, x, y, s=None, c=None, marker=None, cmap=None, norm=None, return collection + @_api.make_keyword_only("3.9", "gridsize") @_preprocess_data(replace_names=["x", "y", "C"], label_namer="y") @_docstring.dedent_interpd def hexbin(self, x, y, C=None, gridsize=100, bins=None, @@ -6698,6 +6708,7 @@ def clabel(self, CS, levels=None, **kwargs): #### Data analysis + @_api.make_keyword_only("3.9", "range") @_preprocess_data(replace_names=["x", 'weights'], label_namer="x") def hist(self, x, bins=None, range=None, density=False, weights=None, cumulative=False, bottom=None, histtype='bar', align='mid', @@ -7245,6 +7256,7 @@ def stairs(self, values, edges=None, *, self._request_autoscale_view() return patch + @_api.make_keyword_only("3.9", "range") @_preprocess_data(replace_names=["x", "y", "weights"]) @_docstring.dedent_interpd def hist2d(self, x, y, bins=10, range=None, density=False, weights=None, @@ -7454,6 +7466,7 @@ def ecdf(self, x, weights=None, *, complementary=False, line.sticky_edges.x[:] = [0, 1] return line + @_api.make_keyword_only("3.9", "NFFT") @_preprocess_data(replace_names=["x"]) @_docstring.dedent_interpd def psd(self, x, NFFT=None, Fs=None, Fc=None, detrend=None, @@ -7565,6 +7578,7 @@ def psd(self, x, NFFT=None, Fs=None, Fc=None, detrend=None, else: return pxx, freqs, line + @_api.make_keyword_only("3.9", "NFFT") @_preprocess_data(replace_names=["x", "y"], label_namer="y") @_docstring.dedent_interpd def csd(self, x, y, NFFT=None, Fs=None, Fc=None, detrend=None, @@ -7667,6 +7681,7 @@ def csd(self, x, y, NFFT=None, Fs=None, Fc=None, detrend=None, else: return pxy, freqs, line + @_api.make_keyword_only("3.9", "Fs") @_preprocess_data(replace_names=["x"]) @_docstring.dedent_interpd def magnitude_spectrum(self, x, Fs=None, Fc=None, window=None, @@ -7753,6 +7768,7 @@ def magnitude_spectrum(self, x, Fs=None, Fc=None, window=None, return spec, freqs, line + @_api.make_keyword_only("3.9", "Fs") @_preprocess_data(replace_names=["x"]) @_docstring.dedent_interpd def angle_spectrum(self, x, Fs=None, Fc=None, window=None, @@ -7822,6 +7838,7 @@ def angle_spectrum(self, x, Fs=None, Fc=None, window=None, return spec, freqs, lines[0] + @_api.make_keyword_only("3.9", "Fs") @_preprocess_data(replace_names=["x"]) @_docstring.dedent_interpd def phase_spectrum(self, x, Fs=None, Fc=None, window=None, @@ -7891,6 +7908,7 @@ def phase_spectrum(self, x, Fs=None, Fc=None, window=None, return spec, freqs, lines[0] + @_api.make_keyword_only("3.9", "NFFT") @_preprocess_data(replace_names=["x", "y"]) @_docstring.dedent_interpd def cohere(self, x, y, NFFT=256, Fs=2, Fc=0, detrend=mlab.detrend_none, @@ -7955,6 +7973,7 @@ def cohere(self, x, y, NFFT=256, Fs=2, Fc=0, detrend=mlab.detrend_none, return cxy, freqs + @_api.make_keyword_only("3.9", "NFFT") @_preprocess_data(replace_names=["x"]) @_docstring.dedent_interpd def specgram(self, x, NFFT=None, Fs=None, Fc=None, detrend=None, @@ -8111,6 +8130,7 @@ def specgram(self, x, NFFT=None, Fs=None, Fc=None, detrend=None, return spec, freqs, t, im + @_api.make_keyword_only("3.9", "precision") @_docstring.dedent_interpd def spy(self, Z, precision=0, marker=None, markersize=None, aspect='equal', origin="upper", **kwargs): @@ -8301,6 +8321,7 @@ def matshow(self, Z, **kwargs): mticker.MaxNLocator(nbins=9, steps=[1, 2, 5, 10], integer=True)) return im + @_api.make_keyword_only("3.9", "vert") @_preprocess_data(replace_names=["dataset"]) def violinplot(self, dataset, positions=None, vert=True, widths=0.5, showmeans=False, showextrema=True, showmedians=False, @@ -8412,6 +8433,7 @@ def _kde_method(X, coords): widths=widths, showmeans=showmeans, showextrema=showextrema, showmedians=showmedians, side=side) + @_api.make_keyword_only("3.9", "vert") def violin(self, vpstats, positions=None, vert=True, widths=0.5, showmeans=False, showextrema=True, showmedians=False, side='both'): """ diff --git a/lib/matplotlib/axes/_axes.pyi b/lib/matplotlib/axes/_axes.pyi index b70d330aa442..be0a0e48d662 100644 --- a/lib/matplotlib/axes/_axes.pyi +++ b/lib/matplotlib/axes/_axes.pyi @@ -166,8 +166,8 @@ class Axes(_AxesBase): xmax: float | ArrayLike, colors: ColorType | Sequence[ColorType] | None = ..., linestyles: LineStyleType = ..., - label: str = ..., *, + label: str = ..., data=..., **kwargs ) -> LineCollection: ... @@ -178,14 +178,15 @@ class Axes(_AxesBase): ymax: float | ArrayLike, colors: ColorType | Sequence[ColorType] | None = ..., linestyles: LineStyleType = ..., - label: str = ..., *, + label: str = ..., data=..., **kwargs ) -> LineCollection: ... def eventplot( self, positions: ArrayLike | Sequence[ArrayLike], + *, orientation: Literal["horizontal", "vertical"] = ..., lineoffsets: float | Sequence[float] = ..., linelengths: float | Sequence[float] = ..., @@ -193,7 +194,6 @@ class Axes(_AxesBase): colors: ColorType | Sequence[ColorType] | None = ..., alpha: float | Sequence[float] | None = ..., linestyles: LineStyleType | Sequence[LineStyleType] = ..., - *, data=..., **kwargs ) -> EventCollection: ... @@ -227,11 +227,11 @@ class Axes(_AxesBase): self, x: ArrayLike, y: ArrayLike, + *, normed: bool = ..., detrend: Callable[[ArrayLike], ArrayLike] = ..., usevlines: bool = ..., maxlags: int = ..., - *, data = ..., **kwargs ) -> tuple[np.ndarray, np.ndarray, LineCollection | Line2D, Line2D | None]: ... @@ -300,6 +300,7 @@ class Axes(_AxesBase): def pie( self, x: ArrayLike, + *, explode: ArrayLike | None = ..., labels: Sequence[str] | None = ..., colors: ColorType | Sequence[ColorType] | None = ..., @@ -315,7 +316,6 @@ class Axes(_AxesBase): center: tuple[float, float] = ..., frame: bool = ..., rotatelabels: bool = ..., - *, normalize: bool = ..., hatch: str | Sequence[str] | None = ..., data=..., @@ -329,6 +329,7 @@ class Axes(_AxesBase): yerr: float | ArrayLike | None = ..., xerr: float | ArrayLike | None = ..., fmt: str = ..., + *, ecolor: ColorType | None = ..., elinewidth: float | None = ..., capsize: float | None = ..., @@ -339,13 +340,13 @@ class Axes(_AxesBase): xuplims: bool | ArrayLike = ..., errorevery: int | tuple[int, int] = ..., capthick: float | None = ..., - *, data=..., **kwargs ) -> ErrorbarContainer: ... def boxplot( self, x: ArrayLike | Sequence[ArrayLike], + *, notch: bool | None = ..., sym: str | None = ..., vert: bool | None = ..., @@ -373,13 +374,13 @@ class Axes(_AxesBase): zorder: float | None = ..., capwidths: float | ArrayLike | None = ..., label: Sequence[str] | None = ..., - *, data=..., ) -> dict[str, Any]: ... def bxp( self, bxpstats: Sequence[dict[str, Any]], positions: ArrayLike | None = ..., + *, widths: float | ArrayLike | None = ..., vert: bool = ..., patch_artist: bool = ..., @@ -406,6 +407,7 @@ class Axes(_AxesBase): y: float | ArrayLike, s: float | ArrayLike | None = ..., c: ArrayLike | Sequence[ColorType] | ColorType | None = ..., + *, marker: MarkerType | None = ..., cmap: str | Colormap | None = ..., norm: str | Normalize | None = ..., @@ -413,7 +415,6 @@ class Axes(_AxesBase): vmax: float | None = ..., alpha: float | None = ..., linewidths: float | Sequence[float] | None = ..., - *, edgecolors: Literal["face", "none"] | ColorType | Sequence[ColorType] | None = ..., plotnonfinite: bool = ..., data=..., @@ -424,6 +425,7 @@ class Axes(_AxesBase): x: ArrayLike, y: ArrayLike, C: ArrayLike | None = ..., + *, gridsize: int | tuple[int, int] = ..., bins: Literal["log"] | int | Sequence[float] | None = ..., xscale: Literal["linear", "log"] = ..., @@ -439,7 +441,6 @@ class Axes(_AxesBase): reduce_C_function: Callable[[np.ndarray | list[float]], float] = ..., mincnt: int | None = ..., marginals: bool = ..., - *, data=..., **kwargs ) -> PolyCollection: ... @@ -542,6 +543,7 @@ class Axes(_AxesBase): self, x: ArrayLike | Sequence[ArrayLike], bins: int | Sequence[float] | str | None = ..., + *, range: tuple[float, float] | None = ..., density: bool = ..., weights: ArrayLike | None = ..., @@ -555,7 +557,6 @@ class Axes(_AxesBase): color: ColorType | Sequence[ColorType] | None = ..., label: str | Sequence[str] | None = ..., stacked: bool = ..., - *, data=..., **kwargs ) -> tuple[ @@ -583,12 +584,12 @@ class Axes(_AxesBase): | tuple[int, int] | ArrayLike | tuple[ArrayLike, ArrayLike] = ..., + *, range: ArrayLike | None = ..., density: bool = ..., weights: ArrayLike | None = ..., cmin: float | None = ..., cmax: float | None = ..., - *, data=..., **kwargs ) -> tuple[np.ndarray, np.ndarray, np.ndarray, QuadMesh]: ... @@ -606,6 +607,7 @@ class Axes(_AxesBase): def psd( self, x: ArrayLike, + *, NFFT: int | None = ..., Fs: float | None = ..., Fc: int | None = ..., @@ -618,7 +620,6 @@ class Axes(_AxesBase): sides: Literal["default", "onesided", "twosided"] | None = ..., scale_by_freq: bool | None = ..., return_line: bool | None = ..., - *, data=..., **kwargs ) -> tuple[np.ndarray, np.ndarray] | tuple[np.ndarray, np.ndarray, Line2D]: ... @@ -626,6 +627,7 @@ class Axes(_AxesBase): self, x: ArrayLike, y: ArrayLike, + *, NFFT: int | None = ..., Fs: float | None = ..., Fc: int | None = ..., @@ -638,44 +640,43 @@ class Axes(_AxesBase): sides: Literal["default", "onesided", "twosided"] | None = ..., scale_by_freq: bool | None = ..., return_line: bool | None = ..., - *, data=..., **kwargs ) -> tuple[np.ndarray, np.ndarray] | tuple[np.ndarray, np.ndarray, Line2D]: ... def magnitude_spectrum( self, x: ArrayLike, + *, Fs: float | None = ..., Fc: int | None = ..., window: Callable[[ArrayLike], ArrayLike] | ArrayLike | None = ..., pad_to: int | None = ..., sides: Literal["default", "onesided", "twosided"] | None = ..., scale: Literal["default", "linear", "dB"] | None = ..., - *, data=..., **kwargs ) -> tuple[np.ndarray, np.ndarray, Line2D]: ... def angle_spectrum( self, x: ArrayLike, + *, Fs: float | None = ..., Fc: int | None = ..., window: Callable[[ArrayLike], ArrayLike] | ArrayLike | None = ..., pad_to: int | None = ..., sides: Literal["default", "onesided", "twosided"] | None = ..., - *, data=..., **kwargs ) -> tuple[np.ndarray, np.ndarray, Line2D]: ... def phase_spectrum( self, x: ArrayLike, + *, Fs: float | None = ..., Fc: int | None = ..., window: Callable[[ArrayLike], ArrayLike] | ArrayLike | None = ..., pad_to: int | None = ..., sides: Literal["default", "onesided", "twosided"] | None = ..., - *, data=..., **kwargs ) -> tuple[np.ndarray, np.ndarray, Line2D]: ... @@ -683,6 +684,7 @@ class Axes(_AxesBase): self, x: ArrayLike, y: ArrayLike, + *, NFFT: int = ..., Fs: float = ..., Fc: int = ..., @@ -693,13 +695,13 @@ class Axes(_AxesBase): pad_to: int | None = ..., sides: Literal["default", "onesided", "twosided"] = ..., scale_by_freq: bool | None = ..., - *, data=..., **kwargs ) -> tuple[np.ndarray, np.ndarray]: ... def specgram( self, x: ArrayLike, + *, NFFT: int | None = ..., Fs: float | None = ..., Fc: int | None = ..., @@ -717,13 +719,13 @@ class Axes(_AxesBase): scale: Literal["default", "linear", "dB"] | None = ..., vmin: float | None = ..., vmax: float | None = ..., - *, data=..., **kwargs ) -> tuple[np.ndarray, np.ndarray, np.ndarray, AxesImage]: ... def spy( self, Z: ArrayLike, + *, precision: float | Literal["present"] = ..., marker: str | None = ..., markersize: float | None = ..., @@ -736,6 +738,7 @@ class Axes(_AxesBase): self, dataset: ArrayLike | Sequence[ArrayLike], positions: ArrayLike | None = ..., + *, vert: bool = ..., widths: float | ArrayLike = ..., showmeans: bool = ..., @@ -748,13 +751,13 @@ class Axes(_AxesBase): | Callable[[GaussianKDE], float] | None = ..., side: Literal["both", "low", "high"] = ..., - *, data=..., ) -> dict[str, Collection]: ... def violin( self, vpstats: Sequence[dict[str, Any]], positions: ArrayLike | None = ..., + *, vert: bool = ..., widths: float | ArrayLike = ..., showmeans: bool = ...,