Pandas: API: API für Pandas-Plot-Backends definieren

Erstellt am 9. Juni 2019  ·  44Kommentare  ·  Quelle: pandas-dev/pandas

In #26414 haben wir das Pandas-Plotting-Modul in ein allgemeines Plotting-Framework aufgeteilt, das verschiedene Backends und die aktuellen Matplotlib-Backends aufrufen kann. Die Idee ist, dass andere Backends einfacher implementiert und von Pandas-Benutzern mit einer gemeinsamen API verwendet werden können.

Die vom aktuellen Matplotlib-Backend definierte API enthält die als nächstes aufgeführten Objekte, aber diese API kann wahrscheinlich vereinfacht werden. Hier die Liste mit Fragen/Vorschlägen:

Nicht umstrittene Methoden, die in der API beibehalten werden sollen (Sie bieten die Series.plot(kind='line') ... Funktionalität):

  • Liniendiagramm
  • BarPlot
  • BarhPlot
  • HistPlot
  • Box-Plot
  • KdePlot
  • BereichPlot
  • PiePlot
  • Streudiagramm
  • HexBinPlot

In Pandas bereitgestellte Plotfunktionen (zB pandas.plotting.andrews_curves(df) )

  • andrews_curves
  • autocorrelation_plot
  • bootstrap_plot
  • lag_plot
  • parallele_koordinaten
  • radviz
  • Scatter_Matrix
  • Tisch

Sollen diese Teil der API sein und andere Backends sollten sie auch implementieren? Wäre es sinnvoll in das Format .plot zu konvertieren (zB DataFrame.plot(kind='autocorrelation') ...)? Ist es sinnvoll, sich von der API fernzuhalten oder zu einem Drittanbietermodul zu wechseln?

Redundante Methoden, die möglicherweise entfernt werden können:

  • hist_series
  • hist_frame
  • Box-Plot
  • boxplot_frame
  • boxplot_frame_groupby

Im Fall von boxplot haben wir derzeit mehrere Möglichkeiten, einen Plot zu generieren (wobei hauptsächlich derselbe Code aufgerufen wird):

  1. DataFrame.plot.boxplot()
  2. DataFrame.plot(kind='box')
  3. DataFrame.boxplot()
  4. pandas.plotting.boxplot(df)

Persönlich würde ich Nummer 4 ablehnen und für Nummer 3 eine separate boxplot_frame Methode im Backend ablehnen oder zumindest nicht benötigen, aber versuchen, BoxPlot wiederzuverwenden (für Kommentare zu Nummer 3, das Gleiche .) gilt für hist ).

Für boxplot_frame_groupby , nicht im Detail überprüft, aber nicht sicher, ob BoxPlot dafür wiederverwendet werden kann?

Funktionen zum Registrieren von Konvertern:

  • registrieren
  • abmelden

Sind diese für andere Backends sinnvoll?

In Pandas 0.23 veraltet, wird entfernt:

  • tsplot

Um zu sehen, was jede dieser Funktionen in der Praxis bewirkt , kann dieses Notizbuch von sein : https://github.com/python-sprints/pandas_plotting_library/blob/master/AllPlottingExamples.ipynb

CC: @pandas-dev/pandas-core @tacaswell , @jakevdp , @philippjfr , @PatrikHlobil

API Design Clean Needs Discussion Visualization

Hilfreichster Kommentar

Hier ist eine auf Einstiegspunkten basierende Implementierung

diff --git a/pandas/plotting/_core.py b/pandas/plotting/_core.py
index 0610780ed..c8ac12901 100644
--- a/pandas/plotting/_core.py
+++ b/pandas/plotting/_core.py
@@ -1532,8 +1532,10 @@ class PlotAccessor(PandasObject):

         return self(kind="hexbin", x=x, y=y, C=C, **kwargs)

+_backends = {}

-def _get_plot_backend(backend=None):
+
+def _get_plot_backend(backend="matplotlib"):
     """
     Return the plotting backend to use (e.g. `pandas.plotting._matplotlib`).

@@ -1546,7 +1548,14 @@ def _get_plot_backend(backend=None):
     The backend is imported lazily, as matplotlib is a soft dependency, and
     pandas can be used without it being installed.
     """
-    backend_str = backend or pandas.get_option("plotting.backend")
-    if backend_str == "matplotlib":
-        backend_str = "pandas.plotting._matplotlib"
-    return importlib.import_module(backend_str)
+    import pkg_resources  # slow import. Delay
+    if backend in _backends:
+        return _backends[backend]
+
+    for entry_point in pkg_resources.iter_entry_points("pandas_plotting_backends"):
+        _backends[entry_point.name] = entry_point.load()
+
+    try:
+        return _backends[backend]
+    except KeyError:
+        raise ValueError("No backend {}".format(backend))
diff --git a/setup.py b/setup.py
index 53e12da53..d2c6b18b8 100755
--- a/setup.py
+++ b/setup.py
@@ -830,5 +830,10 @@ setup(
             "hypothesis>=3.58",
         ]
     },
+    entry_points={
+        "pandas_plotting_backends": [
+            "matplotlib = pandas:plotting._matplotlib",
+        ],
+    },
     **setuptools_kwargs
 )

Ich finde es ganz nett. Pakete von Drittanbietern ändern ihre setup.py (oder pyproject.toml) um etwas wie

entry_points={
    "pandas_plotting_backends": ["altair = pdvega._pandas_plotting_backend"]
}

Mir gefällt, dass es die enge Kopplung zwischen Benennung und Implementierung durchbricht.

Alle 44 Kommentare

Ich denke, dass Dinge wie Autokorrelation aus der austauschbaren Back-End-API herausgehalten werden.

Ich denke, wir haben Dinge wie df.boxplot und hist belassen, weil sie ein etwas anderes Verhalten haben als die .plot-API. Ich würde nicht empfehlen, sie Teil der Back-End-API zu machen.

Hier ist mein Start für eine vorgeschlagene Backend-API von vor einigen Monaten: https://github.com/TomAugspurger/pandas/commit/b07aba28a37b0291fd96a1f571848a7be2b6de8d

Ich denke, es ist erwähnenswert, dass zumindest hvplot (den Rest nicht überprüft) bereits die Funktionen wie andrews_curves , scatter_matrix , lag_plot bereitstellt. ..

