Matplotlib-Projekt

Diese Seite enthält die Details zu einem Projekt für technisches Schreiben, das für die Google-Produktsaison von Google Docs akzeptiert wurde.

Projektzusammenfassung

Open-Source-Organisation:
Matplotlib
Technischer Redakteur:
Brunobeltran
Projektname:
Verbesserung der Auffindbarkeit von Features durch Standardisierung der Dokumentation „impliziter“ Typen
Projektdauer:
Langfristig (5 Monate)

Projektbeschreibung

Ziel

In der Vergangenheit stützte sich die API von Matplotlib hauptsächlich auf "implizite Typen" von Strings als Enum. Diese Parameterstrings ahmen nicht nur die API von Matlab nach, sondern ermöglichen es dem Nutzer, semantisch aussagekräftige Werte als Argumente an matplotlib-Funktionen zu übergeben, ohne einen tatsächlichen ENUM-Wert explizit importieren oder voranstellen zu müssen, um grundlegende Darstellungsoptionen zu übergeben (d.h. plt.plot(x, y, linestyle='solid') ist einfacher einzugeben und weniger redundant als etwas wie plt.plot(x, y, linestyle=mpl.LineStyle.solid)).

Viele dieser impliziten String-as-Enum-Typen haben seitdem anspruchsvollere Funktionen entwickelt. Ein linestyle kann jetzt beispielsweise entweder ein String oder ein 2-Tupel von Sequenzen sein und ein MarkerStyle kann entweder ein String oder ein matplotlib.path.Path sein. Obwohl dies auf viele implizite Typen zutrifft, ist „MarkerStyle“ (meiner Wissen) der einzige, der den Status eines Upgrades auf eine geeignete Python-Klasse hat.

Da diese impliziten Typen keine eigenen Klassen sind, musste Matplotlib bisher eigene Lösungen zur Zentralisierung der Dokumentation und Validierung dieser impliziten Typen (z. B. das Docstring-Interpolationsmuster docstring.interpd.update bzw. das Validierungsmuster cbook._check_in_list) einführen, anstatt die von Python-Muster bereitgestellten Standard-Toolchains (z. B. entsprechende docstrings und die Validierung nach __init__) zu verwenden.

Diese Lösungen haben sich zwar gut bewährt, aber das Fehlen eines expliziten Speicherorts zur Dokumentation jedes impliziten Typs bedeutet, dass die Dokumentation oft schwer zu finden ist. Außerdem wiederholen sich große Tabellen mit zulässigen Werten in der gesamten Dokumentation und oft fehlt in den Dokumenten häufig eine explizite Angabe des Geltungsbereichs eines impliziten Typs. Sehen wir uns die plt.plot-Dokumente an. In der Beschreibung der matlab-ähnlichen Formatstring-Stilmethode werden beispielsweise die Optionen linestyle, color und markers in „Notes“ erwähnt. Es gibt viel mehr Möglichkeiten, diese drei Werte zu übergeben, als angedeutet werden, aber für viele Nutzer ist dies die einzige Quelle, um zu verstehen, welche Werte für diese Optionen möglich sind, bis sie auf eine der relevanten Anleitungen stoßen. Mithilfe einer Tabelle mit Line2D-Attributen soll dem Leser gezeigt werden, welche Möglichkeiten er zur Steuerung seines Diagramms hat. Der Eintrag linestyle stellt zwar eine gute Verbindung zu Line2D.set_linestyle her (zwei Klicks erforderlich), wo die möglichen Eingaben beschrieben werden, die Einträge color und markers jedoch nicht. color ist einfach mit Line2D.set_color verknüpft, was keine Vorstellung davon bietet, welche Arten von Eingaben überhaupt zulässig sind.

Man könnte argumentieren, dass das Problem behoben werden kann, indem die einzelnen docstrings, die Probleme verursachen, einfach aufgeräumt werden. Leider ist das Problem jedoch wesentlich systemischer. Ohne einen zentralen Ort, an dem wir die Dokumentation finden, führt dies einfach dazu, dass wir immer mehr Kopien der immer ausführlicheren Dokumentation überall dort wiederholen müssen, wo jeder dieser impliziten Typen verwendet wird. Dadurch wird es besonders für unerfahrene Nutzer schwieriger, den gewünschten Parameter einfach zu finden. Das aktuelle System, das Nutzer dazu zwingt, langsam ihre mentalen Modelle jedes impliziten Typs durch Wiki-Diving-Stil in unserer Dokumentation oder stückweise aus StackOverflow-Beispielen zusammenzustellen, ist jedoch ebenfalls nicht tragfähig.

Ziel beenden

Idealerweise sollte jede Erwähnung eines impliziten Typs mit einer einzigen Seite verknüpft sein, auf der alle möglichen Werte beschrieben werden, die der Typ annehmen kann. Die Werte sind von einfach und allgemein bis hin zu fortgeschritten oder esoterisch geordnet. Anstatt in der API-Dokumentation auf oberster Ebene wertvollen visuellen Platz zu nutzen, um alle möglichen Eingabetypen für einen bestimmten Parameter stückweise aufzuzählen, können wir denselben Raum verwenden, um eine wortgetreue Beschreibung der grafischen Abstraktion anzugeben, die der Parameter steuern soll.

Um wieder das Beispiel für linestyle zu verwenden, benötigen wir in der LineCollection-Dokumentation einfach Folgendes:

  1. Ein Link zur vollständigen Dokumentation für zulässige Eingaben (eine Kombination aus den in Line2D.set_linestyle und der Linienstilanleitung gefundenen Eingaben).
  2. Eine einfache Beschreibung dessen, was der Parameter erreichen soll. Für Matplotlib-Poweruser ist dies aus dem Parameternamen ersichtlich, für neue Nutzer muss dies jedoch nicht der Fall sein.

