obsarray 0.2.4__tar.gz → 0.2.5__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {obsarray-0.2.4 → obsarray-0.2.5}/.gitignore +2 -2
- {obsarray-0.2.4/obsarray.egg-info → obsarray-0.2.5}/PKG-INFO +5 -4
- obsarray-0.2.5/docs/conf.py +181 -0
- obsarray-0.2.5/docs/index.rst +66 -0
- {obsarray-0.2.4 → obsarray-0.2.5}/obsarray/_version.py +3 -3
- {obsarray-0.2.4 → obsarray-0.2.5}/obsarray/flag_accessor.py +13 -330
- {obsarray-0.2.4 → obsarray-0.2.5}/obsarray/test/test_flag_accessor.py +62 -5
- {obsarray-0.2.4 → obsarray-0.2.5}/obsarray/test/test_unc_accessor.py +12 -0
- {obsarray-0.2.4 → obsarray-0.2.5}/obsarray/unc_accessor.py +14 -13
- {obsarray-0.2.4 → obsarray-0.2.5/obsarray.egg-info}/PKG-INFO +5 -4
- {obsarray-0.2.4 → obsarray-0.2.5}/obsarray.egg-info/requires.txt +3 -1
- {obsarray-0.2.4 → obsarray-0.2.5}/setup.py +14 -4
- {obsarray-0.2.4 → obsarray-0.2.5}/versioneer.py +2 -2
- obsarray-0.2.4/docs/conf.py +0 -364
- obsarray-0.2.4/docs/index.rst +0 -37
- {obsarray-0.2.4 → obsarray-0.2.5}/.pre-commit-config.yaml +0 -0
- {obsarray-0.2.4 → obsarray-0.2.5}/LICENSE +0 -0
- {obsarray-0.2.4 → obsarray-0.2.5}/MANIFEST.in +0 -0
- {obsarray-0.2.4 → obsarray-0.2.5}/README.md +0 -0
- {obsarray-0.2.4 → obsarray-0.2.5}/docs/Makefile +0 -0
- {obsarray-0.2.4 → obsarray-0.2.5}/docs/make.bat +0 -0
- {obsarray-0.2.4 → obsarray-0.2.5}/obsarray/__init__.py +0 -0
- {obsarray-0.2.4 → obsarray-0.2.5}/obsarray/err_corr.py +0 -0
- {obsarray-0.2.4 → obsarray-0.2.5}/obsarray/templater/__init__.py +0 -0
- {obsarray-0.2.4 → obsarray-0.2.5}/obsarray/templater/dataset_util.py +0 -0
- {obsarray-0.2.4 → obsarray-0.2.5}/obsarray/templater/dsdoc.py +0 -0
- {obsarray-0.2.4 → obsarray-0.2.5}/obsarray/templater/dstemplater.py +0 -0
- {obsarray-0.2.4 → obsarray-0.2.5}/obsarray/templater/dswriter.py +0 -0
- {obsarray-0.2.4 → obsarray-0.2.5}/obsarray/templater/template_util.py +0 -0
- {obsarray-0.2.4 → obsarray-0.2.5}/obsarray/templater/template_util_jon.py +0 -0
- {obsarray-0.2.4 → obsarray-0.2.5}/obsarray/templater/tests/__init__.py +0 -0
- {obsarray-0.2.4 → obsarray-0.2.5}/obsarray/templater/tests/test_dataset_util.py +0 -0
- {obsarray-0.2.4 → obsarray-0.2.5}/obsarray/templater/tests/test_dsdoc.py +0 -0
- {obsarray-0.2.4 → obsarray-0.2.5}/obsarray/templater/tests/test_dswriter.py +0 -0
- {obsarray-0.2.4 → obsarray-0.2.5}/obsarray/templater/tests/test_template_util.py +0 -0
- {obsarray-0.2.4 → obsarray-0.2.5}/obsarray/test/__init__.py +0 -0
- {obsarray-0.2.4 → obsarray-0.2.5}/obsarray/test/test_err_corr_forms.py +0 -0
- {obsarray-0.2.4 → obsarray-0.2.5}/obsarray/utils.py +0 -0
- {obsarray-0.2.4 → obsarray-0.2.5}/obsarray.egg-info/SOURCES.txt +0 -0
- {obsarray-0.2.4 → obsarray-0.2.5}/obsarray.egg-info/dependency_links.txt +0 -0
- {obsarray-0.2.4 → obsarray-0.2.5}/obsarray.egg-info/top_level.txt +0 -0
- {obsarray-0.2.4 → obsarray-0.2.5}/quality_documentation/.gitignore +0 -0
- {obsarray-0.2.4 → obsarray-0.2.5}/quality_documentation/QualityDocumentation.tex +0 -0
- {obsarray-0.2.4 → obsarray-0.2.5}/quality_documentation/base/CookiecutterMacros.tex +0 -0
- {obsarray-0.2.4 → obsarray-0.2.5}/quality_documentation/base/acronyms.tex +0 -0
- {obsarray-0.2.4 → obsarray-0.2.5}/quality_documentation/base/history.tex +0 -0
- {obsarray-0.2.4 → obsarray-0.2.5}/quality_documentation/base/metadata.tex +0 -0
- {obsarray-0.2.4 → obsarray-0.2.5}/quality_documentation/base/pythoninputstyle.tex +0 -0
- {obsarray-0.2.4 → obsarray-0.2.5}/quality_documentation/base/sil2.tex +0 -0
- {obsarray-0.2.4 → obsarray-0.2.5}/quality_documentation/base/sil3.tex +0 -0
- {obsarray-0.2.4 → obsarray-0.2.5}/quality_documentation/base/sources.bib +0 -0
- {obsarray-0.2.4 → obsarray-0.2.5}/quality_documentation/base/sources.tex +0 -0
- {obsarray-0.2.4 → obsarray-0.2.5}/quality_documentation/countpdfpages.sh +0 -0
- {obsarray-0.2.4 → obsarray-0.2.5}/quality_documentation/footnotehyper-sphinx.sty +0 -0
- {obsarray-0.2.4 → obsarray-0.2.5}/quality_documentation/obsarray_QF-59.docm +0 -0
- {obsarray-0.2.4 → obsarray-0.2.5}/quality_documentation/obsarray_requirements.docx +0 -0
- {obsarray-0.2.4 → obsarray-0.2.5}/quality_documentation/review_checklists/qf-16a.docx +0 -0
- {obsarray-0.2.4 → obsarray-0.2.5}/quality_documentation/review_checklists/qf-16b.docx +0 -0
- {obsarray-0.2.4 → obsarray-0.2.5}/quality_documentation/review_checklists/qf-16c.docx +0 -0
- {obsarray-0.2.4 → obsarray-0.2.5}/quality_documentation/review_checklists/qf-16d.docx +0 -0
- {obsarray-0.2.4 → obsarray-0.2.5}/quality_documentation/review_checklists/qf-16e.docx +0 -0
- {obsarray-0.2.4 → obsarray-0.2.5}/quality_documentation/review_checklists/qf-16f.docx +0 -0
- {obsarray-0.2.4 → obsarray-0.2.5}/quality_documentation/softwareRequirements.sty +0 -0
- {obsarray-0.2.4 → obsarray-0.2.5}/quality_documentation/sphinx.sty +0 -0
- {obsarray-0.2.4 → obsarray-0.2.5}/quality_documentation/sphinxcyrillic.sty +0 -0
- {obsarray-0.2.4 → obsarray-0.2.5}/quality_documentation/sphinxhighlight.sty +0 -0
- {obsarray-0.2.4 → obsarray-0.2.5}/quality_documentation/sphinxhowto.cls +0 -0
- {obsarray-0.2.4 → obsarray-0.2.5}/quality_documentation/sphinxmanual.cls +0 -0
- {obsarray-0.2.4 → obsarray-0.2.5}/quality_documentation/sphinxmessages.sty +0 -0
- {obsarray-0.2.4 → obsarray-0.2.5}/quality_documentation/sphinxmulticell.sty +0 -0
- {obsarray-0.2.4 → obsarray-0.2.5}/quality_documentation/uml/copy your design png file into this folder.txt +0 -0
- {obsarray-0.2.4 → obsarray-0.2.5}/setup.cfg +0 -0
- {obsarray-0.2.4 → obsarray-0.2.5}/tox.ini +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: obsarray
|
|
3
|
-
Version: 0.2.
|
|
4
|
-
Summary: Measurement
|
|
3
|
+
Version: 0.2.5
|
|
4
|
+
Summary: Measurement data handling in Python
|
|
5
5
|
Home-page: https://github.com/comet-toolkit/obsarray
|
|
6
6
|
Author: CoMet Toolkit Team
|
|
7
7
|
Author-email: team@comet-toolkit.org
|
|
@@ -9,9 +9,10 @@ License: GPLv3
|
|
|
9
9
|
Platform: UNKNOWN
|
|
10
10
|
Classifier: Development Status :: 2 - Pre-Alpha
|
|
11
11
|
Classifier: Programming Language :: Python
|
|
12
|
-
Classifier: Programming Language :: Python :: 3.6
|
|
13
|
-
Classifier: Programming Language :: Python :: 3.7
|
|
14
12
|
Classifier: Programming Language :: Python :: 3.8
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
15
16
|
Provides-Extra: dev
|
|
16
17
|
License-File: LICENSE
|
|
17
18
|
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
#
|
|
3
|
+
# obsarray documentation build configuration file, created by
|
|
4
|
+
# cookiecutter
|
|
5
|
+
#
|
|
6
|
+
# This file is execfile()d with the current directory set to its
|
|
7
|
+
# containing dir.
|
|
8
|
+
#
|
|
9
|
+
# Note that not all possible configuration values are present in this
|
|
10
|
+
# autogenerated file.
|
|
11
|
+
#
|
|
12
|
+
# All configuration values have a default; values that are commented out
|
|
13
|
+
# serve to show the default.
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
# If extensions (or modules to document with autodoc) are in another
|
|
17
|
+
# directory, add these directories to sys.path here. If the directory is
|
|
18
|
+
# relative to the documentation root, use os.path.abspath to make it
|
|
19
|
+
# absolute, like shown here.
|
|
20
|
+
|
|
21
|
+
import sphinx_autosummary_accessors
|
|
22
|
+
import obsarray
|
|
23
|
+
|
|
24
|
+
project_title = "obsarray".replace("_", " ").title()
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
# -- General configuration ---------------------------------------------
|
|
28
|
+
|
|
29
|
+
# If your documentation needs a minimal Sphinx version, state it here.
|
|
30
|
+
#
|
|
31
|
+
# needs_sphinx = '1.0'
|
|
32
|
+
|
|
33
|
+
# Attempt to make links automatially
|
|
34
|
+
default_role = "code"
|
|
35
|
+
|
|
36
|
+
# Add any Sphinx extension module names here, as strings. They can be
|
|
37
|
+
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
|
|
38
|
+
# CFAB added napolean to support google-style docstrings
|
|
39
|
+
extensions = [
|
|
40
|
+
"sphinx.ext.autodoc",
|
|
41
|
+
"sphinx.ext.autosummary",
|
|
42
|
+
"sphinx.ext.intersphinx",
|
|
43
|
+
"sphinx.ext.viewcode",
|
|
44
|
+
"sphinx.ext.napoleon",
|
|
45
|
+
"IPython.sphinxext.ipython_directive",
|
|
46
|
+
"IPython.sphinxext.ipython_console_highlighting",
|
|
47
|
+
"sphinx_design",
|
|
48
|
+
"sphinx_autosummary_accessors",
|
|
49
|
+
]
|
|
50
|
+
|
|
51
|
+
# Add any paths that contain templates here, relative to this directory.
|
|
52
|
+
templates_path = ["_templates", sphinx_autosummary_accessors.templates_path]
|
|
53
|
+
|
|
54
|
+
# The suffix(es) of source filenames.
|
|
55
|
+
# You can specify multiple suffix as a list of string:
|
|
56
|
+
#
|
|
57
|
+
# source_suffix = ['.rst', '.md']
|
|
58
|
+
source_suffix = ".rst"
|
|
59
|
+
|
|
60
|
+
# The master toctree document.
|
|
61
|
+
master_doc = "index"
|
|
62
|
+
|
|
63
|
+
# General information about the project.
|
|
64
|
+
project = project_title
|
|
65
|
+
copyright = "CoMet Toolkit Team"
|
|
66
|
+
author = "CoMet Toolkit Team"
|
|
67
|
+
|
|
68
|
+
# The version info for the project you're documenting, acts as replacement
|
|
69
|
+
# for |version| and |release|, also used in various other places throughout
|
|
70
|
+
# the built documents.
|
|
71
|
+
#
|
|
72
|
+
# The short X.Y version.
|
|
73
|
+
version = obsarray.__version__
|
|
74
|
+
# The full version, including alpha/beta/rc tags.
|
|
75
|
+
release = obsarray.__version__
|
|
76
|
+
|
|
77
|
+
# The language for content autogenerated by Sphinx. Refer to documentation
|
|
78
|
+
# for a list of supported languages.
|
|
79
|
+
#
|
|
80
|
+
# This is also used if you do content translation via gettext catalogs.
|
|
81
|
+
# Usually you set "language" from the command line for these cases.
|
|
82
|
+
language = None
|
|
83
|
+
|
|
84
|
+
# List of patterns, relative to source directory, that match files and
|
|
85
|
+
# directories to ignore when looking for source files.
|
|
86
|
+
# This patterns also effect to html_static_path and html_extra_path
|
|
87
|
+
exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]
|
|
88
|
+
|
|
89
|
+
# The name of the Pygments (syntax highlighting) style to use.
|
|
90
|
+
pygments_style = "sphinx"
|
|
91
|
+
|
|
92
|
+
rst_prolog = """
|
|
93
|
+
.. role:: python(code)
|
|
94
|
+
:language: python
|
|
95
|
+
:class: highlight
|
|
96
|
+
"""
|
|
97
|
+
|
|
98
|
+
# If true, `todo` and `todoList` produce output, else they produce nothing.
|
|
99
|
+
todo_include_todos = False
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
# -- Options for HTML output -------------------------------------------
|
|
103
|
+
|
|
104
|
+
# The theme to use for HTML and HTML Help pages. See the documentation for
|
|
105
|
+
# a list of builtin themes.
|
|
106
|
+
#
|
|
107
|
+
html_theme = "sphinx_book_theme"
|
|
108
|
+
|
|
109
|
+
# Theme options are theme-specific and customize the look and feel of a
|
|
110
|
+
# theme further. For a list of options available for each theme, see the
|
|
111
|
+
# documentation.
|
|
112
|
+
#
|
|
113
|
+
# html_theme_options = {}
|
|
114
|
+
|
|
115
|
+
html_logo = "figs/comet_logo.png"
|
|
116
|
+
|
|
117
|
+
# Add any paths that contain custom static files (such as style sheets) here,
|
|
118
|
+
# relative to this directory. They are copied after the builtin static files,
|
|
119
|
+
# so a file named "default.css" will overwrite the builtin "default.css".
|
|
120
|
+
html_static_path = ["_static"]
|
|
121
|
+
|
|
122
|
+
# -- Options for HTMLHelp output ---------------------------------------
|
|
123
|
+
|
|
124
|
+
# Output file base name for HTML help builder.
|
|
125
|
+
htmlhelp_basename = "obsarraydoc"
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
# -- Options for LaTeX output ------------------------------------------
|
|
129
|
+
|
|
130
|
+
latex_elements = {
|
|
131
|
+
# The paper size ('letterpaper' or 'a4paper').
|
|
132
|
+
#
|
|
133
|
+
# 'papersize': 'letterpaper',
|
|
134
|
+
# The font size ('10pt', '11pt' or '12pt').
|
|
135
|
+
#
|
|
136
|
+
# 'pointsize': '10pt',
|
|
137
|
+
# Additional stuff for the LaTeX preamble.
|
|
138
|
+
#
|
|
139
|
+
# 'preamble': '',
|
|
140
|
+
# Latex figure (float) alignment
|
|
141
|
+
#
|
|
142
|
+
# 'figure_align': 'htbp',
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
# Grouping the document tree into LaTeX files. List of tuples
|
|
146
|
+
# (source start file, target name, title, author, documentclass
|
|
147
|
+
# [howto, manual, or own class]).
|
|
148
|
+
latex_documents = [
|
|
149
|
+
(
|
|
150
|
+
master_doc,
|
|
151
|
+
"user_manual.tex",
|
|
152
|
+
"{} Documentation".format(project_title),
|
|
153
|
+
"CoMet Toolkit Team",
|
|
154
|
+
"manual",
|
|
155
|
+
),
|
|
156
|
+
]
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
# -- Options for manual page output ------------------------------------
|
|
160
|
+
|
|
161
|
+
# One entry per manual page. List of tuples
|
|
162
|
+
# (source start file, name, description, authors, manual section).
|
|
163
|
+
man_pages = [(master_doc, "obsarray", "obsarray Documentation", [author], 1)]
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
# -- Options for Texinfo output ----------------------------------------
|
|
167
|
+
|
|
168
|
+
# Grouping the document tree into Texinfo files. List of tuples
|
|
169
|
+
# (source start file, target name, title, author,
|
|
170
|
+
# dir menu entry, description, category)
|
|
171
|
+
texinfo_documents = [
|
|
172
|
+
(
|
|
173
|
+
master_doc,
|
|
174
|
+
"obsarray",
|
|
175
|
+
"obsarray Documentation",
|
|
176
|
+
author,
|
|
177
|
+
"obsarray",
|
|
178
|
+
"Extension to xarray for handling uncertainty quantified observation data",
|
|
179
|
+
"Miscellaneous",
|
|
180
|
+
),
|
|
181
|
+
]
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
obsarray: Measurement data handling in Python
|
|
2
|
+
=============================================
|
|
3
|
+
|
|
4
|
+
**obsarray** is an extension to `xarray <https://docs.xarray.dev/en/stable/>`_ to support defining, storing and interfacing with measurement data - in particular, measurement uncertainty information using standardised metadata. It is designed to work well with `netCDF <https://www.unidata.ucar.edu/software/netcdf/>`_ files and for the Earth Observation community.
|
|
5
|
+
|
|
6
|
+
**obsarray** is part of the `CoMet Toolkit <https://www.comet-toolkit.org>`_ (community metrology toolkit), and can combined with the `punpy <https://punpy.readthedocs.io/en/latest/>`_ (propagating uncertainties in python) module for very simple propagation of defined data uncertainties through arbitrary python functions.
|
|
7
|
+
|
|
8
|
+
.. grid:: 2
|
|
9
|
+
:gutter: 2
|
|
10
|
+
|
|
11
|
+
.. grid-item-card:: Quickstart Guide
|
|
12
|
+
:link: content/user/quickstart
|
|
13
|
+
:link-type: doc
|
|
14
|
+
|
|
15
|
+
New to *obsarray*? Check out the quickstart guide for an introduction.
|
|
16
|
+
|
|
17
|
+
.. grid-item-card:: User Guide
|
|
18
|
+
:link: content/user/user_guide
|
|
19
|
+
:link-type: doc
|
|
20
|
+
|
|
21
|
+
The user guide provides a documentation and examples how to use **obsarray** to handle measurement data.
|
|
22
|
+
|
|
23
|
+
.. grid-item-card:: API Reference
|
|
24
|
+
:link: content/user/api
|
|
25
|
+
:link-type: doc
|
|
26
|
+
|
|
27
|
+
The API Reference contains a description the **obsarray** API.
|
|
28
|
+
|
|
29
|
+
.. grid-item-card:: Developer Guide
|
|
30
|
+
:link: content/developer/developer_guide
|
|
31
|
+
:link-type: doc
|
|
32
|
+
|
|
33
|
+
Guide for contributing to **obsarray** (under development).
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
Acknowledgements
|
|
37
|
+
----------------
|
|
38
|
+
|
|
39
|
+
obsarray has been developed by `Sam Hunt <https://github.com/shunt16>`_.
|
|
40
|
+
|
|
41
|
+
The development has been funded by:
|
|
42
|
+
|
|
43
|
+
* The UK's Department for Business, Energy and Industrial Strategy's (BEIS) National Measurement System (NMS) programme
|
|
44
|
+
* The IDEAS-QA4EO project funded by the European Space Agency.
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
Project status
|
|
48
|
+
--------------
|
|
49
|
+
|
|
50
|
+
obsarray is under active development. It is beta software.
|
|
51
|
+
|
|
52
|
+
.. toctree::
|
|
53
|
+
:maxdepth: 2
|
|
54
|
+
:hidden:
|
|
55
|
+
:caption: For users
|
|
56
|
+
|
|
57
|
+
Quickstart <content/user/quickstart>
|
|
58
|
+
User Guide <content/user/user_guide>
|
|
59
|
+
API Reference <content/user/api>
|
|
60
|
+
|
|
61
|
+
.. toctree::
|
|
62
|
+
:maxdepth: 2
|
|
63
|
+
:hidden:
|
|
64
|
+
:caption: For developers/contributors
|
|
65
|
+
|
|
66
|
+
Developer Guide <content/developer/developer_guide>
|
|
@@ -8,11 +8,11 @@ import json
|
|
|
8
8
|
|
|
9
9
|
version_json = '''
|
|
10
10
|
{
|
|
11
|
-
"date": "
|
|
11
|
+
"date": "2024-02-14T16:24:15+0000",
|
|
12
12
|
"dirty": false,
|
|
13
13
|
"error": null,
|
|
14
|
-
"full-revisionid": "
|
|
15
|
-
"version": "v0.2.
|
|
14
|
+
"full-revisionid": "a4c0efeceef26dd8201830bc88caab5689f25595",
|
|
15
|
+
"version": "v0.2.5"
|
|
16
16
|
}
|
|
17
17
|
''' # END VERSION_JSON
|
|
18
18
|
|
|
@@ -54,7 +54,7 @@ class Flag:
|
|
|
54
54
|
"""
|
|
55
55
|
|
|
56
56
|
# update slice
|
|
57
|
-
self._sli = self.
|
|
57
|
+
self._sli = self._expand_sli(sli)
|
|
58
58
|
|
|
59
59
|
return self
|
|
60
60
|
|
|
@@ -66,7 +66,7 @@ class Flag:
|
|
|
66
66
|
:param flag_value: flag value as a single value boolean to apply to all data or boolean mask array
|
|
67
67
|
"""
|
|
68
68
|
|
|
69
|
-
self._sli = self.
|
|
69
|
+
self._sli = self._expand_sli(sli)
|
|
70
70
|
|
|
71
71
|
flag_meanings, flag_masks = DatasetUtil.unpack_flag_attrs(
|
|
72
72
|
self._obj[self._flag_var_name].attrs
|
|
@@ -78,11 +78,11 @@ class Flag:
|
|
|
78
78
|
# if boolean to apply to all data
|
|
79
79
|
if isinstance(flag_value, bool):
|
|
80
80
|
if flag_value:
|
|
81
|
-
self._obj[self._flag_var_name][self._sli]
|
|
81
|
+
self._obj[self._flag_var_name].values[self._sli] = (
|
|
82
82
|
self._obj[self._flag_var_name][self._sli].values | flag_mask
|
|
83
83
|
)
|
|
84
84
|
else:
|
|
85
|
-
self._obj[self._flag_var_name][self._sli]
|
|
85
|
+
self._obj[self._flag_var_name].values[self._sli] = (
|
|
86
86
|
self._obj[self._flag_var_name][self._sli].values & ~flag_mask
|
|
87
87
|
)
|
|
88
88
|
|
|
@@ -94,15 +94,15 @@ class Flag:
|
|
|
94
94
|
i_true = np.where(flag_value == True)
|
|
95
95
|
i_false = np.where(flag_value == False)
|
|
96
96
|
|
|
97
|
-
self._obj[self._flag_var_name][self._sli].values[i_true] = (
|
|
97
|
+
self._obj[self._flag_var_name][self._sli].values[i_true] = np.array(
|
|
98
98
|
self._obj[self._flag_var_name][self._sli].values[i_true] | flag_mask
|
|
99
99
|
)
|
|
100
100
|
|
|
101
|
-
self._obj[self._flag_var_name][self._sli].values[i_false] = (
|
|
101
|
+
self._obj[self._flag_var_name][self._sli].values[i_false] = np.array(
|
|
102
102
|
self._obj[self._flag_var_name][self._sli].values[i_false] & ~flag_mask
|
|
103
103
|
)
|
|
104
104
|
|
|
105
|
-
def
|
|
105
|
+
def _expand_sli(self, sli: Optional[tuple] = None) -> tuple:
|
|
106
106
|
"""
|
|
107
107
|
Function to expand the provided sli so that it always has the right number of dimensions
|
|
108
108
|
|
|
@@ -114,9 +114,12 @@ class Flag:
|
|
|
114
114
|
if sli is None:
|
|
115
115
|
out_sli = tuple([slice(None)] * self._obj[self._flag_var_name].ndim)
|
|
116
116
|
|
|
117
|
+
# Otherwise, set each : dimension to slice(None)
|
|
118
|
+
# E.g. if providing [0] for a variable with 3 dimensions, this becomes
|
|
119
|
+
# [0,slice(None),slice(None)]
|
|
117
120
|
else:
|
|
118
121
|
out_sli = list([slice(None)] * self._obj[self._flag_var_name].ndim)
|
|
119
|
-
sli_list = list(sli)
|
|
122
|
+
sli_list = list(sli) if isinstance(sli, tuple) else [sli]
|
|
120
123
|
for i in range(len(sli_list)):
|
|
121
124
|
if not sli_list[i] == ":":
|
|
122
125
|
out_sli[i] = sli_list[i]
|
|
@@ -268,6 +271,8 @@ class FlagVariable:
|
|
|
268
271
|
|
|
269
272
|
return flag_meanings
|
|
270
273
|
|
|
274
|
+
# todo - add return set flags - array of objects, where object is list of set flags
|
|
275
|
+
|
|
271
276
|
|
|
272
277
|
@xr.register_dataset_accessor("flag")
|
|
273
278
|
class FlagAccessor(object):
|
|
@@ -435,325 +440,3 @@ class FlagAccessor(object):
|
|
|
435
440
|
|
|
436
441
|
if __name__ == "__main__":
|
|
437
442
|
pass
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
class DatasetUtil2:
|
|
441
|
-
@staticmethod
|
|
442
|
-
def create_flags_variable(dim_sizes, meanings, dim_names=None, attributes=None):
|
|
443
|
-
"""
|
|
444
|
-
Return default empty 1d xarray flag Variable
|
|
445
|
-
|
|
446
|
-
:type dim_sizes: list
|
|
447
|
-
:param dim_sizes: dimension sizes as ints, i.e. [dim1_size, dim2_size, dim3_size] (e.g. [2,3,5])
|
|
448
|
-
|
|
449
|
-
:type attributes: dict
|
|
450
|
-
:param attributes: (optional) dictionary of variable attributes, e.g. standard_name
|
|
451
|
-
|
|
452
|
-
:type dim_names: list
|
|
453
|
-
:param dim_names: (optional) dimension names as strings, i.e. ["dim1_name", "dim2_name", "dim3_size"]
|
|
454
|
-
|
|
455
|
-
:return: Default empty flag vector variable
|
|
456
|
-
:rtype: xarray.Variable
|
|
457
|
-
"""
|
|
458
|
-
|
|
459
|
-
n_masks = len(meanings)
|
|
460
|
-
|
|
461
|
-
data_type = DatasetUtil.return_flags_dtype(n_masks)
|
|
462
|
-
|
|
463
|
-
variable = DatasetUtil.create_variable(
|
|
464
|
-
dim_sizes,
|
|
465
|
-
data_type,
|
|
466
|
-
dim_names=dim_names,
|
|
467
|
-
attributes=attributes,
|
|
468
|
-
)
|
|
469
|
-
|
|
470
|
-
#initialise flags to zero (instead of fillvalue)
|
|
471
|
-
variable.values=0*variable.values
|
|
472
|
-
|
|
473
|
-
# add flag attributes
|
|
474
|
-
variable.attrs["flag_meanings"] = (
|
|
475
|
-
str(meanings)[1:-1].replace("'", "").replace(",", "")
|
|
476
|
-
)
|
|
477
|
-
variable.attrs["flag_masks"] = str([2 ** i for i in range(0, n_masks)])[1:-1]
|
|
478
|
-
|
|
479
|
-
# todo - make sure flags can't have units
|
|
480
|
-
|
|
481
|
-
return variable
|
|
482
|
-
|
|
483
|
-
@staticmethod
|
|
484
|
-
def return_flags_dtype(n_masks):
|
|
485
|
-
"""
|
|
486
|
-
Return required flags array data type
|
|
487
|
-
|
|
488
|
-
:type n_masks: int
|
|
489
|
-
:param n_masks: number of masks required in flag array
|
|
490
|
-
|
|
491
|
-
:return: data type
|
|
492
|
-
:rtype: dtype
|
|
493
|
-
"""
|
|
494
|
-
|
|
495
|
-
if n_masks <= 8:
|
|
496
|
-
return np.int8
|
|
497
|
-
elif n_masks <= 16:
|
|
498
|
-
return np.int16
|
|
499
|
-
elif n_masks <= 32:
|
|
500
|
-
return np.int32
|
|
501
|
-
else:
|
|
502
|
-
return np.int64
|
|
503
|
-
|
|
504
|
-
@staticmethod
|
|
505
|
-
def add_encoding(
|
|
506
|
-
variable, dtype, scale_factor=1.0, offset=0.0, fill_value=None, chunksizes=None
|
|
507
|
-
):
|
|
508
|
-
"""
|
|
509
|
-
Add encoding to xarray Variable to apply when writing netCDF files
|
|
510
|
-
|
|
511
|
-
:type variable: xarray.Variable
|
|
512
|
-
:param variable: data variable
|
|
513
|
-
|
|
514
|
-
:type dtype: type
|
|
515
|
-
:param dtype: numpy data type
|
|
516
|
-
|
|
517
|
-
:type scale_factor: float
|
|
518
|
-
:param scale_factor: variable scale factor
|
|
519
|
-
|
|
520
|
-
:type offset: float
|
|
521
|
-
:param offset: variable offset value
|
|
522
|
-
|
|
523
|
-
:type fill_value: int/float
|
|
524
|
-
:param fill_value: (optional) fill value
|
|
525
|
-
|
|
526
|
-
:type chunksizes: float
|
|
527
|
-
:param chunksizes: (optional) chucksizes
|
|
528
|
-
"""
|
|
529
|
-
|
|
530
|
-
# todo - make sure flags can't have encoding added
|
|
531
|
-
|
|
532
|
-
encoding_dict = {
|
|
533
|
-
"dtype": dtype,
|
|
534
|
-
"scale_factor": scale_factor,
|
|
535
|
-
"add_offset": offset,
|
|
536
|
-
}
|
|
537
|
-
|
|
538
|
-
if chunksizes is not None:
|
|
539
|
-
encoding_dict.update({"chunksizes": chunksizes})
|
|
540
|
-
|
|
541
|
-
if fill_value is not None:
|
|
542
|
-
encoding_dict.update({"_FillValue": fill_value})
|
|
543
|
-
|
|
544
|
-
variable.encoding = encoding_dict
|
|
545
|
-
|
|
546
|
-
@staticmethod
|
|
547
|
-
def get_default_fill_value(dtype):
|
|
548
|
-
"""
|
|
549
|
-
Returns default fill_value for given data type
|
|
550
|
-
|
|
551
|
-
:type dtype: type
|
|
552
|
-
:param dtype: numpy dtype
|
|
553
|
-
|
|
554
|
-
:return: CF-conforming fill value
|
|
555
|
-
:rtype: fill_value
|
|
556
|
-
"""
|
|
557
|
-
|
|
558
|
-
if dtype == np.int8:
|
|
559
|
-
return np.int8(-129)
|
|
560
|
-
if dtype == np.uint8:
|
|
561
|
-
return np.uint8(-1)
|
|
562
|
-
elif dtype == np.int16:
|
|
563
|
-
return np.int16(-32769)
|
|
564
|
-
elif dtype == np.uint16:
|
|
565
|
-
return np.uint16(-1)
|
|
566
|
-
elif dtype == np.int32:
|
|
567
|
-
return np.int32(-2147483649)
|
|
568
|
-
elif dtype == np.uint32:
|
|
569
|
-
return np.uint32(-1)
|
|
570
|
-
elif dtype == np.int64:
|
|
571
|
-
return np.int64(-9223372036854775808)
|
|
572
|
-
elif dtype == np.float32:
|
|
573
|
-
return np.float32(9.96921e36)
|
|
574
|
-
elif dtype == np.float64:
|
|
575
|
-
return np.float64(9.969209968386869e36)
|
|
576
|
-
|
|
577
|
-
@staticmethod
|
|
578
|
-
def _get_flag_encoding(da):
|
|
579
|
-
"""
|
|
580
|
-
Returns flag encoding for flag type data array
|
|
581
|
-
:type da: xarray.DataArray
|
|
582
|
-
:param da: data array
|
|
583
|
-
:return: flag meanings
|
|
584
|
-
:rtype: list
|
|
585
|
-
:return: flag masks
|
|
586
|
-
:rtype: list
|
|
587
|
-
"""
|
|
588
|
-
|
|
589
|
-
try:
|
|
590
|
-
flag_meanings = da.attrs["flag_meanings"].split()
|
|
591
|
-
flag_masks = [int(fm) for fm in da.attrs["flag_masks"].split(",")]
|
|
592
|
-
except KeyError:
|
|
593
|
-
raise KeyError(da.name + " not a flag variable")
|
|
594
|
-
|
|
595
|
-
return flag_meanings, flag_masks
|
|
596
|
-
|
|
597
|
-
@staticmethod
|
|
598
|
-
def unpack_flags(da):
|
|
599
|
-
"""
|
|
600
|
-
Breaks down flag data array into dataset of boolean masks for each flag
|
|
601
|
-
:type da: xarray.DataArray
|
|
602
|
-
:param da: dataset
|
|
603
|
-
:return: flag masks
|
|
604
|
-
:rtype: xarray.Dataset
|
|
605
|
-
"""
|
|
606
|
-
|
|
607
|
-
flag_meanings, flag_masks = DatasetUtil._get_flag_encoding(da)
|
|
608
|
-
|
|
609
|
-
ds = Dataset()
|
|
610
|
-
for flag_meaning, flag_mask in zip(flag_meanings, flag_masks):
|
|
611
|
-
ds[flag_meaning] = DatasetUtil.create_variable(
|
|
612
|
-
list(da.shape), bool, dim_names=list(da.dims)
|
|
613
|
-
)
|
|
614
|
-
ds[flag_meaning] = (da & flag_mask).astype(bool)
|
|
615
|
-
|
|
616
|
-
return ds
|
|
617
|
-
|
|
618
|
-
@staticmethod
|
|
619
|
-
def get_flags_mask_or(da, flags=None):
|
|
620
|
-
"""
|
|
621
|
-
Returns boolean mask for set of flags, defined as logical or of flags
|
|
622
|
-
|
|
623
|
-
:type da: xarray.DataArray
|
|
624
|
-
:param da: dataset
|
|
625
|
-
|
|
626
|
-
:type flags: list
|
|
627
|
-
:param flags: list of flags (if unset all data flags selected)
|
|
628
|
-
|
|
629
|
-
:return: flag masks
|
|
630
|
-
:rtype: numpy.ndarray
|
|
631
|
-
"""
|
|
632
|
-
|
|
633
|
-
flags_ds = DatasetUtil.unpack_flags(da)
|
|
634
|
-
|
|
635
|
-
flags = flags if flags is not None else flags_ds.variables
|
|
636
|
-
mask_flags = [flags_ds[flag].values for flag in flags]
|
|
637
|
-
|
|
638
|
-
return np.logical_or.reduce(mask_flags)
|
|
639
|
-
|
|
640
|
-
@staticmethod
|
|
641
|
-
def get_flags_mask_and(da, flags=None):
|
|
642
|
-
"""
|
|
643
|
-
Returns boolean mask for set of flags, defined as logical and of flags
|
|
644
|
-
|
|
645
|
-
:type da: xarray.DataArray
|
|
646
|
-
:param da: dataset
|
|
647
|
-
|
|
648
|
-
:type flags: list
|
|
649
|
-
:param flags: list of flags (if unset all data flags selected)
|
|
650
|
-
|
|
651
|
-
:return: flag masks
|
|
652
|
-
:rtype: numpy.ndarray
|
|
653
|
-
"""
|
|
654
|
-
|
|
655
|
-
flags_ds = DatasetUtil.unpack_flags(da)
|
|
656
|
-
|
|
657
|
-
flags = flags if flags is not None else flags_ds.variables
|
|
658
|
-
mask_flags = [flags_ds[flag].values for flag in flags]
|
|
659
|
-
|
|
660
|
-
return np.logical_and.reduce(mask_flags)
|
|
661
|
-
|
|
662
|
-
@staticmethod
|
|
663
|
-
def set_flag(da, flag_name, error_if_set=False):
|
|
664
|
-
"""
|
|
665
|
-
Sets named flag for elements in data array
|
|
666
|
-
:type da: xarray.DataArray
|
|
667
|
-
:param da: dataset
|
|
668
|
-
:type flag_name: str
|
|
669
|
-
:param flag_name: name of flag to set
|
|
670
|
-
:type error_if_set: bool
|
|
671
|
-
:param error_if_set: raises error if chosen flag is already set for any element
|
|
672
|
-
"""
|
|
673
|
-
|
|
674
|
-
set_flags = DatasetUtil.unpack_flags(da)[flag_name]
|
|
675
|
-
|
|
676
|
-
if np.any(set_flags == True) and error_if_set:
|
|
677
|
-
raise ValueError(
|
|
678
|
-
"Flag " + flag_name + " already set for variable " + da.name
|
|
679
|
-
)
|
|
680
|
-
|
|
681
|
-
# Find flag mask
|
|
682
|
-
flag_meanings, flag_masks = DatasetUtil._get_flag_encoding(da)
|
|
683
|
-
flag_bit = flag_meanings.index(flag_name)
|
|
684
|
-
flag_mask = flag_masks[flag_bit]
|
|
685
|
-
|
|
686
|
-
da.values = da.values | flag_mask
|
|
687
|
-
|
|
688
|
-
return da
|
|
689
|
-
|
|
690
|
-
@staticmethod
|
|
691
|
-
def unset_flag(da, flag_name, error_if_unset=False):
|
|
692
|
-
"""
|
|
693
|
-
Unsets named flag for specified index of dataset variable
|
|
694
|
-
:type da: xarray.DataArray
|
|
695
|
-
:param da: data array
|
|
696
|
-
:type flag_name: str
|
|
697
|
-
:param flag_name: name of flag to unset
|
|
698
|
-
:type error_if_unset: bool
|
|
699
|
-
:param error_if_unset: raises error if chosen flag is already set at specified index
|
|
700
|
-
"""
|
|
701
|
-
|
|
702
|
-
set_flags = DatasetUtil.unpack_flags(da)[flag_name]
|
|
703
|
-
|
|
704
|
-
if np.any(set_flags == False) and error_if_unset:
|
|
705
|
-
raise ValueError(
|
|
706
|
-
"Flag " + flag_name + " already set for variable " + da.name
|
|
707
|
-
)
|
|
708
|
-
|
|
709
|
-
# Find flag mask
|
|
710
|
-
flag_meanings, flag_masks = DatasetUtil._get_flag_encoding(da)
|
|
711
|
-
flag_bit = flag_meanings.index(flag_name)
|
|
712
|
-
flag_mask = flag_masks[flag_bit]
|
|
713
|
-
|
|
714
|
-
da.values = da.values & ~flag_mask
|
|
715
|
-
|
|
716
|
-
return da
|
|
717
|
-
|
|
718
|
-
@staticmethod
|
|
719
|
-
def get_set_flags(da):
|
|
720
|
-
"""
|
|
721
|
-
Return list of set flags for single element data array
|
|
722
|
-
:type da: xarray.DataArray
|
|
723
|
-
:param da: single element data array
|
|
724
|
-
:return: set flags
|
|
725
|
-
:rtype: list
|
|
726
|
-
"""
|
|
727
|
-
|
|
728
|
-
if da.shape != ():
|
|
729
|
-
raise ValueError("Must pass single element data array")
|
|
730
|
-
|
|
731
|
-
flag_meanings, flag_masks = DatasetUtil._get_flag_encoding(da)
|
|
732
|
-
|
|
733
|
-
set_flags = []
|
|
734
|
-
for flag_meaning, flag_mask in zip(flag_meanings, flag_masks):
|
|
735
|
-
if da & flag_mask:
|
|
736
|
-
set_flags.append(flag_meaning)
|
|
737
|
-
|
|
738
|
-
return set_flags
|
|
739
|
-
|
|
740
|
-
@staticmethod
|
|
741
|
-
def check_flag_set(da, flag_name):
|
|
742
|
-
"""
|
|
743
|
-
Returns if flag for single element data array
|
|
744
|
-
:type da: xarray.DataArray
|
|
745
|
-
:param da: single element data array
|
|
746
|
-
:type flag_name: str
|
|
747
|
-
:param flag_name: name of flag to set
|
|
748
|
-
:return: set flags
|
|
749
|
-
:rtype: list
|
|
750
|
-
"""
|
|
751
|
-
|
|
752
|
-
if da.shape != ():
|
|
753
|
-
raise ValueError("Must pass single element data array")
|
|
754
|
-
|
|
755
|
-
set_flags = DatasetUtil.get_set_flags(da)
|
|
756
|
-
|
|
757
|
-
if flag_name in set_flags:
|
|
758
|
-
return True
|
|
759
|
-
return False
|