Matplotlib-Projekt

Auf dieser Seite finden Sie die Details zu einem Projekt für technisches Schreiben, das für Google Season of Docs angenommen wurde.

Projektzusammenfassung

Open-Source-Organisation:
Matplotlib
Technischer Redakteur:
Brunobeltran
Projektname:
Die Auffindbarkeit von Funktionen durch die Standardisierung der Dokumentation „impliziter“ Typen verbessern
Projektdauer:
Lang andauernd (5 Monate)

Projektbeschreibung

Motivation

In der Vergangenheit hat sich die API von matplotlib stark auf „Implicit types““ und „String-as-enum“ gestützt. Neben der Nachahmung der API von Matlab ermöglichen diese Parameterstrings dem Nutzer, semantisch reiche Werte als Argumente an matplotlib-Funktionen zu übergeben, ohne einen tatsächlichen Enum-Wert explizit importieren oder ausführlich vorangestellt zu haben, nur um grundlegende Plotoptionen zu übergeben. plt.plot(x, y, linestyle='solid') ist also einfacher zu tippen und weniger redundant als z. B. plt.plot(x, y, linestyle=mpl.LineStyle.solid).

Viele dieser impliziten Typen vom Typ „String als Enum“ wurden inzwischen um ausgefeiltere Funktionen erweitert. Ein linestyle kann jetzt beispielsweise ein String oder ein Paar von Sequenzen sein und ein MarkerStyle kann jetzt ein String oder ein matplotlib.path.Path sein. Das gilt zwar für viele implizite Typen, MarkerStyle ist aber (nach meinem Wissen) der einzige, der zu einer richtigen Python-Klasse aufgerüstet wurde.

Da diese impliziten Typen keine eigenständigen Klassen sind, musste Matplotlib in der Vergangenheit eigene Lösungen für die zentrale Dokumentation und Validierung dieser impliziten Typen entwickeln (z.B. das docstring.interpd.update-Docstring-Interpolationsmuster und das cbook._check_in_list-Validator-Muster), anstatt die Standard-Toolchains von Python-Klassen zu verwenden (z.B. docstrings und das Muster „validate-at-__init__“).

Diese Lösungen haben für uns gut funktioniert, aber da es keinen eindeutigen Ort gibt, an dem jeder implizite Typ dokumentiert wird, ist die Dokumentation oft schwer zu finden. Große Tabellen mit zulässigen Werten werden in der Dokumentation wiederholt und oft fehlt in den Dokumenten eine eindeutige Angabe des Umfangs eines impliziten Typs. Nehmen wir als Beispiel die plt.plot-Dokumente: In den „Hinweisen“ wird in der Beschreibung der Matlab-ähnlichen Formatierungsmethode für Formatstrings die Optionen linestyle, color und markers erwähnt. Es gibt viel mehr Möglichkeiten, diese drei Werte zu übergeben, als hier angedeutet. Für viele Nutzer ist dies jedoch die einzige Quelle, um zu erfahren, welche Werte für diese Optionen möglich sind, bis sie auf eines der entsprechenden Tutorials stoßen. Die Tabelle mit den Line2D-Attributen soll dem Leser zeigen, welche Optionen er zur Steuerung des Plots hat. Der Eintrag linestyle ist jedoch gut mit Line2D.set_linestyle verknüpft (zwei Klicks erforderlich), wo die möglichen Eingaben beschrieben werden. Das gilt nicht für die Einträge color und markers. color verweist einfach auf Line2D.set_color, was keine Vorstellung davon vermittelt, welche Arten von Eingaben überhaupt zulässig sind.

Man könnte argumentieren, dass sich das Problem durch einfaches Aufräumen der einzelnen docstrings beheben lässt, die Probleme verursachen. Das Problem ist jedoch leider viel systemischer. Ohne einen zentralen Ort, an dem die Dokumentation zu finden ist, führt dies einfach dazu, dass wir immer mehr Kopien der zunehmend ausführlichen Dokumentation überall dort haben, wo diese impliziten Typen verwendet werden. Dies erschwert es Anfängern besonders, einfach den benötigten Parameter zu finden. Das aktuelle System, das Nutzer zwingt, ihr mentales Modell jedes impliziten Typs durch Wiki-Diving-Stildurchläufe in unserer Dokumentation oder stückweise aus StackOverflow-Beispielen langsam zusammenzustellen, ist jedoch ebenfalls nicht tragfähig.

Endziel

Idealerweise sollte jede Erwähnung eines impliziten Typs auf eine einzelne Seite verweisen, auf der alle möglichen Werte dieses Typs beschrieben werden, sortiert nach dem einfachsten und gebräuchlichsten bis hin zum fortgeschrittensten oder esoterischsten. Anstatt wertvollen visuellen Raum in der API-Dokumentation auf oberster Ebene zu verwenden, um alle möglichen Eingabetypen für einen bestimmten Parameter aufzulisten, können wir diesen Raum dann nutzen, um eine Beschreibung in einfachen Worten zu geben, welche Darstellungsabstraktion der Parameter steuern soll.

Um wieder das Beispiel von linestyle zu verwenden, benötigen wir in den LineCollection-Dokumenten einfach Folgendes:

  1. Ein Link zu vollständigen Dokumenten zu zulässigen Eingaben (eine Kombination aus den Dokumenten in Line2D.set_linestyle und dem Leitfaden zum Linienstil).
  2. Eine Beschreibung in einfachen Worten, was der Parameter bewirken soll. Für erfahrene Matplotlib-Nutzer ist das aus dem Namen des Parameters ersichtlich, für neue Nutzer muss das aber nicht der Fall sein.

