Source code for tdr

"""TDR objects homologous to `R` package diveMove's main classes

The :class:`TDR` class aims to be a comprehensive class to encapsulate the
processing of `TDR` records from a data file.

This module instantiates an `R` session to interact with low-level
functions and methods of package `diveMove`.

Class & Main Methods Summary
----------------------------

See `API` section for details on minor methods.

Calibration and phase detection
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

.. autosummary::

   TDR
   TDR.zoc
   TDR.detect_wet
   TDR.detect_dives
   TDR.detect_dive_phases
   TDR.calibrate
   TDR.calibrate_speed

Analyses
~~~~~~~~

.. autosummary::

   TDR.dive_stats
   TDR.time_budget
   TDR.stamp_dives

Plotting
~~~~~~~~

.. autosummary::

   TDR.plot
   TDR.plot_zoc
   TDR.plot_phases
   TDR.plot_dive_model

API
---

"""

import logging
import numpy as np
import pandas as pd
from skdiveMove.tdrsource import TDRSource
from skdiveMove.zoc import ZOC
from skdiveMove.tdrphases import TDRPhases
import skdiveMove.plotting as plotting
import skdiveMove.calibrate_speed as speedcal
from skdiveMove.helpers import (get_var_sampling_interval,
                                _get_dive_indices, _add_xr_attr,
                                _one_dive_stats, _speed_stats)
import xarray as xr


logger = logging.getLogger(__name__)
# Add the null handler if importing as library; whatever using this library
# should set up logging.basicConfig() as needed
logger.addHandler(logging.NullHandler())

# Keep attributes in xarray operations
xr.set_options(keep_attrs=True)


