├── pycovjson ├── __init__.py ├── cli │ ├── __init__.py │ ├── viewer.py │ └── convert.py ├── test │ ├── __init__.py │ ├── testdata │ │ └── jsont_template.json │ └── test.py ├── writeNetCDF.py ├── write_netcdf.py ├── convert.py ├── model.py ├── write.py └── read_netcdf.py ├── MANIFEST.in ├── readthedocs.yml ├── docs ├── source │ ├── univ_reading.png │ ├── core │ │ ├── setup.rst │ │ ├── read_netcdf.rst │ │ ├── write.rst │ │ ├── convert.rst │ │ └── model.rst │ ├── cli │ │ └── cli.rst │ ├── introduction.rst │ ├── installation.md │ ├── index.rst │ ├── quickstart.rst │ └── conf.py ├── environment.yml ├── Makefile └── make.bat ├── meta.yml ├── docs.md ├── .travis.yml ├── LICENSE ├── .gitignore ├── setup.py └── README.md /pycovjson/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /pycovjson/cli/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /pycovjson/test/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include LICENSE 2 | include README.md 3 | -------------------------------------------------------------------------------- /readthedocs.yml: -------------------------------------------------------------------------------- 1 | conda: 2 | file: docs/environment.yml 3 | 4 | python: 5 | version: 3.5 6 | setup_py_install: true -------------------------------------------------------------------------------- /docs/source/univ_reading.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Reading-eScience-Centre/pycovjson/HEAD/docs/source/univ_reading.png -------------------------------------------------------------------------------- /docs/environment.yml: -------------------------------------------------------------------------------- 1 | name: pycovjson-docs 2 | 3 | dependencies: 4 | - python=3.5 5 | - numpy=1.11 6 | - pandas=0.18.1 7 | - netCDF4 8 | 9 | -------------------------------------------------------------------------------- /docs/source/core/setup.rst: -------------------------------------------------------------------------------- 1 | .. # encoding: utf-8 2 | 3 | pycovjson setup.py 4 | ******************* 5 | 6 | .. autoclass:: setup 7 | :members: 8 | -------------------------------------------------------------------------------- /docs/source/core/read_netcdf.rst: -------------------------------------------------------------------------------- 1 | .. # encoding: utf-8 2 | 3 | read_netcdf.py 4 | ************** 5 | .. module:: pycovjson.read_netcdf 6 | 7 | .. autoclass:: NetCDFReader 8 | :members: 9 | -------------------------------------------------------------------------------- /docs/source/core/write.rst: -------------------------------------------------------------------------------- 1 | .. # encoding: utf-8 2 | 3 | write.py 4 | ******** 5 | .. module:: pycovjson.write 6 | 7 | .. autoclass:: Writer 8 | :members: 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /docs/source/core/convert.rst: -------------------------------------------------------------------------------- 1 | .. # encoding: utf-8 2 | 3 | convert.py 4 | ********** 5 | 6 | ======= 7 | Convert 8 | ======= 9 | Convert.py is a library API to group the read and write classes together into a single file, 10 | this allows it to be called in a much more simple way 11 | 12 | .. module:: pycovjson.convert 13 | 14 | .. autoclass:: main 15 | :members: 16 | -------------------------------------------------------------------------------- /docs/source/core/model.rst: -------------------------------------------------------------------------------- 1 | .. # encoding: utf-8 2 | 3 | model.py 4 | ******** 5 | .. module:: pycovjson.model 6 | 7 | Coverage 8 | ======== 9 | .. autoclass:: Coverage 10 | :members: to_dict 11 | 12 | Domain 13 | ====== 14 | .. autoclass:: Domain 15 | :members: 16 | 17 | Range 18 | ===== 19 | .. autoclass:: Range 20 | :members: __init__ , to_dict, populate 21 | 22 | TileSet 23 | ======= 24 | .. autoclass:: TileSet 25 | :members: -------------------------------------------------------------------------------- /meta.yml: -------------------------------------------------------------------------------- 1 | package: 2 | name: pycovjson 3 | version: "0.3.4" 4 | 5 | source: 6 | 7 | git_url: https://github.com/Reading-eScience-Centre/pycovjson.git 8 | 9 | requirements: 10 | build: 11 | - python 12 | - setuptools 13 | - hdf5 14 | run: 15 | - python 16 | 17 | test: 18 | imports: 19 | - pycovjson 20 | 21 | about: 22 | home: https://github.com/Reading-eScience-Centre/pycovjson 23 | license: BSD 24 | license_file: LICENSE -------------------------------------------------------------------------------- /docs/source/cli/cli.rst: -------------------------------------------------------------------------------- 1 | Command Line Interface 2 | ********************** 3 | .. module:: pycovjson.cli.convert 4 | 5 | Convert Module 6 | ============== 7 | .. autoclass:: main 8 | 9 | :members: 10 | 11 | Usage 12 | ^^^^^ 13 | :: pycovjson-convert(*path to netcdf file*, *name of output file*, *[list of vars as strings]* [-t] *tiled* [-s] *tile_shape as list* 14 | 15 | 16 | Viewer Module 17 | ============= 18 | .. module:: pycovjson.cli.viewer 19 | 20 | .. autoclass:: main 21 | :members: 22 | 23 | Usage 24 | ^^^^^ 25 | 26 | :: pycovjson-viewer (netcdf file) -------------------------------------------------------------------------------- /docs/source/introduction.rst: -------------------------------------------------------------------------------- 1 | .. # encoding: utf-8 2 | 3 | Introduction to pycovjson 4 | ************************** 5 | 6 | ============ 7 | Introduction 8 | ============ 9 | pycovjson is a python utility library for creating `CoverageJSON `_ files from common scientific data formats (e.g NetCDF). 10 | 11 | ========================== 12 | What does pycovjson offer? 13 | ========================== 14 | The library provides a packaged Python API for the generation of CoverageJSON which is compliant with the `CoverageJSON Format Specification `_. -------------------------------------------------------------------------------- /pycovjson/writeNetCDF.py: -------------------------------------------------------------------------------- 1 | from netCDF4 import Dataset 2 | 3 | from numpy import arange, dtype 4 | 5 | 6 | nx = 4 7 | ny = 4 8 | nz = 4 9 | ncfile = Dataset('test_xy.nc', 'w') 10 | # create the output data. 11 | data_out = arange(nx * ny) 12 | print(data_out) 13 | data_out.shape = (nx, ny) # reshape to 3d array 14 | # create the x and y dimensions. 15 | ncfile.createDimension('x', nx) 16 | ncfile.createDimension('y', ny) 17 | # ncfile.createDimension('z', nz) 18 | data = ncfile.createVariable('data', dtype('float32').char, ('x', 'y')) 19 | 20 | data[:] = data_out 21 | # close the file. 22 | print(ncfile.variables) 23 | print("Wrote file!") 24 | -------------------------------------------------------------------------------- /docs/source/installation.md: -------------------------------------------------------------------------------- 1 | 2 | Installation: 3 | ============= 4 | If you already have netCDF4 and hdf5 installed, the installation process is simple. 5 | Open up a command line and type the following: 6 | ``` 7 | $ pip install pycovjson 8 | ``` 9 | If not, you will need to download [conda](http://anaconda.org) for your operating system, 10 | details of how to do this can be found [here.](http://conda.pydata.org/docs/install/quick.html) 11 | After you have installed conda, type the following in the command line: 12 | ``` 13 | $ conda install netcdf4 14 | $ pip install pycovjson 15 | ``` 16 | Conda will install all of the required binaries for your OS. 17 | -------------------------------------------------------------------------------- /pycovjson/write_netcdf.py: -------------------------------------------------------------------------------- 1 | from netCDF4 import Dataset 2 | 3 | from numpy import arange, dtype 4 | 5 | 6 | nx = 4 7 | ny = 4 8 | nz = 1 9 | ncfile = Dataset('test_xyz.nc', 'w') 10 | # create the output data. 11 | data_out = arange(nx * ny* nz) 12 | print(data_out) 13 | data_out.shape = (nx, ny, nz) # reshape to 3d array 14 | # create the x and y dimensions. 15 | ncfile.createDimension('x', nx) 16 | ncfile.createDimension('y', ny) 17 | ncfile.createDimension('z', nz) 18 | data = ncfile.createVariable('data', dtype('float32').char, ('x', 'y','z')) 19 | 20 | data[:] = data_out 21 | # close the file. 22 | print(ncfile.variables) 23 | print("Wrote file!") 24 | -------------------------------------------------------------------------------- /pycovjson/test/testdata/jsont_template.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Coverage", 3 | "domain": { 4 | "type": "Domain", 5 | "domainType": "Grid", 6 | "axes": { 7 | "x": { 8 | "values": [ 9 | 10 | ] 11 | }, 12 | "y": { 13 | "values": [ 14 | ] 15 | } 16 | }, 17 | "referencing": [{ 18 | "components": [], 19 | "system": { 20 | "type": "", 21 | "id": "" 22 | } 23 | } 24 | ] 25 | 26 | 27 | }, 28 | "parameters": { 29 | 30 | }, 31 | "ranges": { 32 | 33 | 34 | }} 35 | 36 | 37 | -------------------------------------------------------------------------------- /docs/source/index.rst: -------------------------------------------------------------------------------- 1 | .. pycovjson documentation master file, created by 2 | sphinx-quickstart on Mon Aug 29 13:17:47 2016. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Welcome to pycovjson's documentation! 7 | ===================================== 8 | 9 | Contents: 10 | 11 | .. toctree:: 12 | :maxdepth: 4 13 | 14 | introduction 15 | quickstart 16 | installation 17 | cli/cli 18 | core/model 19 | core/convert 20 | core/read_netcdf 21 | core/setup 22 | core/write 23 | 24 | Indices and tables 25 | ================== 26 | 27 | * :ref:`genindex` 28 | * :ref:`modindex` 29 | * :ref:`search` 30 | -------------------------------------------------------------------------------- /pycovjson/convert.py: -------------------------------------------------------------------------------- 1 | from pycovjson.read_netcdf import NetCDFReader as Reader 2 | from pycovjson.write import Writer 3 | from pycovjson.model import TileSet 4 | 5 | def main(input_file, output_file, variable, tiled=False, tile_shape=[], axis=''): 6 | 7 | 8 | if output_file == None: 9 | output_file = 'coverage.json' 10 | 11 | 12 | def tile_by_axis(variable, axis): 13 | """ 14 | 15 | :param variable: 16 | :param axis: 17 | :return: tile_shape 18 | """ 19 | # Get shape of variable 20 | shape = Reader.get_shape(variable) 21 | # Set axis to slice by to 1 22 | TileSet.create_tileset() 23 | # Generate new tile shape 24 | return tile_shape 25 | if tiled: 26 | tile_shape = tile_by_axis(variable, axis) 27 | 28 | Writer(output_file, input_file, [variable], tiled=tiled, tile_shape=tile_shape).write() 29 | 30 | 31 | if __name__ == '__main__': 32 | main() 33 | 34 | 35 | -------------------------------------------------------------------------------- /pycovjson/cli/viewer.py: -------------------------------------------------------------------------------- 1 | """ 2 | Pycovjson - Command line viewer 3 | Author: rileywilliams 4 | Version: 0.1.0 5 | TODO - Add support for other formats and more customisation 6 | """ 7 | import argparse 8 | 9 | 10 | from pycovjson.read_netcdf import NetCDFReader as Reader 11 | 12 | 13 | def main(): 14 | parser = argparse.ArgumentParser(description='View Scientific Data files.') 15 | parser.add_argument('inputfile', action ='store', 16 | help='Name of input file') 17 | 18 | parser.add_argument('-v', '--variables,', dest='variables', 19 | help='Display variables', action='store_true') 20 | 21 | args = parser.parse_args() 22 | inputfile = args.inputfile 23 | variables = args.variables 24 | reader = Reader(inputfile) 25 | ds = reader.get_xarray() 26 | # TODO 27 | # if variables: 28 | # reader.get_vars_with_long_name(inputfile) 29 | 30 | print(ds) 31 | 32 | 33 | if __name__ == '__main__': 34 | main() 35 | -------------------------------------------------------------------------------- /docs.md: -------------------------------------------------------------------------------- 1 | #Initial Documentation - Full Documentation in progress 2 | 3 | Implementations 4 | --------------- 5 | 6 | * **model.py** 7 | * model.py contains all of the classes for each component of the coverage object, as well as helper methods to generate dictionaries and create tilesets. 8 | 9 | * **write.py** 10 | * write.py contains all of the code for constructing and writing to CoverageJSON 11 | 12 | * **readNetCDFOOP.py** 13 | * readNetCDFOOP.py contains all of the code for reading the NetCDF data, as well as code for reformatting data. 14 | 15 | * **convert.py** 16 | * convert.py is the command line interface for pycovjson, used to convert files to CoverageJSON 17 | 18 | * **viewer.py** 19 | * viewer.py is the command line viewer, used to view netCDF files. 20 | 21 | In Progress 22 | ----------- 23 | * API Docs 24 | 25 | Incomplete 26 | ---------- 27 | 28 | * Tiling should be working in the current version of **pycovjson**, 29 | however it has not been tested properly. 30 | * Test classes still need to be implemented 31 | * convert.py could be extended to allow for slicing by dimension instead of specifying a shape manually 32 | * Support for more data formats 33 | 34 | -------------------------------------------------------------------------------- /pycovjson/test/test.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | from pycovjson.model import TileSet, Coverage, Reference 4 | import os 5 | import numpy as np 6 | import pycovjson 7 | from pycovjson.read_netcdf import NetCDFReader 8 | 9 | 10 | def test(): 11 | dir_name = os.path.dirname(__file__) 12 | 13 | json_template = os.path.join(dir_name, '..', 'data', 'jsont_template.json') 14 | 15 | testfile = 'test_xy.nc' 16 | dataset_path = os.path.join(dir_name, 'testdata', testfile) 17 | 18 | dataset = np.arange(60) 19 | dataset.reshape(10, 6) 20 | 21 | urlTemplate = 'localhost:8080/' 22 | 23 | tile_shape = [2, 1] 24 | # tileSet = TileSet(tile_shape, urlTemplate, dataset) 25 | 26 | try: 27 | variable_names = NetCDFReader(testfile).get_var_names() 28 | except OSError: 29 | print('Error: ', OSError) 30 | # for tile in tileSet.get_tiles(tile_shape, 'data'): 31 | # print(tile, '\n') 32 | # variable_names = pycovjson.readNetCDFOOP.get_var_names(netcdf_dataset) 33 | 34 | assert len(variable_names) > 0 35 | 36 | 37 | def read(): 38 | dir_name = os.path.dirname(__file__) 39 | testfile = 'test_xy.nc' 40 | dataset_path = os.path.join(dir_name, 'testdata', testfile) 41 | 42 | # 1. 43 | reader = NetCDFReader(dataset_path) 44 | coverage = reader.read() 45 | 46 | def test_convert(): 47 | import pycovjson.convert 48 | pycovjson.convert('foam_2011-01-01.nc','coverage.covjson', ['SALTY']) 49 | 50 | test() 51 | test_convert() 52 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | python: 3 | - '3.5' 4 | before_install: 5 | - wget http://repo.continuum.io/miniconda/Miniconda-latest-Linux-x86_64.sh -O miniconda.sh 6 | - chmod +x miniconda.sh 7 | - "./miniconda.sh -b" 8 | - export PATH=/home/travis/miniconda2/bin:$PATH 9 | - hash -r 10 | - conda update --yes conda 11 | - conda info -a 12 | - conda create --yes -q -n test-environment python=$TRAVIS_PYTHON_VERSION xarray netCDF4 13 | - source activate test-environment 14 | install: 15 | - python setup.py install 16 | - wget https://www.dropbox.com/s/mmgxijdvhemdzoy/foam_2011-01-01.nc 17 | script: 18 | - pycovjson-convert -i foam_2011-01-01.nc -v SALTY 19 | - test -s coverage.covjson 20 | 21 | 22 | deploy: 23 | provider: pypi 24 | user: rileywilliams 25 | password: 26 | secure: eZeb5zRnUPVY1vezZwAZcmz0lPlGIccgHIM6xotC1VC8TneBl5nrpZaSnNgNULsbh8ZjdK6ucB4nQozJ7jPMeehJsTkZSvMAniAbK6c9vIcQ9nnflfTg3PMtpaIUGGc2HxjiNKQKJG3Cru+NfEbAEnVnJ0uswDD+EwBT5hIpUjsiMYL3j/9zilgd4SNShzaqwCI5lLjfpa4fWwMkTGgt0iMPzCJnC4j1vL6YBhuCmexcb160jWzh2C7GsIu3DXZRm7VIyfCNCk8nO87otiYE5CqQgS8KR5GiZQVKiOt7NFJ+6kQghwtuxIRZ307vCieiQY5iiWpgLvJVOqPFXNo4tVjdU27ymcTOyadmNnRamHRoEOFKWSXb4OGrbHvxUW/QdYE3TS/kscs1TZJQumrfuV1cBL9OhN4zjptXwmlswQkSny/aQ5pykYBB6K9jELJYG+N0XJMnteaFdQh5/URgm+qk6y07eVCxGuQzllDOHoauF7kJ2z2U/rBs/lxXXXKBFUVl7Zf73n8Tyg5Dwr85GF16oq1LEYDiqRVM3rgqE5a8+xWDOGDX2w/OtcNE75JNsn9ig7eVZiF7kphMSxhykjtL/OyP3fXCOWKDTrjEEzKXlgNjD7Ftz/+McuQslRhinMSCgoSVaNoKGvbSkxl3/LwS6Mz/b4vND1tW1SKsvvM= 27 | on: 28 | tags: true 29 | repo: Reading-eScience-Centre/pycovjson 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016 The University of Reading. 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | * Neither the name of pycovjson nor the names of its 15 | contributors may be used to endorse or promote products derived from 16 | this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | env/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | 27 | # PyInstaller 28 | # Usually these files are written by a python script from a template 29 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 30 | *.manifest 31 | *.spec 32 | 33 | # Installer logs 34 | pip-log.txt 35 | pip-delete-this-directory.txt 36 | 37 | # Unit test / coverage reports 38 | htmlcov/ 39 | .tox/ 40 | .coverage 41 | .coverage.* 42 | .cache 43 | nosetests.xml 44 | coverage.xml 45 | *,cover 46 | .hypothesis/ 47 | 48 | # Translations 49 | *.mo 50 | *.pot 51 | 52 | # Django stuff: 53 | *.log 54 | local_settings.py 55 | 56 | # Flask stuff: 57 | instance/ 58 | .webassets-cache 59 | 60 | # Scrapy stuff: 61 | .scrapy 62 | 63 | # Sphinx documentation 64 | docs/_build/ 65 | 66 | # PyBuilder 67 | target/ 68 | 69 | # IPython Notebook 70 | .ipynb_checkpoints 71 | 72 | # pyenv 73 | .python-version 74 | 75 | # celery beat schedule file 76 | celerybeat-schedule 77 | 78 | # dotenv 79 | .env 80 | 81 | # virtualenv 82 | venv/ 83 | ENV/ 84 | 85 | # Spyder project settings 86 | .spyderproject 87 | 88 | # Rope project settings 89 | .ropeproject 90 | /json_output_test.json 91 | 92 | 93 | # NetCDF Files 94 | /pycovjson/util.py 95 | /writeToJSON.py 96 | /.swp 97 | /pycovjson/data/ 98 | /pycovjson/writeJSON.py 99 | /pycovjson/test/testdata/jsont_template.json 100 | 101 | # Eclipse Pydev 102 | .project 103 | .pydevproject 104 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import os.path 2 | from setuptools import find_packages, setup 3 | 4 | # Package data 5 | # ------------ 6 | _author = 'rileywilliams' 7 | _authorEmail = 'resc@reading.ac.uk' 8 | _classifiers = [ 9 | 'Environment :: Console', 10 | 'Intended Audience :: Developers', 11 | 'Intended Audience :: Information Technology', 12 | 'Intended Audience :: Science/Research', 13 | 'Topic :: Scientific/Engineering', 14 | 'Development Status :: 4 - Beta', 15 | 'License :: OSI Approved :: BSD License', 16 | 'Operating System :: OS Independent', 17 | 'Programming Language :: Python :: 3', 18 | 'Topic :: Internet :: WWW/HTTP', 19 | 'Topic :: Software Development :: Libraries :: Python Modules', 20 | ] 21 | _description = 'Create CovJSON files from common scientific data formats' 22 | _downloadURL = 'http://pypi.python.org/pypi/pycovjson/' 23 | _requirements = ["xarray","numpy", "pandas", "pymongo"] 24 | _keywords = ['dataset', 'coverage', 'covjson'] 25 | _license = 'Copyright :: University of Reading' 26 | _long_description = 'A python utility library for creating CovJSON files from common scientific data formats' 27 | _name = 'pycovjson' 28 | _namespaces = [] 29 | _testSuite = 'pycovjson.test' 30 | _url = 'https://github.com/Reading-eScience-Centre/pycovjson' 31 | _version = '0.3.9' 32 | _zipSafe = True 33 | _entry_points = {'console_scripts' : ['pycovjson-convert = pycovjson.cli.convert:main', 'pycovjson-viewer = pycovjson.cli.viewer:main']} 34 | 35 | # Setup Metadata 36 | # -------------- 37 | 38 | 39 | def _read(*rnames): 40 | return open(os.path.join(os.path.dirname(__file__), *rnames)).read() 41 | 42 | _header = '*' * len(_name) + '\n' + _name + '\n' + '*' * len(_name) 43 | 44 | setup( 45 | author=_author, 46 | author_email=_authorEmail, 47 | classifiers=_classifiers, 48 | description=_description, 49 | download_url=_downloadURL, 50 | include_package_data=True, 51 | install_requires=_requirements, 52 | keywords=_keywords, 53 | license=_license, 54 | long_description=_long_description, 55 | name=_name, 56 | namespace_packages=_namespaces, 57 | packages=find_packages(), 58 | test_suite=_testSuite, 59 | url=_url, 60 | version=_version, 61 | zip_safe=_zipSafe, 62 | entry_points=_entry_points, 63 | ) 64 | -------------------------------------------------------------------------------- /docs/source/quickstart.rst: -------------------------------------------------------------------------------- 1 | .. # encoding: utf-8 2 | 3 | Quickstart 4 | ********** 5 | 6 | Purpose 7 | ------- 8 | The following document explains how to quickly get up and running with pycovjson. It explains how to execute the key commands and explains (at a high level) what those commands are doing e.g. what input and output we can expect. More detail on expressive use of the various API's including function level API documentation can be found in subsequent pages of this documentation guide. 9 | 10 | .. _data: 11 | 12 | CoverageJSON Generation 13 | ----------------------- 14 | 15 | pycovjson-viewer 16 | ^^^^^^^^^^^^^^^^ 17 | To quickly view the structure of a NetCDF file, pycovjson-viewer can be used. Usage is simple: :: 18 | 19 | $ pycovjson-viewer (netcdf file) 20 | 21 | Dimensions: (depth: 20, lat: 171, lon: 360) 22 | Coordinates: 23 | * depth (depth) float32 5.0 15.0 25.0 35.0 48.0 67.0 96.0 139.0 204.0 ... 24 | * lat (lat) float32 -81.0 -80.0 -79.0 -78.0 -77.0 -76.0 -75.0 -74.0 ... 25 | * lon (lon) float32 0.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 ... 26 | Data variables: 27 | ICEC (lat, lon) float64 nan nan nan nan nan nan nan nan nan nan nan ... 28 | ICETK (lat, lon) float64 nan nan nan nan nan nan nan nan nan nan nan ... 29 | M (lat, lon) float64 nan nan nan nan nan nan nan nan nan nan nan ... 30 | SALTY (depth, lat, lon) float64 nan nan nan nan nan nan nan nan nan ... 31 | TMP (depth, lat, lon) float64 nan nan nan nan nan nan nan nan nan ... 32 | U (lat, lon) float64 nan nan nan nan nan nan nan nan nan nan nan ... 33 | V (lat, lon) float64 nan nan nan nan nan nan nan nan nan nan nan ... 34 | Attributes: 35 | title: MET OFFICE FOAM GLOBAL 1 DEG DATA 36 | field_date: 2011-01-01 00:00:00 37 | 38 | 39 | pycovjson-convert 40 | ^^^^^^^^^^^^^^^^^ 41 | This is very simple... :: 42 | 43 | # 44 | 45 | # pycovjson-convert -i foam.nc -o coverage.covjson -v [SALTY] 46 | 47 | More on using pycovjson functions later... 48 | 49 | 50 | .. _concl: 51 | 52 | Conclusion 53 | ---------- 54 | That concludes the quick start. Hopefully this has been helpful in providing an overview of the main pycovjson features. If you have any issues with this document then please register them at the `issue tracker `_. Please use `labels `_ to classify your issue. 55 | -------------------------------------------------------------------------------- /pycovjson/cli/convert.py: -------------------------------------------------------------------------------- 1 | """ 2 | Pycovjson - Command line interface 3 | Author: rileywilliams 4 | Version: 0.1.0 5 | """ 6 | import argparse 7 | 8 | from pycovjson.write import Writer 9 | from pycovjson.read_netcdf import NetCDFReader as Reader 10 | 11 | 12 | def main(): 13 | """ 14 | Command line interface for pycovjson - Converts Scientific Data Formats into CovJSON and saves to disk. 15 | 16 | :argument -i: Input file path. 17 | :argument -o: Output file name. 18 | :argument -t: Use Tiling. 19 | :argument -v: Which variable to populate coverage with. 20 | :argument -s: [tile shape]: Tile shape. 21 | :argument -n: Use interactive mode. 22 | :argument -u: MongoDB URL 23 | 24 | 25 | """ 26 | parser = argparse.ArgumentParser( 27 | description='Convert Scientific Data Formats into CovJSON.') 28 | parser.add_argument('-i', '--input', dest='inputfile', 29 | help='Name of input file', required=True) 30 | parser.add_argument('-o', '--output', dest='outputfile', 31 | help='Name and location of output file', default='coverage.covjson') 32 | parser.add_argument('-t', '--tiled', action='store_true', help='Apply tiling') 33 | parser.add_argument('-s', '--shape', nargs='+', 34 | help='Tile shape, list', type=int) 35 | parser.add_argument('-v', dest='variable', 36 | help='Variable to populate coverage with', required=True) 37 | parser.add_argument('-n', '--interactive', action='store_true', help='Enter interactive mode') 38 | parser.add_argument('-u', '--endpoint_url', dest='endpoint_url', nargs=1, 39 | help='MongoDB endpoint for CovJSON persistence') 40 | args = parser.parse_args() 41 | inputfile = args.inputfile 42 | outputfile = args.outputfile 43 | variable = args.variable 44 | tiled = args.tiled 45 | tile_shape = args.shape 46 | interactive = args.interactive 47 | endpoint_url = args.endpoint_url 48 | 49 | if interactive: 50 | axis = input('Which Axis?', Reader.get_axis(variable)) 51 | 52 | if tiled and len(tile_shape) == 0: 53 | reader = Reader(inputfile) 54 | shape_list = reader.get_shape(variable) 55 | dims = reader.get_dimensions(variable) 56 | print(list(zip(dims, shape_list))) 57 | tile_shape = input( 58 | 'Enter the shape tile shape as a list of comma separated integers') 59 | tile_shape = tile_shape.split(',') 60 | tile_shape = list(map(int, tile_shape)) 61 | print(tile_shape) 62 | if outputfile == None: 63 | outputfile = outputfile.default 64 | 65 | Writer(outputfile, inputfile, [variable], 66 | tiled=tiled, tile_shape=tile_shape, endpoint_url=endpoint_url).write() 67 | 68 | if __name__ == '__main__': 69 | main() 70 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # pycovjson 2 | [![Build Status](https://travis-ci.org/Reading-eScience-Centre/pycovjson.svg?branch=master)](https://travis-ci.org/Reading-eScience-Centre/pycovjson) 3 | [![PyPI](https://img.shields.io/pypi/v/pycovjson.svg?maxAge=2592000?style=plastic)](https://pypi.python.org/pypi/pycovjson) 4 | [![Python Badge](https://img.shields.io/badge/python-3-blue.svg)](https://www.python.org/downloads/) 5 | [![Readthedocs Badge](https://readthedocs.org/projects/pycovjson/badge/)](http://pycovjson.readthedocs.io/en/latest/) 6 | [![Anaconda-Server Badge](https://anaconda.org/conda-forge/pycovjson/badges/version.svg)](https://anaconda.org/conda-forge/pycovjson) 7 | [![Anaconda-Server Badge](https://anaconda.org/conda-forge/pycovjson/badges/downloads.svg)](https://anaconda.org/conda-forge/pycovjson) 8 | 9 | Create **[CovJSON](https://covjson.org/)** files from common scientific data formats(e.g NetCDF) 10 | 11 | ## Installation: 12 | 13 | ### From Pypi 14 | If you already have netCDF4 and hdf5 installed, 15 | open up a command line and type the following: 16 | ``` 17 | $ pip install pycovjson 18 | ``` 19 | If not, you will need to download conda for your operating system, 20 | details of how to do this can be found [here.](http://conda.pydata.org/docs/install/quick.html) 21 | After you have installed conda, type the following in the command line: 22 | ``` 23 | $ conda install netcdf4 24 | $ pip install pycovjson 25 | ``` 26 | 27 | ### Using Conda 28 | Installing `pycovjson` from the `conda-forge` channel can be achieved by adding `conda-forge` to your channels with: 29 | 30 | ``` 31 | conda config --add channels conda-forge 32 | ``` 33 | 34 | Once the `conda-forge` channel has been enabled, `pycovjson` can be installed with: 35 | 36 | ``` 37 | conda install pycovjson 38 | ``` 39 | 40 | It is possible to list all of the versions of `pycovjson` available on your platform with: 41 | 42 | ``` 43 | conda search pycovjson --channel conda-forge 44 | ``` 45 | 46 | ## Usage: 47 | Command line interface: 48 | 49 | **[pycovjson-convert](https://github.com/Reading-eScience-Centre/pycovjson/blob/master/pycovjson/cli/convert.py)** accepts 6 parameters, and can be run as followed 50 | ``` 51 | $ pycovjson-convert -i *name of input file(NetCDF)* -o *name of output file* -v *variable* [-t] [-s] *tile shape as list* 52 | ``` 53 | 54 | On running the script, a CoverageJSON file will be generated. 55 | 56 | **[pycovjson-viewer](https://github.com/Reading-eScience-Centre/pycovjson/blob/master/pycovjson/cli/viewer.py)** accepts up to 2 parameters: 57 | ``` 58 | $ pycovjson-viewer [*-v display variable information only*] on running will display information about the input file. 59 | ``` 60 | To be use in conjunction with **pycovjson-convert**. 61 | 62 | ## Examples 63 | 64 | ``` 65 | $ pycovjson-viewer *name of netCDF file* 66 | 67 | $ pycovjson-convert -i melodies_landcover.nc -o coverage.json -v land_cover 68 | ``` 69 | 70 | ## API Usage 71 | 72 | First see [![Readthedocs Badge](https://readthedocs.org/projects/pycovjson/badge/)](http://pycovjson.readthedocs.io/en/latest/) 73 | 74 | ### Convert.py 75 | Once pycovjson is installed, type the following at the top of your code: 76 | ``` 77 | import pycovjson.convert 78 | ``` 79 | Once imported you can then use the convert function within your projects. 80 | 81 | ### Examples 82 | 83 | ``` 84 | pycovjson.convert('polcoms.nc', 'coverage.covjson', [sst]) 85 | ``` 86 | This will generate a file called coverage.covjson in the directory where the script is located. 87 | 88 | ## Supported formats 89 | Currently only NetCDF is supported. In order to support other formats only the reader function would need to be changed, as the pycovjson loads data into python data structures before writing to CovJSON. 90 | 91 | ## Project Roadmap 92 | 93 | The project roadmap can be found [here.](https://github.com/Reading-eScience-Centre/pycovjson/projects/1) 94 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | PAPER = 8 | BUILDDIR = build 9 | 10 | # User-friendly check for sphinx-build 11 | ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) 12 | $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) 13 | endif 14 | 15 | # Internal variables. 16 | PAPEROPT_a4 = -D latex_paper_size=a4 17 | PAPEROPT_letter = -D latex_paper_size=letter 18 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source 19 | # the i18n builder cannot share the environment and doctrees with the others 20 | I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source 21 | 22 | .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest coverage gettext 23 | 24 | help: 25 | @echo "Please use \`make ' where is one of" 26 | @echo " html to make standalone HTML files" 27 | @echo " dirhtml to make HTML files named index.html in directories" 28 | @echo " singlehtml to make a single large HTML file" 29 | @echo " pickle to make pickle files" 30 | @echo " json to make JSON files" 31 | @echo " htmlhelp to make HTML files and a HTML help project" 32 | @echo " qthelp to make HTML files and a qthelp project" 33 | @echo " applehelp to make an Apple Help Book" 34 | @echo " devhelp to make HTML files and a Devhelp project" 35 | @echo " epub to make an epub" 36 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" 37 | @echo " latexpdf to make LaTeX files and run them through pdflatex" 38 | @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" 39 | @echo " text to make text files" 40 | @echo " man to make manual pages" 41 | @echo " texinfo to make Texinfo files" 42 | @echo " info to make Texinfo files and run them through makeinfo" 43 | @echo " gettext to make PO message catalogs" 44 | @echo " changes to make an overview of all changed/added/deprecated items" 45 | @echo " xml to make Docutils-native XML files" 46 | @echo " pseudoxml to make pseudoxml-XML files for display purposes" 47 | @echo " linkcheck to check all external links for integrity" 48 | @echo " doctest to run all doctests embedded in the documentation (if enabled)" 49 | @echo " coverage to run coverage check of the documentation (if enabled)" 50 | 51 | clean: 52 | rm -rf $(BUILDDIR)/* 53 | 54 | html: 55 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html 56 | @echo 57 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." 58 | 59 | dirhtml: 60 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml 61 | @echo 62 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." 63 | 64 | singlehtml: 65 | $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml 66 | @echo 67 | @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." 68 | 69 | pickle: 70 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle 71 | @echo 72 | @echo "Build finished; now you can process the pickle files." 73 | 74 | json: 75 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json 76 | @echo 77 | @echo "Build finished; now you can process the JSON files." 78 | 79 | htmlhelp: 80 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp 81 | @echo 82 | @echo "Build finished; now you can run HTML Help Workshop with the" \ 83 | ".hhp project file in $(BUILDDIR)/htmlhelp." 84 | 85 | qthelp: 86 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp 87 | @echo 88 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \ 89 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:" 90 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/pycovjson.qhcp" 91 | @echo "To view the help file:" 92 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/pycovjson.qhc" 93 | 94 | applehelp: 95 | $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp 96 | @echo 97 | @echo "Build finished. The help book is in $(BUILDDIR)/applehelp." 98 | @echo "N.B. You won't be able to view it unless you put it in" \ 99 | "~/Library/Documentation/Help or install it in your application" \ 100 | "bundle." 101 | 102 | devhelp: 103 | $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp 104 | @echo 105 | @echo "Build finished." 106 | @echo "To view the help file:" 107 | @echo "# mkdir -p $$HOME/.local/share/devhelp/pycovjson" 108 | @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/pycovjson" 109 | @echo "# devhelp" 110 | 111 | epub: 112 | $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub 113 | @echo 114 | @echo "Build finished. The epub file is in $(BUILDDIR)/epub." 115 | 116 | latex: 117 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 118 | @echo 119 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." 120 | @echo "Run \`make' in that directory to run these through (pdf)latex" \ 121 | "(use \`make latexpdf' here to do that automatically)." 122 | 123 | latexpdf: 124 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 125 | @echo "Running LaTeX files through pdflatex..." 126 | $(MAKE) -C $(BUILDDIR)/latex all-pdf 127 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 128 | 129 | latexpdfja: 130 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 131 | @echo "Running LaTeX files through platex and dvipdfmx..." 132 | $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja 133 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 134 | 135 | text: 136 | $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text 137 | @echo 138 | @echo "Build finished. The text files are in $(BUILDDIR)/text." 139 | 140 | man: 141 | $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man 142 | @echo 143 | @echo "Build finished. The manual pages are in $(BUILDDIR)/man." 144 | 145 | texinfo: 146 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 147 | @echo 148 | @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." 149 | @echo "Run \`make' in that directory to run these through makeinfo" \ 150 | "(use \`make info' here to do that automatically)." 151 | 152 | info: 153 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 154 | @echo "Running Texinfo files through makeinfo..." 155 | make -C $(BUILDDIR)/texinfo info 156 | @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." 157 | 158 | gettext: 159 | $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale 160 | @echo 161 | @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." 162 | 163 | changes: 164 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes 165 | @echo 166 | @echo "The overview file is in $(BUILDDIR)/changes." 167 | 168 | linkcheck: 169 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck 170 | @echo 171 | @echo "Link check complete; look for any errors in the above output " \ 172 | "or in $(BUILDDIR)/linkcheck/output.txt." 173 | 174 | doctest: 175 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest 176 | @echo "Testing of doctests in the sources finished, look at the " \ 177 | "results in $(BUILDDIR)/doctest/output.txt." 178 | 179 | coverage: 180 | $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage 181 | @echo "Testing of coverage in the sources finished, look at the " \ 182 | "results in $(BUILDDIR)/coverage/python.txt." 183 | 184 | xml: 185 | $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml 186 | @echo 187 | @echo "Build finished. The XML files are in $(BUILDDIR)/xml." 188 | 189 | pseudoxml: 190 | $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml 191 | @echo 192 | @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." 193 | -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | REM Command file for Sphinx documentation 4 | 5 | if "%SPHINXBUILD%" == "" ( 6 | set SPHINXBUILD=sphinx-build 7 | ) 8 | set BUILDDIR=build 9 | set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% source 10 | set I18NSPHINXOPTS=%SPHINXOPTS% source 11 | if NOT "%PAPER%" == "" ( 12 | set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% 13 | set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% 14 | ) 15 | 16 | if "%1" == "" goto help 17 | 18 | if "%1" == "help" ( 19 | :help 20 | echo.Please use `make ^` where ^ is one of 21 | echo. html to make standalone HTML files 22 | echo. dirhtml to make HTML files named index.html in directories 23 | echo. singlehtml to make a single large HTML file 24 | echo. pickle to make pickle files 25 | echo. json to make JSON files 26 | echo. htmlhelp to make HTML files and a HTML help project 27 | echo. qthelp to make HTML files and a qthelp project 28 | echo. devhelp to make HTML files and a Devhelp project 29 | echo. epub to make an epub 30 | echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter 31 | echo. text to make text files 32 | echo. man to make manual pages 33 | echo. texinfo to make Texinfo files 34 | echo. gettext to make PO message catalogs 35 | echo. changes to make an overview over all changed/added/deprecated items 36 | echo. xml to make Docutils-native XML files 37 | echo. pseudoxml to make pseudoxml-XML files for display purposes 38 | echo. linkcheck to check all external links for integrity 39 | echo. doctest to run all doctests embedded in the documentation if enabled 40 | echo. coverage to run coverage check of the documentation if enabled 41 | goto end 42 | ) 43 | 44 | if "%1" == "clean" ( 45 | for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i 46 | del /q /s %BUILDDIR%\* 47 | goto end 48 | ) 49 | 50 | 51 | REM Check if sphinx-build is available and fallback to Python version if any 52 | %SPHINXBUILD% 2> nul 53 | if errorlevel 9009 goto sphinx_python 54 | goto sphinx_ok 55 | 56 | :sphinx_python 57 | 58 | set SPHINXBUILD=python -m sphinx.__init__ 59 | %SPHINXBUILD% 2> nul 60 | if errorlevel 9009 ( 61 | echo. 62 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 63 | echo.installed, then set the SPHINXBUILD environment variable to point 64 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 65 | echo.may add the Sphinx directory to PATH. 66 | echo. 67 | echo.If you don't have Sphinx installed, grab it from 68 | echo.http://sphinx-doc.org/ 69 | exit /b 1 70 | ) 71 | 72 | :sphinx_ok 73 | 74 | 75 | if "%1" == "html" ( 76 | %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html 77 | if errorlevel 1 exit /b 1 78 | echo. 79 | echo.Build finished. The HTML pages are in %BUILDDIR%/html. 80 | goto end 81 | ) 82 | 83 | if "%1" == "dirhtml" ( 84 | %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml 85 | if errorlevel 1 exit /b 1 86 | echo. 87 | echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. 88 | goto end 89 | ) 90 | 91 | if "%1" == "singlehtml" ( 92 | %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml 93 | if errorlevel 1 exit /b 1 94 | echo. 95 | echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. 96 | goto end 97 | ) 98 | 99 | if "%1" == "pickle" ( 100 | %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle 101 | if errorlevel 1 exit /b 1 102 | echo. 103 | echo.Build finished; now you can process the pickle files. 104 | goto end 105 | ) 106 | 107 | if "%1" == "json" ( 108 | %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json 109 | if errorlevel 1 exit /b 1 110 | echo. 111 | echo.Build finished; now you can process the JSON files. 112 | goto end 113 | ) 114 | 115 | if "%1" == "htmlhelp" ( 116 | %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp 117 | if errorlevel 1 exit /b 1 118 | echo. 119 | echo.Build finished; now you can run HTML Help Workshop with the ^ 120 | .hhp project file in %BUILDDIR%/htmlhelp. 121 | goto end 122 | ) 123 | 124 | if "%1" == "qthelp" ( 125 | %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp 126 | if errorlevel 1 exit /b 1 127 | echo. 128 | echo.Build finished; now you can run "qcollectiongenerator" with the ^ 129 | .qhcp project file in %BUILDDIR%/qthelp, like this: 130 | echo.^> qcollectiongenerator %BUILDDIR%\qthelp\pycovjson.qhcp 131 | echo.To view the help file: 132 | echo.^> assistant -collectionFile %BUILDDIR%\qthelp\pycovjson.ghc 133 | goto end 134 | ) 135 | 136 | if "%1" == "devhelp" ( 137 | %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp 138 | if errorlevel 1 exit /b 1 139 | echo. 140 | echo.Build finished. 141 | goto end 142 | ) 143 | 144 | if "%1" == "epub" ( 145 | %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub 146 | if errorlevel 1 exit /b 1 147 | echo. 148 | echo.Build finished. The epub file is in %BUILDDIR%/epub. 149 | goto end 150 | ) 151 | 152 | if "%1" == "latex" ( 153 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 154 | if errorlevel 1 exit /b 1 155 | echo. 156 | echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. 157 | goto end 158 | ) 159 | 160 | if "%1" == "latexpdf" ( 161 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 162 | cd %BUILDDIR%/latex 163 | make all-pdf 164 | cd %~dp0 165 | echo. 166 | echo.Build finished; the PDF files are in %BUILDDIR%/latex. 167 | goto end 168 | ) 169 | 170 | if "%1" == "latexpdfja" ( 171 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 172 | cd %BUILDDIR%/latex 173 | make all-pdf-ja 174 | cd %~dp0 175 | echo. 176 | echo.Build finished; the PDF files are in %BUILDDIR%/latex. 177 | goto end 178 | ) 179 | 180 | if "%1" == "text" ( 181 | %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text 182 | if errorlevel 1 exit /b 1 183 | echo. 184 | echo.Build finished. The text files are in %BUILDDIR%/text. 185 | goto end 186 | ) 187 | 188 | if "%1" == "man" ( 189 | %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man 190 | if errorlevel 1 exit /b 1 191 | echo. 192 | echo.Build finished. The manual pages are in %BUILDDIR%/man. 193 | goto end 194 | ) 195 | 196 | if "%1" == "texinfo" ( 197 | %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo 198 | if errorlevel 1 exit /b 1 199 | echo. 200 | echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. 201 | goto end 202 | ) 203 | 204 | if "%1" == "gettext" ( 205 | %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale 206 | if errorlevel 1 exit /b 1 207 | echo. 208 | echo.Build finished. The message catalogs are in %BUILDDIR%/locale. 209 | goto end 210 | ) 211 | 212 | if "%1" == "changes" ( 213 | %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes 214 | if errorlevel 1 exit /b 1 215 | echo. 216 | echo.The overview file is in %BUILDDIR%/changes. 217 | goto end 218 | ) 219 | 220 | if "%1" == "linkcheck" ( 221 | %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck 222 | if errorlevel 1 exit /b 1 223 | echo. 224 | echo.Link check complete; look for any errors in the above output ^ 225 | or in %BUILDDIR%/linkcheck/output.txt. 226 | goto end 227 | ) 228 | 229 | if "%1" == "doctest" ( 230 | %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest 231 | if errorlevel 1 exit /b 1 232 | echo. 233 | echo.Testing of doctests in the sources finished, look at the ^ 234 | results in %BUILDDIR%/doctest/output.txt. 235 | goto end 236 | ) 237 | 238 | if "%1" == "coverage" ( 239 | %SPHINXBUILD% -b coverage %ALLSPHINXOPTS% %BUILDDIR%/coverage 240 | if errorlevel 1 exit /b 1 241 | echo. 242 | echo.Testing of coverage in the sources finished, look at the ^ 243 | results in %BUILDDIR%/coverage/python.txt. 244 | goto end 245 | ) 246 | 247 | if "%1" == "xml" ( 248 | %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml 249 | if errorlevel 1 exit /b 1 250 | echo. 251 | echo.Build finished. The XML files are in %BUILDDIR%/xml. 252 | goto end 253 | ) 254 | 255 | if "%1" == "pseudoxml" ( 256 | %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml 257 | if errorlevel 1 exit /b 1 258 | echo. 259 | echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. 260 | goto end 261 | ) 262 | 263 | :end 264 | -------------------------------------------------------------------------------- /pycovjson/model.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import math 3 | from collections import OrderedDict 4 | 5 | 6 | class Coverage(object): 7 | 8 | def __init__(self, domain, ranges, params, reference): 9 | self.domain = domain.to_dict() 10 | self.range = ranges.to_dict() 11 | self.parameter = params.to_dict() 12 | self.reference = reference.to_list() 13 | self.type = 'Coverage' 14 | 15 | def to_dict(self): 16 | cov_dict = OrderedDict() 17 | cov_dict['type'] = self.type 18 | cov_dict['domain'] = self.domain 19 | cov_dict['domain']['referencing'] = self.reference 20 | cov_dict['parameters'] = self.parameter 21 | cov_dict['ranges'] = self.range 22 | 23 | return cov_dict 24 | 25 | 26 | class Domain(object): 27 | 28 | def __init__(self, domain_type, x_values=[], y_values=[], z_values=[], t_values=[]): 29 | self.domain_type = domain_type 30 | 31 | self.x_values = x_values 32 | self.y_values = y_values 33 | self.z_values = z_values 34 | self.t_values = t_values 35 | self.referencing = [] 36 | 37 | def __str__(self): 38 | return 'Domain Type: ' + self.domain_type + '\nAxes:' + str(self.axes) 39 | 40 | def to_dict(self): 41 | domain_dict = OrderedDict() 42 | domain_dict['domainType'] = self.domain_type 43 | domain_dict['axes'] = {} 44 | 45 | domain_dict['axes']['x'] = {'values': self.x_values} 46 | 47 | domain_dict['axes']['y'] = {'values': self.y_values} 48 | 49 | domain_dict['axes']['t'] = {'values': self.t_values} 50 | domain_dict['axes']['z'] = {'values': self.z_values} 51 | if len(self.z_values) == 0: 52 | # domain_dict['axes']['z']= {'values' : self.z_values} 53 | domain_dict['axes'].pop('z', None) 54 | if len(self.t_values) == 0: 55 | # domain_dict['axes']['t']= {'values' : self.t_values} 56 | domain_dict['axes'].pop('t', None) 57 | 58 | domain_dict['referencing'] = [] 59 | return domain_dict 60 | 61 | 62 | class Range(object): 63 | 64 | def __init__(self, range_type, data_type={}, axes=[], shape=[], values=[], variable_name='', tile_sets=[]): 65 | self.range_type = range_type 66 | self.data_type = data_type 67 | self.axis_names = axes 68 | self.shape = shape 69 | self.values = values 70 | self.variable_name = variable_name 71 | self.tile_sets = tile_sets 72 | 73 | def to_dict(self): 74 | range_dict = OrderedDict() 75 | range_dict[self.variable_name] = {} 76 | 77 | range_dict[self.variable_name]['type'] = self.range_type 78 | range_dict[self.variable_name]['dataType'] = self.data_type 79 | range_dict[self.variable_name]['axisNames'] = self.axis_names 80 | range_dict[self.variable_name]['shape'] = self.shape 81 | if self.range_type == 'TiledNdArray': 82 | range_dict[self.variable_name]['tileSets'] = self.tile_sets 83 | 84 | else: 85 | 86 | range_dict[self.variable_name]['values'] = self.values 87 | 88 | return range_dict 89 | 90 | def populate(self, data_type={}, axes=[], shape=[], values=[], variable_name=''): 91 | """ 92 | Function to populate Range object with values 93 | 94 | """ 95 | self.data_type = data_type 96 | self.axis_names = axes 97 | self.shape = shape 98 | self.values = values 99 | self.variable_name = variable_name 100 | 101 | 102 | class Parameter(object): 103 | 104 | def __init__(self, variable_name='', description='', unit='', symbol='', symbol_type='', observed_property='', op_id=None, label_langtag='en'): 105 | self.variable_name = variable_name 106 | self.param_type = 'Parameter' 107 | self.description = description 108 | self.unit = unit 109 | self.label_langtag = label_langtag 110 | self.symbol = symbol 111 | self.symbol_type = symbol_type 112 | self.observed_property = observed_property 113 | self.op_id = op_id 114 | 115 | def to_dict(self): 116 | param_dict = OrderedDict() 117 | param_dict[self.variable_name] = {} 118 | param_dict[self.variable_name]['type'] = self.param_type 119 | param_dict[self.variable_name]['description'] = self.description 120 | param_dict[self.variable_name]['unit'] = {} 121 | param_dict[self.variable_name]['unit'][ 122 | 'label'] = {self.label_langtag: self.unit} 123 | param_dict[self.variable_name]['symbol'] = {} 124 | param_dict[self.variable_name]['symbol']['value'] = self.symbol 125 | param_dict[self.variable_name]['symbol']['type'] = self.symbol_type 126 | param_dict[self.variable_name]['observedProperty'] = {} 127 | param_dict[self.variable_name]['observedProperty']['id'] = self.op_id 128 | param_dict[self.variable_name]['observedProperty'][ 129 | 'label'] = {self.label_langtag: self.observed_property} 130 | return param_dict 131 | 132 | 133 | class Reference(object): 134 | 135 | def __init__(self, obj_list): 136 | self.coordinates = [] 137 | self.obj_list = obj_list 138 | 139 | def get_temporal(self, *args): 140 | return self.TemporalReferenceSystem(*args) 141 | 142 | def get_spatial2d(self, *args): 143 | return self.SpatialReferenceSystem2d(*args) 144 | 145 | def get_spatial3d(self, *args): 146 | return self.SpatialRefrenceSystem3d(*args) 147 | 148 | def to_list(self): 149 | item_list = [] 150 | 151 | for elem in self.obj_list: 152 | item_list.append(elem.to_dict()) 153 | #print('Item list:', item_list) 154 | return item_list 155 | 156 | 157 | class TemporalReferenceSystem(Reference): 158 | 159 | def __init__(self, cal=None): 160 | self.type = 'TemporalRS' 161 | self.coordinates = ['t'] 162 | 163 | if (cal == None): 164 | self.cal = "Gregorian" 165 | else: 166 | self.cal = cal 167 | 168 | def to_dict(self): 169 | ref_dict = OrderedDict() 170 | ref_dict['coordinates'] = self.coordinates 171 | ref_dict['system'] = {} 172 | ref_dict['system']['type'] = self.type 173 | ref_dict['system']['calendar'] = self.cal 174 | return ref_dict 175 | 176 | 177 | class SpatialReferenceSystem2d(Reference): 178 | 179 | def __init__(self): 180 | self.id = "http://www.opengis.net/def/crs/OGC/1.3/CRS84" 181 | self.type = 'GeographicCRS' 182 | Reference.coordinates = ['x', 'y'] 183 | 184 | def set_type(self, new_type): 185 | """ 186 | :type new_type: str 187 | """ 188 | self.type = new_type 189 | 190 | def to_dict(self): 191 | ref_dict = OrderedDict() 192 | ref_dict['coordinates'] = self.coordinates 193 | ref_dict['system'] = {} 194 | ref_dict['system']['type'] = self.type 195 | ref_dict['system']['id'] = self.id 196 | return ref_dict 197 | 198 | 199 | class SpatialReferenceSystem3d(Reference): 200 | 201 | def __init__(self): 202 | self.id = "http://www.opengis.net/def/crs/EPSG/0/4979" 203 | self.type = 'GeographicCRS' 204 | Reference.coordinates = ['x', 'y', 'z'] 205 | 206 | def set_type(self, new_type): 207 | """ 208 | :type new_type: str 209 | """ 210 | self.type = new_type 211 | 212 | def to_dict(self): 213 | ref_dict = OrderedDict() 214 | ref_dict['coordinates'] = self.coordinates 215 | ref_dict['system'] = {} 216 | ref_dict['system']['type'] = self.type 217 | ref_dict['system']['id'] = self.id 218 | return ref_dict 219 | 220 | 221 | class TileSet(object): 222 | 223 | def __init__(self, tile_shape, url_template): 224 | self.tile_shape = tile_shape # List containing shape 225 | self.url_template = url_template 226 | 227 | def create_tileset(self): 228 | tileset = [] 229 | tile_dict = {} 230 | tile_dict['tileShape'] = self.tileShape 231 | tile_dict['urlTemplate'] = self.urlTemplate 232 | tileset.append(tile_dict) 233 | return tileset 234 | 235 | def get_url_template(self, val): 236 | self.val = val 237 | 238 | import re 239 | subject = self.url_template 240 | subject = re.sub(r"({).(})", self.val, subject, 0, re.IGNORECASE) 241 | 242 | def generate_url_template(self, axis_names): 243 | axis_names = axis_names 244 | if len(axis_names) == 1: 245 | url_template = '{' + axis_names[0] + '}.covjson' 246 | elif len(axis_names) == 2: 247 | url_template = '{' + axis_names[0] + \ 248 | '}-{' + axis_names[1] + '}.covjson' 249 | elif len(axis_names) == 3: 250 | url_template = '{' + axis_names[0] + '}-{' + \ 251 | axis_names[1] + '}-{' + axis_names[2] + '}.covjson' 252 | 253 | return url_template 254 | 255 | def get_tiles(self, tile_shape: object, array) -> object: 256 | """ 257 | Function which yields a generator which can be leveraged to return tile arrays from an input array 258 | :param tile_shape: 259 | 260 | :param variable: 261 | :return: 262 | """ 263 | array = array 264 | self.shape = array.shape 265 | # print(self.shape) 266 | 267 | def step(b, dim, tile_indices): 268 | if dim == len(array.shape): 269 | yield (b, tile_indices) 270 | return 271 | 272 | tile_count = math.ceil(self.shape[dim] / tile_shape[dim]) 273 | 274 | for i in range(tile_count): 275 | c = b[tile_shape[dim] * i:tile_shape[dim] * (i + 1)] 276 | c = np.rollaxis(c, 1) 277 | tile_indices[dim] = i 278 | yield from step(c, dim + 1, tile_indices) 279 | 280 | yield from step(array, 0, [0] * len(self.shape)) 281 | 282 | def get_array_shape(self): 283 | print(self.shape) 284 | return self.shape 285 | -------------------------------------------------------------------------------- /docs/source/conf.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # pycovjson documentation build configuration file, created by 4 | # sphinx-quickstart on Mon Aug 29 13:17:47 2016. 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 | import sys 16 | import os 17 | import shlex 18 | import sphinx_rtd_theme 19 | from recommonmark.parser import CommonMarkParser 20 | 21 | source_parsers = { 22 | '.md': CommonMarkParser, 23 | } 24 | autoclass_content = 'both' 25 | 26 | # If extensions (or modules to document with autodoc) are in another directory, 27 | # add these directories to sys.path here. If the directory is relative to the 28 | # documentation root, use os.path.abspath to make it absolute, like shown here. 29 | #sys.path.insert(0, os.path.abspath('.')) 30 | sys.path.insert(0, os.path.abspath('../../')) 31 | 32 | 33 | # -- General configuration ------------------------------------------------ 34 | 35 | # If your documentation needs a minimal Sphinx version, state it here. 36 | #needs_sphinx = '1.0' 37 | 38 | # Add any Sphinx extension module names here, as strings. They can be 39 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 40 | # ones. 41 | extensions = [ 42 | 'sphinx.ext.autodoc', 43 | 'sphinx.ext.doctest', 44 | 'sphinx.ext.coverage', 45 | 'sphinx.ext.mathjax', 46 | 'sphinx.ext.viewcode', 47 | ] 48 | 49 | # Add any paths that contain templates here, relative to this directory. 50 | templates_path = ['_templates'] 51 | 52 | # The suffix(es) of source filenames. 53 | # You can specify multiple suffix as a list of string: 54 | # source_suffix = ['.rst', '.md'] 55 | source_suffix = ['.rst', '.md'] 56 | 57 | # The encoding of source files. 58 | #source_encoding = 'utf-8-sig' 59 | 60 | # The master toctree document. 61 | master_doc = 'index' 62 | 63 | # General information about the project. 64 | project = u'pycovjson' 65 | copyright = u'2016, University of Reading eScience Centre' 66 | author = u'rileywilliams - University of Reading eScience Centre' 67 | 68 | # The version info for the project you're documenting, acts as replacement for 69 | # |version| and |release|, also used in various other places throughout the 70 | # built documents. 71 | # 72 | # The short X.Y version. 73 | version = '0.3.7' 74 | # The full version, including alpha/beta/rc tags. 75 | release = '0.3.7' 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 | # There are two options for replacing |today|: either, you set today to some 85 | # non-false value, then it is used: 86 | #today = '' 87 | # Else, today_fmt is used as the format for a strftime call. 88 | #today_fmt = '%B %d, %Y' 89 | 90 | # List of patterns, relative to source directory, that match files and 91 | # directories to ignore when looking for source files. 92 | exclude_patterns = [] 93 | 94 | # The reST default role (used for this markup: `text`) to use for all 95 | # documents. 96 | #default_role = None 97 | 98 | # If true, '()' will be appended to :func: etc. cross-reference text. 99 | #add_function_parentheses = True 100 | 101 | # If true, the current module name will be prepended to all description 102 | # unit titles (such as .. function::). 103 | #add_module_names = True 104 | 105 | # If true, sectionauthor and moduleauthor directives will be shown in the 106 | # output. They are ignored by default. 107 | #show_authors = False 108 | 109 | # The name of the Pygments (syntax highlighting) style to use. 110 | pygments_style = 'sphinx' 111 | 112 | # A list of ignored prefixes for module index sorting. 113 | #modindex_common_prefix = [] 114 | 115 | # If true, keep warnings as "system message" paragraphs in the built documents. 116 | #keep_warnings = False 117 | 118 | # If true, `todo` and `todoList` produce output, else they produce nothing. 119 | todo_include_todos = False 120 | 121 | 122 | # -- Options for HTML output ---------------------------------------------- 123 | 124 | # The theme to use for HTML and HTML Help pages. See the documentation for 125 | # a list of builtin themes. 126 | html_theme = 'sphinx_rtd_theme' 127 | 128 | # Theme options are theme-specific and customize the look and feel of a theme 129 | # further. For a list of options available for each theme, see the 130 | # documentation. 131 | #html_theme_options = {} 132 | 133 | # Add any paths that contain custom themes here, relative to this directory. 134 | #html_theme_path = [] 135 | 136 | # The name for this set of Sphinx documents. If None, it defaults to 137 | # " v documentation". 138 | #html_title = None 139 | 140 | # A shorter title for the navigation bar. Default is the same as html_title. 141 | #html_short_title = None 142 | 143 | # The name of an image file (relative to this directory) to place at the top 144 | # of the sidebar. 145 | html_logo = os.path.join('.', 'univ_reading.png') 146 | 147 | # The name of an image file (within the static path) to use as favicon of the 148 | # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 149 | # pixels large. 150 | #html_favicon = None 151 | 152 | # Add any paths that contain custom static files (such as style sheets) here, 153 | # relative to this directory. They are copied after the builtin static files, 154 | # so a file named "default.css" will overwrite the builtin "default.css". 155 | html_static_path = ['_static'] 156 | 157 | # Add any extra paths that contain custom files (such as robots.txt or 158 | # .htaccess) here, relative to this directory. These files are copied 159 | # directly to the root of the documentation. 160 | #html_extra_path = [] 161 | 162 | # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, 163 | # using the given strftime format. 164 | #html_last_updated_fmt = '%b %d, %Y' 165 | 166 | # If true, SmartyPants will be used to convert quotes and dashes to 167 | # typographically correct entities. 168 | #html_use_smartypants = True 169 | 170 | # Custom sidebar templates, maps document names to template names. 171 | #html_sidebars = {} 172 | 173 | # Additional templates that should be rendered to pages, maps page names to 174 | # template names. 175 | #html_additional_pages = {} 176 | 177 | # If false, no module index is generated. 178 | #html_domain_indices = True 179 | 180 | # If false, no index is generated. 181 | #html_use_index = True 182 | 183 | # If true, the index is split into individual pages for each letter. 184 | #html_split_index = False 185 | 186 | # If true, links to the reST sources are added to the pages. 187 | #html_show_sourcelink = True 188 | 189 | # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. 190 | #html_show_sphinx = True 191 | 192 | # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. 193 | #html_show_copyright = True 194 | 195 | # If true, an OpenSearch description file will be output, and all pages will 196 | # contain a tag referring to it. The value of this option must be the 197 | # base URL from which the finished HTML is served. 198 | #html_use_opensearch = '' 199 | 200 | # This is the file name suffix for HTML files (e.g. ".xhtml"). 201 | #html_file_suffix = None 202 | 203 | # Language to be used for generating the HTML full-text search index. 204 | # Sphinx supports the following languages: 205 | # 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja' 206 | # 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr' 207 | #html_search_language = 'en' 208 | 209 | # A dictionary with options for the search language support, empty by default. 210 | # Now only 'ja' uses this config value 211 | #html_search_options = {'type': 'default'} 212 | 213 | # The name of a javascript file (relative to the configuration directory) that 214 | # implements a search results scorer. If empty, the default will be used. 215 | #html_search_scorer = 'scorer.js' 216 | 217 | # Output file base name for HTML help builder. 218 | htmlhelp_basename = 'pycovjsondoc' 219 | 220 | # -- Options for LaTeX output --------------------------------------------- 221 | 222 | latex_elements = { 223 | # The paper size ('letterpaper' or 'a4paper'). 224 | #'papersize': 'letterpaper', 225 | 226 | # The font size ('10pt', '11pt' or '12pt'). 227 | #'pointsize': '10pt', 228 | 229 | # Additional stuff for the LaTeX preamble. 230 | #'preamble': '', 231 | 232 | # Latex figure (float) alignment 233 | #'figure_align': 'htbp', 234 | } 235 | 236 | # Grouping the document tree into LaTeX files. List of tuples 237 | # (source start file, target name, title, 238 | # author, documentclass [howto, manual, or own class]). 239 | latex_documents = [ 240 | (master_doc, 'pycovjson.tex', u'pycovjson Documentation', 241 | u'University of Reading eScience Centre', 'manual'), 242 | ] 243 | 244 | # The name of an image file (relative to this directory) to place at the top of 245 | # the title page. 246 | #latex_logo = None 247 | 248 | # For "manual" documents, if this is true, then toplevel headings are parts, 249 | # not chapters. 250 | #latex_use_parts = False 251 | 252 | # If true, show page references after internal links. 253 | #latex_show_pagerefs = False 254 | 255 | # If true, show URL addresses after external links. 256 | #latex_show_urls = False 257 | 258 | # Documents to append as an appendix to all manuals. 259 | #latex_appendices = [] 260 | 261 | # If false, no module index is generated. 262 | #latex_domain_indices = True 263 | 264 | 265 | # -- Options for manual page output --------------------------------------- 266 | 267 | # One entry per manual page. List of tuples 268 | # (source start file, name, description, authors, manual section). 269 | man_pages = [ 270 | (master_doc, 'pycovjson', u'pycovjson Documentation', 271 | [author], 1) 272 | ] 273 | 274 | # If true, show URL addresses after external links. 275 | #man_show_urls = False 276 | 277 | 278 | # -- Options for Texinfo output ------------------------------------------- 279 | 280 | # Grouping the document tree into Texinfo files. List of tuples 281 | # (source start file, target name, title, author, 282 | # dir menu entry, description, category) 283 | texinfo_documents = [ 284 | (master_doc, 'pycovjson', u'pycovjson Documentation', 285 | author, 'pycovjson', 'One line description of project.', 286 | 'Miscellaneous'), 287 | ] 288 | 289 | # Documents to append as an appendix to all manuals. 290 | #texinfo_appendices = [] 291 | 292 | # If false, no module index is generated. 293 | #texinfo_domain_indices = True 294 | 295 | # How to display URL addresses: 'footnote', 'no', or 'inline'. 296 | #texinfo_show_urls = 'footnote' 297 | 298 | # If true, do not generate a @detailmenu in the "Top" node's menu. 299 | #texinfo_no_detailmenu = False 300 | -------------------------------------------------------------------------------- /pycovjson/write.py: -------------------------------------------------------------------------------- 1 | from pycovjson.model import Coverage, Domain, Parameter, Range, Reference, SpatialReferenceSystem2d, SpatialReferenceSystem3d, TemporalReferenceSystem, TileSet 2 | from pycovjson.read_netcdf import NetCDFReader as Reader 3 | import json 4 | from pymongo import MongoClient 5 | from pymongo.son_manipulator import SONManipulator 6 | import time 7 | import uuid 8 | 9 | 10 | class Writer(object): 11 | """Writer class""" 12 | 13 | def __init__(self, output_name: object, dataset_path: object, vars_to_write: object, endpoint_url: object, tiled=False, tile_shape=[]) -> object: 14 | """ 15 | Writer class constructor 16 | 17 | :parameter output_name: Name of output file 18 | :parameter dataset_path: Path to dataset 19 | :parameter vars_to_write: List of variables to write 20 | :parameter tiled: Boolean value (default False) 21 | :parameter tile_shape: List containing shape of tiles 22 | :parameter endpoint_url: MongoDB endpoint for CovJSON persistence 23 | """ 24 | self.output_name = output_name 25 | self.tile_shape = tile_shape 26 | self.vars_to_write = vars_to_write 27 | self.url_template = 'localhost:8080/{t}.covjson' 28 | self.tiled = tiled 29 | if tiled: 30 | self.range_type = 'TiledNdArray' 31 | else: 32 | self.range_type = 'NdArray' 33 | self.dataset_path = dataset_path 34 | self.reader = Reader(dataset_path) 35 | self.axis_dict = self.reader.get_axes() 36 | self.axis_list = list(self.axis_dict.keys()) 37 | self.ref_list = [] 38 | if 't' in self.axis_list and 'z' in self.axis_list: 39 | self.ref_list.append(TemporalReferenceSystem()) 40 | self.ref_list.append(SpatialReferenceSystem3d()) 41 | 42 | if 't' in self.axis_list and 'z' not in self.axis_list: 43 | self.ref_list.append(TemporalReferenceSystem()) 44 | self.ref_list.append(SpatialReferenceSystem2d()) 45 | elif 't' not in self.axis_list and 'z' not in self.axis_list: 46 | self.ref_list.append(SpatialReferenceSystem2d()) 47 | if endpoint_url is not None: 48 | self.endpoint_url = endpoint_url 49 | else: 50 | self.endpoint_url = None 51 | 52 | def write(self): 53 | """ 54 | Writes Coverage object to local disk or MongoDB 55 | """ 56 | 57 | coverage = self._construct_coverage() 58 | if self.endpoint_url is not None: 59 | if self.tiled: 60 | self.save_covjson_tiled(coverage, self.endpoint_url) 61 | else: 62 | self._save_covjson(coverage, self.endpoint_url) 63 | else: 64 | if self.tiled: 65 | self.save_covjson_tiled(coverage, self.output_name) 66 | else: 67 | self._save_covjson(coverage, self.output_name) 68 | 69 | def _construct_coverage(self): 70 | """ 71 | Constructs Coverage object from constituent parts 72 | :return: coverage object 73 | """ 74 | coverage = Coverage(self._construct_domain(), self._construct_range( 75 | ), self._construct_params(), self._construct_refs()).to_dict() 76 | return coverage 77 | 78 | def _construct_domain(self): 79 | """ 80 | Constructs Domain object, populates with values 81 | :return: domain object 82 | """ 83 | 84 | domain_type = 'Grid' 85 | x_values = self.reader.get_x().flatten().tolist() 86 | y_values = self.reader.get_y().flatten().tolist() 87 | t_values = [] 88 | z_values = [] 89 | 90 | if 't' in self.axis_list: 91 | 92 | t_values = self.reader.get_t() 93 | 94 | if 'z' in self.axis_list: 95 | 96 | z_values = self.reader.get_z().flatten().tolist() 97 | 98 | domain = Domain(domain_type, x_values, y_values, z_values, t_values) 99 | 100 | return domain 101 | 102 | def _construct_params(self): 103 | """ 104 | Construct parameter object from constituent parts 105 | :return: Parameter object 106 | """ 107 | for variable in self.vars_to_write: 108 | description = self.reader.get_std_name(variable) 109 | unit = self.reader.get_units(variable) 110 | symbol = self.reader.dataset[variable].units 111 | label = self.reader.dataset[variable].long_name 112 | params = Parameter(description=description, variable_name=variable, 113 | symbol=symbol, unit=unit, observed_property=label) 114 | 115 | return params 116 | 117 | def _construct_refs(self): 118 | """ 119 | Construct reference object 120 | :return: refs 121 | """ 122 | refs = Reference(self.ref_list) 123 | 124 | return refs 125 | 126 | def _construct_range(self): 127 | """ 128 | Construct range object 129 | :return: range 130 | """ 131 | for variable in self.vars_to_write: 132 | print("Constructing Range from variable:", variable) 133 | 134 | axis_names = list(map(str.lower, list(self.reader.get_axis(variable)))) 135 | 136 | if self.tiled: 137 | tile_set_obj = TileSet(self.tile_shape, self.urlTemplate) 138 | variable_type = self.reader.get_type(variable) 139 | variable_shape = self.reader.get_shape(variable) 140 | print('Variable shape:', variable_shape) 141 | 142 | count = 0 143 | for tile in tile_set_obj.get_tiles(self.tile_shape, self.reader.dataset[variable].values): 144 | count += 1 145 | covrange = {'ranges': Range('NdArray', data_type=variable_type, axes=tile[ 146 | 1], shape=variable_shape, values=tile[0].flatten().tolist()).to_dict()} 147 | self.save_covjson_range(covrange, str(count) + '.covjson') 148 | url_template = tile_set_obj.generate_url_template(base_url='localhost:8080', 149 | axis_names=['t']) 150 | tileset = TileSet(variable_shape, url_template).create_tileset(self.tile_shape) 151 | 152 | covrange = Range('TiledNdArray', data_type=variable_type, variable_name=variable, 153 | axes=axis_names, tile_sets=tileset, shape=variable_shape) 154 | return covrange 155 | else: 156 | 157 | shape = self.reader.get_shape(variable) 158 | values = self.reader.get_values(variable).flatten().tolist() 159 | data_type = self.reader.get_type(variable) 160 | axes = self.reader.get_axis(variable) 161 | covrange = Range(range_type='NdArray', data_type=data_type, values=values, shape=shape, 162 | variable_name=variable, axes=axis_names) 163 | 164 | return covrange 165 | 166 | # Adapted from 167 | # https://github.com/the-iea/ecem/blob/master/preprocess/ecem/util.py - 168 | # letmaik 169 | def _save_json(self, obj, path, **kw): 170 | """Save json object to disk""" 171 | with open(path, 'w') as fp: 172 | print("Converting....") 173 | start = time.clock() 174 | jsonstr = json.dumps(obj, fp, cls=CustomEncoder, **kw) 175 | fp.write(jsonstr) 176 | stop = time.clock() 177 | print("Completed in: '%s' seconds." % (stop - start)) 178 | 179 | def _save_covjson(self, obj, resource): 180 | """ 181 | Skip indentation of certain fields to make JSON more compact but still human readable 182 | :param obj: the CovJSON object to write 183 | :param resource: either a local file path or a MongoDB endpoint 184 | 185 | """ 186 | 187 | for axis in obj['domain']['axes'].values(): 188 | self.compact(axis, 'values') 189 | for ref in obj['domain']['referencing']: 190 | self.no_indent(ref, 'coordinates') 191 | for covrange in obj['ranges'].values(): 192 | self.no_indent(covrange, 'axisNames', 'shape') 193 | self.compact(covrange, 'values') 194 | self.save_json(obj, resource, indent=2) 195 | 196 | def save_covjson_tiled(self, obj, resource): 197 | """ 198 | Skip indentation of certain fields to make JSON more compact but still human readable 199 | :param obj: the CovJSON object to write 200 | :param resource: either a local file path or a MongoDB endpoint 201 | """ 202 | 203 | for axis in obj['domain']['axes'].values(): 204 | self.compact(axis, 'values') 205 | for ref in obj['domain']['referencing']: 206 | self.no_indent(ref, 'coordinates') 207 | 208 | self.save_json(obj, resource, indent=2) 209 | 210 | def save_json(self, obj, resource, **kw): 211 | print("Attempting to write CovJSON manifestation to '%s'" % (resource)) 212 | start = time.clock() 213 | if resource[0].startswith('mongo'): 214 | mongo_client = MongoDBClient(obj, resource).write() 215 | else: 216 | with open(resource, 'w') as fp: 217 | jsonstr = json.dumps(obj, cls=CustomEncoder, **kw) 218 | fp.write(jsonstr) 219 | stop = time.clock() 220 | print("Completed in: '%s' seconds." % (stop - start)) 221 | 222 | def save_covjson_range(self, obj, path): 223 | for covrange in obj['ranges'].values(): 224 | self.no_indent(covrange, 'axisNames', 'shape') 225 | self.compact(covrange, 'values') 226 | self.save_json(obj, path, indent=2) 227 | 228 | def compact(self, obj, *names): 229 | for name in names: 230 | obj[name] = Custom(obj[name], separators=(',', ':')) 231 | 232 | def no_indent(self, obj, *names): 233 | for name in names: 234 | obj[name] = Custom(obj[name]) 235 | 236 | 237 | # From http://stackoverflow.com/a/25935321 238 | class Custom(object): 239 | 240 | def __init__(self, value, **custom_args): 241 | self.value = value 242 | self.custom_args = custom_args 243 | 244 | 245 | class CustomEncoder(json.JSONEncoder): 246 | """Custom Json Encoder class - Allows Json to be saved using custom format (no_indent, compact)""" 247 | 248 | def __init__(self, *args, **kwargs): 249 | super(CustomEncoder, self).__init__(*args, **kwargs) 250 | self._replacement_map = {} 251 | 252 | def default(self, o): 253 | if isinstance(o, Custom): 254 | key = uuid.uuid4().hex 255 | self._replacement_map[key] = json.dumps(o.value, **o.custom_args) 256 | return "@@%s@@" % (key,) 257 | else: 258 | return super(CustomEncoder, self).default(o) 259 | 260 | def encode(self, o): 261 | result = super(CustomEncoder, self).encode(o) 262 | for k, v in self._replacement_map.items(): 263 | result = result.replace('"@@%s@@"' % (k,), v) 264 | return result 265 | 266 | 267 | class MongoDBClient(object): 268 | ''' 269 | A client for persisting CovJSON objects into MongoDB 270 | ''' 271 | def __init__(self, covjson_obj, endpoint_url): 272 | self.covjson_obj = covjson_obj 273 | self.endpoint_url = endpoint_url 274 | 275 | def write(self): 276 | """ 277 | Make the MongoDB connection, get/create a DB and/or a Collection 278 | and insert the CovJSON Document into MongoDB 279 | """ 280 | client = MongoClient(self.endpoint_url) 281 | db = client.covjson_db 282 | covjson_collection = db.covjsons 283 | covjson_collection.insert_one(json.loads(json.dumps(self.covjson_obj, cls=CustomEncoder))) 284 | 285 | -------------------------------------------------------------------------------- /pycovjson/read_netcdf.py: -------------------------------------------------------------------------------- 1 | from pycovjson.model import Domain, Range, Parameter, Reference 2 | import xarray as xr 3 | from collections import OrderedDict 4 | import pandas as pd 5 | import numpy as np 6 | import re 7 | 8 | datetime_error = "Failed to decode times encoded in the standard NetCDF datetime format into datetime objects. Attempting less strict opening logic. Reason: " 9 | success_msg = "Successfully opened dataset with less strict logic." 10 | 11 | class NetCDFReader(object): 12 | 13 | def __init__(self, dataset_path): 14 | self.dataset_path = dataset_path 15 | try: 16 | try: 17 | self.dataset = xr.open_dataset(self.dataset_path) 18 | except ValueError as ve: 19 | print(datetime_error, ve) 20 | self.dataset = xr.open_dataset(self.dataset_path, decode_times=False) 21 | print(success_msg) 22 | except OSError: 23 | print('File not found.') 24 | exit() 25 | 26 | def read(self, file_path): 27 | self.file_path = file_path 28 | try: 29 | self.dataset = xr.open_dataset(self.file_path) 30 | except ValueError as ve: 31 | print(datetime_error, ve) 32 | self.dataset = xr.open_dataset(self.file_path, decode_times=False) 33 | print(success_msg) 34 | self.var_names = self.get_var_names(self.dataset) 35 | 36 | def print(self): 37 | print(self.dataset) 38 | return self.dataset 39 | 40 | def get_xarray(self): 41 | try: 42 | self.dataset = xr.open_dataset(self.dataset_path) 43 | except ValueError as ve: 44 | print(datetime_error, ve) 45 | self.dataset = xr.open_dataset(self.dataset_path, decode_times=False) 46 | print(success_msg) 47 | return self.dataset 48 | 49 | def close(self): 50 | self.dataset.close() 51 | 52 | @staticmethod 53 | def _get_domain(self): 54 | domain = Domain('Grid') 55 | return domain 56 | 57 | @staticmethod 58 | def _get_ranges(self): 59 | _range = Range() 60 | return _range 61 | 62 | @staticmethod 63 | def _get_params(self): 64 | params = Parameter() 65 | return params 66 | 67 | @staticmethod 68 | def _get_reference(self): 69 | reference = Reference() 70 | return reference 71 | 72 | @staticmethod 73 | def get_var_names(self, dataset): 74 | try: 75 | variable_names = [var for var in dataset.variables] 76 | return variable_names 77 | except Exception as e: 78 | print("Failed", e) 79 | return None 80 | 81 | def get_long_names(self, dataset): 82 | long_names = [] 83 | for variable in self.get_var_names(dataset): 84 | try: 85 | long_names.append(dataset[variable].long_name) 86 | except: 87 | long_names.append(dataset[variable].name) 88 | return long_names 89 | 90 | def get_vars_with_long_name(self, dataset): 91 | try: 92 | long_names = self.get_long_names(dataset) 93 | vars_long_names = list( 94 | zip(self.get_var_names(dataset), long_names)) 95 | return vars_long_names 96 | except: 97 | pass 98 | 99 | def get_shape(self, variable): 100 | """ 101 | Get shape of specifed variable, as list 102 | :param variable: String specifying variable name 103 | :return: shape_list - List containing shape of specified variable 104 | """ 105 | shape = self.dataset[variable].shape 106 | shape_list = [] 107 | 108 | if len(shape) > 1: 109 | for val in shape: 110 | shape_list.append(val) 111 | else: 112 | shape_list.append(shape[0]) 113 | 114 | return shape_list 115 | 116 | def is_y(self, var): 117 | """ 118 | Detect whether or not specified variable is a y coord 119 | :param var: 120 | :return: Boolean value 121 | """ 122 | y_list = ['lat', 'latitude', 'LATITUDE', 'Latitude', 'y'] 123 | if self.get_units(var) == 'degrees_north' or self.get_name(var) in y_list: 124 | return True 125 | else: 126 | return False 127 | 128 | def is_x(self, var): 129 | """ 130 | Detect whether or not specified variable is an x coord 131 | :param var: 132 | :return: Boolean value 133 | """ 134 | x_list = ['lon', 'longitude', 'LONGITUDE', 'Longitude', 'x'] 135 | 136 | if self.get_units(var) == 'degrees_east': 137 | return True 138 | if self.get_name(var) in x_list: 139 | return True 140 | if self.get_description(var) in x_list: 141 | return True 142 | else: 143 | return False 144 | 145 | def has_time(self): 146 | time_list = ['t', 'TIME', 'time', 's', 'seconds', 'Seconds', ] 147 | for var in self.var_names: 148 | if self.get_units(var) in time_list: 149 | return True 150 | if self.get_name in time_list: 151 | return True 152 | if var in time_list: 153 | return True 154 | else: 155 | return False 156 | 157 | def get_time(self): 158 | time_list = ['t', 'TIME', 'time', 's', 'seconds', 'Seconds'] 159 | time_dict = {} 160 | for var in self.var_names: 161 | if self.get_units(var) in time_list or self.get_name(var) in time_list: 162 | time_dict[var] = True 163 | if len(self.get_shape(var)) == 1: 164 | time_var = var 165 | else: 166 | return False 167 | return time_var 168 | 169 | def get_values(self, variable): 170 | """ 171 | 172 | :param variable: 173 | :return: variable values as ndarray 174 | """ 175 | x = self.dataset[variable].values 176 | y = np.where(np.isnan(x), None, x) 177 | 178 | return y 179 | 180 | def get_type(self, variable): 181 | """ 182 | :param dset: NetCDF dataset object 183 | :param variable: Specified 184 | :return: var_type with digits stripped 185 | """ 186 | try: 187 | var_type = str(self.dataset[variable].dtype) 188 | 189 | return re.sub(r'[0-9]+', '', var_type) 190 | 191 | except Exception as e: 192 | raise e 193 | 194 | def get_dimensions(self, variable): 195 | """ 196 | Return dimension of specified variable. 197 | 198 | :param variable: Input variable 199 | :return: Tuple - Array dimension of specified variable 200 | """ 201 | try: 202 | var_dimension = self.dataset[variable].dims 203 | return var_dimension 204 | except: 205 | print("Error Occurred: No Dimensions detected... Exiting. ") 206 | exit() 207 | 208 | def get_std_name(self, variable): 209 | """ 210 | Return standard name of variable. 211 | 212 | :param variable: input variable 213 | :return: name 214 | """ 215 | try: 216 | std_name = self.dataset[variable].name 217 | return std_name 218 | except: 219 | return None 220 | 221 | def get_description(self, variable): 222 | """ 223 | 224 | :param variable: input variable 225 | :return: long_name 226 | """ 227 | try: 228 | return self.dataset[variable].long_name 229 | except: 230 | return None 231 | 232 | def get_name(self, variable): 233 | """ 234 | 235 | :param variable: input variable 236 | :return: name - string 237 | """ 238 | try: 239 | return self.dataset[variable].name 240 | except: 241 | return None 242 | 243 | def get_units(self, variable): 244 | """ 245 | Return units of specified variable. 246 | :param variable: 247 | :return: units 248 | """ 249 | try: 250 | units = self.dataset[variable].units 251 | return units 252 | except: 253 | return None 254 | 255 | def get_metadata(self, variable): 256 | """ 257 | Returns metadata for a specified variable. 258 | 259 | :param variable: Name of specified 260 | :return: dset[variable] 261 | """ 262 | return self.dataset[variable] 263 | 264 | def get_var_group(self, variable): 265 | """ 266 | Return group which specified variable belongs to. 267 | 268 | :param variable: 269 | :return: group as string 270 | :type string 271 | """ 272 | return self.dataset[variable].group() 273 | 274 | def get_axis(self, variable): 275 | try: 276 | axis = self.dataset[variable].axis 277 | axis = list(map(str.lower, list(axis))) 278 | return axis 279 | except: 280 | print("Variable '%s' has no axis attribute, executing fallback for manual axis value detection." % (variable)) 281 | try: 282 | axes_list = [] 283 | axes_dict = self.get_axes() 284 | for dim in self.dataset[variable].dims: 285 | 286 | index = (list(axes_dict.keys())[ 287 | list(axes_dict.values()).index(dim)]) 288 | 289 | axes_list.append(index) 290 | 291 | print("Manually detected axis as: '%s'" % (axes_list)) 292 | return axes_list 293 | except: 294 | print('Error in axes_dict') 295 | 296 | def get_dims(self, variable): 297 | try: 298 | dims = self.dataset[variable].dims 299 | except: 300 | print("Error Occurred: No Dimensions detected... Exiting. ") 301 | exit() 302 | 303 | def convert_time(self, t_variable): 304 | """ 305 | Formats time objects to CovJSON compliant strings. 306 | 307 | :param t_variable: Time Variable 308 | :return: list of formatted datetime strings 309 | """ 310 | date_list = [] 311 | times = self.dataset[t_variable].values 312 | 313 | for time in times: 314 | try: 315 | time = pd.to_datetime(str(time)) 316 | date_list.append(time.strftime('%Y-%m-%dT%H:%M:%SZ')) 317 | except ValueError as ve: 318 | print("Error parsing and converting '%s' variable object to CovJSON compliant string." % (t_variable), ve) 319 | 320 | return date_list 321 | 322 | def extract_var_data(self, var_names): 323 | """ 324 | Returns dictionary containing the values in each variable specified in the variable list. 325 | 326 | :type var_names: String 327 | :param var_names: 328 | :return variable_dict - Dictionary containing key-val pairs 329 | """ 330 | variable_dict = {} # Declaring dictionary used to store key-val pairs, var_name as key and the array as the value 331 | try: 332 | for var in var_names: 333 | variable_dict[var] = self.dataset[var].values 334 | return variable_dict 335 | except Exception as e: 336 | print("An Error occured:", e) 337 | raise e 338 | 339 | def get_axes(self): 340 | 341 | axes_dict = OrderedDict() 342 | x_list = ['lon', 'longitude', 'LONGITUDE', 'Longitude', 'x', 'X'] 343 | y_list = ['lat', 'latitude', 'LATITUDE', 'Latitude', 'y', 'Y'] 344 | t_list = ['time', 'TIME', 't', 'T'] 345 | z_list = ['depth', 'DEPTH'] 346 | for coord in self.dataset.coords: 347 | try: 348 | if self.dataset[coord].axis == 'T': 349 | axes_dict['t'] = coord 350 | if self.dataset[coord].axis == 'Z': 351 | axes_dict['z'] = coord 352 | except: 353 | pass 354 | 355 | try: 356 | if self.dataset[coord].units == 'degrees_north': 357 | axes_dict['y'] = coord 358 | if self.dataset[coord].units == 'degrees_east': 359 | axes_dict['x'] = coord 360 | except: 361 | pass 362 | 363 | try: 364 | if self.dataset[coord].name.lower() == 'x': 365 | axes_dict['x'] = coord 366 | 367 | if self.dataset[coord].name.lower() == 'y': 368 | axes_dict['y'] = coord 369 | 370 | if self.dataset[coord].name.lower() == 'z': 371 | axes_dict['z'] = coord 372 | except: 373 | pass 374 | 375 | try: 376 | if self.dataset[coord].positive in ['up', 'down']: 377 | axes_dict['z'] = coord 378 | except: 379 | pass 380 | 381 | try: 382 | if coord in t_list or self.dataset[coord].standard_name in t_list or self.dataset[coord].name in t_list: 383 | axes_dict['t'] = coord 384 | if coord in z_list or self.dataset[coord].standard_name in z_list or self.dataset[coord].name in z_list: 385 | axes_dict['z'] = coord 386 | except: 387 | print("Error: DataArray does not include 'standard name' or 'name'.") 388 | 389 | if len(axes_dict) < 2: 390 | print('Error: File does not conform to CF Conventions') 391 | exit() 392 | 393 | return axes_dict 394 | 395 | def get_x(self): 396 | for elem in self.dataset.coords: 397 | 398 | if elem in ['lon', 'longitude', 'LONGITUDE', 'Longitude', 'x', 'X']: 399 | return self.dataset[elem].values 400 | try: 401 | if self.dataset[elem].axis == 'X': 402 | return self.dataset[elem].values 403 | if self.dataset[elem].name in ['lon', 'longitude', 'LONGITUDE', 'Longitude', 'x', 'X']: 404 | return self.dataset[elem].values 405 | if self.dataset[elem].units == 'degrees_east': 406 | return self.dataset[elem].values 407 | except AttributeError: 408 | pass 409 | 410 | def get_y(self): 411 | 412 | y_var = self.get_axes()['y'] 413 | return self.dataset[y_var].values 414 | 415 | def get_t(self): 416 | axis_dict = self.get_axes() 417 | t_var = axis_dict['t'] 418 | return self.convert_time(t_var) 419 | 420 | def get_z(self): 421 | 422 | for elem in self.dataset.coords: 423 | if type(self.dataset[elem]) in ['numpy.datetime64', 'numpy.datetime32', 'datetime.datetime']: 424 | return self.dataset[elem].values 425 | 426 | try: 427 | if self.dataset[elem].axis == 'Z': 428 | return self.dataset[elem].values 429 | 430 | if self.dataset[elem].positive in ['down', 'up']: 431 | return self.dataset[elem].values 432 | 433 | except: 434 | raise AttributeError 435 | 436 | if elem in ['z', 'Z', 'depth', 'DEPTH']: 437 | return self.dataset[elem].values 438 | --------------------------------------------------------------------------------