7 Great Plotting Libraries for Python - Compared (with guides for each)
Tags: python, datascience, webdev
Published: 2021-03-25 17:56:22

# How do I make plots in Python?

This question used to have a simple answer: Matplotlib was the only way. Nowadays, Python is the language of Data Science and there’s a lot more choice. Which should you use?

This guide will help you decide. I’ll show you how to use **seven Python plotting libraries**, with a bonus **in-depth guide for each library**!

I've also packaged an example for each library as an [Anvil](https://anvil.works?utm_source=crosspost:dev.to:/blog/plotting-in-python) app, showing how to build **web-based data apps with nothing but Python**. All these libraries are available in Anvil’s Server Modules, and Plotly works directly in Anvil’s [front-end Python code](https://anvil.works/articles/python-gui-builder-web?utm_source=crosspost:dev.to:/blog/plotting-in-python) too! Click through to the in-depth guides for sample code.

The most popular Python plotting libraries are Matplotlib, Plotly, Seaborn, and Bokeh. I’ve also included some underrated gems that you should definitely consider: Altair, with its expressive API, and Pygal, with its beautiful SVG output. We’ll also look at the very convenient plotting API provided by Pandas.

---

# Our Example Plot

Each of these libraries takes a slightly different approach. To compare them, I'm going to make the same plot with each library, and show you the source code. I’ve chosen a grouped bar chart of British election results since 1966. Here it is:

