JSONで画像をやりとりする python <-> JavaScript (React)
TL;DR
matplotlibは非常に優れたPythonのPlot libraryであり、バックエンド側でpngやsvgを作成しフロントエンド側に送って表示させたい場合があります。そういう場合にどうすればいいのか、まとまっている情報があまりなかったのでメモ。
Python 3.7.4 Node v12.16.2
Python側
基本的にBytesIO
を使ってBufferを読み込んで、その値をJSONにSerializeします。
とりあえずサンプルプロットを作成します。JSONを送信する方法はflaskなりdjangoなりを使ってください。
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
print(matplotlib.__version__)
# '3.2.2'
x = np.linspace(0, 10, 10000)
fig, ax = plt.subplots()
ax.plot(x, np.sin(x))
これについて、png/svgをJSONにシリアライズします。svgはそのままシリアライズできますが、pngについてはbase64 encodingが必要です。pngじゃなくてjpegとかでも同様です。
SVG to JSON
import io
import json
with io.BytesIO() as buf:
fig.savefig(buf, format="svg")
svg = buf.getvalue().decode("utf-8")
print(json.dumps({"svg": svg}))
# 長いので出力は省略
PNG to JSON
import io
import json
import base64
with io.BytesIO() as buf:
fig.savefig(buf, format="png")
png = base64.encodebytes(buf.getvalue()).decode("utf-8")
print(json.dumps({"png": png}))
JavaScript (React)側
こっちは色々方法があると思いますが、JSX使うのが楽なのでReactを使います。JSONはfetchとかaxiosとかで持ってくるものとします。持ってきたデータをjson_data
としておきます。
SVG rendering from JSON
innerHTMLとして埋め込むこともできますが、今回はreact-inlinesvgというパッケージを使ってしまいます。propsで受け渡されていることにしましょう。
npm i react-inlinesvg
import React from "react";
import SVG from "react-inlinesvg";
const Svg = ({ json_data }) => {
return <SVG src={json_data.svg} />;
};
PNG rendering from JSON
こちらはデフォルトで<img src={}>
にblobから作成したURIを入れればいいです。
import React from "react";
const Png = ({ json_data }) => {
const buf = Buffer.from(json_data.png, "base64");
const blob = new Blob([buf], { type: "image/png" });
const uri = URL.createObjectURL(blob);
return <img src={uri} />;
};
最後に
まとまった情報が見つからなかったのでメモがてら残しておきます。