Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Write canonical example of how to use Matplotlib inside a webserver #12628

Closed
tacaswell opened this issue Oct 25, 2018 · 9 comments · Fixed by #13062
Closed

Write canonical example of how to use Matplotlib inside a webserver #12628

tacaswell opened this issue Oct 25, 2018 · 9 comments · Fixed by #13062
Labels
Documentation Good first issue Open a pull request against these issues if there are no active ones!
Milestone

Comments

@tacaswell
Copy link
Member

As shown by #11094 #12612 matplotlib is used inside of webservers to dynamically serve plots. The example should show:

  1. importance of picking a non-GUI backend (both by setting the backend and explicitly by not using pyplot). Given that these servers are multi-threaded, not using pyplot at all may be the best option to avoid any coupling between workers via pyplot and memory leaks due to pyplot holding references to figures forever. Should probably show use of new_figure_manager
  2. saving to a bytesIO buffer to avoid disk
  3. png, svg, and pdf
  4. be applicable to both django and flask (not sure off the top of my head what the differences are), bonus points for cherrypy, aiohttp, tornado, and pyramid
@tacaswell tacaswell added this to the v3.0.0-doc milestone Oct 25, 2018
@anntzer
Copy link
Contributor

anntzer commented Oct 25, 2018

Rather than bothering with any explicit backend at all, I would strongly suggest merging #12450 and have the canonical approach be

from matplotlib.figure import Figure
fig = Figure()
<do the plotting>
fig.savefig(...)

Even with 3.0 (i.e. without that PR) new_figure_manager is totally overkill, just manually attaching a canvas (FigureCanvasAgg(fig) or even just FigureCanvasBase(fig)) is enough.
(... except if you want to use a third-party renderer e.g. mplcairo, but I doubt that's the point of the proposed example)

@mgeier
Copy link
Contributor

mgeier commented Nov 3, 2018

Possible duplicate: #4124.

@tacaswell
Copy link
Member Author

Indeed! I'm going to close the older one.

@anntzer
Copy link
Contributor

anntzer commented Nov 3, 2018

Do you want to make a decision about #12450, by the way? :) (as noted above)

@QuLogic QuLogic modified the milestones: v3.0.0-doc, v3.0.2-doc Nov 27, 2018
@anntzer
Copy link
Contributor

anntzer commented Nov 27, 2018

@tacaswell I think something like

import base64
from io import BytesIO

from flask import Flask
from matplotlib.figure import Figure


app = Flask(__name__)


@app.route("/")
def hello():
    # Generate the figure **without using pyplot**.
    fig = Figure()
    ax = fig.subplots()
    ax.plot([1, 2])
    # Save it to a temporary buffer.
    buf = BytesIO()
    fig.savefig(buf, format="png")
    # Embed the result in the html output.
    data = base64.b64encode(buf.getbuffer()).decode("ascii")
    return f"<img src='data:image/png;base64,{data}'/>"

is what you're looking for?

@story645
Copy link
Member

story645 commented Nov 27, 2018

My version was (stolen from a cookbook)

fig = matplotlib.figure.Figure()
canvas = FigureCanvas(fig)
//plot to figure code
canvas.print_figure(response)

where the outfile is the responsebuffer, like

response = pyramid.response.Response(content_type='image/png')

@anntzer
Copy link
Contributor

anntzer commented Nov 27, 2018

  • canvas = FigureCanvas(fig) is not necessary anymore since Attach a FigureCanvasBase by default to Figures. #12450 (that's the whole point of that PR).
  • I prefer suggesting the use of savefig (and yes you can also pass the Response buffer to it), as it's a regular method that you'd also use in other contents, rather than print_figure, which is a bit an implementation detail.

@tacaswell
Copy link
Member Author

Yes, something as simple as that is what I had in mind.

Agree on preferring savefig over print_figure.

@story645 story645 added the Good first issue Open a pull request against these issues if there are no active ones! label Dec 6, 2018
@QuLogic QuLogic modified the milestones: v3.0-doc, v3.1.0 Feb 23, 2019
@pjmnoble
Copy link

pjmnoble commented Oct 2, 2019

Hi problem goes away really nicely using the AGG backend
I just import matlplotlib at the top of my code and follow this with matplotlib.use('AGG') before importing any other matplotlib components (matplotlib.pyplot in this case)

No need for the matplotlib GUI backend in the web server.

Running on a Mac(High Sierra) with a Django server

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Documentation Good first issue Open a pull request against these issues if there are no active ones!
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants