In [1]:
from pathlib import Path
path = Path('..', 'tests', 'data')
fname = path.joinpath('CTD-spiked-unfiltered.cnv.bz2')
In [2]:
import ctd
cast = ctd.from_cnv(fname)
down, up = cast.split()
down.head()
Out[2]:
It is a pandas.DataFrame with all the pandas methods and properties.
In [3]:
type(cast)
Out[3]:
But with extras for pre-processing and plotting a ocean vertical profiles.
In [4]:
%matplotlib inline
from matplotlib import style
style.use('seaborn-whitegrid')
down['t090C'].plot_cast()
down['c0S/m'].plot_cast();
Sometimes it is useful to plot the second variable in a different axis so we can compare the two.
In [5]:
ax0 = down['t090C'].plot_cast(label='Temperature (°C)')
ax1 = down['c0S/m'].plot_cast(
ax=ax0,
label='Conductivity (S/m)',
color='orange',
secondary_y=True,
)
lines = ax0.get_lines() + ax1.get_lines()
leg = {
line: line.get_label() for line in lines
}
ax0.legend(leg.keys(), leg.values())
ax0.grid(False)
ax1.grid(False)
python-ctd saves of the file metadata in a dictionary to make them easy to access later.
In [6]:
metadata = cast._metadata
metadata.keys()
Out[6]:
In [7]:
print(metadata['header'])
Usually the first pre-processing step is to filter the high frequency jitter in the pressure sensor with a low pass filter, here is a zoom in the pressure data (the pandas index) demonstrating it:
In [8]:
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.plot(down.index, label='unfiltered')
ax.plot(down.lp_filter().index, label='filtered')
ax.axis([20870, 20930, 557.5, 559])
fig.legend();
Thanks to pandas_flavor we can chain all the pre-processing steps together.
In [9]:
down = down[['t090C', 'c0S/m']]
proc = down.remove_above_water()\
.despike(n1=2, n2=20, block=100)\
.lp_filter()\
.press_check()\
.interpolate() \
.bindata(delta=1)\
.smooth(window_len=21, window='hanning')
proc.head()
Out[9]:
In [10]:
lon, lat = metadata['lon'], metadata['lat']
lon, lat
Out[10]:
In [11]:
import gsw
p = proc.index
SP = gsw.SP_from_C(proc['c0S/m'] * 10.0, proc['t090C'], p)
SA = gsw.SA_from_SP(SP, p, lon, lat)
SR = gsw.SR_from_SP(SP)
CT = gsw.CT_from_t(SA, proc['t090C'].values, p)
z = -gsw.z_from_p(p, lat)
sigma0_CT = gsw.sigma0(SA, CT)
proc = proc.assign(SP=SP)\
.assign(SA=SA)\
.assign(SR=SR)\
.assign(CT=CT)\
.assign(z=z)\
.assign(sigma0_CT=sigma0_CT)
In [12]:
labels = [
r'Absolute Salinity (g kg$^{-1}$)',
r'Reference Salinity (g kg$^{-1}$)',
'Practical Salinity',
]
ax = proc[['SA', 'SR', 'SP']].plot_cast(
figsize=(5.25, 9),
label=labels,
)
ax.set_ylabel('Pressure (dbar)')
ax.grid(True)
ax.legend()
ax.set_title('Salinities');
Last but not least let's tweak a three line plot with the main variables measured.
In [13]:
def make_patch_spines_invisible(ax):
ax.set_frame_on(True)
ax.patch.set_visible(False)
for sp in ax.spines.values():
sp.set_visible(False)
In [14]:
fig, ax0 = plt.subplots(figsize=(5, 9))
colors = ['#1f77b4', '#ff7f0e', '#2ca02c']
ax0.invert_yaxis()
ax1 = ax0.twiny()
ax2 = ax0.twiny()
l0, = ax0.plot(proc['CT'], proc.index, color=colors[0], label='CT')
ax0.set_xlabel('Conservative Temperature (°C)')
l1, = ax1.plot(proc['SA'], proc.index, color=colors[1], label='SA')
ax1.set_xlabel('Absolute Salinity (g kg$^{-1}$)')
l2, = ax2.plot(proc['sigma0_CT'], proc.index, color=colors[2], label=r'$\sigma_{0\_CT}$')
ax2.set_xlabel(r'$\sigma_{0\_CT}$ (kg m$^{-3}$)')
make_patch_spines_invisible(ax2)
ax2.spines['top'].set_position(('axes', 1.1))
ax2.spines['top'].set_visible(True)
ax0.xaxis.label.set_color(l0.get_color())
ax1.xaxis.label.set_color(l1.get_color())
ax2.xaxis.label.set_color(l2.get_color())
ax0.tick_params(axis='x', colors=l0.get_color())
ax1.tick_params(axis='x', colors=l1.get_color())
ax2.tick_params(axis='x', colors=l2.get_color())
lines = ax0.get_lines() + ax1.get_lines() + ax2.get_lines()
leg = {
line: line.get_label() for line in lines
}
ax0.legend(leg.keys(), leg.values(), loc=8)
ax0.grid(False)
ax1.grid(False)
ax2.grid(False)