Wenn wir nicht alle Backends zwingen möchten, diese zu implementieren, können wir überprüfen, ob das ausgewählte Backend sie implementiert, und standardmäßig die Matplotlib-Plots verwenden?

Ich nahm an, dass sich boxplot und hist genau gleich verhalten haben, aber ich hatte nur Abkürzungen Series.hist() für Series.plot.hist() . Die "Verknüpfung" zeigt das Plotraster, aber ansonsten habe ich keinen Unterschied gesehen.

IMO, der Hauptwert dieser Option ist der Namespace .plot .

Wenn Benutzer das Andrew-Kurvendiagramm von hvplot wünschen, sollten sie die Funktion importieren
von hvplot und übergeben Sie den Datenrahmen dorthin.

Am Sonntag, den 9. Juni 2019 um 7:17 Uhr schrieb Marc Garcia [email protected] :

Ich denke, es ist erwähnenswert, dass zumindest hvplot (nicht überprüft)
rest) bietet bereits die Funktionen wie andrews_curves,
Scatter_Matrix, lag_plot,...

Wenn wir nicht alle Backends zwingen wollen, diese zu implementieren, können wir das vielleicht tun
Überprüfen Sie, ob das ausgewählte Back-End sie implementiert, und verwenden Sie standardmäßig die
Matplotlib-Plots?

Ich nahm an, dass sich Boxplot und Hist genau gleich verhalten, aber ich hatte einfach
Shortcuts Series.hist() für Series.plot.hist(). Die "Verknüpfung" zeigt die
Plot-Grid, aber ansonsten habe ich keinen Unterschied gesehen.


Sie erhalten dies, weil Sie in einem Team sind, das erwähnt wurde.
Antworten Sie direkt auf diese E-Mail und zeigen Sie sie auf GitHub an
https://github.com/pandas-dev/pandas/issues/26747?email_source=notifications&email_token=AAKAOIRLJHBMXMXKK2IG2NDPZTYFPA5CNFSM4HWIMEK2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKT77PY15DXment
oder den Thread stumm schalten
https://github.com/notifications/unsubscribe-auth/AAKAOISDHL6H7PVOOJAQXELPZTYFPANCNFSM4HWIMEKQ
.

Ich denke, das macht Sinn, aber wenn wir das tun, sollten wir sie in pandas.plotting.matplotlib.andrews_curves statt in pandas.plotting.andrews_curves .

@TomAugspurger Ich muss genauer https://github.com/TomAugspurger/pandas/commit/b07aba28a37b0291fd96a1f571848a7be2b6de8d implementiert haben, ist diejenige, die mehr Sinn macht. Ich werde daran arbeiten, wenn ich #26753 fertig habe. Ich werde auch experimentieren, ob es möglich ist, andrews_curves , scatter_matrix ... in die .plot() Syntax zu verschieben , Bibliotheken von Drittanbietern und Benutzer).

Was ist hier die Absicht in Bezug auf zusätzliche Kwargs, die an Plotfunktionen übergeben werden? Sollten zusätzliche Backends versuchen, die Funktionalität aller Plotanpassungen im Matplotlib-Stil zu duplizieren, oder sollten sie die Übergabe von Schlüsselwörtern zulassen, die denen des jeweiligen Backends entsprechen?

Die erste Option wäre theoretisch schön, würde aber erfordern, dass jedes Nicht-Matplotlib-Plotting-Backend im Wesentlichen seine eigene Matplotlib-Konvertierungsschicht mit einem langen Schwanz von Inkompatibilitäten implementiert, die im Wesentlichen nie vollständig sein würden (aus Erfahrung als jemand, der versucht hat, mpld3 zu erstellen). Jahre zurück).

Die zweite Option ist aus der Sicht der Austauschbarkeit nicht so schön, würde aber das Hinzufügen anderer Backends mit vernünftigeren Erwartungen ermöglichen.

Ich denke, es liegt am Backend, was sie damit machen. Erreichen von 100 %
Kompatibilität über Backends ist nicht wirklich machbar,
da der Rückgabetyp keine Matplotlib Axes mehr sein wird. Und wenn
wir sind beim Rückgabetyp nicht kompatibel, ich glaube nicht, dass Backends
sollte sich nach hinten beugen, um zu versuchen, jedes mögliche Schlüsselwortargument zu verarbeiten.

Ich denke also, Pandas sollten dokumentieren, dass **kwargs durchgereicht wird an
die zugrunde liegende Plotting-Engine, und sie können damit machen, was sie wollen
Sie.

Am Mo, 10.06.2019 um 10:42 Jake Vanderplas [email protected]
schrieb:

Was ist hier die Absicht in Bezug auf zusätzliche Kwargs, die an die Verschwörung weitergegeben werden?
Funktionen? Sollten zusätzliche Back-Ends versuchen, die
Funktionalität aller Plotanpassungen im Matplotlib-Stil, oder sollten sie
erlauben, dass Schlüsselwörter übergeben werden, die denen entsprechen, die von der jeweiligen Person verwendet werden
Backend?

Die erste Option wäre theoretisch schön, würde aber alle erfordern
Nicht-Matplotlib-Plotting-Backend, um im Wesentlichen seine eigene Matplotlib zu implementieren
Konversionsschicht mit einem langen Schwanz von Inkompatibilitäten, die
im Wesentlichen nie vollständig sein (aus Erfahrung sprechend als jemand, der
vor einigen Jahren versucht, mpld3 zu erstellen).

Die zweite Option ist aus der Sicht von nicht so schön
Austauschbarkeit, würde aber das Hinzufügen anderer Back-Ends mit mehr ermöglichen
vernünftige Erwartungshaltung.


Sie erhalten dies, weil Sie erwähnt wurden.
Antworten Sie direkt auf diese E-Mail und zeigen Sie sie auf GitHub an
https://github.com/pandas-dev/pandas/issues/26747?email_source=notifications&email_token=AAKAOIS3IBV4XSSY7BPSCF3PZZY5LA5CNFSM4HWIMEK2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHZ65
oder den Thread stumm schalten
https://github.com/notifications/unsubscribe-auth/AAKAOIQ3GYOGAPUZ4LSNK2DPZZY5LANCNFSM4HWIMEKQ
.

