Interactive backends

Matplotlib can build interactive figures that are far more engaging for readers. Sometimes, a plot might be overwhelmed with graphical elements, making it hard to discern individual data points. On other occasions, some data points may appear so similar, in which it could be hard to spot the differences with our naked eyes. An interactive plot can address these two scenarios by allowing us to zoom in, zoom out, pan, and explore the plot in the way we want.

Through the use of interactive backends, plots in Matplotlib can be embedded in graphical user interfaces (GUI) applications. By default, Matplotlib supports the pairing of the Agg raster graphics renderer with a wide variety of GUI toolkits, including wxWidgets (Wx), GIMP Toolkit (GTK+), Qt and TkInter (Tk). As Tkinter is the de facto standard GUI for Python, which is built on top of Tcl/Tk, we can create an interactive plot with nothing more than calling plt.show() in a standalone Python script. Let's try to copy the following code to a separate text file and name it interactive.py. After that, type python interactive.py in your Terminal (Mac/Linux) or Command Prompt (Windows). If you are unsure about how to open a Terminal or Command Prompt, please refer to Chapter 1Introduction to Matplotlib, for more details:

import matplotlib
import matplotlib.pyplot as plt
import textwrap
import requests
import pandas as pd
from bs4 import BeautifulSoup
# Import Matplotlib radio button widget
from matplotlib.widgets import RadioButtons


url = "https://www.bls.gov/emp/ep_table_001.htm"
response = requests.get(url)
bs = BeautifulSoup(response.text)
thead = bs.select("#bodytext > table > thead")[0]
tbody = bs.select("#bodytext > table > tbody")[0]

headers = []
for col in thead.find_all('th'):
headers.append(col.text.strip())

data = {header:[] for header in headers}
for row in tbody.find_all('tr'):
cols = row.find_all(['th','td'])

for i, col in enumerate(cols):
value = col.text.strip()
if i > 0:
value = float(value.replace(',',''))
data[headers[i]].append(value)

df = pd.DataFrame(data)

fig, ax = plt.subplots(figsize=(6,7))
ind = range(df.shape[0])
rects = ax.barh(ind, df["Median usual weekly earnings ($)"], height=0.5)
ax.set_xlabel('Median weekly earnings (USD)')
ylabels=[textwrap.fill(label,15) for label in df["Educational attainment"]]
ax.set_yticks(ind)
ax.set_yticklabels(ylabels)
fig.subplots_adjust(left=0.3)

# Create axes for holding the radio selectors.
# supply [left, bottom, width, height] in normalized (0, 1) units
bax = plt.axes([0.3, 0.9, 0.4, 0.1])
radio = RadioButtons(bax, ('Weekly earnings', 'Unemployment rate'))

# Define the function for updating the displayed values
# when the radio button is clicked
def radiofunc(label):
# Select columns from dataframe depending on label
if label == 'Weekly earnings':
data = df["Median usual weekly earnings ($)"]
ax.set_xlabel('Median weekly earnings (USD)')
elif label == 'Unemployment rate':
data = df["Unemployment rate (%)"]
ax.set_xlabel('Unemployment rate (%)')

# Update the bar heights
for i, rect in enumerate(rects):
rect.set_width(data[i])

# Rescale the x-axis range
ax.set_xlim(xmin=0, xmax=data.max()*1.1)

# Redraw the figure
plt.draw()
radio.on_clicked(radiofunc)

plt.show()

We shall see a pop-up window similar to the following one. We can pan, zoom to selection, configure subplot margins, save, and go back and forth between different views by clicking on the buttons on the bottom toolbar. If we put our mouse over the plot, we can also observe the exact coordinates in the lower-right corner. This feature is extremely useful for dissecting data points that are close to each other:

Next, we are going to extend the application by adding a radio button widget on top of the figure, such that we can switch between the display of weekly earnings or unemployment rates. The radio button can be found in matplotlib.widgets, and we are going to attach a data updating function to the .on_clicked() event of the button. You can paste the following code right before the plt.show() line to the previous code example (interactive.py). Let's see how it works:

# Import Matplotlib radio button widget
from matplotlib.widgets import RadioButtons

# Create axes for holding the radio selectors.
# supply [left, bottom, width, height] in normalized (0, 1) units
bax = plt.axes([0.3, 0.9, 0.4, 0.1])
radio = RadioButtons(bax, ('Weekly earnings', 'Unemployment rate'))

# Define the function for updating the displayed values
# when the radio button is clicked
def radiofunc(label):
# Select columns from dataframe, and change axis label depending on selection
if label == 'Weekly earnings':
data = df["Median usual weekly earnings ($)"]
ax.set_xlabel('Median weekly earnings (USD)')
elif label == 'Unemployment rate':
data = df["Unemployment rate (%)"]
ax.set_xlabel('Unemployment rate (%)')

# Update the bar heights
for i, rect in enumerate(rects):
rect.set_width(data[i])

# Rescale the x-axis range
ax.set_xlim(xmin=0, xmax=data.max()*1.1)

# Redraw the figure
plt.draw()

# Attach radiofunc to the on_clicked event of the radio button
radio.on_clicked(radiofunc)

You will be welcomed by a new radio selector box on top of the plot. Try switching between the two states and see if the figure would be updated accordingly. The complete code is also available in the code bundle:

Before we conclude this section, we are going to introduce one more interactive backend that is rarely covered by books. Starting with Matplotlib 1.4, there is an interactive backend specifically designed for Jupyter Notebook. To invoke that, we simply need to paste %matplotlib notebook at the start of your notebook. We are going to adapt one of the earlier examples in this chapter to use this backend:

# Import the interactive backend for Jupyter Notebook
%matplotlib notebook
import matplotlib
import matplotlib.pyplot as plt
import textwrap

fig, ax = plt.subplots(figsize=(6,7))
ind = range(df.shape[0])
rects = ax.barh(ind, df["Median usual weekly earnings ($)"], height=0.5)
ax.set_xlabel('Median weekly earnings (USD)')
ylabels=[textwrap.fill(label,15) for label in df["Educational attainment"]]
ax.set_yticks(ind)
ax.set_yticklabels(ylabels)
fig.subplots_adjust(left=0.3)

# Show the figure using interactive notebook backend
plt.show()

The following interactive plot will be embedded right into your Jupyter Notebook:

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.218.37.5