[docs]class TDR(TDRSource): """Base class encapsulating TDR objects and processing TDR subclasses `TDRSource` to provide comprehensive TDR processing capabilities. Attributes ---------- tdr_file : str String indicating the file where data comes from. tdr : xarray.Dataset Dataset with input data. depth_name : str Name of Dataset variable with depth measurements. has_speed : bool Whether input data include speed measurements. speed_name : str Name of Dataset variable with the speed measurements. zoc_depth : ZOC Instance to perform and store zero offset correction operations for depth. phases : TDRPhases Instance for performing wet/dry and dive phase detection. speed_calib_fit : quantreg model fit Model object fit by quantile regression for speed calibration. Examples -------- Construct an instance from diveMove example dataset >>> rstr = ('system.file(file.path("data", "dives.csv"), ' ... 'package="diveMove", mustWork=TRUE)') >>> data_path = robjs.r(rstr)[0] >>> tdrX = TDR(data_path, sep=";", compression="bz2") For convenience, the above operation is wrapped in the function `get_diveMove_sample_data`. Plot the `TDR` object >>> tdrX.plot() """ def __init__(self, *args, **kwargs): """Set up attributes for TDR objects """ TDRSource.__init__(self, *args, **kwargs) # Attributes to be set from other methods: method used, corrected # depth, filtered depth when method="filter" self.zoc_depth = ZOC() # Speed calibration fit self.speed_calib_fit = None # Wet phase activity identification self.phases = TDRPhases() def __str__(self): x = self.tdr xdf = x.to_dataframe() objcls = ("Time-Depth Recorder data -- Class {} object\n" .format(self.__class__.__name__)) src = "{0:<20} {1}\n".format("Source File", self.tdr_file) itv = ("{0:<20} {1}\n" .format("Sampling interval", get_var_sampling_interval(x[self.depth_name]))) nsamples = "{0:<20} {1}\n".format("Number of Samples", xdf.shape[0]) beg = "{0:<20} {1}\n".format("Sampling Begins", xdf.index[0]) end = "{0:<20} {1}\n".format("Sampling Ends", xdf.index[-1]) dur = "{0:<20} {1}\n".format("Total duration", xdf.index[-1] - xdf.index[0]) drange = "{0:<20} [{1},{2}]\n".format("Measured depth range", xdf[self.depth_name].min(), xdf[self.depth_name].max()) others = "{0:<20} {1}\n".format("Other variables", [x for x in xdf.columns if x != self.depth_name]) zocm = "{0:<20}: \'{1}\'\n".format("ZOC method", self.zoc_depth.method) attr_list = "Attributes:\n" for key, val in sorted(x.attrs.items()): attr_list += "{0:>35}: {1}\n".format(key, val) attr_list = attr_list.rstrip("\n") return(objcls + src + itv + nsamples + beg + end + dur + drange + others + zocm + attr_list)
[docs] def zoc(self, method="filter", **kwargs): """Zero offset correction Set the ``zoc_depth`` attribute. Parameters ---------- method : {"filter", "offset"} Name of method to use for zero offset correction. **kwargs : optional keyword arguments - methods 'filter': ('k', 'probs', 'depth_bounds' (defaults to range), 'na_rm' (defaults to True)). - method 'offset': ('offset'). Notes ----- More details in diveMove's ``calibrateDepth`` function. Examples -------- ZOC using the "offset" method >>> from skdiveMove.tests import diveMove2skd >>> tdrX = diveMove2skd() >>> tdrX.zoc("offset", offset=3) Using the "filter" method >>> # Window lengths and probabilities >>> DB = [-2, 5] >>> K = [3, 5760] >>> P = [0.5, 0.02] >>> tdrX.zoc(k=K, probs=P, depth_bounds=DB) Plot the filters that were applied >>> tdrX.plot_zoc(ylim=[-1, 10]) """ depth = self.get_depth("measured") self.zoc_depth(depth, method=method, **kwargs) logger.info("Finished ZOC")
[docs] def detect_wet(self, **kwargs): """Detect wet/dry activity phases Set the ``wet_dry`` attribute. Parameters ---------- **kwargs : Keyword arguments Passed to :meth:`~tdrphases.TDRPhases.detect_wet` Notes ----- See details for arguments in diveMove's ``calibrateDepth``. Unlike `diveMove`, the beginning/ending times for each phase are not stored with the class instance, as this information can be retrieved via the `.time_budget` method. Examples -------- ZOC using the "offset" method for convenience >>> from skdiveMove.tests import diveMove2skd >>> tdrX = diveMove2skd() >>> tdrX.zoc("offset", offset=3) Detect wet/dry phases >>> tdrX.detect_wet() Access the "phases" and "dry_thr" attributes >>> tdrX.get_wet_activity("phases") >>> tdrX.get_wet_activity("dry_thr") """ depth = self.get_depth("zoc") self.phases.detect_wet(depth, **kwargs) logger.info("Finished detecting wet/dry periods")
[docs] def detect_dives(self, dive_thr): """Identify dive events Set the ``dives`` attribute's "row_ids" dictionary element, and update the ``wet_act`` attribute's "phases" dictionary element. Parameters ---------- dry_thr : float Passed to :meth:`~tdrphases.TDRPhases.detect_dives`. Notes ----- See details for arguments in diveMove's ``calibrateDepth``. Examples -------- ZOC using the "offset" method for convenience >>> from skdiveMove.tests import diveMove2skd >>> tdrX = diveMove2skd() >>> tdrX.zoc("offset", offset=3) Detect wet/dry phases and dives with 3 m threshold >>> tdrX.detect_wet() >>> tdrX.detect_dives(3) """ depth = self.get_depth("zoc") self.phases.detect_dives(depth, dive_thr=dive_thr) logger.info("Finished detecting dives")
[docs] def detect_dive_phases(self, **kwargs): """Detect dive phases Complete filling the ``dives`` attribute. Parameters ---------- **kwargs : optional keyword arguments Passed to :meth:`~tdrphases.TDRPhases.detect_dive_phases` Notes ----- See details for arguments in diveMove's ``calibrateDepth``. Examples -------- ZOC using the "offset" method for convenience >>> from skdiveMove.tests import diveMove2skd >>> tdrX = diveMove2skd() >>> tdrX.zoc("offset", offset=3) Detect wet/dry phases and dives with 3 m threshold >>> tdrX.detect_wet() >>> tdrX.detect_dives(3) Detect dive phases using the "unimodal" method and selected parameters >>> tdrX.detect_dive_phases("unimodal", descent_crit_q=0.01, ... ascent_crit_q=0, knot_factor=20) """ depth = self.get_depth("zoc") self.phases.detect_dive_phases(depth, **kwargs) logger.info("Finished detecting dive phases")
[docs] def calibrate(self, zoc_method="filter", dry_thr=70, wet_cond=None, wet_thr=3610, interp_wet=False, dive_thr=4, dive_model="unimodal", smooth_par=0.1, knot_factor=3, descent_crit_q=0, ascent_crit_q=0, **kwargs): """Calibrate TDR object Convenience method to set all instance attributes. Parameters ---------- zoc_method : {"filter", "offset"}, optional Name of method to use for zero offset correction. dry_thr : float, optional wet_cond : bool mask, optional wet_thr : float, optional dive_thr : float, optional dive_model : {"unimodal", "smooth.spline"}, optional smooth_par : float, optional knot_factor : int, optional descent_crit_q, ascent_crit_q : float, optional **kwargs : optional keyword arguments Passed to :meth:`TDR.zoc` method: * method 'filter': ('k', 'probs', 'depth_bounds' (defaults to range), 'na_rm' (defaults to True)). * method 'offset': ('offset'). Notes ----- This method is homologous to diveMove's ``calibrateDepth`` function. Examples -------- ZOC using the "filter" method >>> from skdiveMove.tests import diveMove2skd >>> tdrX = diveMove2skd() >>> # Window lengths and probabilities >>> DB = [-2, 5] >>> K = [3, 5760] >>> P = [0.5, 0.02] >>> tdrX.calibrate(dive_thr=3, zoc_method="filter", ... k=K, probs=P, depth_bounds=DB, descent_crit_q=0.01, ... knot_factor=20) Plot dive phases >>> tdrX.plot_phases() Plot dive model for a dive >>> tdrX.plot_dive_model(40) """ self.zoc(zoc_method, **kwargs) self.detect_wet(dry_thr=dry_thr, wet_cond=wet_cond, wet_thr=wet_thr, interp_wet=interp_wet) self.detect_dives(dive_thr=dive_thr) self.detect_dive_phases(dive_model=dive_model, smooth_par=smooth_par, knot_factor=knot_factor, descent_crit_q=descent_crit_q, ascent_crit_q=ascent_crit_q)
[docs] def calibrate_speed(self, tau=0.1, contour_level=0.1, z=0, bad=[0, 0], save_fig=False, fname=None, **kwargs): """Calibrate speed measurements Set the `speed_calib_fit` attribute Parameters ---------- tau : float, optional Quantile on which to regress speed on rate of depth change. contour_level : float, optional The mesh obtained from the bivariate kernel density estimation corresponding to this contour will be used for the quantile regression to define the calibration line. z : float, optional Only changes in depth larger than this value will be used for calibration. bad : array_like, optional Two-element `array_like` indicating that only rates of depth change and speed greater than the given value should be used for calibration, respectively. save_fig : bool, optional Whether to save the plot. fname : str, optional A path to save plot. Ignored if ``save_fig=False``. **kwargs : optional keyword arguments Passed to :func:`calibrate_speed.calibrate` Returns ------- out : 3-tuple The quantile regression fit object, `matplotlib.pyplot` `Axes` and `Figures` instances. Examples -------- >>> from skdiveMove.tests import diveMove2skd >>> tdrX = diveMove2skd() >>> tdrX.zoc("offset", offset=3) >>> tdrX.calibrate_speed(z=2) """ depth = self.get_depth("zoc").to_series() ddiffs = depth.reset_index().diff().set_index(depth.index) ddepth = ddiffs["depth"].abs() rddepth = ddepth / ddiffs["date_time"].dt.total_seconds() curspeed = self.get_speed("measured").to_series() ok = (ddepth > z) & (rddepth > bad[0]) & (curspeed > bad[1]) rddepth = rddepth[ok] curspeed = curspeed[ok] kde_data = pd.concat((rddepth.rename("depth_rate"), curspeed), axis=1) qfit, fig, ax = speedcal.calibrate(kde_data, tau=tau, contour_level=contour_level, z=z, bad=bad, **kwargs) self.speed_calib_fit = qfit if save_fig: fig.savefig(fname) logger.info("Finished calibrating speed") return(qfit, fig, ax)
[docs] def dive_stats(self, depth_deriv=True): """Calculate dive statistics in `TDR` records Parameters ---------- depth_deriv : bool, optional Whether to compute depth derivative statistics. Returns ------- pandas.DataFrame Notes ----- This method homologous to diveMove's `diveStats` function. Examples -------- ZOC using the "filter" method >>> from skdiveMove.tests import diveMove2skd >>> tdrX = diveMove2skd() >>> # Window lengths and probabilities >>> DB = [-2, 5] >>> K = [3, 5760] >>> P = [0.5, 0.02] >>> tdrX.calibrate(dive_thr=3, zoc_method="filter", ... k=K, probs=P, depth_bounds=DB, ... descent_crit_q=0.01, knot_factor=20) >>> tdrX.dive_stats() """ phases_df = self.get_dives_details("row_ids") # calib_speed=False if no fit object tdr = self.get_tdr(calib_depth=True, calib_speed=bool(self.speed_calib_fit)) intvl = (get_var_sampling_interval(tdr[self.depth_name]) .total_seconds()) tdr = tdr.to_dataframe() dive_ids = phases_df.loc[:, "dive_id"] postdive_ids = phases_df.loc[:, "postdive_id"] ok = (dive_ids > 0) & dive_ids.isin(postdive_ids) okpd = (postdive_ids > 0) & postdive_ids.isin(dive_ids) postdive_ids = postdive_ids[okpd] postdive_dur = (postdive_ids.reset_index() .groupby("postdive_id") .apply(lambda x: x.iloc[-1] - x.iloc[0])) tdrf = (pd.concat((phases_df[["dive_id", "dive_phase"]][ok], tdr[ok]), axis=1).reset_index()) # Ugly hack to re-order columns for `diveMove` convention names0 = ["dive_id", "dive_phase", "date_time", self.depth_name] colnames = tdrf.columns.to_list() if self.has_speed: names0.append(self.speed_name) colnames = names0 + list(set(colnames) - set(names0)) tdrf = tdrf.reindex(columns=colnames) tdrf_grp = tdrf.groupby("dive_id") ones_list = [] for name, grp in tdrf_grp: res = _one_dive_stats(grp, interval=intvl, has_speed=self.has_speed) # Rename to match dive number res = res.rename({0: name}) if depth_deriv: deriv_stats = self.phases._get_dive_deriv_stats(name) res = pd.concat((res, deriv_stats), axis=1) ones_list.append(res) ones_df = pd.concat(ones_list, ignore_index=True) ones_df.set_index(dive_ids[ok].unique(), inplace=True) ones_df.index.rename("dive_id", inplace=True) ones_df["postdive_dur"] = postdive_dur["date_time"] # For postdive total distance and mean speed (if available) if self.has_speed: speed_postd = (tdr[self.speed_name][okpd] .groupby(postdive_ids)) pd_speed_ll = [] for name, grp in speed_postd: res = _speed_stats(grp.reset_index()) onames = ["postdive_tdist", "postdive_mean_speed"] res_df = pd.DataFrame(res[:, :-1], columns=onames, index=[name]) pd_speed_ll.append(res_df) pd_speed_stats = pd.concat(pd_speed_ll) ones_df = pd.concat((ones_df, pd_speed_stats), axis=1) return(ones_df)
[docs] def plot(self, concur_vars=None, concur_var_titles=None, **kwargs): """Plot TDR object Parameters ---------- concur_vars : str or list, optional String or list of strings with names of columns in input to select additional data to plot. concur_var_titles : str or list, optional String or list of strings with y-axis labels for `concur_vars`. **kwargs : optional keyword arguments Arguments passed to plotting function. Returns ------- tuple ``matplotlib.pyplot`` Figure and Axes instances. Examples -------- >>> from skdiveMove.tests import diveMove2skd >>> tdrX = diveMove2skd() >>> tdrX.plot(xlim=["2002-01-05 21:00:00", "2002-01-06 04:10:00"], ... depth_lim=[95, -1]) """ try: depth = self.get_depth("zoc") except IndexError: depth = self.get_depth("measured") if "ylab_depth" not in kwargs: ylab_depth = ("{0} [{1}]" .format(depth.attrs["full_name"], depth.attrs["units"])) kwargs.update(ylab_depth=ylab_depth) depth = depth.to_series() if concur_vars is None: fig, ax = plotting.plot_tdr(depth, **kwargs) elif concur_var_titles is None: ccvars = self.tdr[concur_vars].to_dataframe() fig, ax = plotting.plot_tdr(depth, concur_vars=ccvars, **kwargs) else: ccvars = self.tdr[concur_vars].to_dataframe() ccvars_title = concur_var_titles # just to shorten fig, ax = plotting.plot_tdr(depth, concur_vars=ccvars, concur_var_titles=ccvars_title, **kwargs) return(fig, ax)
[docs] def plot_zoc(self, xlim=None, ylim=None, **kwargs): """Plot zero offset correction filters Parameters ---------- xlim, ylim : 2-tuple/list, optional Minimum and maximum limits for ``x``- and ``y``-axis, respectively. **kwargs : optional keyword arguments Passed to `matplotlib.pyplot.subplots`. Returns ------- tuple `matplotlib.pyplot` Figure and Axes instances. Examples -------- >>> from skdiveMove.tests import diveMove2skd >>> tdrX = diveMove2skd() >>> tdrX.zoc("offset", offset=3) >>> tdrX.plot_zoc() """ zoc_method = self.zoc_depth.method depth_msrd = self.get_depth("measured") ylab = ("{0} [{1}]" .format(depth_msrd.attrs["full_name"], depth_msrd.attrs["units"])) if zoc_method == "filter": zoc_filters = self.zoc_depth.filters depth = depth_msrd.to_series() if "ylab" not in kwargs: kwargs.update(ylab=ylab) fig, ax = (plotting ._plot_zoc_filters(depth, zoc_filters, xlim, ylim, **kwargs)) elif zoc_method == "offset": depth_msrd = depth_msrd.to_series() depth_zoc = self.get_depth("zoc").to_series() fig, ax = plotting.plt.subplots(1, 1, **kwargs) ax = depth_msrd.plot(ax=ax, rot=0, label="measured") depth_zoc.plot(ax=ax, label="zoc") ax.set_xlabel("") ax.set_ylabel(ylab) ax.legend(loc="lower right") ax.set_xlim(xlim) ax.set_ylim(ylim) ax.invert_yaxis() return(fig, ax)
[docs] def plot_phases(self, diveNo=None, concur_vars=None, concur_var_titles=None, surface=False, **kwargs): """Plot major phases found on the object Parameters ---------- diveNo : array_like, optional List of dive numbers (1-based) to plot. concur_vars : str or list, optional String or list of strings with names of columns in input to select additional data to plot. concur_var_titles : str or list, optional String or list of strings with y-axis labels for `concur_vars`. **kwargs : optional keyword arguments Arguments passed to plotting function. Returns ------- tuple `matplotlib.pyplot` Figure and Axes instances. Examples -------- >>> from skdiveMove.tests import diveMove2skd >>> tdrX = diveMove2skd() >>> tdrX.calibrate(dive_thr=3, zoc_method="offset", ... offset=3, descent_crit_q=0.01, knot_factor=20) >>> tdrX.plot_phases(list(range(250, 300)), surface=True) """ row_ids = self.get_dives_details("row_ids") dive_ids = row_ids["dive_id"] dive_ids_uniq = dive_ids.unique() postdive_ids = row_ids["postdive_id"] if diveNo is None: diveNo = np.arange(1, row_ids["dive_id"].max() + 1).tolist() else: diveNo = [x for x in sorted(diveNo) if x in dive_ids_uniq] depth_all = self.get_depth("zoc").to_dataframe() # DataFrame if concur_vars is None: dives_all = depth_all else: concur_df = self.tdr.to_dataframe().loc[:, concur_vars] dives_all = pd.concat((depth_all, concur_df), axis=1) isin_dive_ids = dive_ids.isin(diveNo) isin_postdive_ids = postdive_ids.isin(diveNo) if surface: isin = isin_dive_ids | isin_postdive_ids dives_in = dives_all[isin] sfce0_idx = (postdive_ids[postdive_ids == diveNo[0] - 1] .last_valid_index()) dives_df = pd.concat((dives_all.loc[[sfce0_idx]], dives_in), axis=0) details_df = pd.concat((row_ids.loc[[sfce0_idx]], row_ids[isin]), axis=0) else: idx_ok = _get_dive_indices(dive_ids, diveNo) dives_df = dives_all.iloc[idx_ok, :] details_df = row_ids.iloc[idx_ok, :] wet_dry = self.time_budget(ignore_z=True, ignore_du=True) drys = wet_dry[wet_dry["phase_label"] == "L"][["beg", "end"]] if (drys.shape[0] > 0): dry_time = drys else: dry_time = None if concur_vars is None: fig, ax = (plotting .plot_tdr(dives_df.iloc[:, 0], phase_cat=details_df["dive_phase"], dry_time=dry_time, **kwargs)) else: fig, ax = (plotting .plot_tdr(dives_df.iloc[:, 0], concur_vars=dives_df.iloc[:, 1:], concur_var_titles=concur_var_titles, phase_cat=details_df["dive_phase"], dry_time=dry_time, **kwargs)) return(fig, ax)
[docs] def plot_dive_model(self, diveNo=None, **kwargs): """Plot dive model for selected dive Parameters ---------- diveNo : array_like, optional List of dive numbers (1-based) to plot. **kwargs : optional keyword arguments Arguments passed to plotting function. Examples -------- >>> from skdiveMove.tests import diveMove2skd >>> tdrX = diveMove2skd() >>> tdrX.calibrate(dive_thr=3, zoc_method="offset", ... offset=3, descent_crit_q=0.01, knot_factor=20) >>> tdrX.plot_dive_model(diveNo=20, figsize=(10, 10)) """ dive_ids = self.get_dives_details("row_ids", "dive_id") crit_vals = self.get_dives_details("crit_vals").loc[diveNo] idxs = _get_dive_indices(dive_ids, diveNo) depth = self.get_depth("zoc").to_dataframe().iloc[idxs] depth_s = self.phases._get_dive_spline_slot(diveNo, "xy") depth_deriv = (self.get_dives_details("spline_derivs").loc[diveNo]) # Index with time stamp if depth.shape[0] < 4: depth_s_idx = pd.date_range(depth.index[0], depth.index[-1], periods=depth_s.shape[0], tz=depth.index.tz) depth_s = pd.Series(depth_s.to_numpy(), index=depth_s_idx) dderiv_idx = pd.date_range(depth.index[0], depth.index[-1], periods=depth_deriv.shape[0], tz=depth.index.tz) # Extract only the series and index with time stamp depth_deriv = pd.Series(depth_deriv["y"].to_numpy(), index=dderiv_idx) else: depth_s = pd.Series(depth_s.to_numpy(), index=depth.index[0] + depth_s.index) # Extract only the series and index with time stamp depth_deriv = pd.Series(depth_deriv["y"].to_numpy(), index=depth.index[0] + depth_deriv.index) # Force integer again as `loc` coerced to float above d_crit = crit_vals["descent_crit"].astype(int) a_crit = crit_vals["ascent_crit"].astype(int) d_crit_rate = crit_vals["descent_crit_rate"] a_crit_rate = crit_vals["ascent_crit_rate"] title = "Dive: {:d}".format(diveNo) plotting.plot_dive_model(depth, depth_s=depth_s, depth_deriv=depth_deriv, d_crit=d_crit, a_crit=a_crit, d_crit_rate=d_crit_rate, a_crit_rate=a_crit_rate, leg_title=title, **kwargs)
[docs] def get_depth(self, kind="measured"): """Retrieve depth records Parameters ---------- kind : {"measured", "zoc"} Which depth to retrieve. Returns ------- xarray.DataArray """ kinds = ["measured", "zoc"] if kind == kinds[0]: odepth = TDRSource.get_depth(self) elif kind == kinds[1]: odepth = self.zoc_depth.get_depth() if odepth is None: msg = "ZOC depth not available." logger.error(msg) raise IndexError(msg) else: msg = "kind must be one of: {}".format(kinds) logger.error(msg) raise IndexError(msg) return(odepth)
[docs] def get_speed(self, kind="measured"): """Retrieve speed records Parameters ---------- kind : {"measured", "calibrated"} Which speed to retrieve. Returns ------- xarray.DataArray """ kinds = ["measured", "calibrated"] ispeed = TDRSource.get_speed(self) if kind == kinds[0]: ospeed = ispeed elif kind == kinds[1]: qfit = self.speed_calib_fit if qfit is None: msg = "Calibrated speed not available." logger.error(msg) raise IndexError(msg) else: coefs = qfit.params coef_a = coefs[0] coef_b = coefs[1] ospeed = (ispeed - coef_a) / coef_b _add_xr_attr(ospeed, "history", "speed_calib_fit") else: msg = "kind must be one of: {}".format(kinds) logger.error(msg) raise IndexError(msg) return(ospeed)
[docs] def get_wet_activity(self): """Retrieve wet/dry activity DataFrame """ return(self.phases.get_wet_activity())
[docs] def get_dives_details(self, *args, **kwargs): """Retrieve wet/dry activity DataFrame Returns ------- *args, **kwargs : arguments and keyword arguments Passed to :meth:`~tdrphases.TDRPhases.get_dives_details` """ return(self.phases.get_dives_details(*args, **kwargs))
[docs] def get_dive_deriv(self, *args, **kwargs): """Retrieve depth spline derivative for a given dive Parameters ---------- *args : arguments Passed to :meth:`~tdrphases.TDRPhases.get_dive_deriv` **kwargs : keyword arguments Passed to :meth:`~tdrphases.TDRPhases.get_dive_deriv` """ return(self.phases.get_dive_deriv(*args, **kwargs))
[docs] def get_phases_params(self, key): """Retrieve parameters used for identification of phases Parameters ---------- key : {'wet_dry', 'dives'} Name of type of parameters to retrieve. Returns ------- out : dict """ return(self.phases.get_params(key))
[docs] def time_budget(self, **kwargs): """Summary of wet/dry activities at the broadest scale Parameters ---------- **kwargs : optional keyword arguments Passed to :meth:`~tdrphases.TDRPhases.time_budget` Returns ------- out : pandas.DataFrame Examples -------- >>> from skdiveMove.tests import diveMove2skd >>> tdrX = diveMove2skd() >>> tdrX.calibrate(dive_thr=3, zoc_method="offset", ... offset=3, descent_crit_q=0.01, knot_factor=20) >>> tdrX.time_budget(ignore_z=True, ignore_du=True) """ return(self.phases.time_budget(**kwargs))
[docs] def stamp_dives(self, **kwargs): """Identify the wet/dry activity phase corresponding to each dive Parameters ---------- **kwargs : optional keyword arguments Passed to :meth:`~tdrphases.TDRPhases.stamp_dives` Returns ------- out : pandas.DataFrame Examples -------- >>> from skdiveMove.tests import diveMove2skd >>> tdrX = diveMove2skd() >>> tdrX.calibrate(dive_thr=3, zoc_method="offset", ... offset=3, descent_crit_q=0.01, knot_factor=20) >>> tdrX.stamp_dives(ignore_z=True) """ return(self.phases.stamp_dives(**kwargs))
[docs] def get_tdr(self, calib_depth=True, calib_speed=True): """Return a copy of tdr Dataset Parameters ---------- calib_depth : bool, optional Whether to return calibrated depth measurements. calib_speed : bool, optional Whether to return calibrated speed measurements. Returns ------- xarray.Dataset """ tdr = self.tdr.copy() if calib_depth: depth_name = self.depth_name depth_cal = self.get_depth("zoc") tdr[depth_name] = depth_cal if self.has_speed and calib_speed: speed_name = self.speed_name speed_cal = self.get_speed("calibrated") tdr[speed_name] = speed_cal return(tdr)
[docs] def extract_dive(self, diveNo, **kwargs): """Extract TDR data corresponding to a particular set of dives Parameters ---------- diveNo : array_like, optional List of dive numbers (1-based) to plot. **kwargs : optional keyword arguments Passed to :meth:`get_tdr` Returns ------- xarray.Dataset Examples -------- >>> from skdiveMove.tests import diveMove2skd >>> tdrX = diveMove2skd() >>> tdrX.calibrate(dive_thr=3, zoc_method="offset", ... offset=3, descent_crit_q=0.01, knot_factor=20) >>> tdrX.extract_dive(diveNo=20) """ dive_ids = self.get_dives_details("row_ids", "dive_id") idxs = _get_dive_indices(dive_ids, diveNo) tdr = self.get_tdr(**kwargs) tdr_i = tdr[dict(date_time=idxs.astype(int))] return(tdr_i)
if __name__ == '__main__': # Set up info level logging logging.basicConfig(level=logging.INFO) ifile = r"tests/data/ag_mk7_2002_022.nc" # tdrX = TDRSource(ifile, has_speed=True) # print(tdrX) # xx = ZOC() # xx.offset_depth(tdrX.get_depth(), 3) # xx(tdrX.get_depth(), "offset", offset=3) DB = [-2, 5] K = [3, 5760] P = [0.5, 0.02] # xx(tdrX.get_depth(), "filter", k=K, probs=P, depth_bounds=DB) tdrX = TDR(ifile, has_speed=True) # tdrX.zoc(method="filter", k=K, probs=P, depth_bounds=DB) tdrX.zoc("offset", offset=3) # Compare n dives detected tdrX.detect_wet() tdrX.detect_dives(dive_thr=3) tdrX.detect_dive_phases(dive_model="unimodal", descent_crit_q=0.01, ascent_crit_q=0, knot_factor=20) tdrX.calibrate(zoc_method="offset", offset=3, dive_thr=3, k=K, probs=P, depth_bounds=DB, descent_crit_q=0.01, knot_factor=20) tdrX.calibrate_speed(z=2)