Projekt Matplotlib

Ta strona zawiera szczegółowe informacje na temat projektu technicznego przyjęta do programu Sezon Dokumentów Google.

Podsumowanie projektu

Organizacja open source:
Matplotlib
Pisarz techniczny:
brunobeltran
Nazwa projektu:
Poprawa wykrywalności funkcji przez standaryzację dokumentacji typów niejawnych
Długość projektu:
Długotrwałe (5 miesięcy)

Opis projektu

Motywacja

W przeszłości interfejs API matplotlib w dużej mierze opierał się na „ciągach pośrednich” typu „implicit type” („typy niejawne”). Ciągi parametrów, oprócz imitowania interfejsu API matlab, pozwalają użytkownikowi na przekazywanie wartości o dużej semantyce w postaci argumentów funkcji matplotlib bez konieczności importowania lub szczegółowego poprzedzania rzeczywistej wartości wyliczeniowej w celu przekazywania podstawowych opcji wykresu (np.plt.plot(x, y, linestyle='solid') jest łatwiejszy do wpisania i mniej nadmiarowy niż np. plt.plot(x, y, linestyle=mpl.LineStyle.solid)).

Od tego czasu wiele z tych typów pośrednich typu „ciąg znaków jako wyliczenie” ewoluowało bardziej zaawansowane funkcje. Na przykład obiekt linestyle może być ciągiem tekstowym lub 2 kropkami sekwencji, a element znaczniki Style może być teraz ciągiem tekstowym lub matplotlib.path.Path. Choć dzieje się tak w przypadku wielu typów niejawnych, jako jedyny (o czym wie) jedyna dostępna w Pythonie klasa Pythona.

Ponieważ te typy niejawne nie są klasami własnymi, w Matplotlib występowały własne rozwiązania w celu scentralizowanej dokumentacji i weryfikacji typów niejawnych (np. wzorca interpolacji docstringu docstring.interpd.update i wzorca walidatora cbook._check_in_list), a nie standardowych łańcuchów narzędzi dostarczanych przez klasyfikujące wzorce (np. ciągi znaków w klasach prawidłowego poprawności__init__).

Te rozwiązania się sprawdziły w naszym przypadku, ale brak wyraźnej lokalizacji, w której można by udokumentować każdy typ niejawny, oznacza to, że często trudno jest znaleźć odpowiednią dokumentację. W dokumentacji powtarzają się duże tabele dozwolonych wartości, a często w dokumentacji brakuje wyraźnego zakresu typu niejawnego. Zobacz dokumentację plt.plot, na przykład w sekcji „Notes” opis metody stylu ciągu znaków formatu przypominającego matlab zawiera opcje linestyle, color i markers. Istnieje wiele innych sposobów przekazywania tych 3 wartości, niż wskazujemy na to, ale dla wielu użytkowników jest to jedyne źródło wiedzy o wartościach dostępnych w przypadku tych opcji, dopóki nie natrafią na jeden z odpowiednich samouczków. Tabela atrybutów Line2D ma na celu pokazanie czytelnikowi opcji kontroli fabuły. Mimo że wpis linestyle dobrze sprawdza się jako połączenie z elementem Line2D.set_linestyle (wymagane są 2 kliknięcia), gdy opisane są możliwe dane wejściowe, wpisy color i markers nie. color po prostu łączy się z usługą Line2D.set_color, która nie inspiruje użytkownika pod kątem dozwolonych rodzajów danych wejściowych.

Można by argumentować, że ten problem można rozwiązać, po prostu usuwając poszczególne ciągi w dokumencie, które powodują problemy, ale niestety jest to problem o wiele bardziej systemowy. Brak centralnego miejsca do przeszukiwania dokumentacji sprawia, że po prostu mamy więcej kopii coraz bardziej szczegółowej dokumentacji powtarzanej wszędzie tam, gdzie używany jest każdy z typów niejawnych, co utrudnia początkującym użytkownikom po prostu znalezienie potrzebnego parametru. Jednak obecny system, który zmusza użytkowników do stopniowego łączenia modeli myślowych każdego z nich, korzystając z opisanych w naszej dokumentacji stylów wiki oraz elementów z przykładów StackOverflow, również nie jest zrównoważony.

Cel końcowy

W idealnej sytuacji każda wzmianka o typie niejawnym powinna prowadzić do jednej strony, która zawiera opis wszystkich możliwych wartości, które może przyjąć, uporządkowana od najprostszej, najpowszechniejszej do najbardziej zaawansowanej lub ezoterycznej. Zamiast używać cennej przestrzeni wizualnej w głównej dokumentacji interfejsu API do szczegółowego wyliczania wszystkich możliwych typów danych wejściowych dla danego parametru, możemy użyć tego samego miejsca, aby w prosty sposób opisać, jaką abstrakcje nanoszenia ma sterować dany parametr.

Ponownie spójrzmy na przykład z tabelą linestyle. Dokumenty LineCollection powinny wyglądać tak:

  1. Link do pełnej dokumentacji dotyczącej dozwolonych danych wejściowych (kombinacji tych pochodzących z Line2D.set_linestyle i samouczka dotyczącego stylu linii).
  2. Jasny opis celu, do którego służy dany parametr. W przypadku zaawansowanych użytkowników matplotlib jest to jasne na podstawie nazwy parametru, ale w przypadku nowych użytkowników nie musi tak być.

