Home > Enterprise >  How to save sympy plot to a buffer
How to save sympy plot to a buffer

Time:06-02

I'm writing an API using fastapi in which there is an endpoint for plotting an arbitrary graph. The client posts the graph equation to the server and the server returns the plot. This is my current implementation:

import fastapi
import uvicorn
from sympy import plot, parse_expr
from pydantic import BaseModel

api = fastapi.FastAPI()

class Eq(BaseModel):
    eq: str

@api.post('/plot/')
async def plotGraph(eq: Eq):
    exp = parse_expr(eq.eq)
    p = plot(exp, show=False)
    p.save('./plot.png')
    return fastapi.responses.FileResponse('./plot.png')

uvicorn.run(api, port=3006, host="127.0.0.1")

The thing is here i'm saving the plot on the hard drive then reading it again using FileResponse which is kind of redundant.

How to return the underlying image object to the client without the need to writing it to the hard drive first?

CodePudding user response:

SymPy uses Matplotlib. But to achieve your goal you have to either:

  1. hack your way around with SymPy plotting and use the answer to this question. When you call p.save(), it executes a few important commands. Since we don't want to call p.save() we have to execute those commands instead to generate the plot.
# after this command, p only contains basic information
# to create the plot
p = plot(sin(x), show=False)
# now we create Matplotlib figure and axes
p._backend = p.backend(p)
# then we populate the plot with the data
p._backend.process_series()

# now you are ready to use this answer:
# https://stackoverflow.com/questions/68267874/return-figure-in-fastapi

# this is how you access savefig
p._backend.fig.savefig
  1. Use Matplotlib directly. In this case you would have to create a numerical function with lambdify, create an appropriate discretized range with numpy, evaluate the function and create the plot, then use the above-linked answer.
  • Related