From e2ecd2d8c9a453305436801fea75d48e0673a95e Mon Sep 17 00:00:00 2001 From: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com> Date: Tue, 13 Feb 2024 17:11:08 +0100 Subject: [PATCH] Deprecate positional use of most arguments of plotting functions This increases maintainability for developers and disallows bad practice of passing lots of positional arguments for users. If in doubt, I've erred on the side of allowing as much positional arguments as possible as long as the intent of a call is still readable. Note: This was originally motivated by bxp() and boxplot() having many overlapping parameters but differently ordered. While at it, I think it's better to rollout the change to all plotting functions and communicate that in one go rather than having lots of individual change notices over time. Also, the freedom to reorder parameters only sets in after the deprecation. So let's start this now. --- .../deprecations/27786-TH.rst | 7 ++++++ lib/matplotlib/axes/_axes.py | 23 +++++++++++++++++++ 2 files changed, 30 insertions(+) create mode 100644 doc/api/next_api_changes/deprecations/27786-TH.rst 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/lib/matplotlib/axes/_axes.py b/lib/matplotlib/axes/_axes.py index 711d930a1253..3a783070519b 100644 --- a/lib/matplotlib/axes/_axes.py +++ b/lib/matplotlib/axes/_axes.py @@ -1059,6 +1059,7 @@ def axvspan(self, xmin, xmax, ymin=0, ymax=1, **kwargs): @_preprocess_data(replace_names=["y", "xmin", "xmax", "colors"], label_namer="y") + @_api.make_keyword_only("3.9", "label") def hlines(self, y, xmin, xmax, colors=None, linestyles='solid', label='', **kwargs): """ @@ -1150,6 +1151,7 @@ def hlines(self, y, xmin, xmax, colors=None, linestyles='solid', @_preprocess_data(replace_names=["x", "ymin", "ymax", "colors"], label_namer="x") + @_api.make_keyword_only("3.9", "label") def vlines(self, x, ymin, ymax, colors=None, linestyles='solid', label='', **kwargs): """ @@ -1243,6 +1245,7 @@ def vlines(self, x, ymin, ymax, colors=None, linestyles='solid', "linelengths", "linewidths", "colors", "linestyles"]) @_docstring.dedent_interpd + @_api.make_keyword_only("3.9", "orientation") def eventplot(self, positions, orientation='horizontal', lineoffsets=1, linelengths=1, linewidths=None, colors=None, alpha=None, linestyles='solid', **kwargs): @@ -1744,6 +1747,7 @@ def plot(self, *args, scalex=True, scaley=True, data=None, **kwargs): @_preprocess_data(replace_names=["x", "y"], label_namer="y") @_docstring.dedent_interpd + @_api.make_keyword_only("3.9", "tz") def plot_date(self, x, y, fmt='o', tz=None, xdate=True, ydate=False, **kwargs): """ @@ -2046,6 +2050,7 @@ def acorr(self, x, **kwargs): return self.xcorr(x, x, **kwargs) @_preprocess_data(replace_names=["x", "y"], label_namer="y") + @_api.make_keyword_only("3.9", "normed") def xcorr(self, x, y, normed=True, detrend=mlab.detrend_none, usevlines=True, maxlags=10, **kwargs): r""" @@ -3113,6 +3118,7 @@ def stem(self, *args, linefmt=None, markerfmt=None, basefmt=None, bottom=0, return stem_container @_preprocess_data(replace_names=["x", "explode", "labels", "colors"]) + @_api.make_keyword_only("3.9", "explode") def pie(self, x, explode=None, labels=None, colors=None, autopct=None, pctdistance=0.6, shadow=False, labeldistance=1.1, startangle=0, radius=1, counterclock=True, @@ -3391,6 +3397,7 @@ def _errorevery_to_mask(x, errorevery): @_preprocess_data(replace_names=["x", "y", "xerr", "yerr"], label_namer="y") @_docstring.dedent_interpd + @_api.make_keyword_only("3.9", "ecolor") def errorbar(self, x, y, yerr=None, xerr=None, fmt='', ecolor=None, elinewidth=None, capsize=None, barsabove=False, lolims=False, uplims=False, @@ -3765,6 +3772,7 @@ def apply_mask(arrays, mask): return errorbar_container # (l0, caplines, barcols) @_preprocess_data() + @_api.make_keyword_only("3.9", "notch") def boxplot(self, x, notch=None, sym=None, vert=None, whis=None, positions=None, widths=None, patch_artist=None, bootstrap=None, usermedians=None, conf_intervals=None, @@ -4078,6 +4086,7 @@ def boxplot(self, x, notch=None, sym=None, vert=None, whis=None, capwidths=capwidths) 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, @@ -4535,6 +4544,7 @@ def invalid_shape_exception(csize, xsize): "edgecolors", "c", "facecolor", "facecolors", "color"], label_namer="y") + @_api.make_keyword_only("3.9", "marker") @_docstring.interpd def scatter(self, x, y, s=None, c=None, marker=None, cmap=None, norm=None, vmin=None, vmax=None, alpha=None, linewidths=None, *, @@ -4813,6 +4823,7 @@ def scatter(self, x, y, s=None, c=None, marker=None, cmap=None, norm=None, @_preprocess_data(replace_names=["x", "y", "C"], label_namer="y") @_docstring.dedent_interpd + @_api.make_keyword_only("3.9", "gridsize") def hexbin(self, x, y, C=None, gridsize=100, bins=None, xscale='linear', yscale='linear', extent=None, cmap=None, norm=None, vmin=None, vmax=None, @@ -6591,6 +6602,7 @@ def clabel(self, CS, levels=None, **kwargs): #### Data analysis @_preprocess_data(replace_names=["x", 'weights'], label_namer="x") + @_api.make_keyword_only("3.9", "range") def hist(self, x, bins=None, range=None, density=False, weights=None, cumulative=False, bottom=None, histtype='bar', align='mid', orientation='vertical', rwidth=None, log=False, @@ -7136,6 +7148,7 @@ def stairs(self, values, edges=None, *, @_preprocess_data(replace_names=["x", "y", "weights"]) @_docstring.dedent_interpd + @_api.make_keyword_only("3.9", "range") def hist2d(self, x, y, bins=10, range=None, density=False, weights=None, cmin=None, cmax=None, **kwargs): """ @@ -7345,6 +7358,7 @@ def ecdf(self, x, weights=None, *, complementary=False, @_preprocess_data(replace_names=["x"]) @_docstring.dedent_interpd + @_api.make_keyword_only("3.9", "NFFT") def psd(self, x, NFFT=None, Fs=None, Fc=None, detrend=None, window=None, noverlap=None, pad_to=None, sides=None, scale_by_freq=None, return_line=None, **kwargs): @@ -7456,6 +7470,7 @@ def psd(self, x, NFFT=None, Fs=None, Fc=None, detrend=None, @_preprocess_data(replace_names=["x", "y"], label_namer="y") @_docstring.dedent_interpd + @_api.make_keyword_only("3.9", "NFFT") def csd(self, x, y, NFFT=None, Fs=None, Fc=None, detrend=None, window=None, noverlap=None, pad_to=None, sides=None, scale_by_freq=None, return_line=None, **kwargs): @@ -7558,6 +7573,7 @@ def csd(self, x, y, NFFT=None, Fs=None, Fc=None, detrend=None, @_preprocess_data(replace_names=["x"]) @_docstring.dedent_interpd + @_api.make_keyword_only("3.9", "Fs") def magnitude_spectrum(self, x, Fs=None, Fc=None, window=None, pad_to=None, sides=None, scale=None, **kwargs): @@ -7644,6 +7660,7 @@ def magnitude_spectrum(self, x, Fs=None, Fc=None, window=None, @_preprocess_data(replace_names=["x"]) @_docstring.dedent_interpd + @_api.make_keyword_only("3.9", "Fs") def angle_spectrum(self, x, Fs=None, Fc=None, window=None, pad_to=None, sides=None, **kwargs): """ @@ -7713,6 +7730,7 @@ def angle_spectrum(self, x, Fs=None, Fc=None, window=None, @_preprocess_data(replace_names=["x"]) @_docstring.dedent_interpd + @_api.make_keyword_only("3.9", "Fs") def phase_spectrum(self, x, Fs=None, Fc=None, window=None, pad_to=None, sides=None, **kwargs): """ @@ -7782,6 +7800,7 @@ def phase_spectrum(self, x, Fs=None, Fc=None, window=None, @_preprocess_data(replace_names=["x", "y"]) @_docstring.dedent_interpd + @_api.make_keyword_only("3.9", "NFFT") def cohere(self, x, y, NFFT=256, Fs=2, Fc=0, detrend=mlab.detrend_none, window=mlab.window_hanning, noverlap=0, pad_to=None, sides='default', scale_by_freq=None, **kwargs): @@ -7846,6 +7865,7 @@ def cohere(self, x, y, NFFT=256, Fs=2, Fc=0, detrend=mlab.detrend_none, @_preprocess_data(replace_names=["x"]) @_docstring.dedent_interpd + @_api.make_keyword_only("3.9", "NFFT") def specgram(self, x, NFFT=None, Fs=None, Fc=None, detrend=None, window=None, noverlap=None, cmap=None, xextent=None, pad_to=None, sides=None, @@ -8001,6 +8021,7 @@ def specgram(self, x, NFFT=None, Fs=None, Fc=None, detrend=None, return spec, freqs, t, im @_docstring.dedent_interpd + @_api.make_keyword_only("3.9", "precision") def spy(self, Z, precision=0, marker=None, markersize=None, aspect='equal', origin="upper", **kwargs): """ @@ -8191,6 +8212,7 @@ def matshow(self, Z, **kwargs): return im @_preprocess_data(replace_names=["dataset"]) + @_api.make_keyword_only("3.9", "vert") def violinplot(self, dataset, positions=None, vert=True, widths=0.5, showmeans=False, showextrema=True, showmedians=False, quantiles=None, points=100, bw_method=None): @@ -8295,6 +8317,7 @@ def _kde_method(X, coords): widths=widths, showmeans=showmeans, showextrema=showextrema, showmedians=showmedians) + @_api.make_keyword_only("3.9", "vert") def violin(self, vpstats, positions=None, vert=True, widths=0.5, showmeans=False, showextrema=True, showmedians=False): """