Skip to content

Commit 43311a1

Browse files
committed
Add a note to pyplot docstrings referencing the corresponding object
methods Partial fix for #17786: This adds notes for the pyplot functions auto-generated by boilerplate.py.
1 parent 132033b commit 43311a1

File tree

2 files changed

+72
-0
lines changed

2 files changed

+72
-0
lines changed

galleries/users_explain/figure/api_interfaces.rst

+2
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ is very flexible, and allows us to customize the objects after they are created,
5858
but before they are displayed.
5959

6060

61+
.. _pyplot_interface:
62+
6163
The implicit "pyplot" interface
6264
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6365

lib/matplotlib/pyplot.py

+70
Original file line numberDiff line numberDiff line change
@@ -179,9 +179,79 @@ def _copy_docstring_and_deprecators(
179179
method = method.__wrapped__
180180
for decorator in decorators[::-1]:
181181
func = decorator(func)
182+
_add_pyplot_note(func, method)
182183
return func
183184

184185

186+
_NO_PYPLOT_NOTE = [
187+
'FigureBase._gci', # wrapped_func is private
188+
'_AxesBase._sci', # wrapped_func is private
189+
'Artist.findobj', # not a standard pyplot wrapper because it does not operate
190+
# on the current Figure / Axes. Explanation of relation would
191+
# be more complex and is not too important.
192+
]
193+
194+
195+
def _add_pyplot_note(func, wrapped_func):
196+
"""
197+
Add a note to the docstring of *func* that it is a pyplot wrapper.
198+
199+
The note is added to the "Notes" section of the docstring. If that does
200+
not exist, a "Notes" section is created. In numpydoc, the "Notes"
201+
section is the third last possible section, only potentially followed by
202+
"References" and "See Also".
203+
"""
204+
if not func.__doc__:
205+
return # nothing to do
206+
207+
qualname = wrapped_func.__qualname__
208+
if qualname in _NO_PYPLOT_NOTE:
209+
return
210+
211+
wrapped_func_is_method = True
212+
if "." not in qualname:
213+
# method qualnames are prefixed by the class and ".", e.g. "Axes.plot"
214+
wrapped_func_is_method = False
215+
link = f"{wrapped_func.__module__}.{qualname}"
216+
elif qualname.startswith("Axes."): # e.g. "Axes.plot"
217+
link = ".axes." + qualname
218+
elif qualname.startswith("_AxesBase."): # e.g. "_AxesBase.set_xlabel"
219+
link = ".axes.Axes" + qualname[9:]
220+
elif qualname.startswith("Figure."): # e.g. "Figure.figimage"
221+
link = "." + qualname
222+
elif qualname.startswith("FigureBase."): # e.g. "FigureBase.gca"
223+
link = ".Figure" + qualname[10:]
224+
elif qualname.startswith("FigureCanvasBase."): # "FigureBaseCanvas.mpl_connect"
225+
link = "." + qualname
226+
else:
227+
raise RuntimeError(f"Wrapped method from unexpected class: {qualname}")
228+
229+
if wrapped_func_is_method:
230+
message = f"This is the :ref:`pyplot wrapper <pyplot_interface>` for `{link}`."
231+
else:
232+
message = f"This is equivalent to `{link}`."
233+
234+
# Find the correct insert position:
235+
# - either we already have a "Notes" section into which we can insert
236+
# - or we create one before the next present section. Note that in numpydoc, the
237+
# "Notes" section is the third last possible section, only potentially followed
238+
# by "References" and "See Also".
239+
# - or we append a new "Notes" section at the end.
240+
doc = inspect.cleandoc(func.__doc__)
241+
if "\nNotes\n-----" in doc:
242+
before, after = doc.split("\nNotes\n-----", 1)
243+
elif (index := doc.find("\nReferences\n----------")) != -1:
244+
before, after = doc[:index], doc[index:]
245+
elif (index := doc.find("\nSee Also\n--------")) != -1:
246+
before, after = doc[:index], doc[index:]
247+
else:
248+
# No "Notes", "References", or "See Also" --> append to the end.
249+
before = doc + "\n"
250+
after = ""
251+
252+
func.__doc__ = f"{before}\nNotes\n-----\n\n.. note::\n\n {message}\n{after}"
253+
254+
185255
## Global ##
186256

187257

0 commit comments

Comments
 (0)