The recommended way to make plots in Anvil is to use Anvil’s Plot component. This uses Anvil’s client-side Python Plotly library, so you can configure and reconfigure the plot dynamically without making a round-trip to the server.
Because Anvil code is just Python, it’s simple to use lots of different plotting libraries with Anvil. This page gives instructions for some of the most popular.
If your favourite is not here, it may have been mentioned on the Forum. If it hasn’t, please start a new thread about it!
There’s also a comprehensive comparison of the best-known Python plotting libraries on the Anvil blog.
There are three main types of plotting library in Python. We’ll show you how to use each of them:
The Matplotlib family: Matplotlib, Seaborn and Pandas
The HTML generators: Bokeh, Altair and Pygal
The client-side library: Plotly
plotly.expresswith Anvil, check out our Plotly Express in Anvil how-to guide.
Matplotlib, Seaborn and Pandas all render plots on the server-side. To display a plot on the client, you can export it as an image in a Media object.
There’s a simple function to do this – and it’s the same for all three libraries, since Seaborn and Pandas are based on Matplotlib.
Instead of calling
plt.show() to display the plot on your screen, in Anvil you call
anvil.mpl_util.plot_image() to render it as an image.
That function returns a Media object, so you can return it to the client code and display it
in an Image component. You could also offer the image for download (with the
Link component), or even add it to a database.
Let’s look at a full example.
Full example: Matplotlib
We’re going to walk through a simple Matplotlib example that makes a graph like this:
Matplotlib is available in Anvil’s Server Modules, if you choose the Full Python runtime.
Here’s the server function that makes our plot:
import anvil.mpl_util import numpy as np import matplotlib.pyplot as plt @anvil.server.callable def make_plot(): # Make a nice wiggle x = np.arange(0.0, 5.0, 0.02) y = np.exp(-x) * np.cos(2*np.pi*x) # Plot it in the normal Matplotlib way plt.figure(1, figsize=(10,5)) plt.plot(x, y, 'crimson') # Return this plot as a PNG image in a Media object return anvil.mpl_util.plot_image()
This returns an Anvil Media object.
Here’s the client-side code to display that plot and make it downloadable:
def __init__(self, **properties): # Set Form properties and Data Bindings. self.init_components(**properties) # Any code you write here will run when the form opens. media_obj = anvil.server.call('make_plot') self.image_1.source = media_obj self.download_link.url = media_obj
This produces the plot shown in the image above.
Click here to open the full source code for that example in your Anvil Editor:
Here’s a clone link for the same example using Seaborn:
Here’s a clone link for the same example using Pandas:
Bokeh, Altair and Pygal produce HTML or SVG plots that you can display in an IFrame. This gives you dynamic plots in the browser.
You will need an IFrame component to display them in. Here’s a clone link that gives you an IFrame component you can use as a dependency:
These libraries write out their plots as an HTML or SVG file. In Anvil you can turn this file into a
Media object using
# Generate a Media object containing the plot media_object = anvil.media.from_file('/tmp/altair.html', 'text/html')
You can then set the
src of the IFrame to a “data URL” obtained from the Media object. See below for a full example.
Full example: Bokeh
Here’s an example of plotting in Anvil using Bokeh. We’ll make the same line plot as we did for Matplotlib:
First, we include the IFrame component as a dependency:
This makes it available in the Toolbox so we can drag-and-drop it onto our main Form:
Then we add some lines to the Form’s
__init__ method that fetch a Media object from the server. The Media object contains the HTML of the plot. We assign its URL to the
url of the IFrame component:
def __init__(self, **properties): # Set Form properties and Data Bindings. self.init_components(**properties) # Any code you write here will run when the form opens. media_obj = anvil.server.call('make_plot') self.i_frame_1.url = media_obj.get_url(True)
Here’s the server function that makes the plot and returns it as a Media object to the client:
import anvil.server import anvil.media import numpy as np from bokeh.plotting import figure, output_file, show @anvil.server.callable def make_plot(): # Point Bokeh at a file output_file("/tmp/bokeh.html") # Make a nice wiggle x = np.arange(0.0, 5.0, 0.02) y = np.exp(-x) * np.cos(2*np.pi*x) # Plot it in the usual Bokeh way p = figure(width=600, height=300) p.line(x, y) # Save the plot show(p) # Return this plot as HTML in a Media object return anvil.media.from_file('/tmp/bokeh.html', 'text/html')
This produces the plot shown in the image above.
Here’s a clone link for that example:
Here’s a clone link for the same example using Altair:
Here’s a clone link for the same example using Pygal:
The Pygal example doesn’t need to write to a file, since Pygal has a
render method to output an SVG as a bytestring:
c = pygal.Line(show_dots=False, width=400, height=200) # ... return anvil.BlobMedia(content=c.render(), content_type='text/html', name='pygal.svg')
Anvil has Plotly’s Graph Objects built into its client-side Python, so you can construct Plotly plots on the client side in the same way you would construct them using Graph Objects locally. Use Anvil’s Plot component to show the plot in your app. For full details, see the Plot component documentation:
Here’s the same graph shown in the examples above, but this time as a front-end Plotly plot:
Here’s a clone link for that app:
On the client side, it’s simply:
class Form1(Form1Template): def __init__(self, **properties): # Set Form properties and Data Bindings. self.init_components(**properties) # Any code you write here will run when the form opens. x, y = anvil.server.call('get_data') self.plot_1.data = go.Scatter(x=x, y=y, mode='lines')
and the data is fetched from the server using this server function:
import anvil.server import numpy as np @anvil.server.callable def get_data(): x = np.arange(0.0, 5.0, 0.02) y = np.exp(-x) * np.cos(2*np.pi*x) return x, y