繁体   English   中英

如何使用 FastAPI/Nextjs 显示 Matplotlib 图表而不在本地保存图表?

[英]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()作为Responsecontent传递,以便获取包含缓冲区全部内容的字节。 此外,如果整个图像数据已经加载到 memory 中(在这种情况下,在内存字节缓冲区中),则不应使用StreamingResponse ,而是直接返回Response并设置Content-Disposition header,以便可以在浏览器中查看图像,如this answer以及thisthis 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM