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.
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:
- nature of the smoothing pre-processing;
- different devices used in the profiles.
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.
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.
fig, ax = plt.subplots(figsize=(4, 6))
ax.invert_yaxis()
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.invert_yaxis()
axins.axis([3.5, 3.8, 1420, 1300])
axins.xaxis.tick_top()
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),
bbox_transform=ax.figure.transFigure)
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])
axins_2.invert_yaxis()
axins_2.set_yticks([])
axins_2.set_xticks([])
axins_2.set_axis_bgcolor('none')
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 ;)
HTML(html)