Skip to content

Commit

Permalink
Merge branch 'main' into teos10
Browse files Browse the repository at this point in the history
  • Loading branch information
callumrollo authored Nov 12, 2024
2 parents 4b7e0a3 + e5dc1f1 commit 50eb2f1
Showing 1 changed file with 156 additions and 25 deletions.
181 changes: 156 additions & 25 deletions glidertest/tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,25 @@


def _necessary_variables_check(ds: xr.Dataset, vars: list):
"""Checks that all of a list of variables are present in a dataset
"""
Checks that all of a list of variables are present in a dataset
Args:
ds (xarray.Dataset): _description_
vars (list): _description_
Parameters
----------
ds (xarray.Dataset): _description_
vars (list): _description_
Raises:
KeyError: Raises an error if all vars not present in ds
Raises
----------
KeyError: Raises an error if all vars not present in ds
Original author
----------------
Callum Rollo
"""
missing_vars = set(vars).difference(set(ds.variables))
if missing_vars:
msg = f"Required variables {list(missing_vars)} do not exist in the suppllied dataset."
msg = f"Required variables {list(missing_vars)} do not exist in the supplied dataset."
raise KeyError(msg)


Expand Down Expand Up @@ -64,6 +71,10 @@ def compute_grid2d(x, y, v, xi=1, yi=1):
XI: x data gridded in x and y space with xi and yi resolution
YI: y data gridded in x and y space with xi and yi resolution
Original author
----------------
Bastien Queste (https://github.com/bastienqueste/gliderad2cp/blob/de0652f70f4768c228f83480fa7d1d71c00f9449/gliderad2cp/process_adcp.py#L140)
"""
if np.size(xi) == 1:
xi = np.arange(np.nanmin(x), np.nanmax(x) + xi, xi)
Expand Down Expand Up @@ -94,6 +105,9 @@ def compute_updown_bias(ds, var='PSAL', v_res=1):
-------
df: pandas dataframe containing dc (Dive - Climb average), cd (Climb - Dive average) and depth
Original author
----------------
Chiara Monforte
"""
_necessary_variables_check(ds, ['PROFILE_NUMBER', 'DEPTH', var])
p = 1 # Horizontal resolution
Expand Down Expand Up @@ -128,6 +142,10 @@ def plot_updown_bias(df: pd.DataFrame, ax: plt.Axes = None, xlabel='Temperature
Returns
-------
A line plot comparing the day and night average over depth for the selected day
Original author
----------------
Chiara Monforte
"""
if ax is None:
fig, ax = plt.subplots(figsize=(5, 5))
Expand All @@ -152,15 +170,26 @@ def plot_updown_bias(df: pd.DataFrame, ax: plt.Axes = None, xlabel='Temperature
def compute_cline(var, depth_array):
"""
Find the depth of the maximum vertical difference for a specified variables
Input data has to be gridded
Parameters
----------
var: 2D array containing data from a selected variable gridded over time/profile/distance etc. and depth (y-axis))
depth_array: 2D array containing pressure/depth data gridded over time/profile/distance etc. and depth (y-axis))
Returns
-------
1D array containing the depth of the cline at each timestamp/profile/distance etc.
Original author
----------------
Chiara Monforte
"""
with warnings.catch_warnings():
warnings.simplefilter("ignore", category=RuntimeWarning)
clin = np.where(np.abs(np.diff(np.nanmean(var, axis=0))) == np.nanmax(np.abs(np.diff(np.nanmean(var, axis=0)))))
return np.round(depth_array[0, clin[0]], 1)


def plot_basic_vars(ds, v_res=1, start_prof=0, end_prof=-1):
def plot_basic_vars(ds: xr.Dataset, v_res=1, start_prof=0, end_prof=-1):
"""
This function plots the basic oceanographic variables temperature, salinity and density. A second plot is created and filled with oxygen and
chlorophyll data if available.
Expand All @@ -178,6 +207,10 @@ def plot_basic_vars(ds, v_res=1, start_prof=0, end_prof=-1):
-------
Line plots for the averages of the different variables.
Thermo, halo and pycnocline are computed and plotted. A sentence stating the depth of the clines is printed too
Original author
----------------
Chiara Monforte
"""
_necessary_variables_check(ds, ['PROFILE_NUMBER', 'DEPTH', 'TEMP', 'PSAL', 'LATITUDE', 'LONGITUDE'])
ds = _calc_teos10_variables(ds)
Expand Down Expand Up @@ -256,8 +289,21 @@ def plot_basic_vars(ds, v_res=1, start_prof=0, end_prof=-1):

def process_optics_assess(ds, var='CHLA'):
"""
Function to assess any drift in deep optics data and the presence of any possible negative data
This function returns plots and text
Function to assess visually any drift in deep optics data and the presence of any possible negative data. This function returns both plots and text
Parameters
----------
ds: xarray dataset in OG1 format containing at least time, depth and the selected optical variable
var: name of the selected variable
Returns
-------
Text giving info on where and when negative data was observed
Plot showing bottom data with a linear regression line to highlight any drift
Original author
----------------
Chiara Monforte
"""
_necessary_variables_check(ds, [var, 'TIME', 'DEPTH'])
# Check how much negative data there is
Expand Down Expand Up @@ -307,7 +353,6 @@ def process_optics_assess(ds, var='CHLA'):
def compute_sunset_sunrise(time, lat, lon):
"""
Calculates the local sunrise/sunset of the glider location from GliderTools.
[https://github.com/GliderToolsCommunity/GliderTools/blob/master/glidertools/optics.py]
The function uses the Skyfield package to calculate the sunrise and sunset
times using the date, latitude and longitude. The times are returned
Expand All @@ -331,6 +376,10 @@ def compute_sunset_sunrise(time, lat, lon):
sunset: numpy.ndarray
An array of the sunset times.
Original author
----------------
Function from GliderTools (https://github.com/GliderToolsCommunity/GliderTools/blob/master/glidertools/optics.py)
"""

ts = api.load.timescale()
Expand Down Expand Up @@ -441,10 +490,12 @@ def compute_daynight_avg(ds, sel_var='CHLA', start_time=None, end_time=None, sta
we recommend selecting small section of few days to a few weeks. Defaults to the central week of the deployment
end_time: End date of the data selection. As missions can be long and can make it hard to visualise NPQ effect,
we recommend selecting small section of few days to a few weeks. Defaults to the central week of the deployment
start_prof: Start profile of the data selection. If no profile is specified, the specified time selction will be used or the the central week of the deployment.
start_prof: Start profile of the data selection. If no profile is specified, the specified time selection will be used
or the the central week of the deployment.
It is important to have a large enough number of dives to have some day and night data otherwise the function will not run
end_prof: End profile of the data selection. If no profile is specified, the specified time selction will be used or the the central week of the deployment.
It is important to have a large enough number of dives to have some day and night data otherwise the function will not run
end_prof: End profile of the data selection. If no profile is specified, the specified time selection will be used
or the the central week of the deployment.
It is important to have a large enough number of dives to have some day and night data otherwise the function will not run
Returns
-------
Expand All @@ -460,6 +511,10 @@ def compute_daynight_avg(ds, sel_var='CHLA', start_time=None, end_time=None, sta
depth: Depth values for the average
dat: Average value for the selected variable
day: Actual date for the batch
Original author
----------------
Chiara Monforte
"""
_necessary_variables_check(ds, ['TIME', sel_var, 'DEPTH'])
Expand Down Expand Up @@ -518,6 +573,10 @@ def plot_daynight_avg(day: pd.DataFrame, night: pd.DataFrame, ax: plt.Axes = Non
-------
A line plot comparing the day and night average over depth for the selected day
Original author
----------------
Chiara Monforte
"""
if not sel_day:
dates = list(day.date.dropna().values) + list(night.date.dropna().values)
Expand Down Expand Up @@ -550,15 +609,21 @@ def plot_quench_assess(ds: xr.Dataset, sel_var: str, ax: plt.Axes = None, start_
Data should not be gridded.
sel_var: selected variable to plot
ax: axis to plot the data
start_time: Start date of the data selection format 'YYYY-MM-DD'. As missions can be long and came make it hard to visualise NPQ effect. Defaults to mid 4 days
end_time: End date of the data selection format 'YYYY-MM-DD'. As missions can be long and came make it hard to visualise NPQ effect. Defaults to mid 4 days
start_prof: Start profile of the data selection. If no profile is specified, the specified time selction will be used or the mid 4 days of the deployment
end_prof: End profile of the data selection. If no profile is specified, the specified time selction will be used or the mid 4 days of the deployment
start_time: Start date of the data selection format 'YYYY-MM-DD'. As missions can be long and came make it hard to visualise NPQ effect.
Defaults to mid 4 days
end_time: End date of the data selection format 'YYYY-MM-DD'. As missions can be long and came make it hard to visualise NPQ effect.
Defaults to mid 4 days
start_prof: Start profile of the data selection. If no profile is specified, the specified time selection will be used or the mid 4 days of the deployment
end_prof: End profile of the data selection. If no profile is specified, the specified time selection will be used or the mid 4 days of the deployment
ylim: specified limit for the maximum y-axis value. The minimum is computed as ylim/30
Returns
-------
A section showing the variability of the selected data over time and depth
Original author
----------------
Chiara Monforte
"""
_necessary_variables_check(ds, ['TIME', sel_var, 'DEPTH'])
if ax is None:
Expand Down Expand Up @@ -600,6 +665,25 @@ def plot_quench_assess(ds: xr.Dataset, sel_var: str, ax: plt.Axes = None, start_


def check_temporal_drift(ds: xr.Dataset, var: str, ax: plt.Axes = None, **kw: dict, ) -> tuple({plt.Figure, plt.Axes}):
"""
This function can be used to plot sections for any variable with the sunrise and sunset plotted over
Parameters
----------
ds: xarray on OG1 format containing at least time, depth, latitude, longitude and the selected variable.
Data should not be gridded.
var: selected variable to plot
ax: axis to plot the data
Returns
-------
A figure with two subplots. One is a section containing the data over time and depth. The other one is a scatter of data from the variable
over depth and colored by date
Original author
----------------
Chiara Monforte
"""
_necessary_variables_check(ds, ['TIME', var, 'DEPTH'])
if ax is None:
fig, ax = plt.subplots(1, 2, figsize=(14, 6))
Expand All @@ -622,7 +706,7 @@ def check_temporal_drift(ds: xr.Dataset, var: str, ax: plt.Axes = None, **kw: di
def check_monotony(da):
"""
This function check weather the selected variable over the mission is monotonically increasing or not. This is developed in particular for profile number.
If the profile number is not monotonically increasing, this may mean that whatever function was used to assign the profile number may have misassigned some points.
If the profile number is not monotonically increasing, this may mean that whatever function was used to assign the profile number may have misassigned at some points.
Parameters
----------
Expand All @@ -632,6 +716,10 @@ def check_monotony(da):
-------
It will print a sentence stating whether data is
Original author
----------------
Chiara Monforte
"""
if not pd.Series(da).is_monotonic_increasing:
print(f'{da.name} is not always monotonically increasing')
Expand All @@ -651,10 +739,15 @@ def plot_profIncrease(ds: xr.Dataset, ax: plt.Axes = None, **kw: dict, ) -> tupl
ds: xarray dataset in OG1 format with at least PROFILE_NUMBER, TIME, DEPTH. Data should not be gridded
ax: axis to plot the data
Returns -------
Returns
-------
Two plots, one line plot with the profile number over time (expected to be always increasing). A
second plot which is a scatter plot showing at which depth over time there was a profile index where the
difference was neither 0 nor 1 (meaning there are possibly issues with how the profile index was assigned)
difference was neither 0 nor 1 (meaning there are possibly issues with how the profile index was assigned).
Original author
----------------
Chiara Monforte
"""
_necessary_variables_check(ds, ['TIME', 'PROFILE_NUMBER', 'DEPTH'])
Expand Down Expand Up @@ -695,6 +788,10 @@ def plot_glider_track(ds: xr.Dataset, ax: plt.Axes = None, **kw: dict) -> tuple(
One plot with the map of the glider track.
fig: matplotlib.figure.Figure
ax: matplotlib.axes._subplots.AxesSubplot
Original author
----------------
Eleanor Frajka-Williams
"""
_necessary_variables_check(ds, ['TIME', 'LONGITUDE', 'LATITUDE'])
if ax is None:
Expand Down Expand Up @@ -755,6 +852,10 @@ def plot_grid_spacing(ds: xr.Dataset, ax: plt.Axes = None, **kw: dict) -> tuple(
Two histograms showing the distribution of grid spacing for depth and time.
fig: matplotlib.figure.Figure
ax: matplotlib.axes._subplots.AxesSubplot
Original author
----------------
Eleanor Frajka-Williams
"""
_necessary_variables_check(ds, ['TIME', 'DEPTH'])
if ax is None:
Expand Down Expand Up @@ -831,6 +932,10 @@ def plot_ts(ds: xr.Dataset, ax: plt.Axes = None, **kw: dict) -> tuple({plt.Figur
Three plots: histogram of temperature, histogram of salinity, and 2D histogram of salinity and temperature with density contours.
fig: matplotlib.figure.Figure
ax: matplotlib.axes._subplots.AxesSubplot
Original author
----------------
Eleanor Frajka-Williams
"""
_necessary_variables_check(ds, ['DEPTH', 'LONGITUDE', 'LATITUDE', 'PSAL', 'TEMP'])

Expand Down Expand Up @@ -902,6 +1007,10 @@ def calc_DEPTH_Z(ds):
Returns
-------
xarray.Dataset: The dataset with an additional 'DEPTH_Z' variable.
Original author
----------------
Eleanor Frajka-Williams
"""
_necessary_variables_check(ds, ['PRES', 'LONGITUDE', 'LATITUDE'])

Expand Down Expand Up @@ -936,6 +1045,10 @@ def calc_w_meas(ds):
-------
ds (xarray.Dataset): Containing the new variable
- GLIDER_VERT_VELO_DZDT (array-like): with vertical velocities calculated from dz/dt
Original author
----------------
Eleanor Frajka-Williams
"""
_necessary_variables_check(ds, ['TIME'])
# Ensure inputs are numpy arrays
Expand Down Expand Up @@ -981,7 +1094,13 @@ def calc_w_sw(ds):
-------
ds (xarray.Dataset): Dataset with the new variable 'VERT_SW_SPEED', which is the inferred vertical seawater velocity.
Eleanor's note: This could be bundled with calc_glider_w_from_depth, but keeping them separate allows for some extra testing/flexibility for the user.
Note
-----
This could be bundled with calc_glider_w_from_depth, but keeping them separate allows for some extra testing/flexibility for the user.
Original author
----------------
Eleanor Frajka-Williams
"""
_necessary_variables_check(ds, ['GLIDER_VERT_VELO_MODEL', 'GLIDER_VERT_VELO_DZDT'])

Expand Down Expand Up @@ -1015,6 +1134,10 @@ def plot_vertical_speeds_with_histograms(ds, start_prof=None, end_prof=None):
Returns
-------
fig, axs (tuple): The figure and axes objects for the plot.
Original author
----------------
Eleanor Frajka-Williams
"""
_necessary_variables_check(ds, ['GLIDER_VERT_VELO_MODEL', 'GLIDER_VERT_VELO_DZDT', 'VERT_CURR_MODEL','PROFILE_NUMBER'])

Expand Down Expand Up @@ -1118,6 +1241,10 @@ def compute_ramsey_binavg(ds, var='VERT_CURR', zgrid=None, dz=None):
Note
----
I know this is a non-sensical name. We should re-name, but is based on advice from Ramsey Harcourt.
Original author
----------------
Eleanor Frajka-Williams
"""
_necessary_variables_check(ds, [var, 'PRES'])
press = ds.PRES.values
Expand Down Expand Up @@ -1197,7 +1324,7 @@ def findbetw(arr, bounds):
)
return ds_out

def plot_combined_velocity_profiles(ds_out_dives, ds_out_climbs):
def plot_combined_velocity_profiles(ds_out_dives: xr.Dataset, ds_out_climbs: xr.Dataset):
"""
Plots combined vertical velocity profiles for dives and climbs.
Expand All @@ -1214,6 +1341,10 @@ def plot_combined_velocity_profiles(ds_out_dives, ds_out_climbs):
Note
----
Assumes that the vertical velocities are in m/s and the depth grid is in meters.
Original author
----------------
Eleanor Frajka-Williams
"""
conv_factor = 100 # Convert m/s to cm/s
depth_negative = ds_out_dives.zgrid.values * -1
Expand Down Expand Up @@ -1255,4 +1386,4 @@ def plot_combined_velocity_profiles(ds_out_dives, ds_out_climbs):
ax.spines['right'].set_visible(False)
ax.spines['top'].set_visible(False)
plt.show()
ax.tick_params(axis='both', which='major', labelsize=12)
ax.tick_params(axis='both', which='major', labelsize=12)

0 comments on commit 50eb2f1

Please sign in to comment.