Visualising Data

Jon Reades

Choices, Choices…

  1. matplotlib: the ‘big beast’ of visualisation in Python. Similar to MATLAB. Highly customisable. Very complex.
  2. seaborn: a layer that sits over top of matplotlib and makes it easier to produce good-quality graphics.
  3. bokeh: web-based visualisation tool that can integrate with Jupyter or output to static HTML files.
  4. plotly: another web-based visualisation tool that can integrate with Jupyter.

More emerging all the time: Vega/Altair, HoloViews, etc.

Seaborn

Designed to provide ggplot-like quality output using matplotlib:

  • Improve on default colourmaps and colour defaults.
  • Integration with pandas data frames (Note: not geopandas!).
  • Offers more plot types out of the box.
  • Still offers access to matplotlib’s back-end.

Plot Types

Partial Overview of Seaborn Plots

In Practice

import seaborn as sns
sns.set_theme(style="darkgrid")
fmri = sns.load_dataset("fmri")
sns.lineplot(x="timepoint", y="signal",
             hue="region", style="event",
             data=fmri)

In Practice 2

sns.set_theme(style="whitegrid", palette="muted")
df = sns.load_dataset("penguins")

ax = sns.swarmplot(data=df, x="body_mass_g", y="sex", hue="species")
ax.set(ylabel="")

Configuring Seaborn

Seaborn ‘themes’ act as shortcuts for setting multiple matplotlib parameters:

Seaborn Command Accomplishes
set_theme(...) Set multiple theme parameters in one step.
axes_style(...) Return a parameter dict for the aesthetic style of the plots.
set_style(...) Set the aesthetic style of the plots.
plotting_context(...) Return a parameter dict to scale elements of the figure.
set_context(...) Set the plotting context parameters.

You can also access:

  • Palettes: colormaps can be generated using sns.color_palette(...) and set using sns.set_palette(...).
  • Axes Styles: includes darkgrid, whitegrid, dark, white, ticks.

Anatomy of a Figure

Source.

Writing a Figure

There are multiple ways to access/write elements of a plot:

  • Figure: high-level features (e.g. title, padding, etc.). Can be accessed via plt.gcf() (get current figure) or upon creation (e.g. f, ax = plt.subplots(1,1) or f = plt.figure()).
  • Axes: axis-level features (e.g. labels, tics, spines, limits, etc.). Can be accessed via plt.gca() (get current axes) or upon creation (e.g. f, ax = plt.subplots(1,1) or ax = f.add_subplot(1,1,1)).

Annotations, artists, and other features are typically written into the axes using the coordinate space of the figure (e.g. decimal degrees for lat/long, metres for BNG, etc.).

Adding a 3rd Dimension

This ‘feature’ is less well-developed but does work:

from mpl_toolkits.mplot3d import Axes3D
fig = plt.figure()
ax  = plt.axes(projection='3d')
# OR
fig = plt.figure()
ax  = fig.add_subplot(111, projection='3d')
# THEN
ax.contour3D(X, Y, Z, ...)
ax.plot_surface(x, y, z, ...)
ax.plot3D(xline, yline, zline, ...)
ax.scatter3D(x, y, z, ...)
# ax.plot_surface and ax.plot_wire also give you 3D renderings

You can then set the elevation and azimuth using: ax.view_init(<elevation>, <azimuth>).

Saving Outputs

Straightforward via save figure function, but lots of options!

plt.savefig(fname, dpi=None, facecolor='w', edgecolor='w',
    orientation='portrait', papertype=None, format=None,
    transparent=False, bbox_inches=None, pad_inches=0.1,
    frameon=None, metadata=None)

The format can be largely determined by the file extension in the fname (file name) and the supported formats depends on what you’ve installed! You can find out what’s available to you using: plt.gcf().canvas.get_supported_filetypes().

Jupyter

By default, Jupyter’s output is static matplotlib, but we can extend this in three ways:

  1. Make the static plot zoomable and pannable using %matplotlib widget (declare this at the top of your notebook).
  2. Make the plot more directly interactive using ipywidgets (import interact and related libs as needed).
  3. Use a browser-based visualisation tool such as bokeh, plotly, altair/vega, holoviews, or even d3 (format may be very, very different from what you are ‘used to’ in Python).

Widgets

%matplotlib widget
rs = gpd.sjoin(gdf, hackney, how='left', op='within')
rs.NAME.fillna('None', inplace=True)
ax = hackney.plot(edgecolor='k', facecolor='none')
rs.plot(ax=ax, column='NAME', legend=True)

Interact()

Taking an example from Dani’s work:

from ipywidgets import interact
# Alternatives: interactive, fixed, interact_manual
interact(
    <function>, # Function to make interactive
    <param0>,   # e.g. Data to use
    <param1>,   # e.g. Range start/end/step
    <param2>    # e.g. Fixed value
);

Bokeh

Automation

Plots built on top of matploblib can, to some extent, be automated using functions. For example, to draw circles and place text:

def circle(ax, x, y, radius=0.15):
    from matplotlib.patches import Circle
    from matplotlib.patheffects import withStroke
    circle = Circle((x, y), radius, clip_on=False, zorder=10, 
                    linewidth=1, edgecolor='black', 
                    facecolor=(0, 0, 0, .0125),
                    path_effects=[withStroke(linewidth=5, 
                                  foreground='w')])
    ax.add_artist(circle)

def text(ax, x, y, text):
    ax.text(x, y, text, backgroundcolor="white",
         ha='center', va='top', weight='bold', color='blue')

Don’t Underestimate Text!1

Click to cycle through the examples:

Resources