In der tatsächlichen LineCollection-Dokumentation würde dies so aussehen: 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. """""", wobei der LineStyle-Typverweis von Sphinx aufgelöst wird, um auf einen einzelnen, maßgeblichen und vollständigen Dokumentationssatz für die Behandlung von Linienstilen durch Matplotlib zu verweisen.

Vorteile

Zu den leistungsstarken Funktionen dieses Ansatzes gehören

  1. Vollständige Darstellung dessen, was jede Funktion im Nur-Text-Format deutlich machen kann (ohne Klicks erforderlich).
  2. Standardoption sichtbar machen (ohne Klicks) Die Standardoption reicht oft aus, um das Gedächtnis wiederkehrender Nutzer zu verbessern.
  3. Geben Sie eine vollständige Beschreibung der „am häufigsten vorkommenden“ und „einfachsten“ Optionen für einen Parameter an, der beim Browsen (mit einem einzigen Klick) leicht verfügbar ist.
  4. Machen Sie das Entdecken leistungsstärkerer Funktionen und Eingabemethoden so einfach wie „nach unten scrollen“, um erweiterte Optionen zu sehen (mit nur einem Klick).
  5. Bereitstellung einer zentralisierten Strategie für die Verknüpfung von „API“-Dokumenten der obersten Ebene mit den relevanten „Tutorials“.
  6. Vermeiden Sie eine explosionsartige API-Dokumentation, bei der das Scannen der vielen möglichen Optionen für die einzelnen Parameter die einzelnen Dokumentstrings unhandlich macht.

Weitere Vorteile dieses Ansatzes gegenüber den bisherigen Dokumenten sind folgende:

  1. Dokumente werden aufgrund der Zentralisierung mit geringerer Wahrscheinlichkeit veraltet.
  2. Kanonisierung vieler „impliziter Standards“ von Matplotlib (z. B. was ein „Grenzen“ im Vergleich zu einer „Erweiterung“ ist), die derzeit durch Lesen des Codes gelernt werden müssen.
  3. So lassen sich Probleme mit der API-Konsistenz auf eine Weise hervorheben, die sich leichter über die GitHub-Problemverfolgung nachverfolgen lässt, was zur Verbesserung der API beiträgt.
  4. Schnellere Dokumenterstellung, da deutlich weniger Text geparst werden muss.

Implementierung

Die oben beschriebenen Verbesserungen erfordern zwei Hauptanstrengungen, für die ein engagierter technischer Redakteur von unschätzbarem Wert ist. Die erste besteht darin, eine zentrale „Tutorial“-Seite pro impliziten Typ zu erstellen. Dazu müssen Sie mit dem Kernentwicklerteam zusammenarbeiten, um eine konkrete Liste impliziter Typen zu erstellen, deren Dokumentation für die Nutzer nützlich wäre. Dies liegt in der Regel daran, dass sie leistungsstarke, versteckte Funktionen unserer Bibliothek enthalten, deren Dokumentation derzeit nur in schwer zu überschaubaren Anleitungen zu finden ist. Für jeden impliziten Typ fasse ich dann die verschiedenen relevanten Anleitungen, API-Dokumente und Beispielseiten in einer einzigen maßgeblichen Dokumentationsquelle zusammen, die mit jedem Verweis auf diesen bestimmten Typ verknüpft werden kann.

Sobald die zentralisierte Dokumentation für einen bestimmten impliziten Typ abgeschlossen ist, beginnt der zweite große Aufwand: Die vorhandene API-Dokumentation durch Links zur neuen Dokumentation zu ersetzen, um die tatsächliche Verwendung dieser neuen Dokumentation so einfach wie möglich zu gestalten – sowohl für diejenigen, die das integrierte help()-Dienstprogramm von Python verwenden als auch für diejenigen, die unsere Dokumentation online durchsuchen.

Das genaue Format der hier vorgeschlagenen Dokumentation kann sich im Zuge der Weiterentwicklung dieses Projekts zwar ändern, ich habe jedoch während der wöchentlichen „Dev-Calls“ mit dem Kernteam von Matplotlib zusammengearbeitet, um einen Konsens zu erzielen, dass die hier vorgeschlagene Strategie der effizienteste, nützlichste und technisch nachvollziehbarste Ansatz ist, um mit der Dokumentation dieser „impliziten Typen“ zu beginnen. Hinweise zu diesen Hacks finden Sie. Ich verwende die vorhandene „Tutorials“-Infrastruktur für die Anfangsphase der Erstellung der zentralen Dokumentation für jeden impliziten Typ. So kann ich diese Seiten ganz einfach so referenzieren, ohne neue öffentliche Klassen erstellen zu müssen (auch hier als Beispiel: LineCollection-Dokumente verwenden):

""""""
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önnten wir dann einfach die Schreibweise dieser Verweise ändern, sobald sich das Kernentwicklungsteam auf die beste langfristige Strategie für die Einbindung unserer neuen „types“-Dokumentation in guten Python-Kursen geeinigt hat, wie ich sie zum Beispiel im Matplotlib Enhancement Vorschlag 30 vorgeschlagen habe.

Abschließend noch eine vorläufige Liste der impliziten Typen, die ich während dieser Google-Staffel von Docs dokumentiert habe:

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

Eine lebendige Version dieses Dokuments finden Sie in unserem Diskurs.