Es tut mir leid, wenn dies eine dumme Frage ist, aber wenn Sie eine Plotter-"API" definieren, die im Grunde eine Gruppe von vorgefertigten Plots ist, würde dann nicht jedes Backend mehr oder weniger die gleiche Ausgabe produzieren? welche neue Fähigkeit soll damit ermöglicht werden? so etwas wie ein pandas to vega exporteur vielleicht?

Ich glaube nicht, dass es richtig ist zu sagen, dass jedes Backend mehr oder weniger die gleiche Ausgabe produziert.

Matplotlib ist beispielsweise wirklich gut für statische Diagramme, aber nicht für die Erstellung tragbarer interaktiver Diagramme.

Auf der anderen Seite können Bokeh, Altair et al. eignen sich hervorragend für interaktive Diagramme, sind jedoch nicht ganz so ausgereift wie matplotlib für statische Diagramme.

In der Lage zu sein, beide mit derselben API zu produzieren, wäre ein großer Gewinn.

Die erste Option wäre theoretisch schön, würde aber erfordern, dass jedes Nicht-Matplotlib-Plotting-Backend im Wesentlichen seine eigene Matplotlib-Konvertierungsschicht mit einem langen Schwanz von Inkompatibilitäten implementiert, die im Wesentlichen nie vollständig sein würden (aus Erfahrung als jemand, der versucht hat, mpld3 zu erstellen). Jahre zurück).

und bindet Matplotlib auch noch mehr fest, als wir es bereits API-technisch sind. Ich denke, es ist sinnvoll, dass Pandas angeben, welche Style-Knöpfe sie freigeben möchten, und erwarten, dass die Backend-Implementierungen herausfinden, was das bedeutet. Dies kann bedeuten, dass **kwargs _nicht_ blind übergeben wird und stattdessen sichergestellt wird, dass die zurückgegebenen Objekte "das Richtige" für das angegebene Backend sind, um nachträgliche Stilanpassungen vornehmen zu können.

Matplotlib ist beispielsweise wirklich gut für statische Diagramme, aber nicht für die Erstellung tragbarer interaktiver Diagramme.

Danke @jakevdp , ja, interaktive Diagramme zu unterstützen ist ein gutes Ziel.

Bevor die Dinge auf diesem speziellen Weg zu weit gehen, ist hier eine alternative Lösung.

Anstatt die Pandas-Plotting-API jetzt als Spezifikation zu proklamieren und Viz-Pakete zu bitten, sie speziell zu implementieren, warum nicht eine Zwischendarstellung (wie eine vega-JSON-Datei) des Plots generieren und Back-Ends ermutigen, dies als Eingabe zu verwenden.

Vorteile sind:

  1. Nicht an die Ausdruckskraft einer verdinglichten Pandas-API gebunden zu sein, die nicht als Spezifikation konzipiert wurde.
  2. Die Arbeit, die durch das Plotten von Paketen zur Unterstützung von Pandas geleistet wird, wird anderen Pydata-Paketen zur Verfügung gestellt, die IR erzeugen.
  3. Förderung einer gemeinsamen Sprache für die Austauschvisualisierung im pydata-Raum
  4. Das macht das neue Tool leistungsstärker, weil breiter anwendbar
  5. Das macht den Aufwand, sie zu schreiben, vernünftiger. Grundsätzlich verbesserte Anreize.

Vega/Vega-lite , als moderne, etablierte, offene und JSON-basierte Visualisierungs-Spezifikationssprache, die mehrere Mannjahre in Design und Implementierung gesteckt hat, und vorhandene Tools, die darauf aufgebaut sind, scheinen ausdrücklich für diesen Zweck entwickelt worden zu sein . (nur bitte nicht ).

Wissen Sie, frontend->IR->backend , wie Compiler entworfen sind.

Mindestens drei Pakete implementieren die API bereits. Alles, was Pandas tun müssen, ist eine Option zum Ändern des Backends anzubieten und seine Verwendung zu dokumentieren, was für unser Geld ein guter Knaller zu sein scheint.

Am 15. Juni 2019 um 16:28 Uhr schrieb pilkibun [email protected] :

Matplotlib ist beispielsweise wirklich gut für statische Diagramme, aber nicht für die Erstellung tragbarer interaktiver Diagramme.

Danke @jakevdp , ja, interaktive Diagramme zu unterstützen ist ein gutes Ziel.

Bevor die Dinge auf diesem speziellen Weg zu weit gehen, ist hier eine alternative Lösung.

Anstatt die Pandas-Plotting-API jetzt als Spezifikation zu proklamieren und Viz-Pakete zu bitten, sie speziell zu implementieren, warum nicht eine Zwischendarstellung (wie eine vega-JSON-Datei) des Plots generieren und Back-Ends ermutigen, dies als Eingabe zu verwenden.

Vorteile sind:

Nicht an die Ausdruckskraft einer verdinglichten Pandas-API gebunden zu sein, die nicht als Spezifikation konzipiert wurde.
Die Arbeit, die durch das Plotten von Paketen zur Unterstützung von Pandas geleistet wird, wird anderen Pydata-Paketen zur Verfügung gestellt, die IR erzeugen.
Förderung einer gemeinsamen Sprache für die Austauschvisualisierung im pydata-Raum
Das macht das neue Tool leistungsstärker, weil breiter anwendbar
Das macht den Aufwand, sie zu schreiben, vernünftiger. Grundsätzlich verbesserte Anreize.
Vega/Vega-lite, als moderne, etablierte, offene und JSON-basierte Viz-Spezifikationssprache, mehrere Mannjahre in Design und Implementierung gesteckt, und bestehende Tools, die darauf aufgebaut sind, scheinen ausdrücklich für diesen Zweck entwickelt worden zu sein . (nur bitte nicht).

Sie wissen, Frontend->IR->Backend, wie Compiler entworfen sind.


Sie erhalten dies, weil Sie erwähnt wurden.
Antworten Sie direkt auf diese E-Mail, zeigen Sie sie auf GitHub an oder schalten Sie den Thread stumm.

Wir haben jetzt #26753 zusammengeführt und das Plot-Backend kann von Pandas geändert werden. Beim Aufteilen des Matplotlib-Codes haben wir SeriesPlotMethods und FramePlotMethods auf der Pandas-Seite (nicht Matplotlib) belassen. Das war hauptsächlich, um die Docstrings auf der Panda-Seite zu belassen.

