Search
Matplotlib renderuje data na displej nebo do souboru prostřednictvím backendu, což je vykreslovací zařízení poskytované operačním systémem prostřednictvím vhodné knihovny (např. Qt). Pro naše účely použijeme neinteraktivní statické backendy (tj. nebude se vytvářet vykreslovací okno) a graf budeme transformovanat na proud binárních dat. Tato data pak pošleme společně s vhodným mime-type jako odpověď na dotaz GET z prohlížeče, který renderuje HTML kód obsahující tag <img/>.
mime-type
GET
<img/>
import io import random from matplotlib.figure import Figure from matplotlib.backends.backend_agg import FigureCanvasAgg from matplotlib.backends.backend_svg import FigureCanvasSVG @app.route("/matplot-as-image-<int:num_x_points>.png") def plot_png(num_x_points=50): fig = Figure() axis = fig.add_subplot(1, 1, 1) x_points = range(num_x_points) axis.plot(x_points, [random.randint(1, 30) for x in x_points]) output = io.BytesIO() FigureCanvasAgg(fig).print_png(output) return Response(output.getvalue(), mimetype="image/png")
HTML kód, který požádá server o graf 200 náhodných bodů ve formátu PNG pak vypadá následovně.
<img src="/matplot-as-image-200.png" alt="random points as png" height="200"/>
@app.route("/matplot-as-image-<int:num_x_points>.svg") def plot_svg(num_x_points=50): fig = Figure() axis = fig.add_subplot(1, 1, 1) x_points = range(num_x_points) axis.plot(x_points, [random.randint(1, 30) for x in x_points]) output = io.BytesIO() FigureCanvasSVG(fig).print_svg(output) return Response(output.getvalue(), mimetype="image/svg+xml")
Data URI je způsob, jak obsah externího souboru zapsat přímo do HTML/CSS. Pokud není použit protokol HTTP/2, režie navázání spojení pro získáním jednotlivého souboru může být mnohem větší než samotné stažení dat. Při velkém počtu souborů hraje navíc roli maximální počet souběžných spojení, kvůli kterému musí soubory čekat ve frontě.
Následující příklad produkuje datový proud v kódování base64, navíc se využívá toho, že od verze 3.1 knihovny Matplotlib není třeba instacionovat CanvasAgg. Celý příklad je zde.
base64
CanvasAgg
fig = Figure() # kod pro vytvoreni grafu output = io.BytesIO() fig.savefig(output, format="png") data = base64.b64encode(buf.getbuffer()).decode("ascii") return f"<img src='data:image/png;base64,{data}'/>"
Pro kreslení grafů lze samozřejmě využít render na straně klienta, např. pomocí vhodné knihovny v JavaScriptu. Takovou knihovnou je např. chart.js.
Knihovna umožňuje vykreslovat datové řady do HTML elementu canvas. Nejprve je třeba vytvořit instanci třídy Chart, které se předá handler na element.
var ctx = document.getElementById('tempChart').getContext('2d'); var tempChart = new Chart(ctx, { type: 'line', data: { labels: [], datasets: [{ label: 'temperature', data: [] },{ label: 'humidity', data: [] }] } });
Předpokládejme, že data přichází do prohlížeče asynchronně např. prostřednictvím SSE a jsou tvořena třemi hodnotami (čas, teplota, vlhkost) oddělenými čárkou. Funkce pro zpracování takových dat může vypadat třeba takto:
SSE
var eventSource = new EventSource('/stats'); eventSource.onmessage = function (event) { var data = event.data.split(','); console.log(data); var currentTime = data[0]; var temp = parseInt(data[1]); var humi = parseInt(data[2]); tempChart.data.labels.push(currentTime); tempChart.data.datasets[0].data.push(temp); tempChart.data.datasets[1].data.push(humi); if (tempChart.data.labels.length > 30) { tempChart.data.labels.shift(); tempChart.data.datasets[0].data.shift(); tempChart.data.datasets[1].data.shift(); } tempChart.update(); };
Element pro vykreslování pak může vypadat třeba takto:
<canvas id="tempChart" width="800" height="400"></canvas>
Celý příklad ke stažení zde