![image](https://anvil.works/blog/img/plotting-in-python/plotting-in-anvil.png)

I compiled a dataset of British election history [from Wikipedia](https://en.wikipedia.org/wiki/United_Kingdom_general_elections_overview): the number of seats in the UK parliament won by the Conservative, Labour, and Liberal parties (broadly defined) in each election from 1966 to 2019, plus the number of seats won by ‘others’. You can download it as a CSV file [here](https://anvil.works/blog/img/plotting-in-python/uk-election-results.csv).

---

# 1. Matplotlib

[Matplotlib](https://anvil.works/blog/plotting-in-matplotlib?utm_source=crosspost:dev.to:/blog/plotting-in-python) is the oldest Python plotting library, and it’s still the most popular. It was created in 2003 as part of the [SciPy Stack](https://www.scipy.org/about.html), an open-source scientific computing library similar to Matlab.

Matplotlib gives you precise control over your plots – for example, you can define the individual x-position of each bar in your barplot. I’ve written a more detailed guide to Matplotlib, and you can find it [here](https://anvil.works/blog/plotting-in-matplotlib?utm_source=crosspost:dev.to:/blog/plotting-in-python).

![image](https://anvil.works/blog/img/plotting-in-python/matplotlib.png)

```python
    import matplotlib.pyplot as plt
    import numpy as np
    from votes import wide as df

    # Initialise a figure. subplots() with no args gives one plot.
    fig, ax = plt.subplots()

    # A little data preparation
    years = df['year']
    x = np.arange(len(years))

    # Plot each bar plot. Note: manually calculating the 'dodges' of the bars
    ax.bar(x - 3*width/2, df['conservative'], width, label='Conservative', color='#0343df')
    ax.bar(x - width/2, df['labour'], width, label='Labour', color='#e50000')
    ax.bar(x + width/2, df['liberal'], width, label='Liberal', color='#ffff14')
    ax.bar(x + 3*width/2, df['others'], width, label='Others', color='#929591')

    # Customise some display properties
    ax.set_ylabel('Seats')
    ax.set_title('UK election results')
    ax.set_xticks(x)    # This ensures we have one tick per year, otherwise we get fewer
    ax.set_xticklabels(years.astype(str).values, rotation='vertical')
    ax.legend()

    # Ask Matplotlib to show the plot
    plt.show()
``` 

### [Full Guide & Example Code: Plotting in Matplotlib >](https://anvil.works/blog/plotting-in-matplotlib?utm_source=crosspost:dev.to:/blog/plotting-in-python)

---

# Seaborn

[Seaborn](https://anvil.works/blog/plotting-in-seaborn?utm_source=crosspost:dev.to:/blog/plotting-in-python) is an abstraction layer on top of Matplotlib - it gives you a really neat interface to make a wide range of useful plot types very easily.

It doesn’t compromise on power, though! Seaborn gives you [escape hatches](https://anvil.works/blog/escape-hatches-and-ejector-seats?utm_source=crosspost:dev.to:/blog/plotting-in-python) to access the underlying Matplotlib objects, so you still have complete control. You can check out a more detailed guide to Seaborn [here](https://anvil.works/blog/plotting-in-seaborn?utm_source=crosspost:dev.to:/blog/plotting-in-python).

Here’s our election-results plot in Seaborn. You can see that the code is a lot simpler than the raw Matplotlib.

![image](https://anvil.works/blog/img/plotting-in-python/seaborn-tweaked.png)

```python
    import seaborn as sns
    from votes import long as df

    # Some boilerplate to initialise things
    sns.set()
    plt.figure()

    # This is where the actual plot gets made
    ax = sns.barplot(data=df, x="year", y="seats", hue="party", palette=['blue', 'red', 'yellow', 'grey'], saturation=0.6)

    # Customise some display properties
    ax.set_title('UK election results')
    ax.grid(color='#cccccc')
    ax.set_ylabel('Seats')
    ax.set_xlabel(None)
    ax.set_xticklabels(df["year"].unique().astype(str), rotation='vertical')

    # Ask Matplotlib to show it
    plt.show()
```

### [Full Guide & Example Code: Plotting in Seaborn >](https://anvil.works/blog/plotting-in-seaborn?utm_source=crosspost:dev.to:/blog/plotting-in-python)


---

# Plotly

[Plotly](https://anvil.works/blog/plotting-in-plotly?utm_source=crosspost:dev.to:/blog/plotting-in-python) is a plotting ecosystem that includes a Python plotting library. There are three different interfaces to it:

- an object-oriented interface
- an imperative interface that allows you to specify your plot using JSON-like data structures
- and a high-level interface similar to Seaborn called Plotly Express.

Plotly plots are designed to be embedded in web apps. At its core, Plotly is actually a JavaScript library! It uses D3 and stack.gl to draw the plots.

You can build Plotly libraries in other languages by passing JSON to the JavaScript library. The official Python and R libraries do just that. At Anvil, we ported the Python Plotly API to [run in the web browser](https://anvil.works/docs/client/components/plots?utm_source=crosspost:dev.to:/blog/plotting-in-python).

Here’s the election results plot in Plotly:

![image](https://anvil.works/blog/img/plotting-in-python/plotting-in-anvil.gif)

```python
import plotly.graph_objects as go
    from votes import wide as df

    #  Get a convenient list of x-values
    years = df['year']
    x = list(range(len(years)))

    # Specify the plots
    bar_plots = [
        go.Bar(x=x, y=df['conservative'], name='Conservative', marker=go.bar.Marker(color='#0343df')),
        go.Bar(x=x, y=df['labour'], name='Labour', marker=go.bar.Marker(color='#e50000')),
        go.Bar(x=x, y=df['liberal'], name='Liberal', marker=go.bar.Marker(color='#ffff14')),
        go.Bar(x=x, y=df['others'], name='Others', marker=go.bar.Marker(color='#929591')),
    ]

    # Customise some display properties
    layout = go.Layout(
        title=go.layout.Title(text="Election results", x=0.5),
        yaxis_title="Seats",
        xaxis_tickmode="array",
        xaxis_tickvals=list(range(27)),
        xaxis_ticktext=tuple(df['year'].values),
    )

    # Make the multi-bar plot
    fig = go.Figure(data=bar_plots, layout=layout)

    # Tell Plotly to render it
    fig.show()
```

### [Full Guide & Example Code: Plotting with Plotly >](https://anvil.works/blog/plotting-in-plotly?utm_source=crosspost:dev.to:/blog/plotting-in-python)


---

# Bokeh

Bokeh (pronounced “BOE-kay”) specialises in building interactive plots, so this example doesn’t show it off to its best. Check out [this extended guide to Bokeh](https://anvil.works/blog/plotting-in-bokeh?utm_source=crosspost:dev.to:/blog/plotting-in-python), where we add some custom tooltips! Like Plotly, Bokeh’s plots are designed to be embedded in web apps - it outputs its plots as HTML files.

Here are the election results plotted in Bokeh:

![image](https://anvil.works/blog/img/plotting-in-python/bokeh.png)
 
```python
from bokeh.io import show, output_file
    from bokeh.models import ColumnDataSource, FactorRange, HoverTool
    from bokeh.plotting import figure
    from bokeh.transform import factor_cmap
    from votes import long as df

    # Specify a file to write the plot to
    output_file("elections.html")

    # Tuples of groups (year, party)
    x = [(str(r[1]['year']), r[1]['party']) for r in df.iterrows()]
    y = df['seats']

    # Bokeh wraps your data in its own objects to support interactivity
    source = ColumnDataSource(data=dict(x=x, y=y))

    # Create a colourmap
    cmap = {
        'Conservative': '#0343df',
        'Labour': '#e50000',
        'Liberal': '#ffff14',
        'Others': '#929591',
    }
    fill_color = factor_cmap('x', palette=list(cmap.values()), factors=list(cmap.keys()), start=1, end=2)

    # Make the plot
    p = figure(x_range=FactorRange(*x), width=1200, title="Election results")
    p.vbar(x='x', top='y', width=0.9, source=source, fill_color=fill_color, line_color=fill_color)

    # Customise some display properties
    p.y_range.start = 0
    p.x_range.range_padding = 0.1
    p.yaxis.axis_label = 'Seats'
    p.xaxis.major_label_orientation = 1
    p.xgrid.grid_line_color = None
  ```

### [Full Guide & Example Code: Plotting with Bokeh >](https://anvil.works/blog/plotting-in-bokeh?utm_source=crosspost:dev.to:/blog/plotting-in-python)

---

# Altair

Altair is based on a declarative plotting language (or ‘visualisation grammar’) called [Vega](https://vega.github.io/vega/). This means a well-thought-through API that scales well for complex plots, saving you from getting lost in nested-for-loop hell.

As with Bokeh, Altair outputs its plots as HTML files. Check out the extended guide to Altair [here](https://anvil.works/blog/plotting-in-altair?utm_source=crosspost:dev.to:/blog/plotting-in-python).

Here’s how our election results plot looks in Altair. Note how expressively the actual plot is specified, with just six lines of Python:

![image](https://anvil.works/blog/img/plotting-in-python/altair.png)

```python
import altair as alt
    from votes import long as df

    # Set up the colourmap
    cmap = {
        'Conservative': '#0343df',
        'Labour': '#e50000',
        'Liberal': '#ffff14',
        'Others': '#929591',
    }

    # Cast years to strings
    df['year'] = df['year'].astype(str)

    # Here's where we make the plot
    chart = alt.Chart(df).mark_bar().encode(
        x=alt.X('party', title=None),
        y='seats',
        column=alt.Column('year', sort=list(df['year']), title=None),
        color=alt.Color('party', scale=alt.Scale(domain=list(cmap.keys()), range=list(cmap.values())))
    )

    # Save it as an HTML file.
    chart.save('altair-elections.html')
```

### [Full Guide & Example Code: Plotting with Plotly >](https://anvil.works/blog/plotting-in-altair?utm_source=crosspost:dev.to:/blog/plotting-in-python)


---

# Pygal

[Pygal](https://anvil.works/blog/plotting-in-pygal?utm_source=crosspost:dev.to:/blog/plotting-in-python) focuses on visual appearance. It produces SVG plots by default, so you can zoom them forever – or print them out – without them getting pixellated. Pygal plots also come with some good interactivity features built-in, making Pygal another underrated candidate if you’re looking to embed plots in a web app.

Here's the election results plot in Pygal:

![image](https://anvil.works/blog/img/plotting-in-python/pygal.png)
 
```python
 import pygal
    from pygal.style import Style
    from votes import wide as df

    # Define the style
    custom_style = Style(
        colors=('#0343df', '#e50000', '#ffff14', '#929591')
        font_family='Roboto,Helvetica,Arial,sans-serif',
        background='transparent',
        label_font_size=14,
    )

    # Set up the bar plot, ready for data
    c = pygal.Bar(
        title="UK Election Results",
        style=custom_style,
        y_title='Seats',
        width=1200,
        x_label_rotation=270,
    )

    # Add four data sets to the bar plot
    c.add('Conservative', df['conservative'])
    c.add('Labour', df['labour'])
    c.add('Liberal', df['liberal'])
    c.add('Others', df['others'])

    # Define the X-labels
    c.x_labels = df['year']

    # Write this to an SVG file
    c.render_to_file('pygal.svg')
  ```

### [Full Guide & Example Code: Plotting with PyGal >](https://anvil.works/blog/plotting-in-pygal?utm_source=crosspost:dev.to:/blog/plotting-in-python)

---

# Pandas

[Pandas](https://anvil.works/blog/plotting-in-pandas?utm_source=crosspost:dev.to:/blog/plotting-in-python) is an extremely popular Data Science library for Python. It allows you to do all sorts of data manipulation scalably, but it also has a convenient plotting API. Because it operates directly on data frames, our Pandas example is the most concise code snippet in this article – even shorter than the Seaborn one!

The Pandas API is a wrapper around Matplotlib, so you can also use the underlying Matplotlib API to get fine-grained control of your plots.

Here’s the plot in Pandas. The code is beautifully concise!

![image](https://anvil.works/blog/img/plotting-in-python/pandas.png)

```python
    from matplotlib.colors import ListedColormap
    from votes import wide as df

    cmap = ListedColormap(['#0343df', '#e50000', '#ffff14', '#929591'])

    ax = df.plot.bar(x='year', colormap=cmap)

    ax.set_xlabel(None)
    ax.set_ylabel('Seats')
    ax.set_title('UK election results')

    plt.show()
 ``` 

### [Full Guide & Example Code: Plotting with Pandas >](https://anvil.works/blog/plotting-in-pandas?utm_source=crosspost:dev.to:/blog/plotting-in-python)


---

# Plotting with Anvil

Anvil is a system for building full-stack web apps with nothing but Python – no JavaScript required!

You can use any of the libraries I’ve talked about in this article to make plots in Anvil, and display them in the web browser. It’s great for [building dashboards](https://anvil.works/learn/tutorials/dashboard?utm_source=crosspost:dev.to:/blog/plotting-in-python):

![image](https://anvil.works/learn/tutorials/img/dashboard/business-dash.png)

In each of the in-depth guides to [Matplotlib](https://anvil.works/blog/plotting-in-matplotlib?utm_source=crosspost:dev.to:/blog/plotting-in-python), [Plotly](https://anvil.works/blog/plotting-in-plotly?utm_source=crosspost:dev.to:/blog/plotting-in-python), [Seaborn](https://anvil.works/blog/plotting-in-seaborn?utm_source=crosspost:dev.to:/blog/plotting-in-python), [Bokeh](https://anvil.works/blog/plotting-in-bokeh?utm_source=crosspost:dev.to:/blog/plotting-in-python), [Altair](https://anvil.works/blog/plotting-in-altair?utm_source=crosspost:dev.to:/blog/plotting-in-python), and [Pygal](https://anvil.works/blog/plotting-in-pygal?utm_source=crosspost:dev.to:/blog/plotting-in-python), you’ll find an example web application you can open and edit in Anvil, showing you how to use each of these Python plotting libraries.

You can also find Anvil-specific advice in the [Anvil plotting guide](https://anvil.works/docs/how-to/plot?utm_source=crosspost:dev.to:/blog/plotting-in-python). It tells you how to use plots from each of the libraries mentioned in this article in your Anvil app, including the fully front-end Python version of Plotly.