Aber ich sehe, dass Backends diese Klassen neu implementieren. Derzeit erwarten wir also, dass die Backends eine Klasse pro Plot haben (zB LinePlot , BarPlot ), aber stattdessen implementieren sie eine Klasse mit einem Plot pro Methode (zB hvPlot, or the same names as pandas for pdvega `).

Was ich zumindest als erste Version für sinnvoll halte, ist, dass wir die API wie hvplot und pdvega implementieren. Ich würde einfach eine abstrakte Klasse in Pandas erstellen, von der Backends erben.

Wenn das Gefühl für alle macht, ich durch die Schaffung der abstrakten Klasse beginnen werden und die Anpassung des matplotlib Backend wir in Pandas haben, und sobald dies geschehen ist, wir passen hvplot und pdvega (die Änderungen es sollte ziemlich klein sein).

Die Gedanken?

Was ich zumindest als erste Version für sinnvoll halte, ist, dass wir die API wie hvplot und pdvega implementieren. Ich würde einfach eine abstrakte Klasse in Pandas erstellen, von der Backends erben.

Ich denke, dass dieser Ansatz insgesamt sauberer sein wird. Ich kann nicht mit anderen Plot-Backends sprechen, aber zumindest in hvPlot teilen sich verschiedene Plotmethoden ziemlich viel Code, zB scatter , line und area sind weitgehend analog, und Ich würde es vorziehen, mich nicht auf Unterklassen zu verlassen, um Code zwischen ihnen zu teilen. Außerdem denke ich, dass verschiedene Backends die Möglichkeit haben sollten, zusätzliche Plottypen hinzuzufügen, und diese als zusätzliche öffentliche Methoden verfügbar zu machen, scheint der einfachste und natürlichste Ansatz zu sein.

Nur um sicher zu gehen, dass ich es verstehe, wenn Sie I'd prefer not to rely on subclassing to share code between them sagen, meinen Sie wie in class LinePlot(MPLPlot) , richtig? Und nicht, dass Sie es für eine schlechte Idee halten, von einer abstrakten Basisklasse zu erben?

Ich denke, ich bin +1, wenn es darum geht, Backends Plottypen definieren zu lassen, die nicht in Pandas enthalten sind. Aber ich werde es jetzt wohl nicht umsetzen. Wir planen, Pandas in ungefähr einer Woche freizulassen. Und ich denke, dies erfordert etwas mehr Nachdenken, als die Methoden von Backends blind aufzurufen, wenn der Benutzer kind='foo' bereitstellt und das Backend die Methode foo bereitstellt (z dass einige kind in der Dokumentation stehen und andere nicht).

Nur um sicherzugehen, dass ich es verstehe, wenn Sie sagen, ich würde es vorziehen, mich nicht auf Unterklassen zu verlassen, um Code zwischen ihnen zu teilen, meinen Sie wie in der Klasse LinePlot (MPLPlot), oder? Und nicht, dass Sie es für eine schlechte Idee halten, von einer abstrakten Basisklasse zu erben?

Ja, das ist richtig. Konkreter würde ich es vorziehen, so etwas nicht tun zu müssen:

class MPL1dPlot(MPLPlot):

    def _some_shared_method(self, ...):
        ...

class LinePlot(MPL1dPlot):
    ...

class AreaPlot(MPL1dPlot):
    ...

Sorry, wenn das nicht klar war.

Sehr zu Gunsten einer einfacheren API, die öffentlich als einzelne Funktion bereitgestellt wird, anstelle der Klassen, wie jetzt in https://github.com/pandas-dev/pandas/pull/27009 vorgeschlagen

Allgemeine Frage/Anmerkung, wie die Backend-Option jetzt funktioniert. Angenommen, ich bin der pdvega Entwickler und stelle dieses Backend zur Verfügung. Das heißt, wenn Benutzer pd.options.plotting.backend = 'pdvega' , muss die pdvega Bibliothek eine plot Funktion der obersten Ebene haben?
1) als Bibliothek Autor, die nicht unbedingt ist die Funktion , die Sie wollen öffentlich (Bedeutung aussetzen, für die Top-Level - plot Methode vom Standpunkt der Bibliothek aus betrachtet, ist es nicht unbedingt die API , dass Sie möchten , dass Ihre Benutzer direkt zu verwenden) und 2) für diesen Fall möchten Sie vielleicht tatsächlich pd.options.plotting.backend = 'altair' tun können? (falls Altair-Entwickler damit einverstanden sind)
Meine Frage ist also im Grunde: Muss es eine genaue 1:1-Zuordnung des Backend-Namens geben und was wird importiert? (was jetzt benötigt wird, da es einfach den bereitgestellten Backend-String importiert).

EDIT: Ich sehe, dass in der PR #26753 tatsächlich etwas Ähnliches diskutiert wurde

Wenn wir die Entscheidung treffen, dass Pandas nicht weiß/einschränkt, welche Backends verwendet werden können (was ich nachdrücklich befürworte), müssen wir entscheiden, wie/was in den Backends aufgerufen werden soll.

Was es in der PR, an der ich arbeite, implementiert und vorgeschlagen wurde, ist, dass die Option plotting.backend ein Modul ist (kann pdvega , altair , altair.pandas , oder was auch immer), und dieses Modul muss eine öffentliche plot Funktion haben, die wir nennen werden.

Wir können andere Optionen in Betracht ziehen, z. B. wenn die Option pdvega , wir pdvega.pandas importieren, oder wir können die Funktion plot_pandas oder was auch immer nennen. Ich denke, der vorgeschlagene Weg ist der einfachste, aber wenn es andere Vorschläge gibt, die sinnvoller sind, ändere ich ihn gerne.

Eine andere Diskussion ist, ob wir die Benutzer zwingen möchten, die Backends manuell zu importieren:

import pandas
import hvplot

pandas.Series([1, 2, 3]).plot()

Wenn wir das tun, können sich die Module selbst registrieren, sie können auch Aliase registrieren (damit set_option andere Namen als den Namen des Moduls verstehen kann). Sie können auch benutzerdefinierte Funktionen oder Maschinen (zB Kontextmanager) implementieren, um mit bestimmten Backends zu plotten,... Ich persönlich denke, je einfacher wir die Dinge halten, desto besser.

Und obwohl es nett sein könnte, pandas.set_option('plotting.backend', 'bokeh') zu tun, um in Bokeh zu plotten, denke ich, dass dies zwei Dinge impliziert, die ich persönlich nicht mag:

  • pandas.set_option('plotting.backend', 'bokeh') funktioniert nur, wenn import pandas_bokeh aufgerufen wurde und wird für die Benutzer verwirrend sein.
  • Es impliziert auch, dass es nur ein Modul zum Plotten in bokeh . Was nicht wahr sein muss und den Benutzern den falschen Eindruck vermittelt, dass Sie direkt mit Bokeh plotten und nicht mit einem Pandas-Backend für Bokeh.

@datapythonista danke für die ausführliche Antwort. Ich bin damit einverstanden, es jetzt so zu belassen, wie es für die erste Veröffentlichung ist (Möglichkeit für Alias ​​kann später immer hinzugefügt werden).

Wenn Benutzer das Andrew-Kurvendiagramm von hvplot wünschen, sollten sie die Funktion von hvplot importieren und den Datenrahmen dorthin übergeben.

+1, würde ich auch nicht alle zusätzlichen Plotting-Funktionen über das Backend bereitstellen.

Aber das Verschieben nach pandas.plotting.matplotlib scheint mir ein unnötiger, rückwärts inkompatibler Bruch zu sein (vorausgesetzt, Sie wollten nicht nur die Implementierung verschieben).

pandas.set_option('plotting.backend', 'bokeh') funktioniert nur, wenn import pandas_bokeh aufgerufen wurde, und wird für die Benutzer verwirrend sein.

Wenn wir Einstiegspunkte verwenden , um Erweiterungen zu registrieren, muss dies nicht der Fall sein: Wenn das Paket auf dem System installiert ist, wird der Einstiegspunkt registriert und für Pandas sichtbar gemacht. Dies verwendet Altair beispielsweise, um verschiedene Renderer zu erkennen, die der Benutzer möglicherweise installiert hat.

Außerdem denke ich, dass ich pdvega, wenn es einmal drin ist, wahrscheinlich verwerfen und den relevanten Code in ein neues Paket namens pandas_altair oder etwas Ähnliches verschieben würde.

@datapythonista Ich denke, wir sollten vor 0.25.0 über den Umfang der Plotting-Backend-API entscheiden (allerdings nicht für den RC).

Sie sind dafür, die sonstigen Plotfunktionen (sowie Hist/Boxplot) beizubehalten?

@datapythonista das schließen, als wir die PR zusammengeführt haben?

@jreback Ich würde dies offen halten, bis wir uns auf die API einigen, @TomAugspurger und @jorisvandenbossche wollten nichts außer den Accessor-Plots an das Backend delegieren.

Was ich für die Plotter Pandas tun würde - das Backend ist als nächstes dran.

Zur Freigabe:

  • Lassen Sie die Dinge so, wie sie sind, hvplot implementiert alle Plots, die von den Accessoren und die, die es nicht sind. Und ich denke, alles zu delegieren macht die Dinge einfach.
  • Ich bin mir nicht sicher, ob ich die register_converters von den oben genannten ausschließen würde. Zumindest sollten wir den Namen von register_matplotlib_converters ändern, wenn wir sie delegieren

Für die nächste Ausgabe:

  • Ich würde alle Duplikate pandas.plotting.boxplot , Series.hist ,...
  • Ich würde alle Plots verschieben, die von Accessoren aufgerufen werden sollen (andrew_curves, radviz, parallel_curves,...).

Für eine erste Veröffentlichung der Back-End-API wäre ich lieber konservativer in dem, was wir veröffentlichen, als alles einzubeziehen. Es ist viel einfacher, Dinge später hinzuzufügen, als sie zu entfernen.

Ich persönlich würde auch nicht all diese Misc-Plots in den Accessor verschieben (es könnte einige Ausnahmen geben, wie Scatter-Matrix), IMO sind die andrew_curves und radviz usw. keine Methode "wert".

Das heißt: Wollen wir Backends erlauben, zusätzliche "Arten" zu implementieren? Wir müssen uns als Pandas also nicht genau entscheiden, welche Zugriffsmethoden verfügbar sein können. Wenn der Benutzer ein bestimmtes kind übergibt oder versucht, auf ein Attribut zuzugreifen, könnten wir es trotzdem mit einem benutzerdefinierten __getattribute__ an das Backend plot __getattribute__ .

Nur um ein bisschen zu erklären, warum die Dinge so sind, wie sie jetzt sind. Es ist relevant, weil ich nicht ganz sicher bin, wie ich die von Ihnen vorgeschlagenen Änderungen implementieren soll, oder die Dinge im Allgemeinen nicht offen legen. Ich sage hier nicht, dass es nicht anders gemacht werden kann, es soll nur die Diskussion bereichern.

Die erste Entscheidung war, den gesamten Code mit Matplotlib in ein separates Modul zu verschieben ( pandas.plotting._matplotlib ). Dadurch wurde dieses Modul irgendwie zum Matplotlib-Backend.

Alles, was in pandas.plotting öffentlich war, wurde dort als öffentlich gehalten. Und um die Dinge so einfach wie möglich zu machen, lädt jede dieser Funktionen, wenn sie einmal aufgerufen wurde, das Backend (Aufruf von _get_plot_backend ) und ruft die Funktion dort auf.

An der öffentlichen API für den Benutzer ändert sich überhaupt nichts, den Benutzern stehen weiterhin dieselben Methoden und Funktionen zur Verfügung. Wir enthüllen nichts Neues.

So wie ich die Dinge verstehe, wenn wir entscheiden, dass ein vorhandener Plot wie andrew_curves nicht an das Backend delegiert wird, bedeutet dies, dass wir, anstatt das Backend vom Benutzer auswählen zu lassen, immer noch das Matplotlib-Backend auswählen. Da mindestens hvplot andrew_curves bereits implementiert, sehe ich persönlich keinen Sinn. Wenn der Benutzer einen andrew_curves Plot in Matplotlib haben möchte, ist es so einfach, das Backend nicht zu ändern (oder es erneut einzustellen, wenn es geändert wurde). Mit der Änderung würden wir den Benutzern das Leben einfach viel schwerer machen, indem wir Pandas zusätzliche Komplexität verleihen.

Wenn wir mit Backend-Entwicklern nett sein wollen und sie nicht zwingen wollen, Plots zu implementieren, die möglicherweise nicht so Mainstream sind (ich denke, das ist eine der Gründe?), können wir möglicherweise alles, was im ausgewählten Backend fehlt, standardmäßig auf das Matplotlib-Backend setzen ?

Was das Delegieren einer unbekannten Art von Handlung an das Backend betrifft, bin ich gerade -1 dabei, es zu tun. Sicherlich kann es irgendwann Sinn machen. Aber ich denke, es fühlt sich ein bisschen hackig an, mehrere Handlungsarten in Pandas dokumentiert zu haben und zusätzliche zu haben, die wir nicht dokumentieren. Ich denke, es kann auf die nächste Version warten, nachdem wir Feedback dazu haben, wie verschiedene Backends für Benutzer funktionieren, und wir mehr Zeit haben, um im Detail zu diskutieren und zu analysieren.

Wenn der Benutzer einen andrew_curves-Plot in Matplotlib haben möchte, ist es so einfach, das Backend nicht zu ändern (oder es erneut einzustellen, wenn es geändert wurde). Mit der Änderung würden wir den Benutzern das Leben einfach viel schwerer machen, indem wir Pandas zusätzliche Komplexität verleihen.

Ich glaube nicht, dass wir dem Benutzer das Leben schwerer machen würden. Anstatt sie aus pandas.plotting zu importieren, können sie die Version eines hvplot einfach von dort importieren. Was für die DataFrame.plot-Methode nicht möglich ist, da sie auf dem Objekt definiert ist. Für mich ist das der Hauptgrund für das Plotten-Backend.

Wenn wir mit Backend-Entwicklern nett sein und sie nicht zwingen wollen, Plots zu implementieren, die vielleicht nicht so Mainstream sind

Mir geht es nicht darum, nett zu sein oder alles umzusetzen wäre nötig (es ist völlig in Ordnung, wenn ein Backend nicht alle Plotting-Typen unterstützt, IMO), sondern eher eine unnötige Erweiterung der Plotting-Backend-API, die uns auch daran bindet .
Wenn wir Pandas von Grund auf neu starten würden, glaube ich nicht, dass diese verschiedenen Plottypen enthalten wären. Aber mit der Plotting-Backend-API beginnen wir in gewisser Weise etwas Neues.

Gibt es hierzu noch andere Meinungen?

Einverstanden mit @jorisvandenbossche.


Nur um sicherzustellen, dass dies nicht verloren geht, denke ich, dass der Vorschlag von @jakevdp, die Einstiegspunkte von setuptool zu verwenden, in Betracht gezogen werden sollte, um das Problem mit der Registrierung der Importbestellung zu lösen: https://github.com/pandas-dev/pandas/issues/26747 #issuecomment -507415929

@jorisvandenbossche wie würdest du das im Code ändern? Anstatt das Backend zu erhalten, das in den Einstellungen für diese Methoden definiert ist, erhalten Sie das Matplotlib-Backend? Ich denke, das ist konzeptionell falsch, aber ich bin damit einverstanden, wenn es Übereinstimmung gibt. Alles, was die Entkopplung des Matplotlib-Codes vom Rest rückgängig macht, bin ich -1.

Da Sie erwähnen, dass wir diese Plots nicht in einen Panda von Grund auf einbeziehen würden, sollten wir sie verwerfen? Ich bin +1, wenn es darum geht, alle Plots, die keine Methoden von Series oder DataFrame in ein Drittanbieterpaket zu verschieben. Oder wenn eine wichtig genug ist, um sie zu behalten, verschieben Sie sie so, dass sie mit .plot() wie die anderen aufgerufen wird.

Ich würde die nicht standardmäßigen Plots in Pandas ablehnen
und zu einem externen Paket wechseln

Joris ist eine Weile offline.

Ich denke, wenn wir in der Vergangenheit darüber diskutiert haben, ist seine und meine Position zu Thesen, sie einfach unberührt zu lassen, bis sie zu einer Wartungslast werden.

Damit wir auf derselben Seite sind, ist dies eine Zusammenfassung dessen, was wir haben, und mein Verständnis des Stands der Diskussion:

Wird als Methoden von Series und DataFrame (wir alle behalten sie gerne so wie sie sind, delegiert an das ausgewählte Backend):

  • PlotAccessor
  • boxplot_frame
  • boxplot_frame_groupby
  • hist_frame
  • hist_series

Andere Plots (in Diskussion, ob sie veraltet, an das Matplotlib-Backend oder an das ausgewählte Backend delegiert werden sollten):

  • Box-Plot
  • Scatter_Matrix
  • radviz
  • andrews_curves
  • bootstrap_plot
  • parallele_koordinaten
  • lag_plot
  • autocorrelation_plot
  • Tisch

Andere öffentliche Sachen in pandas.plotting (auch in Diskussion):

  • plot_params
  • register_matplotlib_converters
  • deregister_matplotlib_converters

Was den Abschnitt Other plots betrifft, denke ich persönlich, dass sie zu diesem Zeitpunkt eine Wartungslast darstellen, und ich bin +1, wenn es darum geht, sie aus Pandas zu entfernen und sie in 0.25 zu verabschieden.

Für die Konverter und das andere Zeug ist das, was wir jetzt haben, sicherlich nicht richtig, da register_matplotlib_converters an den ausgewählten Plot delegiert, der nicht matplotlib sein kann. Die Optionen, die wir meiner Meinung nach in Betracht ziehen können, sind:

  • Benennen Sie sie in register_converters / deregister_converters , verwerfen Sie die aktuellen und delegieren Sie weiter an das Backend
  • Verschieben Sie sie von pandas.plotting nach pandas.plotting.matplotlib (was bedeuten würde, das Matplotlib-Backend öffentlich zu machen, also würde ich es nicht tun)
  • Lassen Sie sie wie sie sind und delegieren Sie an das Matplotlib-Backend anstelle des ausgewählten Backends (ich sehe dies eher als Hack denn als eine gute Designentscheidung, ich würde es vorziehen, pandas.plotting unabhängig davon zu lassen, welche Backends existieren)

Für den Abschnitt Andere Plots denke ich persönlich, dass sie zu diesem Zeitpunkt eine Wartungslast darstellen, und ich bin +1, wenn ich sie aus Pandas herausbekomme und sie in 0,25 verabschiede.

Wie empfinden Sie die "anderen Grundstücke" als Wartungsaufwand? Wenn man sich den Verlauf der "misc"-Plots ansieht: https://github.com/pandas-dev/pandas/commits/0.24.x/pandas/plotting/_misc.py , wir haben seit 2017 ~10-15 Commits Mehrheit sind globale Bereinigungen, die auf die gesamte Codebasis angewendet werden (also eine kleine marginale Belastung). Ich sehe nur 1-2 Commits, die Dokumente ändern, und keine Commits, die die Funktionalität ändern.

Benennen Sie sie in register_converters/deregister_converters um, verwerfen Sie die aktuellen und delegieren Sie weiter an das Backend

Ich glaube nicht, dass dies sinnvoll wäre. Es gibt Matplotlib-spezifische Konverter, die wir für Matplotlib geschrieben haben. Andere Back-Ends haben sie nicht. Es sollte wahrscheinlich nicht Teil der Back-End-API sein.

Ich meinte nicht, dass diese Plots aufgrund des Wartungsaufwands in den letzten Monaten der Jahre eine Belastung darstellen, sondern aufgrund des Problems, von dem sie jetzt ausgehen, dass sie eine konsistente und intuitive API für Benutzer und eine gute Modularität haben Code-Design für uns.

In Bezug auf die Konverter weiß ich nicht, ob Backend-Autoren in einigen Fällen das Äquivalent zu denen für matplotlib implementieren möchten. Aber es scheint kein Problem zu sein, wenn dies nicht der Fall ist, und diese Funktionen tun für einige oder alle anderen Backends nichts. Option 2 finde ich auch ok, finde ich aber nicht so ordentlich.

aber wegen des Problems, von dem sie jetzt annehmen, dass es eine konsistente und intuitive API für Benutzer und ein gutes modulares Codedesign für uns hat.

Sie sind jedoch bereits etwas inkonsistent mit DataFrame.plot. Der Name "misc" impliziert das :) Macht ein austauschbares Backend das noch schlimmer? In dem Maße, in dem es sich lohnt, den Benutzercode abzuwälzen? Ich glaube nicht.

Ich weiß nicht, ob Backend-Autoren in einigen Fällen das Äquivalent zu denen für matplotlib implementieren möchten.

Ich glaube nicht. Der Sinn dieser Konverter besteht darin, Matplotlib über Pandas-Objekte beizubringen. Bibliotheken, die das Backend implementieren, werden dieses Problem nicht haben, da sie bereits von Pandas abhängig sind.

Persönlich denke ich daran hauptsächlich im Hinblick auf das Management von Komplexität. Eine Standard-Plotting-API zu haben, die über eine einzige API an das Back-End delegiert wird, ist leicht zu verstehen und zu warten. Benutzer und Betreuer müssen nur lernen, dass es eine plot Funktion mit einem kind Argument gibt und diese im ausgewählten Backend ausgeführt wird.

Im Backend eine Reihe von heterogenen Plots zu haben, die nicht der gleichen API folgen, sondern ein Backend verwenden, aber nicht das für die anderen Plots ausgewählte, sondern das Matplotlib, fügt IMHO für jeden zu viel Komplexität hinzu.

Und die Kosten für das Verschieben erscheinen mir gering. Ich vermute, dass nicht ein großer Teil unserer Benutzer diese Plots überhaupt kennt. Und diejenigen, die dies tun, müssen nur ein zusätzliches Conda-Paket installieren und import pandas_plotting; pandas_plotting.andrews_curves(df) anstelle von pandas.plotting.andrews_curves(df) .

Für mich scheint es viel zu gewinnen, für wenig Geld, aber natürlich ist es nur eine Meinung.

Können wir dokumentieren, dass das austauschbare Backend nur für Series/DataFrame.plot ist? Das scheint eine ziemlich einfache Regel zu sein.

Fühlt sich an wie ein Hack, der mir unnötige Komplexität hinzufügt; Ich glaube nicht, dass es weniger intuitiv ist, wenn es in der Dokumentation erklärt wird.

Aber egal, keine große Sache. Wenn dies die bevorzugte Option ist, würde ich sie so implementieren, zumindest ist die Zunahme der Codekomplexität minimal: #27432

Wenn ich mir das jetzt genauer anschaue: Wenn ich das richtig verstehe, wird das Plot-Backend folgendermaßen eingestellt:

pd.set_option('plotting.backend', 'name_of_module')

Mein Verständnis ist also, wenn ich die folgende Arbeit machen möchte:

pd.set_option('plotting.backend', 'altair')

dann benötige ich das Altair-Paket der obersten Ebene, um alle Funktionen in https://github.com/pandas-dev/pandas/blob/master/pandas/plotting/_core.py zu definieren

Wenn ich das richtig verstehe, bedeutet dies, dass es für mich keine Möglichkeit gibt, pd.set_option('plotting.backend', 'altair') korrekt zum Laufen zu bringen, ohne das Altair-Paket in Pandas so zu kodieren, wie Matplotlib derzeit hartkodiert ist, ist das richtig?

https://github.com/pandas-dev/pandas/blob/f1b9fc1fab93caa59aebcc738eed7813d9bd92ee/pandas/plotting/_core.py#L1550 -L1551

Wenn ja, würde ich dringend empfehlen, die Mittel zu überdenken, mit denen diese API in Paketen von Drittanbietern verfügbar gemacht wird.

Meine vorgeschlagene Lösung wäre, ein eintrittspunktbasiertes Framework zu verwenden, mit dem ich beispielsweise ein Paket wie altair_pandas erstellen kann, das den altair Einstiegspunkt registriert, um die API zu implementieren. Andernfalls werden die Benutzer für immer verwirrt sein, dass pd.set_option('plotting.backend', 'altair') nicht das tut, was sie erwarten.

Einverstanden. Ich denke, Einstiegspunkte sind der richtige Weg. Ich werde etwas Prototypen.

Am Fr, 19. Juli 2019 um 13:16 Jake Vanderplas [email protected]
schrieb:

Schau dir das jetzt genauer an: wenn ich das richtig verstehe, so
Das Plot-Backend wird eingestellt mit:

pd.set_option('plotting.backend', 'name_of_module')

Mein Verständnis ist also, wenn ich die folgende Arbeit machen möchte:

pd.set_option('plotting.backend', 'altair')

dann benötige ich das Altair-Paket der obersten Ebene, um alle Funktionen zu definieren
in
https://github.com/pandas-dev/pandas/blob/master/pandas/plotting/_core.py.
Ich würde es vorziehen, den Top-Level-Namespace von Altair nicht mit all diesen zu verschmutzen
zusätzliche APIs. Tatsächlich würde ich es vorziehen, wenn Altairs Pandas-Erweiterung
lebe in einem separaten Paket, also ist es nicht an die Release-Kadenz von . gebunden
Altair selbst.

Wenn ich das richtig verstehe, bedeutet dies, dass ich keine Möglichkeit habe, pd.set_option('plotting.backend',
'altair') funktionieren korrekt, ohne das altair-Paket in Pandas fest zu codieren
die Art und Weise, wie Matplotlib derzeit hartcodiert ist, ist das richtig?

Wenn ja, würde ich dringend raten, zu überdenken, wie dies ermöglicht wird durch
Pakete von Drittanbietern. Insbesondere die Einführung eines zugangspunktbasierten Frameworks
würde mich ein Paket wie altair_pandas erstellen lassen, das den altair registriert
Einstiegspunkt. Andernfalls werden die Benutzer für immer verwirrt sein, dass pd.set_option('plotting.backend',
'altair') tut nicht das, was sie erwarten.


Sie erhalten dies, weil Sie erwähnt wurden.
Antworten Sie direkt auf diese E-Mail und zeigen Sie sie auf GitHub an
https://github.com/pandas-dev/pandas/issues/26747?email_source=notifications&email_token=AAKAOITQM7HH5X4SZ4IAPS3QAIAIBA5CNFSM4HWIMEK2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVW2HJD5
oder den Thread stumm schalten
https://github.com/notifications/unsubscribe-auth/AAKAOISFLHDGXLGQ3PUMNLDQAIAIBANCNFSM4HWIMEKQ
.

Es gab einen Zeitpunkt, an dem das, was Sie sagten, größtenteils richtig war, aber das ist nicht mehr der Fall.

Wenn Sie pandas.options.plotting.backend = 'altair' , brauchen Sie in 0.25 nur eine Funktion altair.plot() . Irgendwann dachte ich, es wäre besser, die Funktion pandas_plot statt einfach plot aufzurufen, also war es spezifisch in einem Backend, das andere Dinge hatte, aber wir haben die Änderung schließlich nicht vorgenommen.

Wenn das Erstellen der Funktion plot in der obersten Ebene von Altair ein Problem darstellt, können wir sie in einer zukünftigen Version umbenennen, oder Sie können auch altair.pandas.plot , aber dann müssen Benutzer pandas.options.plotting.backend = 'altair.pandas' festlegen

Sie können die Option sicherlich selbst ändern, sobald Benutzer import altair . Und wir könnten eine Registrierung von Backends implementieren. Aber ich denke, es wäre für Benutzer verwirrend, wenn sie die pandas.options.plotting.backend = 'altair' und es scheitert, weil sie die import altair vorher vergessen haben.

Eine letzte Sache ist zu bedenken, dass wir möglicherweise mehr als ein Pandas-Backend für Altair (oder eine andere Visualisierungsbibliothek) implementieren könnten. Dass der Name des Backends nicht altair , ist für mich also nicht unbedingt eine schlechte Sache.

Hier ist eine auf Einstiegspunkten basierende Implementierung

diff --git a/pandas/plotting/_core.py b/pandas/plotting/_core.py
index 0610780ed..c8ac12901 100644
--- a/pandas/plotting/_core.py
+++ b/pandas/plotting/_core.py
@@ -1532,8 +1532,10 @@ class PlotAccessor(PandasObject):

         return self(kind="hexbin", x=x, y=y, C=C, **kwargs)

+_backends = {}

-def _get_plot_backend(backend=None):
+
+def _get_plot_backend(backend="matplotlib"):
     """
     Return the plotting backend to use (e.g. `pandas.plotting._matplotlib`).

@@ -1546,7 +1548,14 @@ def _get_plot_backend(backend=None):
     The backend is imported lazily, as matplotlib is a soft dependency, and
     pandas can be used without it being installed.
     """
-    backend_str = backend or pandas.get_option("plotting.backend")
-    if backend_str == "matplotlib":
-        backend_str = "pandas.plotting._matplotlib"
-    return importlib.import_module(backend_str)
+    import pkg_resources  # slow import. Delay
+    if backend in _backends:
+        return _backends[backend]
+
+    for entry_point in pkg_resources.iter_entry_points("pandas_plotting_backends"):
+        _backends[entry_point.name] = entry_point.load()
+
+    try:
+        return _backends[backend]
+    except KeyError:
+        raise ValueError("No backend {}".format(backend))
diff --git a/setup.py b/setup.py
index 53e12da53..d2c6b18b8 100755
--- a/setup.py
+++ b/setup.py
@@ -830,5 +830,10 @@ setup(
             "hypothesis>=3.58",
         ]
     },
+    entry_points={
+        "pandas_plotting_backends": [
+            "matplotlib = pandas:plotting._matplotlib",
+        ],
+    },
     **setuptools_kwargs
 )

Ich finde es ganz nett. Pakete von Drittanbietern ändern ihre setup.py (oder pyproject.toml) um etwas wie

entry_points={
    "pandas_plotting_backends": ["altair = pdvega._pandas_plotting_backend"]
}

Mir gefällt, dass es die enge Kopplung zwischen Benennung und Implementierung durchbricht.

Ich habe nicht mit Einstiegspunkten gearbeitet, sind sie wie eine globale Registrierung der Python-Umgebung? Da ich neu für sie bin, mag ich die Idee nicht, aber ich denke, das wäre dann ein vernünftiger Weg.

Ich möchte immer noch beide Optionen haben, also wenn der Benutzer pandas.options.plottting.backend = 'my_own_project.my_custom_small_backend' tut, funktioniert es und erfordert nicht das Erstellen eines Pakets und das Festlegen von Einstiegspunkten.

Ich habe nicht mit Einstiegspunkten gearbeitet, sind sie wie eine globale Registrierung der Python-Umgebung?

Ich habe sie auch nicht benutzt, aber ich denke, das ist die Idee. Soweit ich weiß, stammen sie von setuptools (aber Pakete wie Flit Hooks?). Sie sind also nicht Teil der Standardbibliothek, aber setuptools verwendet sowieso jeder.

Ich hätte trotzdem gerne beide Möglichkeiten

Es erscheint vernünftig, auf import_module(backend_name) .

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen