Note

Go to the endto download the full example code.

Embedding WebAgg#

This example demonstrates how to embed Matplotlib WebAgg interactive plottingin your own web application and framework. It is not necessary to do all thisif you merely want to display a plot in a browser or use Matplotlib's built-inTornado-based server "on the side".

The framework being used must support web sockets.

importargparseimportioimportjsonimportmimetypesfrompathlibimportPathimportsignalimportsockettry:importtornadoexceptImportErroraserr:raiseRuntimeError("This example requires tornado.")fromerrimporttornado.httpserverimporttornado.ioloopimporttornado.webimporttornado.websocketimportnumpyasnpimportmatplotlibasmplfrommatplotlib.backends.backend_webaggimport(FigureManagerWebAgg,new_figure_manager_given_figure)frommatplotlib.figureimportFiguredefcreate_figure():"""    Creates a simple example figure.    """fig=Figure()ax=fig.add_subplot()t=np.arange(0.0,3.0,0.01)s=np.sin(2*np.pi*t)ax.plot(t,s)returnfig# The following is the content of the web page.  You would normally# generate this using some sort of template facility in your web# framework, but here we just use Python string formatting.html_content="""<!DOCTYPE html><html lang="en">  <head>    <!-- TODO: There should be a way to include all of the required javascript               and CSS so matplotlib can add to the set in the future if it               needs to. -->    <link rel="stylesheet" href="_static/css/page.css" type="text/css">    <link rel="stylesheet" href="_static/css/boilerplate.css" type="text/css">    <link rel="stylesheet" href="_static/css/fbm.css" type="text/css">    <link rel="stylesheet" href="_static/css/mpl.css" type="text/css">    <script src="mpl.js"></script>    <script>      /* This is a callback that is called when the user saves         (downloads) a file.  Its purpose is really to map from a         figure and file format to a url in the application. */      function ondownload(figure, format) {        window.open('download.' + format, '_blank');      };      function ready(fn) {        if (document.readyState != "loading") {          fn();        } else {          document.addEventListener("DOMContentLoaded", fn);        }      }      ready(        function() {          /* It is up to the application to provide a websocket that the figure             will use to communicate to the server.  This websocket object can             also be a "fake" websocket that underneath multiplexes messages             from multiple figures, if necessary. */          var websocket_type = mpl.get_websocket_type();          var websocket = new websocket_type("%(ws_uri)sws");          // mpl.figure creates a new figure on the webpage.          var fig = new mpl.figure(              // A unique numeric identifier for the figure%(fig_id)s,              // A websocket object (or something that behaves like one)              websocket,              // A function called when a file type is selected for download              ondownload,              // The HTML element in which to place the figure              document.getElementById("figure"));        }      );    </script>    <title>matplotlib</title>  </head>  <body>    <div id="figure">    </div>  </body></html>"""classMyApplication(tornado.web.Application):classMainPage(tornado.web.RequestHandler):"""        Serves the main HTML page.        """defget(self):manager=self.application.managerws_uri=f"ws://{self.request.host}/"content=html_content%{"ws_uri":ws_uri,"fig_id":manager.num}self.write(content)classMplJs(tornado.web.RequestHandler):"""        Serves the generated matplotlib javascript file.  The content        is dynamically generated based on which toolbar functions the        user has defined.  Call `FigureManagerWebAgg` to get its        content.        """defget(self):self.set_header('Content-Type','application/javascript')js_content=FigureManagerWebAgg.get_javascript()self.write(js_content)classDownload(tornado.web.RequestHandler):"""        Handles downloading of the figure in various file formats.        """defget(self,fmt):manager=self.application.managerself.set_header('Content-Type',mimetypes.types_map.get(fmt,'binary'))buff=io.BytesIO()manager.canvas.figure.savefig(buff,format=fmt)self.write(buff.getvalue())classWebSocket(tornado.websocket.WebSocketHandler):"""        A websocket for interactive communication between the plot in        the browser and the server.        In addition to the methods required by tornado, it is required to        have two callback methods:            - ``send_json(json_content)`` is called by matplotlib when              it needs to send json to the browser.  `json_content` is              a JSON tree (Python dictionary), and it is the responsibility              of this implementation to encode it as a string to send over              the socket.            - ``send_binary(blob)`` is called to send binary image data              to the browser.        """supports_binary=Truedefopen(self):# Register the websocket with the FigureManager.manager=self.application.managermanager.add_web_socket(self)ifhasattr(self,'set_nodelay'):self.set_nodelay(True)defon_close(self):# When the socket is closed, deregister the websocket with# the FigureManager.manager=self.application.managermanager.remove_web_socket(self)defon_message(self,message):# The 'supports_binary' message is relevant to the# websocket itself.  The other messages get passed along# to matplotlib as-is.# Every message has a "type" and a "figure_id".message=json.loads(message)ifmessage['type']=='supports_binary':self.supports_binary=message['value']else:manager=self.application.managermanager.handle_json(message)defsend_json(self,content):self.write_message(json.dumps(content))defsend_binary(self,blob):ifself.supports_binary:self.write_message(blob,binary=True)else:data_uri=("data:image/png;base64,"+blob.encode('base64').replace('\n',''))self.write_message(data_uri)def__init__(self,figure):self.figure=figureself.manager=new_figure_manager_given_figure(id(figure),figure)super().__init__([# Static files for the CSS and JS(r'/_static/(.*)',tornado.web.StaticFileHandler,{'path':FigureManagerWebAgg.get_static_file_path()}),# Static images for the toolbar(r'/_images/(.*)',tornado.web.StaticFileHandler,{'path':Path(mpl.get_data_path(),'images')}),# The page that contains all of the pieces('/',self.MainPage),('/mpl.js',self.MplJs),# Sends images and events to the browser, and receives# events from the browser('/ws',self.WebSocket),# Handles the downloading (i.e., saving) of static images(r'/download.([a-z0-9.]+)',self.Download),])if__name__=="__main__":parser=argparse.ArgumentParser()parser.add_argument('-p','--port',type=int,default=8080,help='Port to listen on (0 for a random port).')args=parser.parse_args()figure=create_figure()application=MyApplication(figure)http_server=tornado.httpserver.HTTPServer(application)sockets=tornado.netutil.bind_sockets(args.port,'')http_server.add_sockets(sockets)forsinsockets:addr,port=s.getsockname()[:2]ifs.familyissocket.AF_INET6:addr=f'[{addr}]'print(f"Listening on http://{addr}:{port}/")print("Press Ctrl+C to quit")ioloop=tornado.ioloop.IOLoop.instance()defshutdown():ioloop.stop()print("Server stopped")old_handler=signal.signal(signal.SIGINT,lambdasig,frame:ioloop.add_callback_from_signal(shutdown))try:ioloop.start()finally:signal.signal(signal.SIGINT,old_handler)

Gallery generated by Sphinx-Gallery