W rzeczywistych dokumentach LineCollection wyglądałoby to tak: 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. """""", gdzie Sphinx rozpoznałby odniesienie do typu LineStyle, by wskazać pojedynczy, rzetelny i kompletny zestaw dokumentacji dotyczącej sposobu, w jaki Matplotlib traktuje style linii.

Zalety

Oto kilka zalet tego podejścia:

  1. Pełne obliczenie właściwości każdej funkcji w sposób oczywisty w postaci zwykłego tekstu (nie trzeba więc klikać żadnych kliknięć).
  2. Pokazywanie opcji domyślnej (bez kliknięć). Zauważenie opcji domyślnej często wystarcza, aby „wydobyć” z pamięci powracających użytkowników.
  3. Stwórz pełny opis „najczęstszych” i „najprostszych” opcji parametru, które są łatwo dostępne podczas przeglądania danych (jednym kliknięciem).
  4. Odkrywanie bardziej zaawansowanych funkcji i metod wprowadzania danych może być bardzo łatwe – wystarczy kliknąć „przewiń w dół”, aby zobaczyć bardziej zaawansowane opcje.
  5. Udostępnij scentralizowaną strategię łączenia dokumentów najwyższego poziomu dotyczących interfejsu API z odpowiednimi samouczkami.
  6. Unikaj eksplozji dokumentów w interfejsie API, ponieważ przeglądanie wielu możliwych opcji każdego z parametrów sprawia, że poszczególne ciągi dokumentów stają się nieporęczne.

Inne zalety tego podejścia w porównaniu z obecnymi dokumentami:

  1. Dokumenty rzadziej staną się nieaktualne dzięki centralizacji.
  2. Stosowanie kanonicznej liczby „dorozumianych standardów” (takich jak „granice” i „zakresy”) matplotlib, których należy się obecnie opanować poprzez odczytanie kodu.
  3. Proces ten wskazuje problemy ze spójnością interfejsu API w sposób, który można łatwiej śledzić za pomocą narzędzia do śledzenia problemów na GitHubie, co usprawnia proces ulepszania API.
  4. Szybsze tworzenie dokumentów ze względu na znaczne zmniejszenie ilości tekstu do przeanalizowania.

Implementacja

Opisane wyżej ulepszenia będą wymagały 2 dużych starań, w których bezcenny będzie cenny autor pracy technicznej. Pierwszym z nich jest utworzenie 1 scentralizowanej strony „tutorial” na każdy typ niejawny. Wymaga to współpracy z głównym zespołem programistów w celu opracowania konkretnej listy typów niejawnych, których dokumentacja będzie przydatna dla użytkowników (zwykle dlatego, że zawierają one zaawansowane, ukryte funkcje naszej biblioteki, której dokumentację można obecnie znaleźć tylko w samouczkach złożonych z trudnościami). W przypadku każdego typu niejawnego łączę różne odpowiednie samouczki, dokumenty API i przykładowe strony w jedno wiarygodne źródło dokumentacji, która może być połączona z dowolnymi odwołaniami do konkretnego typu.

Po zakończeniu scentralizowanej dokumentacji danego typu niejawnego rozpoczyna się drugi główny cel: zastąpienie dotychczasowej dokumentacji interfejsów API linkami do nowej dokumentacji w taki sposób, aby korzystanie z nowej dokumentacji było jak najprostsze zarówno dla użytkowników korzystających z wbudowanego narzędzia help() w Pythonie, jak i dla osób przeglądających naszą dokumentację online.

Chociaż dokładny format proponowanej dokumentacji może się zmieniać w miarę rozwoju projektu, podczas cotygodniowych „rozmów z deweloperem” Matplotlib współpracowałem z podstawowym zespołem Matplotlib w celu ustalenia, że proponowana tu strategia jest najskuteczniejszym, przydatnym i technicznie możliwym rozwiązaniem do rozpoczęcia dokumentowania tych „typów” (dostępne są informacje na temat tych połączeń). Na początkowych etapach tworzenia scentralizowanej dokumentacji dla każdego typu domyślnego będę korzystać z istniejącej infrastruktury „samouczki”, aby móc łatwo odwoływać się do tych stron w następujący sposób, bez konieczności tworzenia nowych klas publicznych (ponownie, na przykład z dokumentów LineCollection):

""""""
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`.
""""""

W przyszłości moglibyśmy z łatwością zmienić pisownię tych odniesień, gdy główny zespół programistów ustali najlepszą długoterminową strategię włączania nowej dokumentacji „types” do rzetelnych klas Pythona, na przykład zaproponowanego przeze mnie w ramach propozycji rozszerzenia Matplotlib ">3030<br class="ph-1-1.

Na koniec wstępna lista rodzajów niejawnych, które proponuję udokumentować w tym sezonie Dokumentów Google, to:

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

Aktualizowaną wersję tego dokumentu można znaleźć na naszym dysku.