[英]How to display a Matplotlib chart with FastAPI/ Nextjs without saving chart locally?
我正在为网站使用 Nextjs 前端和 FastAPI 后端。 我在前端有一个“以太坊地址”的输入表单,并使用输入的地址,我在后端生成了一个 matplotlib 图表,显示“随时间变化的以太坊余额”。 现在,我正在尝试使用 FastAPI 返回此图表,以便可以在前端显示它。 我不想在本地保存图表。
到目前为止,这是我的相关代码:
名为“Chart.tsx”的前端/nexjs 文件。 正文中的“ethAddress”正在捕获输入表单中输入的数据。
fetch("http://localhost:8000/image", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(ethAddress),
}).then(fetchEthAddresses);
后端 python 文件生成名为 ethBalanceTracker.py 的 matplotlib 图表
#Imports
#Logic for chart here
plt.plot(times, balances)
buf = BytesIO()
plt.savefig(buf, format="png")
buf.seek(0)
return StreamingResponse(buf, media_type="image/png")
后端 python 文件使用称为 api.py 的 FastAPI
@app.get("/image")
async def get_images() -> dict:
return {"data": images}
@app.post("/image")
async def add_image(ethAddress: dict) -> dict:
test = EthBalanceTracker.get_transactions(ethAddress["ethAddress"])
images.append(test)
我已经尝试了上面的代码和其他一些变体。 我正在使用StreamingResponse
,因为我不想在本地保存图表。 我的问题是我无法让图表显示在localhost:8000/images
中,并且出现'Internal Server Error'
。
您应该将buf.getvalue()
作为Response
的content
传递,以便获取包含缓冲区全部内容的字节。 此外,如果整个图像数据已经加载到 memory 中(在这种情况下,在内存字节缓冲区中),则不应使用StreamingResponse
,而是直接返回Response
并设置Content-Disposition
header,以便可以在浏览器中查看图像,如this answer以及this和this answer中所述。 如果您使用 Fetch API 或 Axios 来获取图像,请查看这个关于如何在客户端显示图像的答案。 您还可以使用 FastAPI/Starlette 的BackgroundTasks
在返回响应后关闭缓冲区,以释放 memory,如此处所述。 例子:
import io
import matplotlib
matplotlib.use('AGG')
import matplotlib.pyplot as plt
from fastapi import FastAPI, Response, BackgroundTasks
app = FastAPI()
def create_img():
plt.rcParams['figure.figsize'] = [7.50, 3.50]
plt.rcParams['figure.autolayout'] = True
plt.plot([1, 2])
img_buf = io.BytesIO()
plt.savefig(img_buf, format='png')
plt.close()
return img_buf
@app.get('/')
def get_img(background_tasks: BackgroundTasks):
img_buf = create_img()
background_tasks.add_task(img_buf.close)
headers = {'Content-Disposition': 'inline; filename="out.png"'}
return Response(img_buf.getvalue(), headers=headers, media_type='image/png')
另一方面,如果您在使用matplotlib
时收到以下警告:
UserWarning: Starting a Matplotlib GUI outside of the main thread will likely fail.
WARNING: QApplication was not created in the main() thread.
这是因为matplotlib
不是线程安全的,并且大多数 GUI 后端需要从主线程运行(这实际上是来自 Qt 库本身的警告)。 为避免收到该警告,您可以使用matplotlib.use()
简单地切换到非 GUI 后端 - 因为您甚至不需要一个,因为您在客户端的用户浏览器中显示图像,如所示后端文档和上面的示例(注意:在导入pyplot
之前必须使用matplotlib.use()
)。 上例中使用的AGG
是将图形呈现为 PNG 的后端。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.