Turning ripples into waves

Matplotlib zoomed axis

This post is just a very simple example on how to use matplotlib's zoomed_inset_axes. It is an easy shortcut to create very sophisticated plots.

We need to import mark_inset, to show lines marking where we are zooming, and zoomed_inset_axes to create the actual zoomed axes.

In [2]:
import numpy as np
import matplotlib.pyplot as plt

from matplotlib.ticker import MaxNLocator
from mpl_toolkits.axes_grid1.inset_locator import mark_inset
from mpl_toolkits.axes_grid1.inset_locator import zoomed_inset_axes

To demonstrate this feature we will load three different versions of the same data. A raw XBT, a smoothed version of the ame XBT, data and the accompanying CTD data. All these three temperature profiles have, of course, some differences and similarities that are worth taking a look to understand the:

  1. nature of the smoothing pre-processing;
  2. different devices used in the profiles.
In [3]:
dtype = [('temp', 'f4'), ('depth', 'f4')]
kw = dict(usecols=(0, 1), dtype=dtype)
xbt_raw = np.genfromtxt('./data/C4_XBT_22.EDF', skip_header=41, **kw)
xbt_smoo = np.loadtxt('./data/C4_XBT_22.ASC', **kw)
ctd = np.loadtxt("./data/C4_CTD_22.ASC", **kw)

This block defines some handy kw dicts that we will use in all three plots.

In [4]:
deg = u"\u00b0"
raw = dict(color='#FF8000', marker='.', linestyle='none', alpha=0.5, label='XBT Raw')
smoo = dict(color='#2E2E2E', linestyle='-.', label='XBT Smooth')
comp = dict(color='#0B610B', label='CTD')

The next block creates the main plot and the two zoomed levels. The two zooms are created in a different manner to demonstrate two different techniques. For the first one we use the automatic locator keyword loc=. And for the second one, since we placed it outside of the main plot, we specified the x, y coordinates in Figure units.

In [5]:
fig, ax = plt.subplots(figsize=(4, 6))
ax.plot(ctd['depth'], ctd['temp'], **comp)
ax.plot(xbt_raw['depth'], xbt_raw['temp'], **raw)
ax.plot(xbt_smoo['depth'], xbt_smoo['temp'], **smoo)
ax.set_ylabel('Pressure [dbar]')
ax.set_xlabel(u'Temperature %sC' % deg)
ax.legend(numpoints=1, loc='upper left')

# Zoom 1.
axins = zoomed_inset_axes(ax, 5, loc=5)
axins.plot(ctd['depth'], ctd['temp'], **comp)
axins.plot(xbt_raw['depth'], xbt_raw['temp'], **raw)
axins.plot(xbt_smoo['depth'], xbt_smoo['temp'], **smoo)
axins.axis([3.5, 3.8, 1420, 1300])
mark_inset(ax, axins, loc1=2, loc2=4, fc="none", ec="0.5")
axins.xaxis.set_major_locator(MaxNLocator(nbins=1, prune='lower'))

# Zoom 2.
axins_2 = zoomed_inset_axes(axins, 10,  loc=4,
                     bbox_to_anchor=(1.2, 0.75),

axins_2.plot(ctd['depth'], ctd['temp'], **comp)
axins_2.plot(xbt_raw['depth'], xbt_raw['temp'], **raw)
axins_2.plot(xbt_smoo['depth'], xbt_smoo['temp'], **smoo)
axins_2.axis([3.6, 3.75, 1360, 1340])
axes = mark_inset(axins, axins_2, loc1=2, loc2=4, fc="none", ec="0.5")

That's it! We can note that the raw XBT data is a little "off" when compared with the CTD. That difference seemed to be corrected by the smoothing at some points but not in others.

This plot was created to show my students the need to correct the XBT's depth velocity, and the dangers of smoothing the data before a proper pre-processing.

A future version of this plot, using the Bokeh package, might show up here in the blog. That way we will be able to use the interactive pan/zoom to explore more those details I'm talking about.

If we correct the XBT descent velocity properly the raw data will be closer to the CTD data, and very little to no smoothing would be needed.

More regarding this pre-processing in future posts ;)

In [6]:

This post was written as an IPython notebook. It is available for download or as a static html.

Creative Commons License
python4oceanographers by Filipe Fernandes is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.
Based on a work at