In der tatsächlichen LineCollection-Dokumentation würde dies wie in python """""" linestyles: `LineStyle` or list thereof, default: :rc:`lines.linestyle` ('-') A description of whether the stroke used to draw each line in the collection is dashed, dotted or solid, or some combination thereof. """""" aussehen. Hier wird der LineStyle-Typverweis von Sphinx aufgelöst, um auf einen einzelnen, verbindlichen und vollständigen Satz an Dokumentationen zur Behandlung von Linienstilen durch Matplotlib zu verweisen.

Vorteile

Zu den leistungsstarken Funktionen dieses Ansatzes gehören:

  1. Die Funktionen werden in einfachen Textzeilen beschrieben, ohne dass Klicks erforderlich sind.
  2. Die Standardoption wird ohne Klicks angezeigt. Das Anzeigen der Standardoption reicht oft aus, um wiederkehrende Nutzer aufzufrischen.
  3. Geben Sie eine vollständige Beschreibung der „häufigsten“ und „einfachsten“ Optionen für einen Parameter an, der beim Surfen mit nur einem Klick verfügbar ist.
  4. Sie können jetzt ganz einfach nach unten scrollen, um erweiterte Optionen zu sehen (mit nur einem Klick).
  5. Stellen Sie eine zentrale Strategie für die Verknüpfung von API-Dokumenten der obersten Ebene mit den relevanten Anleitungen bereit.
  6. Vermeiden Sie eine Explosion der API-Dokumente, bei der das Durchsuchen der vielen möglichen Optionen für die einzelnen Parameter die einzelnen Docstrings unübersichtlich macht.

Weitere Vorteile dieses Ansatzes gegenüber den aktuellen Dokumenten:

  1. Durch die Zentralisierung sind Dokumente weniger anfällig für Veralterung.
  2. Kanonisierung vieler der „impliziten Standards“ von matplotlib (z. B. was „bounds“ im Vergleich zu „extents“ ist), die derzeit durch Lesen des Codes gelernt werden müssen.
  3. Dadurch werden Probleme mit der API-Konsistenz auf eine Weise hervorgehoben, die sich über den GitHub-Issue-Tracker leichter verfolgen lässt. Das hilft uns, unsere API zu verbessern.
  4. Die Erstellung von Dokumenten ist jetzt schneller, da die Menge an Text, die geparst werden muss, deutlich reduziert wurde.

Implementierung

Die oben beschriebenen Verbesserungen erfordern zwei große Anstrengungen, bei denen ein engagierter Technischer Redakteur unverzichtbar ist. Der erste Schritt besteht darin, eine zentrale Seite mit einer Anleitung für jeden impliziten Typ zu erstellen. Dazu ist es erforderlich, mit dem Kernentwicklerteam zusammenzuarbeiten, um eine konkrete Liste impliziter Typen zu ermitteln, deren Dokumentation für Nutzer wertvoll sein könnte. Dies liegt in der Regel daran, dass sie leistungsstarke, versteckte Funktionen unserer Bibliothek enthalten, deren Dokumentation derzeit nur in schwer zugänglichen Anleitungen zu finden ist. Für jeden impliziten Typ werde ich dann die verschiedenen relevanten Tutorials, API-Dokumente und Beispielseiten in einer einzigen maßgeblichen Dokumentationsquelle zusammenfassen, die mit jeder Stelle verknüpft werden kann, an der auf diesen bestimmten Typ verwiesen wird.

Sobald die zentrale Dokumentation für einen bestimmten impliziten Typ fertig ist, beginnt die zweite große Aufgabe: das Ersetzen der vorhandenen API-Dokumentation durch Links zur neuen Dokumentation. Ziel dabei ist es, die Nutzung dieser neuen Dokumentation so einfach wie möglich zu gestalten, sowohl für Nutzer des integrierten help()-Dienstprogramms von Python als auch für Nutzer, die unsere Dokumentation online aufrufen.

Das genaue Format der hier vorgeschlagenen Dokumentation kann sich im Laufe des Projekts ändern. Ich habe mit dem Kernteam von Matplotlib während der wöchentlichen „Dev-Calls“ zusammengearbeitet, um einen Konsens darüber zu erzielen, dass die hier vorgeschlagene Strategie der zweckmäßigste, nützlichste und technisch umsetzbare Ansatz ist, um mit der Dokumentation dieser „impliziten Typen“ zu beginnen. Notizen zu diesen Calls sind auf hackmd verfügbar. Ich verwende die vorhandene Infrastruktur für „Anleitungen“ in den ersten Phasen der Erstellung der zentralen Dokumentation für jeden impliziten Typ. So kann ich diese Seiten wie unten beschrieben ganz einfach referenzieren, ohne neue öffentliche Klassen erstellen zu müssen (erneut anhand der LineCollection-Dokumente als Beispiel):

""""""
linestyles: LineStyle or list thereof, default: :rc:`lines.linestyle` ('-')
    A description of whether the stroke used to draw each line in the collection
    is dashed, dotted or solid, or some combination thereof. For a full
    description of possible LineStyle's, see :doc:`tutorials/types/linestyle`.
""""""

In Zukunft können wir die Schreibweise dieser Verweise dann ganz einfach ändern, sobald sich das Kernentwicklungsteam auf die beste langfristige Strategie zur Einbindung unserer neuen „types“-Dokumentation in echte Python-Klassen geeinigt hat, wie ich es in Matplotlib Enhancement Proposal 30 vorgeschlagen habe.

Hier ist eine vorläufige Liste der impliziten Typen, die ich während der Google Season of Docs dokumentieren möchte:

  1. capstyle
  2. joinstyle
  3. bounds
  4. extents
  5. linestyle
  6. colors/lists of colors
  7. colornorm/colormap
  8. tick formatters

Eine aktuelle Version dieses Dokuments finden Sie in unserem Discourse-Forum.