Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add option for custom reading method name to adapters #245

Merged
merged 21 commits into from
Jul 30, 2021
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,5 @@ MANIFEST
# Per-project virtualenvs
.venv*/

# playground dir
*/_local_scripts/*
.artifacts/
# GithubActions
.artifacts/
37 changes: 19 additions & 18 deletions LICENSE.txt
Original file line number Diff line number Diff line change
@@ -1,25 +1,26 @@
#Copyright (c) 2020, TU Wien, Department of Geodesy and Geoinformation
#All rights reserved.
# Copyright (c) 2020, TU Wien, Department of Geodesy and Geoinformation
# All rights reserved.

#Redistribution and use in source and binary forms, with or without
#modification, are permitted provided that the following conditions are met:
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# * Neither the name of the TU Wien, Department of Geodesy and Geoinformation nor the
# names of its contributors may be used to endorse or promote products
# derived from this software without specific prior written permission.
# * Neither the name of the TU Wien, Department of Geodesy and
# Geoinformation nor the names of its contributors may be used to endorse
# or promote products derived from this software without specific prior
# written permission.

#THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
#ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
#WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
#DISCLAIMED. IN NO EVENT SHALL VIENNA UNIVERSITY OF TECHNOLOGY,
#DEPARTMENT OF GEODESY AND GEOINFORMATION BE LIABLE FOR ANY
#DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
#(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
#LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
#ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
#(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
#SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL VIENNA UNIVERSITY OF TECHNOLOGY,
# DEPARTMENT OF GEODESY AND GEOINFORMATION BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
466 changes: 425 additions & 41 deletions docs/examples/validation_framework.ipynb

Large diffs are not rendered by default.

48 changes: 28 additions & 20 deletions src/pytesmo/colormaps/load_cmap.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,55 +13,63 @@
import glob
from pytesmo.utils import deprecated

@deprecated

@deprecated()
def colormaps_path():
"""Returns application's default path for storing user-defined colormaps"""
return os.path.dirname(__file__)

@deprecated

@deprecated()
def get_system_colormaps():
"""Returns the list of colormaps that ship with matplotlib"""
return [m for m in cm.datad]

@deprecated

@deprecated()
def get_user_colormaps(cmap_fldr=colormaps_path()):
"""Returns a list of user-defined colormaps in the specified folder (defaults to
standard colormaps folder if not specified)."""
"""Returns a list of user-defined colormaps in the specified folder
(defaults to standard colormaps folder if not specified)."""
user_colormaps = []
for root, dirs, files in os.walk(cmap_fldr):
files = glob.glob(root + '/*.cmap')
files = glob.glob(root + "/*.cmap")
for name in files:
with open(os.path.join(root, name), "r") as fidin:
cmap_dict = json.load(fidin)
user_colormaps.append(cmap_dict.get('name', name))
user_colormaps.append(cmap_dict.get("name", name))
return user_colormaps

@deprecated

@deprecated()
def load_colormap(json_file):
"""Generates and returns a matplotlib colormap from the specified JSON file,
or None if the file was invalid."""
colormap = None
with open(json_file, "r") as fidin:
cmap_dict = json.load(fidin)
if cmap_dict.get('colors', None) is None:
if cmap_dict.get("colors", None) is None:
return colormap
colormap_type = cmap_dict.get('type', 'linear')
colormap_name = cmap_dict.get('name', os.path.basename(json_file))
if colormap_type == 'linear':
colormap = colors.LinearSegmentedColormap.from_list(name=colormap_name,
colors=cmap_dict['colors'])
elif colormap_type == 'list':
colormap = colors.ListedColormap(name=colormap_name, colors=cmap_dict['colors'])
colormap_type = cmap_dict.get("type", "linear")
colormap_name = cmap_dict.get("name", os.path.basename(json_file))
if colormap_type == "linear":
colormap = colors.LinearSegmentedColormap.from_list(
name=colormap_name, colors=cmap_dict["colors"]
)
elif colormap_type == "list":
colormap = colors.ListedColormap(
name=colormap_name, colors=cmap_dict["colors"]
)
return colormap

@deprecated

@deprecated()
def load(cmap_name, cmap_folder=colormaps_path()):
"""Returns the matplotlib colormap of the specified name -
if not found in the predefined
colormaps, searches for the colormap in the specified
folder (defaults to standard colormaps
folder if not specified)."""
cmap_name_user = cmap_name + '.cmap'
cmap_name_user = cmap_name + ".cmap"
user_colormaps = get_user_colormaps(cmap_folder)
system_colormaps = get_system_colormaps()

Expand All @@ -71,5 +79,5 @@ def load(cmap_name, cmap_folder=colormaps_path()):
elif cmap_name in system_colormaps:
return cm.get_cmap(cmap_name)
else:
raise ValueError('Colormap not found')
return cmap
raise ValueError("Colormap not found")
return cmap
108 changes: 65 additions & 43 deletions src/pytesmo/df_metrics.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@
# names of its contributors may be used to endorse or promote products
# derived from this software without specific prior written permission.

# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL VIENNA UNIVERSITY OF TECHNOLOGY,
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL VIENNA UNIVERSITY OF TECHNOLOGY,
# DEPARTMENT OF GEODESY AND GEOINFORMATION BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
Expand Down Expand Up @@ -67,7 +67,9 @@ def n_combinations(iterable, n, must_include=None, permutations=False):
The possible combinations of n elements.
"""
if must_include:
if (not isinstance(must_include, Iterable)) or isinstance(must_include, str):
if (not isinstance(must_include, Iterable)) or isinstance(
must_include, str
):
must_include = [must_include]

if permutations:
Expand Down Expand Up @@ -111,8 +113,7 @@ def _wrap_metric(metric, symmetric=True, name=None):

def wrapped(df):
return _dict_to_namedtuple(
nwise_apply(df, metric, n=2, comm=symmetric),
metric_name
nwise_apply(df, metric, n=2, comm=symmetric), metric_name
)

# add name and docstring
Expand Down Expand Up @@ -172,13 +173,15 @@ def mse_decomposition(df):
mse, mse_corr, mse_bias, mse_var = nwise_apply(
df, metrics.mse_decomposition, n=2, comm=True
)
return (_dict_to_namedtuple(mse, 'MSE'),
_dict_to_namedtuple(mse_corr, 'MSEcorr'),
_dict_to_namedtuple(mse_bias, 'MSEbias'),
_dict_to_namedtuple(mse_var, 'MSEvar'))
return (
_dict_to_namedtuple(mse, "MSE"),
_dict_to_namedtuple(mse_corr, "MSEcorr"),
_dict_to_namedtuple(mse_bias, "MSEbias"),
_dict_to_namedtuple(mse_var, "MSEvar"),
)


@deprecated
@deprecated()
def mse(df):
"""
Deprecated: use :py:func:`pytesmo.df_metrics.msd` and the functions for the
Expand All @@ -201,14 +204,18 @@ def mse(df):
pytesmo.metrics.mse

"""
MSE, MSEcorr, MSEbias, MSEvar = nwise_apply(df, metrics.mse, n=2, comm=True)
return (_dict_to_namedtuple(MSE, 'MSE'),
_dict_to_namedtuple(MSEcorr, 'MSEcorr'),
_dict_to_namedtuple(MSEbias, 'MSEbias'),
_dict_to_namedtuple(MSEvar, 'MSEvar'))
MSE, MSEcorr, MSEbias, MSEvar = nwise_apply(
df, metrics.mse, n=2, comm=True
)
return (
_dict_to_namedtuple(MSE, "MSE"),
_dict_to_namedtuple(MSEcorr, "MSEcorr"),
_dict_to_namedtuple(MSEbias, "MSEbias"),
_dict_to_namedtuple(MSEvar, "MSEvar"),
)


@deprecated
@deprecated()
def tcol_error(df):
"""
Deprecated: use :py:func:`pytesmo.df_metrics.tcol_metrics` instead.
Expand All @@ -231,19 +238,21 @@ def tcol_error(df):
"""
# For TC, the input order has NO effect --> comm=True
err0, err1, err2 = nwise_apply(df, metrics.tcol_error, n=3, comm=True)
trips = list(err0.keys()) # triples in all err are equal
trips = list(err0.keys()) # triples in all err are equal
assert trips == list(err0.keys()) == list(err1.keys()) == list(err2.keys())

errors = []
for trip in trips:
res = [err0[trip], err1[trip], err2[trip]]
Inner = namedtuple('triple_collocation_error', OrderedDict(zip(trip, res)))
Inner = namedtuple(
"triple_collocation_error", OrderedDict(zip(trip, res))
)
errors.append(Inner(*res))

return tuple(errors)


@deprecated
@deprecated()
def tcol_snr(df, ref_ind=0):
"""DEPRECATED: use `tcol_metrics` instead."""
return tcol_metrics(df, ref_ind=0)
Expand Down Expand Up @@ -282,18 +291,24 @@ def tcol_metrics(df, ref_ind=0):
# the reference.
incl = None
ref_ind = 0
snr, err, beta = nwise_apply(df, metrics.tcol_metrics, n=3, comm=True,
must_include=incl, ref_ind=ref_ind)
snr, err, beta = nwise_apply(
df,
metrics.tcol_metrics,
n=3,
comm=True,
must_include=incl,
ref_ind=ref_ind,
)

results = {}
var_dict = {'snr': snr, 'err_std_dev': err, 'beta': beta}
var_dict = {"snr": snr, "err_std_dev": err, "beta": beta}
for var_name, var_vals in var_dict.items():
results[var_name] = []
for trip, res in var_vals.items():
Inner = namedtuple(var_name, OrderedDict(zip(trip, res)))
results[var_name].append(Inner(*res))

return (results['snr'], results['err_std_dev'], results['beta'])
return (results["snr"], results["err_std_dev"], results["beta"])


def pearsonr(df):
Expand All @@ -314,10 +329,9 @@ def pearsonr(df):
"""
r, p = nwise_apply(df, stats.pearsonr, n=2, comm=True)
return (
_dict_to_namedtuple(r, 'Pearsons_r'),
_dict_to_namedtuple(p, 'p_value')
_dict_to_namedtuple(r, "Pearsons_r"),
_dict_to_namedtuple(p, "p_value"),
)



def spearmanr(df):
Expand All @@ -338,8 +352,8 @@ def spearmanr(df):
"""
r, p = nwise_apply(df, stats.spearmanr, n=2, comm=True)
return (
_dict_to_namedtuple(r, 'Spearman_r'),
_dict_to_namedtuple(p, 'p_value')
_dict_to_namedtuple(r, "Spearman_r"),
_dict_to_namedtuple(p, "p_value"),
)


Expand All @@ -361,8 +375,8 @@ def kendalltau(df):
"""
r, p = nwise_apply(df, stats.kendalltau, n=2, comm=True)
return (
_dict_to_namedtuple(r, 'Kendall_tau'),
_dict_to_namedtuple(p, 'p_value')
_dict_to_namedtuple(r, "Kendall_tau"),
_dict_to_namedtuple(p, "p_value"),
)


Expand All @@ -386,7 +400,7 @@ def pairwise_apply(df, method, comm=False):
"""
warnings.warn(
"pairwise_apply() is deprecated, use nwise_apply(..., n=2) instead",
DeprecationWarning
DeprecationWarning,
)
numeric_df = df._get_numeric_data()
cols = numeric_df.columns
Expand Down Expand Up @@ -432,8 +446,16 @@ def pairwise_apply(df, method, comm=False):
return tuple(return_list)


def nwise_apply(df, method, n=2, comm=False, as_df=False, ds_names=True,
must_include=None, **method_kwargs):
def nwise_apply(
df,
method,
n=2,
comm=False,
as_df=False,
ds_names=True,
must_include=None,
**method_kwargs,
):
"""
Compute given method for column combinations of a data frame, excluding
NA/null values.
Expand Down Expand Up @@ -493,7 +515,7 @@ def nwise_apply(df, method, n=2, comm=False, as_df=False, ds_names=True,
c = applyf(*array_dropna(*[mat[i] for i in range(n)]))
for index, value in enumerate(np.atleast_1d(c)):
result.append(OrderedDict([(c, np.nan) for c in combs]))
result = np.array(result) # array of OrderedDicts
result = np.array(result) # array of OrderedDicts
# each return value result is a dict that gets filled with dicts that have
# the cols and keys and the results as values

Expand All @@ -516,12 +538,13 @@ def nwise_apply(df, method, n=2, comm=False, as_df=False, ds_names=True,

if as_df:
if n != 2:
raise ValueError('Array structure only available for n=2')
raise ValueError("Array structure only available for n=2")
else:
if not ds_names:
lut_comb_cols = None
result = [_to_df(r, comm=comm, lut_names=lut_comb_cols)
for r in result]
result = [
_to_df(r, comm=comm, lut_names=lut_comb_cols) for r in result
]
else:
if ds_names:
formatted_results = []
Expand Down Expand Up @@ -559,7 +582,7 @@ def _to_df(result, comm=False, lut_names=None):
# find out how large the matrix is
imax = max([max(r) for r in list(result.keys())])
# create and fill the matrix
res = np.full((imax+1, imax+1), np.nan)
res = np.full((imax + 1, imax + 1), np.nan)
for k, v in result.items():
res[k[::-1]] = v
res = res.transpose()
Expand All @@ -571,8 +594,7 @@ def _to_df(result, comm=False, lut_names=None):

if lut_names is not None:
res = pd.DataFrame(
data={lut_names[i]: res[:, i]
for i in list(range(max(res.shape)))}
data={lut_names[i]: res[:, i] for i in list(range(max(res.shape)))}
)
else:
res = pd.DataFrame(
Expand All @@ -592,7 +614,7 @@ def _dict_to_namedtuple(res_dict, name):
values = []

for k, v in res_dict.items():
names.append('_and_'.join(k))
names.append("_and_".join(k))
values.append(v)

result = namedtuple(name, names)
Expand Down
Loading