Wir nutzen Plotly-Diagramme in großem Umfang in dem Unternehmen, für das ich arbeite. Sie machen es einfach, interaktive Grafiken zu erstellen, die gut aussehen. Das Python-Erlebnis über die Plotly Express-Bibliothek ist großartig und die Hürde für den Einstieg ist niedrig.
Wir haben zwei Hauptanwendungsfälle für Plotly-Diagramme:
Für einen typischen PDF-Bericht verwenden wir 5–20 Zahlen, um die Entwicklung einer bestimmten Metrik im Zeitverlauf, die Verteilung eines Werts über mehrere Kategorien oder den Vergleich verschiedener Kategorien nebeneinander darzustellen.
Um unsere PDF-Berichte zu erstellen, verwenden wir eine Kombination aus Weasyprint-, Jinja- und Plotly-Diagrammen. Um einen Bericht als PDF darzustellen, müssen wir zunächst alle Grafiken als Bilder rendern.
Dazu nutzen wir das tolle Kaleido-Paket. Es verwendet einen Chrome-Browser, um das Diagramm zu rendern und als Bild zu speichern. Die API ist einfach zu verwenden.
from kaleido.scopes.plotly import PlotlyScope scope = PlotlyScope() img_bytes = scope.transform( figure=figure, format="png", width=1000, height=1000, scale=4, )
Dadurch wird die Figur in der Abbildung als Bild mit 1000 Pixel Höhe und Breite und einem Rendering-Maßstab von 4 gerendert (d. h. das Bild hat tatsächlich die Abmessungen 4000 Pixel x 4000 Pixel). Je höher der Maßstab, desto mehr DPI hat das endgültige Bild, desto besser sieht es aus und desto größer ist das endgültige PDF.
Das Rendern von Diagrammen nimmt ein wenig Zeit in Anspruch, und wenn Sie viele davon (10–20) rendern, wird es einen erheblichen Teil der Laufzeit Ihres Programms ausmachen. Um unsere PDF-Rendering-Pipeline zu beschleunigen, haben wir die folgende Lösung bereitgestellt.
Intern lagert Kaleido lediglich das Problem der Darstellung des Diagramms als Bild an einen mitgelieferten Chrome-Webbrowser aus. Das bedeutet, dass Python selbst beim Rendern dieses Bildes im Grunde auf E/A wartet.
Um diesen speziellen Prozess zu beschleunigen und da wir nur auf E/A warten, können wir Multithreading verwenden.
Beginnen wir damit, eine zufällige Figur zu erstellen, etwa so:
import pandas as pd import numpy as np import plotly.graph_objects as go def get_random_figure() -> go.Figure: n_bars = 50 dates = pd.date_range(start="2021-01-01", end="2021-12-31", freq="M") figure = go.Figure() for i in range(n_bars): values = np.random.rand(len(dates)) figure.add_trace(go.Bar(x=dates, y=values, name=f"Label {i+1}")) figure.update_layout( dict( barmode="group", legend=dict(orientation="h", yanchor="top", xanchor="left"), ) ) figure.update_layout(yaxis=dict(tickformat=".0%"), xaxis=dict(showgrid=False)) return figure
Nun kann die Umwandlung einer Figur in ein Bild mit dem Code von oben erfolgen:
from kaleido.scopes.plotly import PlotlyScope import plotly.graph_objects as go def figure_to_bytes(figure: go.Figure) -> bytes: scope = PlotlyScope() return scope.transform(figure=figure, format="png", width=1000, height=1000, scale=4)
Und schließlich definieren wir auch für später:
def transform_random_figure() -> bytes: return figure_to_bytes(get_random_figure())
Sie wissen vielleicht oder auch nicht, dass aufgrund der GIL (Global Interpreter Lock) in Python nur ein Thread gleichzeitig Python-Code ausführen kann. Da die Umwandlung des Diagramms in ein Bild kein Python-Code ist, können wir Threads verwenden, um die Umwandlung vieler Diagramme gleichzeitig zu starten und dann die Ergebnisse zu sammeln.
Dazu definieren wir eine Hilfsklasse:
from kaleido.scopes.plotly import PlotlyScope scope = PlotlyScope() img_bytes = scope.transform( figure=figure, format="png", width=1000, height=1000, scale=4, )
Diese Klasse hilft uns, das Ergebnis der Transformation (d. h. die Bytes des Bildes) abzurufen.
Als nächstes müssen wir dem Standardmuster für die Arbeit mit Threads in Python folgen:
Unsere Threads sollten jeweils transform_random_figure() aufrufen und dann die Bytes zurückgeben. Wir starten in diesem Fall 10 Threads.
import pandas as pd import numpy as np import plotly.graph_objects as go def get_random_figure() -> go.Figure: n_bars = 50 dates = pd.date_range(start="2021-01-01", end="2021-12-31", freq="M") figure = go.Figure() for i in range(n_bars): values = np.random.rand(len(dates)) figure.add_trace(go.Bar(x=dates, y=values, name=f"Label {i+1}")) figure.update_layout( dict( barmode="group", legend=dict(orientation="h", yanchor="top", xanchor="left"), ) ) figure.update_layout(yaxis=dict(tickformat=".0%"), xaxis=dict(showgrid=False)) return figure
Die start()-Methode ruft auch die run()-Methode des Threads auf, der die eigentliche Logik startet (d. h. die angegebene Funktion ausführt, was in unserem Fall transform_random_figure() bedeutet).
Um die Ergebnisse zu sammeln, verwenden wir die Methode join() der Threads und schreiben das Ergebnis in Dateien.
from kaleido.scopes.plotly import PlotlyScope import plotly.graph_objects as go def figure_to_bytes(figure: go.Figure) -> bytes: scope = PlotlyScope() return scope.transform(figure=figure, format="png", width=1000, height=1000, scale=4)
Die Hauptidee hier ist, wann immer wir ein Diagramm in ein Bild umwandeln möchten, einen Thread zu starten und dieser Thread wartet im Hintergrund darauf, dass das Diagramm fertiggestellt wird.
Sobald wir den gesamten Bericht zusammengestellt haben, rufen wir join() für alle Threads auf, rufen die Bilder für alle Diagramme ab und fügen sie dann in den Bericht ein.
Auf diese Weise können wir bereits den gesamten Bericht ohne Diagramme erstellen und Zeit sparen, indem wir nicht darauf warten müssen, dass jedes Diagramm einzeln transformiert wird.
Zusammenfassend lässt sich sagen: Wenn Sie mehrere Plotly-Diagramme in Bilder umwandeln möchten, verwenden Sie das Multithreading-Modul in der Python-Standardbibliothek, um Ihren Konvertierungsprozess zu beschleunigen.
Sie können dies ganz einfach tun, indem Sie einfach den transform()-Aufruf in einen Thread verschieben und dann warten, bis alle Threads abgeschlossen sind.
def transform_random_figure() -> bytes: return figure_to_bytes(get_random_figure())
Das obige ist der detaillierte Inhalt vonParalleles Konvertieren von Plotly-Diagrammen in Bilder. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!