From 5e418d42436a2dd4420270c59d49970a63e3e6d2 Mon Sep 17 00:00:00 2001 From: Rob Cermak Date: Thu, 20 May 2021 17:48:53 -0400 Subject: [PATCH 01/40] Establish a new branch - Add a few informational links - Update to push exp/bathyV1 --- conda/docs/Documentation.md | 16 - conda/docs/conda/README.md | 122 ---- conda/docs/development/CHANGELOG.md | 271 -------- conda/docs/development/CREDITS.md | 19 - conda/docs/development/Design.md | 53 -- conda/docs/development/ImportantReferences.md | 71 -- conda/docs/development/Jupyter.md | 54 -- conda/docs/development/TODO.md | 167 ----- .../development/python/libraries/leaflet.md | 3 - .../development/python/libraries/panel.md | 30 - .../development/python/libraries/pyroms.md | 49 -- conda/docs/grids/Examples.md | 60 -- conda/docs/grids/Grids.md | 12 - conda/docs/grids/MOM6.md | 10 - conda/docs/grids/MOM6ROMS.md | 69 -- conda/docs/grids/ROMS.md | 3 - conda/docs/manual/Application.md | 12 - conda/docs/manual/GridUtils.md | 352 ---------- conda/docs/manual/Logging.md | 43 -- conda/docs/manual/Reporting.md | 30 - conda/docs/resources/Bathymetry.md | 24 - docs/development/CHANGELOG.md | 9 + docs/development/ImportantReferences.md | 12 +- docs/development/TODO.md | 10 +- examples/mkGridInteractive.ipynb | 647 +++++++++++++++++- 25 files changed, 658 insertions(+), 1490 deletions(-) delete mode 100644 conda/docs/Documentation.md delete mode 100644 conda/docs/conda/README.md delete mode 100644 conda/docs/development/CHANGELOG.md delete mode 100644 conda/docs/development/CREDITS.md delete mode 100644 conda/docs/development/Design.md delete mode 100644 conda/docs/development/ImportantReferences.md delete mode 100644 conda/docs/development/Jupyter.md delete mode 100644 conda/docs/development/TODO.md delete mode 100644 conda/docs/development/python/libraries/leaflet.md delete mode 100644 conda/docs/development/python/libraries/panel.md delete mode 100644 conda/docs/development/python/libraries/pyroms.md delete mode 100644 conda/docs/grids/Examples.md delete mode 100644 conda/docs/grids/Grids.md delete mode 100644 conda/docs/grids/MOM6.md delete mode 100644 conda/docs/grids/MOM6ROMS.md delete mode 100644 conda/docs/grids/ROMS.md delete mode 100644 conda/docs/manual/Application.md delete mode 100644 conda/docs/manual/GridUtils.md delete mode 100644 conda/docs/manual/Logging.md delete mode 100644 conda/docs/manual/Reporting.md delete mode 100644 conda/docs/resources/Bathymetry.md diff --git a/conda/docs/Documentation.md b/conda/docs/Documentation.md deleted file mode 100644 index e6b01fe..0000000 --- a/conda/docs/Documentation.md +++ /dev/null @@ -1,16 +0,0 @@ -# Documentation - -We have not settled on a documentation parsing system as of yet. MOM6 -uses a combination of doxygen and sphinx. This will be the toolset -that will also be adopted to this project. For now, there are some -planning notes. - -# Documentation/Sphinx/Python - -https://thomas-cokelaer.info/tutorials/sphinx/docstring_python.html -https://devguide.python.org/documenting/ - -of course there are differences of opinion! - -https://docs.python-guide.org/writing/documentation/ - diff --git a/conda/docs/conda/README.md b/conda/docs/conda/README.md deleted file mode 100644 index caeeca9..0000000 --- a/conda/docs/conda/README.md +++ /dev/null @@ -1,122 +0,0 @@ -# conda - -This explains some things about how to utilize conda to -manage python environments. To learn much more details about -conda, we suggest visiting the -[conda documentation](https://docs.conda.io/projects/conda/en/latest/index.html) website. - -A YAML specification file is to configurate a python environment. We have prepared -a few specification files, please see the conda directory. - -These instructions assume you have conda/miniconda installed. If conda is not installed, -please consult this -[webpage](https://docs.conda.io/projects/conda/en/latest/user-guide/install/index.html). - -There is a generic YAML file that pulls together a development environment. To -expidite the conda environment solver, a YAML\_export file is also provided for -quicker recovery of a generic environment. - -Initialization: -``` -$ conda env create -f conda/xesmfTools.yml -$ conda env export > conda/xesmfTools_export.yml -``` - -For a quicker recovery of a conda environment, use the exported YAML file: -``` -$ conda env remove --name xesmfTools -$ conda env create conda/xesmfTools_export.yaml -``` - -NOTE: Initialization of holoviz from the generic YAML file took over an hour. -It only took a couple of minutes from the resolved export YAML file. - -AND: Sometimes it is faster to slowly bootstrap an environment and then -capture the result. - -Example: -``` -$ conda env create -f gridtools/conda/gridTools.yml -$ conda activate gridTools -(gridTools) $ conda install -c conda-forge geopandas matplotlib ipympl cartopy netcdf4 conda -(gridTools) $ conda env export -n gridTools > gridtools/conda/gridTools_export.yml -``` - -You can capture the time it takes to run the creation of an enviroment as well -as set a timeout so you can tune the YAML file. In this example, the timeout -is set to 5 minutes to allow resolution of the environment. -``` -$ time timeout 5m conda env create -f gridtools/conda/gridTools.yml -``` - -## xesmfTools - -This is the main enviroment for utilizing the grid generation libraries. - -Some of the main libraries within this environment: - * cartopy - * esmf - * esmpy - * xarray - * xesmf - -NOTE: Avoid version 0.5.2 of xesmf. If you need to use the xgcm library, - install it as a separate environment. - -# Environments - -Current operational environment for the grid toolset: ***xesmfTools*** - -## Initialization - -Initialization times: - * bokeh: 9m 17s - * gridTools: 11m 47s(!) - * legacyTools: 4m 53s(!) - * pangeo: 10m 41s - * pyroms: 1m 43s - * xesmfTools: 5m 5s(!) - -(!) Requires post installation steps, see below. - -This list of environments may change over time. Other environments -are used for experimentation and development purposes in another -development [repository](https://github.com/jr3cermak/gridtools). - -## xesmfTools - -Please read the YAML configuration file, -[xesmfTools.yml](../../conda/xesmfTools.yml), -for additional steps to create a complete environment. - -If you use the export file, you only need to install datashader. If you use -the xesmfTools.yml, you will need to install additional libraries in conda -and install datashader. - -Attempting to load all the libraries together initially takes conda a very -long time to resolve package conflicts or it fails completely. Partitioning -the install process speeds up the process and is more successful. - -## gridTools - -After installing the initial environment, two jupyter lab extensions may need -to be installed before you can use interactive bokeh elements. You can check -to see if extensions are installed first and install extensions as needed. - -``` -$ conda env create -f gridtools/conda/gridTools.yml -$ conda activate gridTools -(gridTools) $ jupyter labextension list -(gridTools) $ jupyter labextension install @jupyter-widgets/jupyterlab-manager -(gridTools) $ jupyter labextension install @bokeh/jupyter_bokeh -``` - -## legacyTools - -NOTE: This is a very limited environment with netcdf4 and matplotlib's basemap -to review former functionality of older libraries and software. - -This environment supported investigation into the following libraries: - * [leaflet](../development/python/libraries/leaflet.md) - * [pyroms](../development/python/libraries/pyroms.md) - diff --git a/conda/docs/development/CHANGELOG.md b/conda/docs/development/CHANGELOG.md deleted file mode 100644 index 3376f0e..0000000 --- a/conda/docs/development/CHANGELOG.md +++ /dev/null @@ -1,271 +0,0 @@ -# Change Log - -# 2021-05-06 - - - BUG(app): Stereographic grid generation does not work when dx/dy is not - evenly divisible by grid resolution. TODO - - IBCAO grid exhausts memory on mybinder.org - - Try to implement dask features in Example4a (incomplete) - - Updated grid center text in application - - Rename an example script to conform to mkGrids - - Remove mkMapInteractive.ipynb - - Fix metadata for IBCAO grid in Example 5 and 5a - - Add jupyter-resource-usage to conda:xesmfTools - - BUG(app): Add missing self on plotTitle FIXED - - Add information to examples/README.md - - BUG(app): x/y color and line controls are swapped FIXED - - app: adjusted grid resolution to take larger numbers. - - app: erase debug cell at the bottom of mkGridInteractive.ipynb - - publish to ESMG:dev branch and test mybinder.org - -# 2021-05-05 - - - This day in history. SpaceX launches and lands starship prototype number 15. - - Add wish list task for delta method import of boundary conditions and forcing fields. - - Add/update documentation for the application. - -# 2021-05-04 - - - Merge PR#1 into robTest - - Provide user with more descriptive plotting failure whether it is due to a non-existent grid or really a plotting error. - - Add errorNoGridFigure(). - - Move coordinates of existing message on plot. - - Add self.gridMode flag to GridUtils() - - Upon use of saveGrid() adjust x in grids from 0,360 to -180,+180 - - - Still some rough edges to clean up. - - One more pass at the application and application documentation - - Application changes: - - Adjust projection parameters depending on selected projection in make_plot and make_grid - - allow projection center to be separate from grid center - - define more controls for plot and grid to match recent API changes to GridUtils - - Ellipsoid for grids and plotting set to WGS84 - - Add a grid "Center" tab - - Expand ranges of dx, dy, gridResolutionX and gridResolutionY to also support meters - -# 2021-05-03 - - - WARNING: This commit leaves the Application broken (temporarily). - - API CHANGES - - Created grid generation function for spherical units given in meters and degrees. - - Add warning when grid generation fails. - - Add informational message when grid metrics are not computed. - - Check for lat_0 of +90 or -90 for spherical projection plots. - - Example mkGridsExample4.ipynb complete - - Checked operation of mkGridsExample1.py - - Checked operation of mkGridsExample5.py and mkGridsExample5a.py - - Issue a warning for grids that might not be conformal. - - Update app:make_plot for various projection inputs - - Remove an unneeded string expansion for Mercator. - -# 2021-05-02 - - - API CHANGES - - Performing parameter checks upfront and converting some to float for use later. - - Update mercator with Niki's routine to allow users to specify tilt. - - Define _default_availableGridTypes - - Add ensureEvenI flag for MOM6 grids - - Whitespace cleanup - - Begin to leverage args and kwargs in python functions. This will allow us to - use developed math functions for use with other grid types that might require - different options. - - Adding code guards for MOM6 specific operations. - -# 2021-05-01 - - - Move generic API demonstrations into mkGridsExample2.py so it - does not detract from specific grid generation demonstrations - in mkGridsIterative.ipynb. - - API CHANGES (incomplete) - - Enforce grid center parameters: centerX, centerY, centerUnits. - - mkGridsInterative.ipynb (incomplete) - - Add Niki's example of a Stereographic grid - - Add Niki's example of a rotated Mercator grid - - Added more of Niki's functions for Mercator grid generation - - NOTE: Grid generation techniques sometimes require projection - information and sometimes grid generation techniques change - projection information. All details should be specifically - documented. - -# 2021-04-30 - - - API CHANGES - - gridResolution is now units based instead of scale based as Niki defined it in his notebook example. - - gridutils - - Enforce degrees as units for Mercator and Lambert Conformal Conic. - - TODO: Niki performs some clipping of points along the j direction. This should be an expanded feature - to warn the user about grids with odd number of points in the i and j direction and offer an expansion - or clipping method. For supercomputing, it is easier to decompose a grid with even amounts of - points. - - Plotting: follow proj convention, when lat_ts is missing, attempt to use lat_0. - - Plottind defaults: follow proj defaults. - - drop "+units" from Mercator proj string - - add lat_ts to Stereographic proj string if available - - fix proj string bug for Lambert Conformal Conic - - Allow users to set the verbose Level by name instead of by number - - makeGrid() refactoring: use a flag to track when a new grid is created and then compute - grid metrics after attempting to establish a proj string. Creating a proj string too - early did not work for the delayed information from the Lambert Conformal Conic grid. Now - we compute the proj string at the latest possible moment. This would break the Spherical - grid generator for units in meters. This routine will have to construct the proj string early. - - Build out of Spherical grid generator begins (not complete) - -# 2021-04-29 - - - Unify user manual. The user manual will hold the bulk of the operational details. Application details - will be a small subset enough to explain the operational details of the graphical user interface. - - Merge NorthPolarStero and SouthPolarStereo to Sterographic in which grid generation will - need to pay attention to lat_0 defined for the projection. - - Update application to merge North and South polar stereographic to Stereographic. - - TODO: grab github revision used by each specific mybinder.org instance - - User can specify ellipsoid (ellps) and earth radius (R) through projection options to grid and plot. - - Do not forecast milestones past the next logical one; put other major milestones into a generic X milestone. - - We assume the user is familiar with the python programming language. We will point the user to helpful - materials when appropriate. - - API CHANGES - - Implementation requires vetting application and examples for proper operation - - Change user specification of grid center to "centerX" and "centerY" and specify those units in "centerUnits". - - BUG: Updating grid or plot parameter nested arguments will get clobbered. Queued to be fixed later. - -# 2021-04-28 - - - Raphael pointed us code he wrote that allows conversion from XY to LATLON over a 2D field. It was - exactly what we needed to get the IBCAO grid working in the polar projection. - - Unify MOM6/proj defaults for grid generation - - Default radius is 6.378137e6 - - Default ellipse is GRS80 - - Add warnings to various areas where we create the projection string - - Add warnings to determiniation of the radius of the earth to use - - Add three examples on how to create the IBCAO grid. One example shows how - things change when a slightly different radius is specified for WGS84. - - Move some milestones around with polar grids now possibly working - - Keep milestones under 1.0 for now - - Add datetime and pyproj to gridutils imports - - Return a version number for gridutils library - - Better metadata for xarray/netCDF structures - - Determine earth radius based on projection string on the fly - - Move construction of proj string into a function so it will work for grid and - plot projections as needed - - TODO: improve documentation for grid and plot parameters and finish implementation work - for all projections. For now, keep the grid construction simplified. - - Added a plotting demo for illustrating unstructured grid interpolation and differences - between using grid edges and grid center points for plotting. - -# 2021-04-26 - - - Avoid use of xesmf 0.5.2 - - split xesmfTools environment and move xgcm into its own environment - - Add xgcmTools environment - - Remapping an ice field using xesmf regridder - - Begin rework field flood algorythm that pyroms utilizes - - Added more bookmarks and sorted them - - Added xesmf to pangeo environment - - app.py; gridtools.py updates - - Add appropriate spacing between items - - If tilt is zero, remove it from any message or title - - Split refine into two arguments - - Update message if regular lat lon grid is being built on the equator or not - - Move plotBathyArctic6.py into pyroms directory - -# 2021-04-22 - - - The supergrid plotting would fail if grid type was two(2) and resolution was 0.5. When - multiplied together, it results in 1.0 which confused the current system. - - Add simple mercator grid generation method - - Add a couple of bathy examples to debug a masking issue. We can use xarray to display a - GEBCO 2020 figure and a ROMS figure with bathymetry. - - Add xmap examples that almost work - - Fix some spacing in some gridutils functions - - Update metadata for NEP7 grid in README - - Disable mercator tilt - - Separate refine inputs to grid functions that use gridResolution and gridMode - - Update some messaging - -# 2021-04-10 - - - Shore up messaging and debugging code in GridUtils(). A lot of missing level= in 2nd arguments - calls to printMsg and debugMsg. - - Add a TODO to refactor messaging and debugging into its own package/module. - - Add an example on how to work with logging levels and debug levels. - - Add showPlotParameters function. - - Add more explanation to example1. - - Testing NSIDC's grid generation software: mapx - - https://github.com/nsidc/mapx - - Learn how to read binary and reshape a numpy array after reading a mapx binary grid file - - FIX: GridUtils: Reformat lon > 180 - - lcc_grid.gpd almost replicates Niki's example grid; degress vs meters - - Create a 3rd example that generates a 1x1 grid for testing - -# 2021-04-09 - - - Fix warning in GridUtils.plotGrid() - - Change warnings to logging.WARNING messages - - Moved all print statements to printMsg calls - - Fix printing to STDOUT when msgBox is not defined - - Add a function that allows tweaking of noisy python modules that send information to the log. - - Add Manual documentation - - Add application Setup tab for other obscure toolset options; add setter and getter methods in GridUtils() - - Use numpypi: True/False - - Enable logging: True/False - - Specify logfile: "filename" - - Specify logging level - - Specify verbose level - - Specify debug level - - Log erase button - - Update some important references - - We can add param.watch to any control to trigger events when certain things happen. - - We also learned that a lot of python modules leverage the logging module and that some of - those modules are very verbose. We setup a function to reduce some of that noise. - - Once a logger is created, it cannot be deleted. It can be enabled and disabled. - - Add a small program example to show all available loggers after a GridUtils object is created. - - TODO: Creating more small program examples to demonstrate logging and debugging techniques. - - Use the setter functions in mkGridScripts and examples instead of setting the object variables directly. - - TODO: consider moving important variables to private/hidden variables. - -# 2021-04-08 - - - Experimentation with panel.pane.HTML did not work pan out. No great control over width and height. - Text updates did not automatically resize the window. The TextAreaInput automatically adds a - scrollbar to the box when enough lines are added to the window. - - Fixed up documentation of Grid Representation in the app manual. - - Panel markdown honors the usage of options after a link. - Ex: [MOM6 User Manual](https://mom6.readthedocs.io/){target="\_blank"} - - Testing of new printMsg facility is working. - - Added a clear information button to clear the inforamtion window. - -# 2021-04-07 - - - Move Spherical.py to spherical.py to match coding standards - - Use R from GridUtils class in spherical - -# 2021-04-03 - - - BUG: add ccrs.SouthPolarStereo() to projCarto - - Remove plotExtentX0,X1 checks for lon>180 - - Moving the boilerplate into its own module works - - BUG(migration): makeGrid() contained a small bug, parallels were not updating; missing self - - reworked the way we start the app via show() and display() - - BUG(migration): Plot button stopped working; missing self - - BUG(migration): Saving local files are fixed - - BUG(migration): Call the showManual method with () - -# 2021-04-02 - - - combined xgcmTools with xecmfTools configuration - - added nbserverproxy to xecmfTools - - moved documentation around - - merge code updates from James - - proj; applied application changes into gridutils so it is available to all - - applied widget clean up for local file selection - - add todos: LCC limitations; consider numpypi code - - initial move to hide application boilerplate; help diff/debugging - - discovered how to suppress xarray \_FillValue attributes - - created mkGridScripts.py to demonstrate command line/ipython use - - more documentation needed - - document how numpypi and datashader should be installed - - update extent display to show -180 to +180 - - most spinner widgets updated to numeric values instead of integer - - establish a global for the defaultGridFilename - - still need to understand how libraries, modules and packages are handled in python - - migration of mkMap to mkGrid filename; we started with maps but have moved onto grids - diff --git a/conda/docs/development/CREDITS.md b/conda/docs/development/CREDITS.md deleted file mode 100644 index 81ef428..0000000 --- a/conda/docs/development/CREDITS.md +++ /dev/null @@ -1,19 +0,0 @@ -# Credits - -## Grid tool applications - -Main authors for integration of various sources of -software are: - - * [Rob Cermak](https://github.com/jr3cermak) - * [James Simkins](https://github.com/jsimkins2) - -## Code contributions - - * [Alistair Adcroft](https://github.com/adcroft) - * [Liz Drenkard](https://github.com/amoebaliz) - * [Raphael Dussin](https://github.com/raphaeldussin) - * [Matthew Harrison](https://github.com/MJHarrison-GFDL) - * [Kate Hedstrom](https://github.com/kshedstrom) - * [Mehmet Ilicak](https://github.com/milicak) - * [Niki Zadeh](https://github.com/nikizadehgfdl) diff --git a/conda/docs/development/Design.md b/conda/docs/development/Design.md deleted file mode 100644 index 0833a5c..0000000 --- a/conda/docs/development/Design.md +++ /dev/null @@ -1,53 +0,0 @@ -# Library design - -These are the overarching design elements. To follow along -with actual milestones, task, todo and extras list, please -consult the [TODO](TODO.md) page. - -## Requirements - -These are MUST HAVE elements. - -The ocean grids are conformal. This means the angles between the horizontal -and vertical intersections are 90 degrees. - -Long term view is to be able to create subsets of grids from an existing global -grid. - -Must work with these conformal projections: - * Mercator - * Lambert Conformal Conic - * Polar Stereographic (N and S) - * Tri Polar - -Grid operation: - * Set, increase, decrease number of grid points (x, y) - * Set, increase, decrease cell size (dx, dy) - * Set or unset the requirement that dx = dy - * Zoom in/out - * Draw, adjust or delete the drawn grid - -### Features - -This is a list of elements that would be nice to have. - -Grid operation: - * Adjust the drawn box with a fixed boundary or point - * Grid rotation - -Field import: - * Regrid bathymetry to new grid - * Build boundary and forcing files - * Adaptation of other routines from pyroms - -Ability to work in mapping and non-mapping frames of reference. The -ability to work in raw coordinate systems as needed by example problems. - -### Operational modes - -Desired operational modes - * Command line - * Command line widget mode - * jupyter notebook - * jupyter lab - * cloud: mybinder.org diff --git a/conda/docs/development/ImportantReferences.md b/conda/docs/development/ImportantReferences.md deleted file mode 100644 index 01c8129..0000000 --- a/conda/docs/development/ImportantReferences.md +++ /dev/null @@ -1,71 +0,0 @@ -# Important references - -These are people, references and bookmarks that provided useful information to make this project go. - -## Alistair Adcroft - * numpypi: https://github.com/adcroft/numpypi - -## Raphael Dussin - * Use of pyproj to convert coordinates in 2D array - * https://github.com/raphaeldussin/regrid_weights_bedmachine_gebco/blob/master/create_grids.py - -## Mehmet Ilicak; Alistair Adcroft; Matthew Harrison - * ROMS to MOM6 grid converter - * https://raw.githubusercontent.com/ESMG/pyroms/python3/examples/grid_MOM6/convert_ROMS_grid_to_MOM6.py - * https://raw.githubusercontent.com/ESMG/pyroms/python3/examples/grid_MOM6/Spherical.py - -## Niki Zadeh - * Lambert Conformal Conic grid generation provided by: - https://github.com/nikizadehgfdl/grid_generation/blob/dev/jupynotebooks/regional_grid_spherical.ipynb - -## mapx - * NSIDC Map Transformations Library (Mapx) - https://nsidc.org/support/42415620-Mapx-Map-Transformations-Library - -## Bookmarks - * https://www.digitalocean.com/community/tutorials/how-to-use-args-and-kwargs-in-python-3 - * https://docs.conda.io/projects/conda/en/latest/user-guide/tasks/manage-environments.html - * https://en.wikipedia.org/wiki/Arakawa_grids - * https://en.wikipedia.org/wiki/World_Geodetic_System - * https://geohackweek.github.io/nDarrays/09-masking/ - * https://github.com/binder-examples/conda - * https://github.com/SciTools/cartopy/issues/787 - * https://math.libretexts.org/Bookshelves/Calculus/Book%3A_Calculus_(OpenStax)/12%3A_Vectors_in_Space/12.7%3A_Cylindrical_and_Spherical_Coordinates#:~:text=In%20the%20Cartesian%20coordinate%20system%2C%20the%20location%20of%20a%20point,an%20angle%20measure%20(%CE%B8). - * http://mathworld.wolfram.com - * https://matplotlib.org/stable/gallery/images_contours_and_fields/image_masked.html - * https://matplotlib.org/stable/gallery/images_contours_and_fields/pcolormesh_levels.html#sphx-glr-gallery-images-contours-and-fields-pcolormesh-levels-py - * https://matplotlib.org/stable/gallery/images_contours_and_fields/pcolormesh_grids.html#sphx-glr-gallery-images-contours-and-fields-pcolormesh-grids-py - * https://matplotlib.org/stable/tutorials/colors/colormaps.html - * https://matplotlib.org/stable/tutorials/colors/colorbar_only.html#sphx-glr-tutorials-colors-colorbar-only-py - * https://panel.holoviz.org/gallery/index.html - - * https://pangeo-xesmf.readthedocs.io/en/latest/notebooks/Compare_algorithms.html - * https://rabernat.github.io/research_computing/xarray.html - * https://rabernat.github.io/research_computing_2018/maps-with-cartopy.html - * https://realpython.com/python-bindings-overview/ - * https://scitools.org.uk/cartopy/docs/latest/index.html - * https://scitools.org.uk/cartopy/docs/latest/crs/projections.html - * https://scitools.org.uk/cartopy/docs/latest/gallery/effects_of_the_ellipse.html - * https://softwareengineering.stackexchange.com/questions/329348/classes-vs-modules-in-python - * https://stackoverflow.com/questions/3277367/how-does-pythons-super-work-with-multiple-inheritance - * https://stackoverflow.com/questions/6999621/how-to-use-extent-in-matplotlib-pyplot-imshow - * https://stackoverflow.com/questions/12575421/convert-a-1d-array-to-a-2d-array-in-numpy - * https://stackoverflow.com/questions/21778118/counting-the-number-of-non-nan-elements-in-a-numpy-ndarray-in-python - * https://stackoverflow.com/questions/32234156/how-to-unimport-a-python-module-which-is-already-imported - * https://stackoverflow.com/questions/44412432/cartopy-zoom-in-to-a-region - * https://stackoverflow.com/questions/51357691/python-logging-only-for-own-imported-modules - * https://towardsdatascience.com/plt-subplot-or-plt-subplots-understanding-state-based-vs-object-oriented-programming-in-pyplot-4ba0c7283f5d - * https://unidata.github.io/MetPy/latest/examples/Four_Panel_Map.html - * https://www.kite.com/python/answers/how-to-hide-a-figure-from-being-shown-in-matplotlib-in-python - * https://www.mathsisfun.com/geometry/interior-angles-polygons.html - * https://www.python.org/dev/peps/pep-0008/#package-and-module-names - * https://xarray.pydata.org/en/stable/examples/ROMS_ocean_model.html - * https://xarray.pydata.org/en/stable/data-structures.html#dictionary-like-methods - * https://xarray.pydata.org/en/stable/dask.html - -## Paywall Bookmarks - -## For Review Later - - * http://dsrs.atmos.umd.edu/DATA/aosc/greenland/code/MOM4SODA/MOM_TEST/src/tools/make_hgrid/make_hgrid.c - * Be aware, this may be Arakawa B grid code diff --git a/conda/docs/development/Jupyter.md b/conda/docs/development/Jupyter.md deleted file mode 100644 index 72994a2..0000000 --- a/conda/docs/development/Jupyter.md +++ /dev/null @@ -1,54 +0,0 @@ -# Jupyter - -I currently run a Oracle VirtualBox on a MacOS and have the network setting for -Adapter 1 set as bridged over the wifi interface (en0). Doing so, I get a DHCP -address for my local network at the same level as the MacOS computer. This allows -me to use that IP for sharing the jupyter and bokah servers from the VM to a local -browser on the MacOS. In this documentation, I assume the VM is on the address -192.168.131.54. - -Launching a jupyterlab session, I prefer not to have it try and start a browser -from the VM. The default port is 8888. -``` -$ conda activate -(env) $ jupyter lab --ip=192.168.131.54 --no-browser -``` - -A jupyterlab can be started for each conda enviroment, but do not attempt to -open the same notebook file between two jupyterlab instances. It will do it, -but will cause odd things to happen. - -To enable multiple environments, use separate ports via (--port). It turns out -jupyterlab is able to figure out other ports are busy and auto increments the -port number. Specifying the port number is not necessary unless you want it to -be really different. -``` -(env) $ jupyter lab --ip=192.168.131.34 --port=8889 --no-browser -``` - -To test a bokeh application to make sure it can be embedded in a jupyter lab -notebook with working interactive widgets, use this example -[script](https://github.com/bokeh/bokeh/blob/2.3.0/examples/howto/server_embed/notebook_embed.ipynb). - -Using the above default launching of jupyter lab, the last line of the -notebook should read: -``` -show(bkapp, notebook_url="http://192.168.131.54:8888") -``` - -# Jupyter Shortcuts - -You can install the shortcuts within JupyterLab web interface through Settings, -Advanced Setting Editor and Keyboard Shortcuts and edit the "User Preferences" -pane. Or copy "shortcuts.jupyterlab-settings" to: - -```text -${HOME}/.jupyter/lab/user-settings/@jupyterlab/shortcuts-extension/shortcuts.jupyterlab-settings -``` - -The current shortcuts add two keyboard shortcuts to the notebook editor: - * Ctrl Shift ArrowUp: move cell up - * Ctrl Shift ArrowDown: move cell down - -You must not be editing the cell. The cell to move must be selected just to the -left and is denoted by a vertical bar highlighting the cell. diff --git a/conda/docs/development/TODO.md b/conda/docs/development/TODO.md deleted file mode 100644 index 943693c..0000000 --- a/conda/docs/development/TODO.md +++ /dev/null @@ -1,167 +0,0 @@ -# Planned work - -## Milestones - - - [ ] Version 0.1 - - [X] Simple polar grid generation - - [X] Clean up documentation - - [X] Generify current examples - - [X] Test examples for LCC grid generation - - [X] Test examples for regular Mercator grid generation - - [X] Test examples for stereographic grid generation - - [X] Test application for LCC grid generation - - [X] Test application for regular Mercator grid generation - - [X] Test application for stereographic grid generation - - [X] Tackle critical TODO items - - [X] Publish initial commit to ESMG - - [ ] Ensure mybinder.org works with the published github commit - - [ ] Version 0.2 - - [ ] Estabish sphinx document generator and link to readthedocs - - [ ] Allow import of ROMS grid for conversion to MOM6 - - [ ] Enhanced grid/plot projection options - - [ ] Explore the extent problem for lon defined as +0,+360 vs -180,+180 - - [ ] Leverage dask (expecially for binder.org) - - [ ] Verison 0.x - - [ ] Bathymetry and boundery condition support - - [ ] Grid filling options (flooding) - - [ ] Grid mask editor - - [ ] This library is installable via pip - - [ ] This library is installable via conda - -# BUGS - - [ ] A nested dictionary will clobber other nested elements instead - of updating elements. Recode `setPlotParameters` and - `setGridParameters` to recursively update dictionary elements. - -# TASKS - - - [ ] general documentation - - [X] grid parameters - - [X] plot parameters - - [ ] enable sphinx as the documentation generator - - [ ] link to readthedocs - - [ ] grid creation/editor - - [ ] grid metrics - - [X] Spherical solution is complete via Niki's ROMS to MOM6 converter - - [X] Mercator (angle_dx might be 0 as it is lined up along latitude lines; except for tilt?) - - [X] Polar - - [ ] make Lambert Conformal Conic Grids; needs testing - - [ ] LCC cannot take custom lat_1 and lat_2; it generates - lat_1 and lat_2 based on grid inputs. - - [X] Update new lat_1 and lat_2 for application after makeGrid() is run - - [ ] changing plot parameters lat_1 and lat_2 do not seem to impact the view - - [ ] make Mercator grids; needs testing - - [ ] issue a warning if tilt is non-zero - disabled - - [ ] Niki might have solved lat lon tilt? - - [ ] having tilt may not produce conformal grids - - [X] Niki's example added; but it may not be correct - - [X] make Stereographic grids; needs testing - - [X] using meters; no tilt; based on code from Raphael - - [X] using degrees; with tilt; based on code from Niki; may not be correct - - [ ] grid generation in other projections (tri-polar, etc) - - [X] on saveGrid() convert lon [+0,+360] to [-180,+180] - - [ ] Unify code that adjusts lon (robTest:PR#1) - - [X] Unify ellipse radius (R) constants throughout code - - [X] Gridutils initializes with proj GRS80 - - [X] Allow user control - - [ ] grid mask editor (land, etc) - - [ ] integration of bathymetric sources and apply to grids - - [ ] https://github.com/nikizadehgfdl/ocean_model_topog_generator - - [ ] xesmf regridder - - [X] add nbserverproxy/xgcm to conda software stacks; copied to binder environment.yml - - [ ] Add option to use Alistair's numpypi package as a configurable option in toolsets - - [ ] turn numpypi into a loadable package via pip - - [X] add datashader and numpypi from github sources; see postBuild script - - [ ] implement and document in application - - [ ] implement and document for programming use - - [X] xarray \_FillValue needs to be turned off somehow - - [X] place display(dashboard) as a separate notebook cell - - [ ] on load of a grid - - [ ] calculate R - - [ ] calculate tilt (may not be possible) - - [ ] update any tool metadata that is appropriate for that grid - - [ ] parse and utilize any available proj string; must be a global or variable attribute - - [X] Create an application method within the GridUtils() class; GridTools().app() - - [ ] Using xesmf regridder and other tools to create bathymetry and other forcing and boundary files - - [ ] Develop a field "flood" routine similar to pyroms - - [ ] create a setup.py to allow this library to be installable via pip - - [ ] Perform checks for ensureEvenI and ensureEvenJ everywhere. This applies only to the grid not - the supergrid. - -# TODO - - - [X] Further consolidate matplotlib plotting code - - [X] Refactor plotting code. It is mostly the same except for setting the projection. - - [ ] Plotting - - [X] Grid - - [X] Gridboxes - - [ ] Supergrid - - [ ] Add "Refresh Plot" buttons to other Plot tabs or figure out how to squeeze a single plot button into the layout - - [ ] Do we have to declare everything in __init__ first or can be push all that to respective reset/clear functions? - - [ ] refactor messaging/logging out of GridUtils into its own package so we can import printMsg/debugMsg as standalone calls - - [X] refactor refineS and refineR options as Niki had them defined - - [X] makeGrid assumes working in degrees - - [X] Allow library to work in degree or meters - - [X] Pass back an error graphic instead of None for figures that do not render - - [ ] Add a formal logging/message mechanism. - - [X] Allow display of important messages and warnings in panel application: widget=TextAreaInput - - [X] Create options in application and other tools for user configuration of logging and output. - - [X] Create a message buffer/system for information. - - [ ] Create a separate app to watch a log file? https://discourse.holoviz.org/t/scrollable-log-text-viewer/317 - - [ ] log github revision used by mybinder.org instances - - [ ] For now, the gridParameters are always in reference to a center point in a grid - in the future, one may fix a side or point of the grid and grow out from that point - instead of the center. - - [ ] application - - [ ] enable user configurable plot and widget sizes (hardcoded in __init__) - - [ ] enable user to change ellipsoid, R, x_0 and y_0 grid and plot parameters - - [ ] plotting: adjust satellite_height, for now it is fixed to the default - - [ ] title is misleading; it should show the projections in use if different - - [ ] Develop a GridUtils() function - - [ ] Run `proj -le` and return the names or display the details - - [ ] Populates the ellps field for the application - - [ ] x_0 and y_0 are hard coded to be zero offsets. The user can modify these values. - - [ ] Deploy use of self.gridMade (robTest:PR#1) - - [ ] After success in makeGrid() - - [ ] Successful load of grid from a file - - [ ] Reset appropriately when clearGrid() is called - - [ ] More contemplation of longitude range with respect 0, +/-180, 360. - - [ ] How does this library respond for grids draped over 0 degree longitude vs +/-180 degrees longitude - - [ ] Add testing harnesses. - - [ ] pytest: This will allow testing of core code via command line and iterative methods. - - [ ] selenium: Testing interactive methods may be harder. - -# WISH - - - [ ] Add an activity spinner to indicate the notebook is busy - - [ ] Compute angle_dy for testing of grid conformality. Theoretically, we can do this check for all grid - and supergrid cells. - - [ ] tripolar grids: use FRE-NCtools via cython? - - [ ] Bring in code that converts ROMS grids to MOM6 grids - - [ ] Allow conversion of MOM6 grids to ROMS grids - - [ ] grid reading and plot parameter defaults should be dynamic with grid type declaration and potentially - split out into separate library modules? lib/gridTools/grids/{MOM6,ROMS,WRF} - - [ ] Place additional projection metadata into MOM6 grid files - - [X] Added proj string to netCDF file - - [ ] Tri polar grid description - - [ ] Work with generic non-mapping reference systems for use with some of the sample MOM6 problems - - [ ] Refactor any grid math into a gridmath library. Any grid computation that can stand on its own - should be moved into a separate gridmath library. - - [ ] gridtools::makeGrid() will need a refactor to work with other grid types - - [ ] write out all MOM6 ancillary files when writing a grid - - [ ] refactor expansion/clipping of grid points when fitting grid - - [ ] Add a notebook or two that demonstrates some of the esoteric API - features of the library: help, debugging, etc. - - [ ] Dask optimizations - - [ ] IBCAO grid is too big for mybinder.org - - [ ] Pull in BC and forcing fields from various sources - - [ ] Delta method: "We extract 20-30 years of a future projection from several models, build an average of each forcing variable which we superpose on modern day climate. It’s the so-called delta method. It debiases climate projections relative to modern day (reanalysis constrained) dynamics, but adds the climate change signal on top of it (as a secular change/delta)." - - [ ] CMIP/ESM - - [ ] Browser catalog: https://esgf-node.llnl.gov/search/cmip6/ - - [ ] Programmatic access: https://github.com/intake/intake-esm - - [ ] http://gallery.pangeo.io/repos/pangeo-gallery/cmip6/ - - [ ] https://github.com/aradhakrishnanGFDL/gfdl-aws-analysis/tree/master/examples - - [ ] https://github.com/aradhakrishnanGFDL/gfdl-aws-analysis/tree/master/esm-collection-spec-examples - - [ ] https://github.com/MackenzieBlanusa/OHC_CMIP6 - - [ ] https://github.com/xarray-contrib/cf-xarray - - [ ] https://github.com/jbusecke/cmip6_preprocessing diff --git a/conda/docs/development/python/libraries/leaflet.md b/conda/docs/development/python/libraries/leaflet.md deleted file mode 100644 index 4b62128..0000000 --- a/conda/docs/development/python/libraries/leaflet.md +++ /dev/null @@ -1,3 +0,0 @@ -### leaflet -If panning of maps fails or freezes, it usually requires a full reload of the -entire web page and the contents of JupyterLab to restore. \ No newline at end of file diff --git a/conda/docs/development/python/libraries/panel.md b/conda/docs/development/python/libraries/panel.md deleted file mode 100644 index be21b66..0000000 --- a/conda/docs/development/python/libraries/panel.md +++ /dev/null @@ -1,30 +0,0 @@ -# Panel - -Developer notes from usage of the [Panel](https://panel.holoviz.org/index.html) library. - -# Notes - -Any control without a callback function feature like "on\_click" for the button can gain -a callback function using the param.watch method. For example, a Checkbox. Suppose, you -would like to have an event when the checkbox is toggled. - -Here is the code to create the checkbox control: -``` -logEnableControl = pn.widgets.Checkbox(name="Enable file logging") -``` - -To setup a watch for a change in the "value" property, use: -``` -logEnableControl.param.watch(logEnableCallback, 'value') -``` - -The callback function should trap the emitted event: -``` -def logEnableCallback(event): - print(event) -``` - -Which will result in something like: -```text -Event(what='value', name='value', obj=Checkbox(name='Enable file logging', value=True), cls=Checkbox(name='Enable file logging', value=True), old=False, new=True, type='changed') -``` diff --git a/conda/docs/development/python/libraries/pyroms.md b/conda/docs/development/python/libraries/pyroms.md deleted file mode 100644 index 3c41f71..0000000 --- a/conda/docs/development/python/libraries/pyroms.md +++ /dev/null @@ -1,49 +0,0 @@ -# pyroms - -[pyroms](https://github.com/ESMG/pyroms) - -This is a legacy software library for specific use with ROMS grids. - -# Notes - -NOTE: This is a very limited environment with netcdf4 and matplotlib's basemap -to review former functionality. This should be migrated ASAP to utilize modern -libraries. - -``` -# The current path is your SRC directory -$ git clone https://github.com/ESMG/pyroms.git -# The cloned directory is ${SRC}/pyroms -``` - -Install the pyroms conda environment. This installs the appropriate fortran -compiler for netcdf. - -If you need scrip.so: -``` -$ cd ${SRC}/pyroms/pyroms/external/scrip/source -# edit makefile -# change PREFIX = /usr/local -# to PREFIX ?= /usr/local -$ export PREFIX=$CONDA_PREFIX -$ make DEVELOP=1 -$ cp scrip.cpython-38-x86_64-linux-gnu.so ${SRC}/pyroms/pyroms/pyroms/ -``` - -Using pyroms: -``` -# define the location of gridid.txt -# edit gridid.txt to point to Arctic6 nc file -$ export PYROMS_GRIDID_FILE=/home/cermak/gridtools/gridTools/configs/Arctic6/roms/gridid.txt -``` - -For now the only known working way to run editmask.py is via: -``` -$ ipython --pylab -``` - -Cut and paste line by line into the interactive command above. The last line -in editmask.py saves any edits made to the grid. - -However, this should also work in jupyterlab via ipympl which is untested at -the moment. diff --git a/conda/docs/grids/Examples.md b/conda/docs/grids/Examples.md deleted file mode 100644 index c5d7341..0000000 --- a/conda/docs/grids/Examples.md +++ /dev/null @@ -1,60 +0,0 @@ -# Examples - -Grid examples have been provided to demonstrate the utility of -the grid generation software. - -# Lambert Conformal Conic - -## NEP7 - -This grid description was provided by Kate Hedstrom. - -This grid is Lambert Conformal Conic. -Grid resolution is 10km (10000 meters) -The LCC attributes are: - Standard parallel latitudes: 40.0 and 60.0 North (lat_1, lat_2) - Central longitude: -91.0 West (lon_0) - Central latitude: unknown (seems ok for plotting) - Corner points: (-130,0N) (-220,70N) - -## Pacific - -The code creates a grid in spherical coordinates. It appears the final -grid is in Lambert Conformal Conic. The code allows a tilt to be provided -as input. - -This example recreates the the grid demonstrated by Niki Zadah's -[jupyter notebook](https://github.com/nikizadehgfdl/grid_generation/blob/dev/jupynotebooks/regional_grid_spherical.ipynb). - -# North Polar Stereo - -## Arctic6 - -This grid description was provided by Kate Hedstrom. - -This grid is in the North Polar Stereo projection. -This grid has a central longitude of 160.0 West. -The true scale latitude is unknown. Kate thinks it might be 90N? -Having true scale latitude unset for plotting seems to work. - -## IBCAO - -IBCAO is a North Polar Stero projection grid. The -[technical reference](https://www.ngdc.noaa.gov/mgg/bathymetry/arctic/IBCAO_TechnicalReference.PDF) -describes the grid in full detail. See page 9 for grid format. - -A Polarstereographic projection with the true scale at -75 °N is “preserved” in the Cartesian grid. The horizontal -datum is World Geodetic System (WGS 84). - -The center of the grid is the North Pole. - -Grid corners: -```text - X Y lon lat --------- -------- ------ ------------- --2902500 +2902500 -135.0 +53:49:1.4687 -+2902500 +2902500 +135.0 +53:49:1.4687 --2902500 -2902500 -45.0 +53:49:1.4687 -+2902500 -2902500 +45.0 +53:49:1.4687 -``` diff --git a/conda/docs/grids/Grids.md b/conda/docs/grids/Grids.md deleted file mode 100644 index aea2138..0000000 --- a/conda/docs/grids/Grids.md +++ /dev/null @@ -1,12 +0,0 @@ -# Grids - -For showing a grid not in its native projection, you have to -plot every line between grid box nodes to form the vertices. - -A simple bounding box, extent, may be used for a grid shown -in its native projection. You can plot from outer grid edges -to form the vertices. This also seems to hold true for tilted -grids in Lambert Conformal Conic. - -A conformal grid shown in its native projection should show up -as a square or rectangular grid. diff --git a/conda/docs/grids/MOM6.md b/conda/docs/grids/MOM6.md deleted file mode 100644 index a571e6d..0000000 --- a/conda/docs/grids/MOM6.md +++ /dev/null @@ -1,10 +0,0 @@ -# MOM6 Grids - -## MOM6 Notes - -Within the netCDF file for MOM6 grids the following descriptions of -variables and dimensions: - - * Dimensions - * nx, ny : grid centers - * nxp, nxp : grid verticies diff --git a/conda/docs/grids/MOM6ROMS.md b/conda/docs/grids/MOM6ROMS.md deleted file mode 100644 index aef9944..0000000 --- a/conda/docs/grids/MOM6ROMS.md +++ /dev/null @@ -1,69 +0,0 @@ -# MOM6 and MOM6 grids - -``` -# Both ROMS and MOM6 horizontal grids use an Arakawa C-grid, with four -# types of points: -# rho: the centers of the cells -# psi: the corners of the cells, located diagonally between the -# 'rho' points -# u: the u-velocity points, located between 'rho' points in the -# east/west direction -# v: the v-velocity points, located between 'rho' points in the -# north/south direction - -# The main differences between the two grids are: -# * the outermost points of the ROMS grid are the 'rho' points, while -# the outermost points of the MOM6 grid are the 'psi' points (both -# with interspersed 'u' and 'v' points); and -# * the MOM6 grid interleaves all four types of points into a single -# "supergrid", while ROMS stores them as separate grids. - -# The ROMS grid looks like this, with an extra layer of 'rho' points -# around the outside: -# (see https://www.myroms.org/wiki/Numerical_Solution_Technique) -# -# p - p - p - p - p -# 3 | + | + | + | + | p = rho (center) points -# p - p - p - p - p + = psi (corner) points -# 2 | + | + | + | + | - = u points -# p - p - p - p - p | = v points -# 1 | + | + | + | + | -# p - p - p - p - p -# -# 1 2 3 4 - -# The MOM6 grid has 'psi' points on the outside, not 'rho': -# -# 3 + | + | + | + p = rho (center) points -# - p - p - p - + = psi (corner) points -# 2 + | + | + | + - = u points -# - p - p - p - | = v points -# 1 + | + | + | + -# -# 1 2 3 4 -``` - -Here is a representation of a (2, 3) MOM6 grid adapted from convert_ROMS_grid_to_MOM6.py -by Mehmet Ilicak and Alistair Adcroft. NOTE: The MOM6 supergrid is (5, 7) in shape. - -```text - G SG - 5 + | + | + | + - 2 4 - p - p - p - - 3 + | + | + | + - 1 2 - p - p - p - - 1 + | + | + | + - 1 2 3 G - 1 2 3 4 5 6 7 SG - -KEY: p = ROMS rho (center) points; also MOM6 h (center) points - + = ROMS psi (corner) points - - = ROMS u points - | = ROMS v points - G = grid points - SG = supergrid points -``` - -A MOM6 grid of (ny, nx) will have (ny\*2+1, nx\*2+1) points on the supergrid. -NOTE: In python, array storage is zero based. In the above example, supergrid -point (1, 1) is stored in memory location (0, 0). diff --git a/conda/docs/grids/ROMS.md b/conda/docs/grids/ROMS.md deleted file mode 100644 index 7cd1535..0000000 --- a/conda/docs/grids/ROMS.md +++ /dev/null @@ -1,3 +0,0 @@ -# ROMS - -Has an extra grid box around the regular grid. diff --git a/conda/docs/manual/Application.md b/conda/docs/manual/Application.md deleted file mode 100644 index 8fdb72b..0000000 --- a/conda/docs/manual/Application.md +++ /dev/null @@ -1,12 +0,0 @@ -# Application - -This details the application portion of the grid tools library. - -# Getting Started - -The application is generally run inside a python notebook, -jupyter notebook, jupyter lab or jupyter hub. Once the script -it loaded, all the cells should be executed to start the application. - -The developers have prepared the code to operate on a remote cloud -system at mybinder.org. diff --git a/conda/docs/manual/GridUtils.md b/conda/docs/manual/GridUtils.md deleted file mode 100644 index 028fddb..0000000 --- a/conda/docs/manual/GridUtils.md +++ /dev/null @@ -1,352 +0,0 @@ -# GridUtils - -Welcome to the user manual for the GridUtils python library. This library -provides a one stop shop for grid preparation and manipulation software. -The [design](../development/Design.md) for this library is to keep it -simple and provide a variety of usage patterns. Work is ongoing with a -laundry list of [TODO](../development/TODO.md) items. - -This library currently returns a netCDF file that should be -compatible with a typical `ocean_hgrid.nc` input file. - -# Under the hood - -The library makes use of xarray for input and output (IO). Several -open source libraries are used for manipulation of grid and -associated grid fields (boundary files and forcing fields). The -primary storage format is netCDF. The dask library is leveraged -where possible. The library also leverages the geospatial -library pyproj where possible. - -# Getting Started - -This project assumes the user is familiar with using python as a -programming language. To get started with using this library, the -first step is [instantiation](https://www.tutorialspoint.com/Explain-Inheritance-vs-Instantiation-for-Python-classes) -of the library's class with a python variable that will point to -the python object. This also assumes the library has been installed -and is accessible. - -``` -from gridtools import GridUtils - -grd = GridUtils() -``` - -The `grd` variable or object's functions and methods can not be -used to create or load the users grid and leverage the library's -tools for other available operations. - -If working with more than one grid at one time, it is advised to -create or instantiate more than one object. Use one object for -each grid in use in a single program. - -The user manual and examples will refer to this `grd` object -frequently. - -In the application form of this library, once all the notebook -cells have run, there is a `grd` object that can be accessed by -adding cells at the bottom of the notebook. Manipulation of the -`grd` object outside the application can have unexpected -consequences. The application can only work with one grid at -one time. - -Additional details about the application not covered by the -internal application help menu can be found in the -[application](Application.md) portion of the user manual. - -Additional details may be gleamed from the internal python -documentation using the built-in -[help()](https://docs.python.org/3/library/functions.html#help) -function. After importing GridUtils or any library, the internal -help is displayed by using `help(GridUtils)` in a python script or -in a notebook cell. This also works for individual methods or -functions. - -## Feedback - -The library provides feedback to the user and the developers by -providing messages back to the screen or logging them to files. -As the library is utilized, it will emit warnings or error as -needed. If you want to increase or decrease the verbosity -of these messages, please see the [logging](Logging.md) portion -of the user manual. - -# Terminology - -**grid**: This refers to the entire grid. - -**grid cell**: This refers to a grid cell within a grid. - -## MOM6 - -**supergrid**: This refers a denser grid where -there are not only the grid verticies of the **grid cells** but additional -verticies through the center points of the **grid cells** in both the i -and j direction. This grid is twice the nominal resolution of the model. - -Grid orientation, with **no rotation**, is from the lower left to the upper -right. The i direction increases from lower to upper portion of the grid. -The j direction incrases from left to right. - -More grid specifics for MOM6 can be found at these locations: - * [Cheat sheet for using a Moasic grid with MOM6 output](https://gist.github.com/adcroft/c1e207024fe1189b43dddc5f1fe7dd6c) - * [Discrete Horizontal and Vertical Grids](https://mom6.readthedocs.io/en/dev-gfdl/api/generated/pages/Discrete_Grids.html) - -# Parameters - -The library acts on user provided grid and plot parameters. - -The user must specify projection information for both the grid and plot -parameters if the grid is to be used on a geographic surface. In most -cases, the grid and plot projections will be the same unless you wish -to see the grid in a different projection. - -The library has also been designed to allow the grid center to be -in a different location than the projection center. The library -makes *limited* assumptions for parameters and it is highly -recommended to provide complete information no matter how -redundant it may seem. - -There are certain assumptions made by the `pyproj` library for -certain projection parameters. - -# Grid Creation - -The library supports one mode of grid creation at present. The user -must provide: - * Size of the grid in the i(dy) and j(dx) direction in degrees or meters. - * Grid center in degrees or meters. - * Grid resolution in degrees or meters. - -The number of grid cells depends on the total size of the grid -and selected grid resolution. The library may automatically -adjust number of grid points in the i and j direction. Automatic -adjustment can be disabled. - -## Projections - -The user may select from three available projections: - * Lambert Conformal Conic - * Mercator - * Stereographic - -Since `pyproj` is utilized by this library, the -default ellipsoids for [projections](https://proj.org/operations/projections/index.html) -is GRS80. If `proj` is installed, use `proj -le` to produce a -list of available ellipoids. - -## Projection Support - -These grids are believed to be conformal as generated by the library: - * Lambert Conformal Conic - * Mercator (no tilt) - * Stereographic (with grid distance in meters) - -Other grids may be generated, but they are not guaranteed to be conformal. - -### Lambert Conformal Conic - -All grid parameters must be specified in degrees. - -### Mercator - -All grid parameters must be specified in degrees. - -### Stereographic - -The central grid point must be specified in degrees. -Grid distance must be specified in meters. - -# Defaults - -This section shows all available grid and plot parameters. Parameter -definitions are provided. - -All the available parameters are shown for completeness. Not all -parameters are needed to create a grid or request a plot. It some -cases, it does not make sense to mix parameters. Some parameters -are only available for specific grid types. - -## Grid - -Grid parameters may be changed through the `setGridParameters` function by -passing a python dictionary. The order of the parameters does not matter. -The parameter names are case sensitive. - -``` -grd.setGridParameters({ - 'centerUnits': 'degrees', - 'centerX': 0.0, - 'centerY': 0.0, - 'dx': 0.0, - 'dy': 0.0, - 'dxUnits': 'degrees', - 'dyUnits': 'degrees', - 'nx': 0, - 'ny': 0, - 'tilt': 0.0, - 'gridResolution': 0.0, - 'gridResolutionX': 0.0, - 'gridResolutionY': 0.0, - 'gridResolutionUnits': 'degrees', - 'gridResolutionXUnits': 'degrees', - 'gridResolutionYUnits': 'degrees', - 'projection': { - 'name': 'Mercator', - 'lat_0': 0.0, - 'lat_1': 0.0, - 'lat_2': 0.0, - 'lat_ts': 0.0, - 'lon_0': 0.0, - 'ellps': 'GRS80', - 'R': 6378137.0, - 'x_0': 0.0, - 'y_0': 0.0, - 'k_0': 1.0 - }, - 'gridMode': 2, - 'ensureEvenJ': True -}) -``` - -Parameter definitions: - -Parameter | Definition | Type | Valid Values | Default ---------- | ---------- | ---- | ------------ | ------- -centerUnits | units for center grid point | string | 'degrees', 'meters' | 'degrees' -centerX | grid center in j direction | float | **(1)** | n/a -centerY | grid center in i direction | float | **(1)** | n/a -dx | grid length in the j direction | float | **(2)** | n/a -dy | grid length in the i direction | float | **(2)** | n/a -dxUnits | grid length units | string | 'degrees', 'meters' | 'degrees' -dyUnits | grid length units | string | 'degrees', 'meters' | 'degrees' -nx | number of grid points in the j direction | integer | **(3)** | n/a -ny | number of grid points in the i direction | integer | **(3)** | n/a -tilt | degree to rotate the grid | float | 0.0 to 360.0 | 0.0 **(4)** -gridResolution | grid cell size in the i and j direction | float | **(5)** | n/a -gridResolutionX | grid cell size in the j direction | float | **(5)** | n/a -gridResolutionY | grid cell size in the i direction | float | **(5)** | n/a -gridResolutionUnits | grid cell size units in the i and j direction | string | 'degrees', 'meters' | 'degrees' -gridResolutionXUnits | grid cell size units in the j direction | string | 'degrees', 'meters' | 'degrees' -gridResolutionYUnits | grid cell size units in the i direction | string | 'degrees', 'meters' | 'degrees' - -NOTES: - * **(1)** If centerUnits is in 'degrees', the limits for centerX are +0.0 to +360.0 and centerY are -90.0 to +90.0. - * **(2)** This is a reasonable float number representing degrees or meters. - * **(3)** This feature has not been implemented yet. - * **(4)** This parameter only applies to the Lambert Conformal Conic projection. - * **(5)** Specifying gridResolutionX and/or gridResolutionY will override the value specified for gridResolution - -MOM6 parameter definitions: - -Parameter | Definition | Type | Valid Values | Default ---------- | ---------- | ---- | ------------ | ------- -gridMode | grid generation mode | integer | **(1)** | 2 -ensureEvenI | ensure even number of grid points in the i direction | boolean | True, False | True -ensureEvenJ | ensure even number of grid points in the j direction | boolean | True, False | True - -NOTES: - * **(1)** Valid values are 1 and 2. Grid mode one (1) generates only the specified grid with grid cell distances given by the grid resolution. Grid metrics will NOT be computed. Grid mode two (2) generates a standard MOM6 grid with supergrid. Grid metrics will be computed. - * `ensureEvenJ` flag allows the grid generator clip the grid if the number of points in the j direction is uneven. - -Projection definitions: - -Parameter | Definition | Type | Valid Values | Default ---------- | ---------- | ---- | ------------ | ------- -name | projection name | string | 'LambertConformalConic', 'Mercator', 'Stereographic' | n/a -lat\_0 | latitude of projection center | degrees | -90.0 to +90.0 | 0.0 -lat\_1 | first standard parallel latitude | degrees | -90.0 to +90.0 | 0.0 -lat\_2 | second standard parallel latitude | degrees | -90.0 to +90.0 | 0.0 -lat\_ts | latitude of true scale | degrees | -90.0 to +90.0 | 0.0 **(1)** -lon\_0 | longitude of projection center | degrees | +0.0 to +360.0 | 0.0 -ellps | ellipsoid | string | **(2)** | 'GRS80' -R | radius of the earth sphere | float | **(3)** | n/a -x\_0 | false easting | float | always expressed in meters | 0.0 -y\_0 | false northing | float | always expressed in meters | 0.0 -k\_0 | scale factor for natural origin or the ellipsoid | float | **(2)** | 1.0 - -NOTES: - * **(1)** This parameters take precedence over `k_0` if both options are specified. For stereographic projections, `lat_0` is used if `lat_ts` is not specified. - * **(2)** This is a proj string that sets the ellipsoid of the earth or sphere. See `proj -le` to show all available ellipoids. Even if an ellipsoid is selected, the radius can be changed by also supplying the `R` argument. - * **(3)** The radius is normally defined by the ellipsoid. Use this parameter if the radius of the sphere is slightly different. Depending on the projection selected, the parameter `k_0` may scale the natural origin or the ellipsoid. - -## Plot - -Plot parameters may be changed through the `setPlotParameters` function by -passing a python dictionary. The order of the parameters does not matter. -The parameter names are case sensitive. - -``` -grd.setPlotParameters({ - 'figsize': (5.0, 3.75), - 'extent': [-180.0, +180.0, -90.0, +90.0], - 'showGrid': True, - 'showGridCells': False, - 'showSupergrid': False, - 'title': 'Plot title', - 'iColor': 'k', - 'jColor': 'k', - 'iLinewidth': 1.0, - 'jLinewidth': 1.0, - 'projection': { - 'name': 'Mercator', - 'lat_0': 0.0, - 'lat_1': 0.0, - 'lat_2': 0.0, - 'lat_ts': 0.0, - 'lon_0': 0.0, - 'ellps': 'GRS80', - 'R': 6378137.0, - 'x_0': 0.0, - 'y_0': 0.0, - 'k_0': 1.0 - } -}) -``` - -Parameter definitions: - -Parameter | Definition | Type | Valid Values | Default ---------- | ---------- | ---- | ------------ | ------- -figsize | default figure size for plots in inches | tuple | (float, float) | (5.0, 3.75) **(1)** -extent | plot extent | list | [float, float, float, float] | n/a **(2)** -extentCRS | plot extent projection | cartopy crs object | **(3)** | cartopy.crs.PlateCarree() -showGrid | plots only show the grid edge | boolean | False, True | True **(4)** -showGridCells | plots show grid cells | boolean | False, True | False **(4)** -showSupergrid | plots show the supergrid | boolean | False, True | False **(4)** -title | plot title | string | any string | n/a **(5)** -iColor | i grid line color | string | **(6)** | 'k' -jColor | j grid line color | string | **(6)** | 'k' -iLinewidth | i grid line width | float | **(7)** | 1.0 -jLinewidth | j grid line width | float | **(7)** | 1.0 - -NOTES: - * **(1)** The tuple arguments are (width, height) in inches. This -default figure size is optimized for use in the application portion -of the library. The library is designed to pass back a figure and -axes matlab object for further customization before rendering. - * **(2)** By default, this parameter is not set. When this parameter -is not set, a geographic map plot will default to a global extent. -The parameter list is [min x0, max x1, min y0, max y1] where x is -typically longitude and y is latitude. NOTE: The library pyproj -utilizes longitudes +0.0 to +360.0. The library cartopy utilizes -longitudes -180.0 to +180.0. - * **(3)** See [cartopy.crs](https://scitools.org.uk/cartopy/docs/latest/crs/projections.html) -for other projections and required units. Changing the projection will -require loading the cartopy library. `import cartopy` - * **(4)** Not all grid model types will support `showSupergrid`. If -multiple parameters are set to True, the plot will show the denser of -all the selections. - * **(5)** By default, the parameter is not set. When set, this is -the title that is shown on the plot. - * **(6)** By default, grid lines are plotted as black ('k'). The -library utilizes colors available in -[matplotlib](https://matplotlib.org/stable/tutorials/colors/colors.html). - * **(7)** Grid line width is specified in points (1/72 of an inch). A grid -can sometimes be viewable at a witdh of 0.1 points. The grid also -becomes somewhat opaque. - -The projection definitions for plot parameters are -the same as the grid parameters and will not be -repeated here. diff --git a/conda/docs/manual/Logging.md b/conda/docs/manual/Logging.md deleted file mode 100644 index c184b38..0000000 --- a/conda/docs/manual/Logging.md +++ /dev/null @@ -1,43 +0,0 @@ -# Logging - -At the default state, the program will emit important messages about -assumptions it made in creating or modifying the grid in memory. - -This library, and many other python libraries, heavily leverage the -built-in [logging](https://docs.python.org/3/library/logging.html) -library. - -The logging mechanism in this application and GridUtils() is slightly complex. For messages -emitted to the "Information" panel or using iterative means, you can control the amount of -detail presented to you or logged in a file. The logging levels from low to high are: NOTSET, -DEBUG, INFO, WARNING, ERROR and CRITICAL. The level set means only messages of that level or higher -will be shown or logged. If you want to see all available detail, use NOTSET. NOTE: The detail sent -to the applications "Information" window by default is INFO or higher. The detail sent to a log file, -if enabled, is WARNING or higher. The function for emitting messages is `GridUtils.printMsg()`. - -# Log file - -You can only change the log file name or delete the log file when the logging system is disabled. -To assist the software developers, we request that you provide a log file of activity to help us -discover problems with the code. The log file will continue to grow over time. It is a good idea -to periodically erase the log file. - -# Debug level - -This is a special feature mainly for developers. If you are planning to "hack" this code, you can -utilize this feature to assist with debugging existing or new code. The available debug levels -do not operate like the logging levels. For operational use, the debug level is usually OFF. You -can use the MESSAGE level to simply emit messsages for debugging. The debug level RAISE, can emit a -message and then raise a python exception. This can normally be done in a try/except block where you -can try a bit of code and in the except block raise the exception after emitting a debugging message. -The last level is BREAKPOINT. This is similar to RAISE except that after the message is emitted, the -program will attempt to start the python debugger (pdb) using `pdb.set_trace()`. All messages sent -via `GridUtils.debugMsg()` are shown at the DEBUG level. - -Please review the [mkGridsExample2.py](../gridTools/mkGridsExample2.py) -python script for an example on how to work with the -messaging and logging portion of the library. - -If you discover a bug or problem with the, we will want to be provided as much -information as possible to help us fix the issue. Please see the -[reporting](Reporting.md) section of the user manual to assist developers. diff --git a/conda/docs/manual/Reporting.md b/conda/docs/manual/Reporting.md deleted file mode 100644 index 7433dfa..0000000 --- a/conda/docs/manual/Reporting.md +++ /dev/null @@ -1,30 +0,0 @@ -# Reporting - -Found a BUG? We love bugs as much as we love grids! - -It is very helpful to tell us as much as possible about the situation -that triggers this bug. It is helpful if the developers can -`reproduce` the bug on our systems. - -What information is helpful: - * What software are you using? - * Application? - * Writing your own script? - * Please provide a copy of your code and any input files - * Large files may require other means to provide access - * Please describe the steps to reproduce the problem or error - * Please provide as much as possible - * Cut and paste error messages; provide log output - * Screenshots can be useful - * Copies of code, input and output files - * If you have a solution to the problem - * Code may be submitted in the form of a github pull request - * Other useful information - * Windows or Unix/Linux (`uname -a`) - * Python and other module versions - * Use the sysinfo module to provide python and module information. See mkGridsExample2.py for an example of use. The - sysinfo module only works for conda based environments. - -After all the information is collected, it is helpful to file an -[issue](https://github.com/ESMG/gridtools/issues) -on the github repository for tracking purposes. diff --git a/conda/docs/resources/Bathymetry.md b/conda/docs/resources/Bathymetry.md deleted file mode 100644 index 1a3d701..0000000 --- a/conda/docs/resources/Bathymetry.md +++ /dev/null @@ -1,24 +0,0 @@ -# Bathymetry - -# GEBCO - -[GEBCO](https://www.gebco.net/data_and_products/gridded_bathymetry_data/) - -The GEBCO grid can be assumed to be relative to WGS84. - -## Web Mapping Service - -https://www.gebco.net/data_and_products/gebco_web_services/web_map_service/ -https://www.gebco.net/data_and_products/gebco_web_services/web_map_service/mapserv? - -Layers: - * GEBCO_Latest - shaded relief imagery - * GEBCO_Latest_2 - colour-shaded for elevation imagery - * GEBCO_Lastest_TID - imagery based on the TID grid with grid cells based on interpolation transparent - -# IBCAO - -[IBCAO](https://www.gebco.net/data_and_products/gridded_bathymetry_data/arctic_ocean/) - -This grid is North Polar Stereo. -The true scale latitude is 75 North. diff --git a/docs/development/CHANGELOG.md b/docs/development/CHANGELOG.md index 29f6871..94fc10b 100644 --- a/docs/development/CHANGELOG.md +++ b/docs/development/CHANGELOG.md @@ -1,7 +1,16 @@ # Change Log +# 2021-05-20 + + - Add a few informational links + - Update to push exp/bathyV1 + # 2021-05-18 + - Add info on running dask in a cluster environment + - Delete duplicate conda/docs directory; not sure how that got there + - Create exp/bathyV1 branch + - Merge https://github.com/ESMG/gridtools/pull/1 - Finish out documentation updates for PR#1 # 2021-05-17 diff --git a/docs/development/ImportantReferences.md b/docs/development/ImportantReferences.md index 4979c01..58cab0a 100644 --- a/docs/development/ImportantReferences.md +++ b/docs/development/ImportantReferences.md @@ -18,9 +18,9 @@ These are people, references and bookmarks that provided useful information to m * Lambert Conformal Conic grid generation provided by: https://github.com/nikizadehgfdl/grid_generation/blob/dev/jupynotebooks/regional_grid_spherical.ipynb -## mapx - * NSIDC Map Transformations Library (Mapx) - https://nsidc.org/support/42415620-Mapx-Map-Transformations-Library + * A set of tools to generate model topography given model grid and observation data: + Branch: create_spear_grid (generates tri-polar grids) + https://github.com/nikizadehgfdl/ocean_model_topog_generator ## Bookmarks * https://www.digitalocean.com/community/tutorials/how-to-use-args-and-kwargs-in-python-3 @@ -33,7 +33,9 @@ These are people, references and bookmarks that provided useful information to m * https://docs.pytest.org/en/6.2.x/skipping.html * https://en.wikipedia.org/wiki/Arakawa_grids * https://en.wikipedia.org/wiki/World_Geodetic_System + * https://edbennett.github.io/high-performance-python/11-dask/index.html * https://geohackweek.github.io/nDarrays/09-masking/ + * https://www.git-tower.com/learn/git/faq/delete-remote-branch/ * https://github.com/binder-examples/conda * https://github.com/marketplace/actions/setup-miniconda * https://github.com/SciTools/cartopy/issues/787 @@ -44,11 +46,15 @@ These are people, references and bookmarks that provided useful information to m * https://matplotlib.org/stable/gallery/images_contours_and_fields/pcolormesh_grids.html#sphx-glr-gallery-images-contours-and-fields-pcolormesh-grids-py * https://matplotlib.org/stable/tutorials/colors/colormaps.html * https://matplotlib.org/stable/tutorials/colors/colorbar_only.html#sphx-glr-tutorials-colors-colorbar-only-py + * https://mpi4py.readthedocs.io/en/stable/tutorial.html + * https://nsidc.org/support/42415620-Mapx-Map-Transformations-Library * https://panel.holoviz.org/gallery/index.html + * https://pangeo-xesmf.readthedocs.io/en/latest/large_problems_on_HPC.html#technical-point-mpi4py-considerations * https://pangeo-xesmf.readthedocs.io/en/latest/notebooks/Compare_algorithms.html * https://rabernat.github.io/research_computing/xarray.html * https://rabernat.github.io/research_computing_2018/maps-with-cartopy.html * https://realpython.com/python-bindings-overview/ + * https://researchcomputing.princeton.edu/support/knowledge-base/mpi4py * https://rietta.com/blog/github-merge-types/ * https://scitools.org.uk/cartopy/docs/latest/index.html * https://scitools.org.uk/cartopy/docs/latest/crs/projections.html diff --git a/docs/development/TODO.md b/docs/development/TODO.md index b8b37a5..c23e3fc 100644 --- a/docs/development/TODO.md +++ b/docs/development/TODO.md @@ -35,6 +35,7 @@ - [ ] Subset existing grids and infrastructure # BUGS + - [ ] app:Remote Files does not save the grid in the specified directory - [ ] A nested dictionary will clobber other nested elements instead of updating elements. Recode `setPlotParameters` and `setGridParameters` to recursively update dictionary elements. @@ -76,7 +77,7 @@ - [ ] xesmf regridder - [X] add nbserverproxy/xgcm to conda software stacks; copied to binder environment.yml - [ ] include a dump of conda environment in the grid file (nc) - - [ ] Add option to use Alistair's numpypi package as a configurable option in gridtools + - [ ] Add option to use numpypi package (Alistair) as a configurable option in gridtools - [X] turn numpypi into a loadable package via pip - [X] add datashader and numpypi from github sources; see postBuild script - [ ] implement and document in application @@ -153,7 +154,10 @@ - [ ] Allow conversion of MOM6 grids to ROMS grids - [ ] grid reading and plot parameter defaults should be dynamic with grid type declaration and potentially split out into separate library modules? lib/gridTools/grids/{MOM6,ROMS,WRF} - - [ ] Place additional projection metadata into MOM6 grid files + - [ ] Place additional metadata into MOM6 grid files + - [X] Grid parameters + - [X] Software stack, git information + - [ ] Alternate version/software capture if conda and/or git is not available - [X] Added proj string to netCDF file - [ ] Tri polar grid description - [ ] Work with generic non-mapping reference systems for use with some of the sample MOM6 problems @@ -183,4 +187,4 @@ - [ ] https://github.com/MackenzieBlanusa/OHC_CMIP6 - [ ] https://github.com/xarray-contrib/cf-xarray - [ ] https://github.com/jbusecke/cmip6_preprocessing - + - [ ] triton node issue: python netCDF4 large file reading seems to hang nodes diff --git a/examples/mkGridInteractive.ipynb b/examples/mkGridInteractive.ipynb index 259786f..b75b471 100644 --- a/examples/mkGridInteractive.ipynb +++ b/examples/mkGridInteractive.ipynb @@ -2,10 +2,421 @@ "cells": [ { "cell_type": "code", - "execution_count": null, + "execution_count": 1, "id": "a655cdec", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "application/javascript": [ + "\n", + "(function(root) {\n", + " function now() {\n", + " return new Date();\n", + " }\n", + "\n", + " var force = true;\n", + "\n", + " if (typeof root._bokeh_onload_callbacks === \"undefined\" || force === true) {\n", + " root._bokeh_onload_callbacks = [];\n", + " root._bokeh_is_loading = undefined;\n", + " }\n", + "\n", + " if (typeof (root._bokeh_timeout) === \"undefined\" || force === true) {\n", + " root._bokeh_timeout = Date.now() + 5000;\n", + " root._bokeh_failed_load = false;\n", + " }\n", + "\n", + " function run_callbacks() {\n", + " try {\n", + " root._bokeh_onload_callbacks.forEach(function(callback) {\n", + " if (callback != null)\n", + " callback();\n", + " });\n", + " } finally {\n", + " delete root._bokeh_onload_callbacks\n", + " }\n", + " console.debug(\"Bokeh: all callbacks have finished\");\n", + " }\n", + "\n", + " function load_libs(css_urls, js_urls, js_modules, callback) {\n", + " if (css_urls == null) css_urls = [];\n", + " if (js_urls == null) js_urls = [];\n", + " if (js_modules == null) js_modules = [];\n", + "\n", + " root._bokeh_onload_callbacks.push(callback);\n", + " if (root._bokeh_is_loading > 0) {\n", + " console.debug(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n", + " return null;\n", + " }\n", + " if (js_urls.length === 0 && js_modules.length === 0) {\n", + " run_callbacks();\n", + " return null;\n", + " }\n", + " console.debug(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n", + " root._bokeh_is_loading = css_urls.length + js_urls.length + js_modules.length;\n", + "\n", + " function on_load() {\n", + " root._bokeh_is_loading--;\n", + " if (root._bokeh_is_loading === 0) {\n", + " console.debug(\"Bokeh: all BokehJS libraries/stylesheets loaded\");\n", + " run_callbacks()\n", + " }\n", + " }\n", + "\n", + " function on_error() {\n", + " console.error(\"failed to load \" + url);\n", + " }\n", + "\n", + " for (var i = 0; i < css_urls.length; i++) {\n", + " var url = css_urls[i];\n", + " const element = document.createElement(\"link\");\n", + " element.onload = on_load;\n", + " element.onerror = on_error;\n", + " element.rel = \"stylesheet\";\n", + " element.type = \"text/css\";\n", + " element.href = url;\n", + " console.debug(\"Bokeh: injecting link tag for BokehJS stylesheet: \", url);\n", + " document.body.appendChild(element);\n", + " }\n", + "\n", + " var skip = [];\n", + " if (window.requirejs) {\n", + " window.requirejs.config({'paths': {'tabulator': 'https://unpkg.com/tabulator-tables@4.9.3/dist/js/tabulator'}});\n", + " require([\"tabulator\"], function(Tabulator,) {\n", + " window.Tabulator = Tabulator;\n", + " })\n", + " }\n", + " if (((window['tabulator'] !== undefined) && (!(window['tabulator'] instanceof HTMLElement))) || window.requirejs) {\n", + " var urls = ['https://unpkg.com/tabulator-tables@4.9.3/dist/js/tabulator.js', 'https://unpkg.com/moment@2.27.0/moment.js'];\n", + " for (var i = 0; i < urls.length; i++) {\n", + " skip.push(urls[i])\n", + " }\n", + " }\n", + " for (var i = 0; i < js_urls.length; i++) {\n", + " var url = js_urls[i];\n", + " if (skip.indexOf(url) >= 0) { on_load(); continue; }\n", + " var element = document.createElement('script');\n", + " element.onload = on_load;\n", + " element.onerror = on_error;\n", + " element.async = false;\n", + " element.src = url;\n", + " console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n", + " document.head.appendChild(element);\n", + " }\n", + " for (var i = 0; i < js_modules.length; i++) {\n", + " var url = js_modules[i];\n", + " if (skip.indexOf(url) >= 0) { on_load(); continue; }\n", + " var element = document.createElement('script');\n", + " element.onload = on_load;\n", + " element.onerror = on_error;\n", + " element.async = false;\n", + " element.src = url;\n", + " element.type = \"module\";\n", + " console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n", + " document.head.appendChild(element);\n", + " }\n", + " if (!js_urls.length && !js_modules.length) {\n", + " on_load()\n", + " }\n", + " };\n", + "\n", + " function inject_raw_css(css) {\n", + " const element = document.createElement(\"style\");\n", + " element.appendChild(document.createTextNode(css));\n", + " document.body.appendChild(element);\n", + " }\n", + "\n", + " var js_urls = [\"https://unpkg.com/tabulator-tables@4.9.3/dist/js/tabulator.js\", \"https://unpkg.com/moment@2.27.0/moment.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-2.3.2.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-widgets-2.3.2.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-tables-2.3.2.min.js\", \"https://unpkg.com/@holoviz/panel@^0.11.3/dist/panel.min.js\"];\n", + " var js_modules = [];\n", + " var css_urls = [\"https://unpkg.com/tabulator-tables@4.9.3/dist/css/tabulator_simple.min.css\", \"https://unpkg.com/@holoviz/panel@0.11.3/dist/css/card.css\", \"https://unpkg.com/@holoviz/panel@0.11.3/dist/css/widgets.css\", \"https://unpkg.com/@holoviz/panel@0.11.3/dist/css/markdown.css\", \"https://unpkg.com/@holoviz/panel@0.11.3/dist/css/json.css\", \"https://unpkg.com/@holoviz/panel@0.11.3/dist/css/dataframe.css\", \"https://unpkg.com/@holoviz/panel@0.11.3/dist/css/alerts.css\", \"https://unpkg.com/@holoviz/panel@0.11.3/dist/css/loading.css\"];\n", + " var inline_js = [\n", + " function(Bokeh) {\n", + " inject_raw_css(\"\\n .bk.pn-loading.arcs:before {\\n background-image: url(\\\"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiBzdHlsZT0ibWFyZ2luOiBhdXRvOyBiYWNrZ3JvdW5kOiBub25lOyBkaXNwbGF5OiBibG9jazsgc2hhcGUtcmVuZGVyaW5nOiBhdXRvOyIgdmlld0JveD0iMCAwIDEwMCAxMDAiIHByZXNlcnZlQXNwZWN0UmF0aW89InhNaWRZTWlkIj4gIDxjaXJjbGUgY3g9IjUwIiBjeT0iNTAiIHI9IjMyIiBzdHJva2Utd2lkdGg9IjgiIHN0cm9rZT0iI2MzYzNjMyIgc3Ryb2tlLWRhc2hhcnJheT0iNTAuMjY1NDgyNDU3NDM2NjkgNTAuMjY1NDgyNDU3NDM2NjkiIGZpbGw9Im5vbmUiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCI+ICAgIDxhbmltYXRlVHJhbnNmb3JtIGF0dHJpYnV0ZU5hbWU9InRyYW5zZm9ybSIgdHlwZT0icm90YXRlIiByZXBlYXRDb3VudD0iaW5kZWZpbml0ZSIgZHVyPSIxcyIga2V5VGltZXM9IjA7MSIgdmFsdWVzPSIwIDUwIDUwOzM2MCA1MCA1MCI+PC9hbmltYXRlVHJhbnNmb3JtPiAgPC9jaXJjbGU+PC9zdmc+\\\")\\n }\\n \");\n", + " },\n", + " function(Bokeh) {\n", + " Bokeh.set_log_level(\"info\");\n", + " },\n", + " function(Bokeh) {} // ensure no trailing comma for IE\n", + " ];\n", + "\n", + " function run_inline_js() {\n", + " if ((root.Bokeh !== undefined) || (force === true)) {\n", + " for (var i = 0; i < inline_js.length; i++) {\n", + " inline_js[i].call(root, root.Bokeh);\n", + " }} else if (Date.now() < root._bokeh_timeout) {\n", + " setTimeout(run_inline_js, 100);\n", + " } else if (!root._bokeh_failed_load) {\n", + " console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n", + " root._bokeh_failed_load = true;\n", + " }\n", + " }\n", + "\n", + " if (root._bokeh_is_loading === 0) {\n", + " console.debug(\"Bokeh: BokehJS loaded, going straight to plotting\");\n", + " run_inline_js();\n", + " } else {\n", + " load_libs(css_urls, js_urls, js_modules, function() {\n", + " console.debug(\"Bokeh: BokehJS plotting callback run at\", now());\n", + " run_inline_js();\n", + " });\n", + " }\n", + "}(window));" + ], + "application/vnd.holoviews_load.v0+json": "\n(function(root) {\n function now() {\n return new Date();\n }\n\n var force = true;\n\n if (typeof root._bokeh_onload_callbacks === \"undefined\" || force === true) {\n root._bokeh_onload_callbacks = [];\n root._bokeh_is_loading = undefined;\n }\n\n if (typeof (root._bokeh_timeout) === \"undefined\" || force === true) {\n root._bokeh_timeout = Date.now() + 5000;\n root._bokeh_failed_load = false;\n }\n\n function run_callbacks() {\n try {\n root._bokeh_onload_callbacks.forEach(function(callback) {\n if (callback != null)\n callback();\n });\n } finally {\n delete root._bokeh_onload_callbacks\n }\n console.debug(\"Bokeh: all callbacks have finished\");\n }\n\n function load_libs(css_urls, js_urls, js_modules, callback) {\n if (css_urls == null) css_urls = [];\n if (js_urls == null) js_urls = [];\n if (js_modules == null) js_modules = [];\n\n root._bokeh_onload_callbacks.push(callback);\n if (root._bokeh_is_loading > 0) {\n console.debug(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n return null;\n }\n if (js_urls.length === 0 && js_modules.length === 0) {\n run_callbacks();\n return null;\n }\n console.debug(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n root._bokeh_is_loading = css_urls.length + js_urls.length + js_modules.length;\n\n function on_load() {\n root._bokeh_is_loading--;\n if (root._bokeh_is_loading === 0) {\n console.debug(\"Bokeh: all BokehJS libraries/stylesheets loaded\");\n run_callbacks()\n }\n }\n\n function on_error() {\n console.error(\"failed to load \" + url);\n }\n\n for (var i = 0; i < css_urls.length; i++) {\n var url = css_urls[i];\n const element = document.createElement(\"link\");\n element.onload = on_load;\n element.onerror = on_error;\n element.rel = \"stylesheet\";\n element.type = \"text/css\";\n element.href = url;\n console.debug(\"Bokeh: injecting link tag for BokehJS stylesheet: \", url);\n document.body.appendChild(element);\n }\n\n var skip = [];\n if (window.requirejs) {\n window.requirejs.config({'paths': {'tabulator': 'https://unpkg.com/tabulator-tables@4.9.3/dist/js/tabulator'}});\n require([\"tabulator\"], function(Tabulator,) {\n window.Tabulator = Tabulator;\n })\n }\n if (((window['tabulator'] !== undefined) && (!(window['tabulator'] instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://unpkg.com/tabulator-tables@4.9.3/dist/js/tabulator.js', 'https://unpkg.com/moment@2.27.0/moment.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(urls[i])\n }\n }\n for (var i = 0; i < js_urls.length; i++) {\n var url = js_urls[i];\n if (skip.indexOf(url) >= 0) { on_load(); continue; }\n var element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (var i = 0; i < js_modules.length; i++) {\n var url = js_modules[i];\n if (skip.indexOf(url) >= 0) { on_load(); continue; }\n var element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n if (!js_urls.length && !js_modules.length) {\n on_load()\n }\n };\n\n function inject_raw_css(css) {\n const element = document.createElement(\"style\");\n element.appendChild(document.createTextNode(css));\n document.body.appendChild(element);\n }\n\n var js_urls = [\"https://unpkg.com/tabulator-tables@4.9.3/dist/js/tabulator.js\", \"https://unpkg.com/moment@2.27.0/moment.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-2.3.2.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-widgets-2.3.2.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-tables-2.3.2.min.js\", \"https://unpkg.com/@holoviz/panel@^0.11.3/dist/panel.min.js\"];\n var js_modules = [];\n var css_urls = [\"https://unpkg.com/tabulator-tables@4.9.3/dist/css/tabulator_simple.min.css\", \"https://unpkg.com/@holoviz/panel@0.11.3/dist/css/card.css\", \"https://unpkg.com/@holoviz/panel@0.11.3/dist/css/widgets.css\", \"https://unpkg.com/@holoviz/panel@0.11.3/dist/css/markdown.css\", \"https://unpkg.com/@holoviz/panel@0.11.3/dist/css/json.css\", \"https://unpkg.com/@holoviz/panel@0.11.3/dist/css/dataframe.css\", \"https://unpkg.com/@holoviz/panel@0.11.3/dist/css/alerts.css\", \"https://unpkg.com/@holoviz/panel@0.11.3/dist/css/loading.css\"];\n var inline_js = [\n function(Bokeh) {\n inject_raw_css(\"\\n .bk.pn-loading.arcs:before {\\n background-image: url(\\\"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiBzdHlsZT0ibWFyZ2luOiBhdXRvOyBiYWNrZ3JvdW5kOiBub25lOyBkaXNwbGF5OiBibG9jazsgc2hhcGUtcmVuZGVyaW5nOiBhdXRvOyIgdmlld0JveD0iMCAwIDEwMCAxMDAiIHByZXNlcnZlQXNwZWN0UmF0aW89InhNaWRZTWlkIj4gIDxjaXJjbGUgY3g9IjUwIiBjeT0iNTAiIHI9IjMyIiBzdHJva2Utd2lkdGg9IjgiIHN0cm9rZT0iI2MzYzNjMyIgc3Ryb2tlLWRhc2hhcnJheT0iNTAuMjY1NDgyNDU3NDM2NjkgNTAuMjY1NDgyNDU3NDM2NjkiIGZpbGw9Im5vbmUiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCI+ICAgIDxhbmltYXRlVHJhbnNmb3JtIGF0dHJpYnV0ZU5hbWU9InRyYW5zZm9ybSIgdHlwZT0icm90YXRlIiByZXBlYXRDb3VudD0iaW5kZWZpbml0ZSIgZHVyPSIxcyIga2V5VGltZXM9IjA7MSIgdmFsdWVzPSIwIDUwIDUwOzM2MCA1MCA1MCI+PC9hbmltYXRlVHJhbnNmb3JtPiAgPC9jaXJjbGU+PC9zdmc+\\\")\\n }\\n \");\n },\n function(Bokeh) {\n Bokeh.set_log_level(\"info\");\n },\n function(Bokeh) {} // ensure no trailing comma for IE\n ];\n\n function run_inline_js() {\n if ((root.Bokeh !== undefined) || (force === true)) {\n for (var i = 0; i < inline_js.length; i++) {\n inline_js[i].call(root, root.Bokeh);\n }} else if (Date.now() < root._bokeh_timeout) {\n setTimeout(run_inline_js, 100);\n } else if (!root._bokeh_failed_load) {\n console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n root._bokeh_failed_load = true;\n }\n }\n\n if (root._bokeh_is_loading === 0) {\n console.debug(\"Bokeh: BokehJS loaded, going straight to plotting\");\n run_inline_js();\n } else {\n load_libs(css_urls, js_urls, js_modules, function() {\n console.debug(\"Bokeh: BokehJS plotting callback run at\", now());\n run_inline_js();\n });\n }\n}(window));" + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/javascript": [ + "\n", + "if ((window.PyViz === undefined) || (window.PyViz instanceof HTMLElement)) {\n", + " window.PyViz = {comms: {}, comm_status:{}, kernels:{}, receivers: {}, plot_index: []}\n", + "}\n", + "\n", + "\n", + " function JupyterCommManager() {\n", + " }\n", + "\n", + " JupyterCommManager.prototype.register_target = function(plot_id, comm_id, msg_handler) {\n", + " if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n", + " var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n", + " comm_manager.register_target(comm_id, function(comm) {\n", + " comm.on_msg(msg_handler);\n", + " });\n", + " } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n", + " window.PyViz.kernels[plot_id].registerCommTarget(comm_id, function(comm) {\n", + " comm.onMsg = msg_handler;\n", + " });\n", + " } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n", + " google.colab.kernel.comms.registerTarget(comm_id, (comm) => {\n", + " var messages = comm.messages[Symbol.asyncIterator]();\n", + " function processIteratorResult(result) {\n", + " var message = result.value;\n", + " console.log(message)\n", + " var content = {data: message.data, comm_id};\n", + " var buffers = []\n", + " for (var buffer of message.buffers || []) {\n", + " buffers.push(new DataView(buffer))\n", + " }\n", + " var metadata = message.metadata || {};\n", + " var msg = {content, buffers, metadata}\n", + " msg_handler(msg);\n", + " return messages.next().then(processIteratorResult);\n", + " }\n", + " return messages.next().then(processIteratorResult);\n", + " })\n", + " }\n", + " }\n", + "\n", + " JupyterCommManager.prototype.get_client_comm = function(plot_id, comm_id, msg_handler) {\n", + " if (comm_id in window.PyViz.comms) {\n", + " return window.PyViz.comms[comm_id];\n", + " } else if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n", + " var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n", + " var comm = comm_manager.new_comm(comm_id, {}, {}, {}, comm_id);\n", + " if (msg_handler) {\n", + " comm.on_msg(msg_handler);\n", + " }\n", + " } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n", + " var comm = window.PyViz.kernels[plot_id].connectToComm(comm_id);\n", + " comm.open();\n", + " if (msg_handler) {\n", + " comm.onMsg = msg_handler;\n", + " }\n", + " } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n", + " var comm_promise = google.colab.kernel.comms.open(comm_id)\n", + " comm_promise.then((comm) => {\n", + " window.PyViz.comms[comm_id] = comm;\n", + " if (msg_handler) {\n", + " var messages = comm.messages[Symbol.asyncIterator]();\n", + " function processIteratorResult(result) {\n", + " var message = result.value;\n", + " var content = {data: message.data};\n", + " var metadata = message.metadata || {comm_id};\n", + " var msg = {content, metadata}\n", + " msg_handler(msg);\n", + " return messages.next().then(processIteratorResult);\n", + " }\n", + " return messages.next().then(processIteratorResult);\n", + " }\n", + " }) \n", + " var sendClosure = (data, metadata, buffers, disposeOnDone) => {\n", + " return comm_promise.then((comm) => {\n", + " comm.send(data, metadata, buffers, disposeOnDone);\n", + " });\n", + " };\n", + " var comm = {\n", + " send: sendClosure\n", + " };\n", + " }\n", + " window.PyViz.comms[comm_id] = comm;\n", + " return comm;\n", + " }\n", + " window.PyViz.comm_manager = new JupyterCommManager();\n", + " \n", + "\n", + "\n", + "var JS_MIME_TYPE = 'application/javascript';\n", + "var HTML_MIME_TYPE = 'text/html';\n", + "var EXEC_MIME_TYPE = 'application/vnd.holoviews_exec.v0+json';\n", + "var CLASS_NAME = 'output';\n", + "\n", + "/**\n", + " * Render data to the DOM node\n", + " */\n", + "function render(props, node) {\n", + " var div = document.createElement(\"div\");\n", + " var script = document.createElement(\"script\");\n", + " node.appendChild(div);\n", + " node.appendChild(script);\n", + "}\n", + "\n", + "/**\n", + " * Handle when a new output is added\n", + " */\n", + "function handle_add_output(event, handle) {\n", + " var output_area = handle.output_area;\n", + " var output = handle.output;\n", + " if ((output.data == undefined) || (!output.data.hasOwnProperty(EXEC_MIME_TYPE))) {\n", + " return\n", + " }\n", + " var id = output.metadata[EXEC_MIME_TYPE][\"id\"];\n", + " var toinsert = output_area.element.find(\".\" + CLASS_NAME.split(' ')[0]);\n", + " if (id !== undefined) {\n", + " var nchildren = toinsert.length;\n", + " var html_node = toinsert[nchildren-1].children[0];\n", + " html_node.innerHTML = output.data[HTML_MIME_TYPE];\n", + " var scripts = [];\n", + " var nodelist = html_node.querySelectorAll(\"script\");\n", + " for (var i in nodelist) {\n", + " if (nodelist.hasOwnProperty(i)) {\n", + " scripts.push(nodelist[i])\n", + " }\n", + " }\n", + "\n", + " scripts.forEach( function (oldScript) {\n", + " var newScript = document.createElement(\"script\");\n", + " var attrs = [];\n", + " var nodemap = oldScript.attributes;\n", + " for (var j in nodemap) {\n", + " if (nodemap.hasOwnProperty(j)) {\n", + " attrs.push(nodemap[j])\n", + " }\n", + " }\n", + " attrs.forEach(function(attr) { newScript.setAttribute(attr.name, attr.value) });\n", + " newScript.appendChild(document.createTextNode(oldScript.innerHTML));\n", + " oldScript.parentNode.replaceChild(newScript, oldScript);\n", + " });\n", + " if (JS_MIME_TYPE in output.data) {\n", + " toinsert[nchildren-1].children[1].textContent = output.data[JS_MIME_TYPE];\n", + " }\n", + " output_area._hv_plot_id = id;\n", + " if ((window.Bokeh !== undefined) && (id in Bokeh.index)) {\n", + " window.PyViz.plot_index[id] = Bokeh.index[id];\n", + " } else {\n", + " window.PyViz.plot_index[id] = null;\n", + " }\n", + " } else if (output.metadata[EXEC_MIME_TYPE][\"server_id\"] !== undefined) {\n", + " var bk_div = document.createElement(\"div\");\n", + " bk_div.innerHTML = output.data[HTML_MIME_TYPE];\n", + " var script_attrs = bk_div.children[0].attributes;\n", + " for (var i = 0; i < script_attrs.length; i++) {\n", + " toinsert[toinsert.length - 1].childNodes[1].setAttribute(script_attrs[i].name, script_attrs[i].value);\n", + " }\n", + " // store reference to server id on output_area\n", + " output_area._bokeh_server_id = output.metadata[EXEC_MIME_TYPE][\"server_id\"];\n", + " }\n", + "}\n", + "\n", + "/**\n", + " * Handle when an output is cleared or removed\n", + " */\n", + "function handle_clear_output(event, handle) {\n", + " var id = handle.cell.output_area._hv_plot_id;\n", + " var server_id = handle.cell.output_area._bokeh_server_id;\n", + " if (((id === undefined) || !(id in PyViz.plot_index)) && (server_id !== undefined)) { return; }\n", + " var comm = window.PyViz.comm_manager.get_client_comm(\"hv-extension-comm\", \"hv-extension-comm\", function () {});\n", + " if (server_id !== null) {\n", + " comm.send({event_type: 'server_delete', 'id': server_id});\n", + " return;\n", + " } else if (comm !== null) {\n", + " comm.send({event_type: 'delete', 'id': id});\n", + " }\n", + " delete PyViz.plot_index[id];\n", + " if ((window.Bokeh !== undefined) & (id in window.Bokeh.index)) {\n", + " var doc = window.Bokeh.index[id].model.document\n", + " doc.clear();\n", + " const i = window.Bokeh.documents.indexOf(doc);\n", + " if (i > -1) {\n", + " window.Bokeh.documents.splice(i, 1);\n", + " }\n", + " }\n", + "}\n", + "\n", + "/**\n", + " * Handle kernel restart event\n", + " */\n", + "function handle_kernel_cleanup(event, handle) {\n", + " delete PyViz.comms[\"hv-extension-comm\"];\n", + " window.PyViz.plot_index = {}\n", + "}\n", + "\n", + "/**\n", + " * Handle update_display_data messages\n", + " */\n", + "function handle_update_output(event, handle) {\n", + " handle_clear_output(event, {cell: {output_area: handle.output_area}})\n", + " handle_add_output(event, handle)\n", + "}\n", + "\n", + "function register_renderer(events, OutputArea) {\n", + " function append_mime(data, metadata, element) {\n", + " // create a DOM node to render to\n", + " var toinsert = this.create_output_subarea(\n", + " metadata,\n", + " CLASS_NAME,\n", + " EXEC_MIME_TYPE\n", + " );\n", + " this.keyboard_manager.register_events(toinsert);\n", + " // Render to node\n", + " var props = {data: data, metadata: metadata[EXEC_MIME_TYPE]};\n", + " render(props, toinsert[0]);\n", + " element.append(toinsert);\n", + " return toinsert\n", + " }\n", + "\n", + " events.on('output_added.OutputArea', handle_add_output);\n", + " events.on('output_updated.OutputArea', handle_update_output);\n", + " events.on('clear_output.CodeCell', handle_clear_output);\n", + " events.on('delete.Cell', handle_clear_output);\n", + " events.on('kernel_ready.Kernel', handle_kernel_cleanup);\n", + "\n", + " OutputArea.prototype.register_mime_type(EXEC_MIME_TYPE, append_mime, {\n", + " safe: true,\n", + " index: 0\n", + " });\n", + "}\n", + "\n", + "if (window.Jupyter !== undefined) {\n", + " try {\n", + " var events = require('base/js/events');\n", + " var OutputArea = require('notebook/js/outputarea').OutputArea;\n", + " if (OutputArea.prototype.mime_types().indexOf(EXEC_MIME_TYPE) == -1) {\n", + " register_renderer(events, OutputArea);\n", + " }\n", + " } catch(err) {\n", + " }\n", + "}\n" + ], + "application/vnd.holoviews_load.v0+json": "\nif ((window.PyViz === undefined) || (window.PyViz instanceof HTMLElement)) {\n window.PyViz = {comms: {}, comm_status:{}, kernels:{}, receivers: {}, plot_index: []}\n}\n\n\n function JupyterCommManager() {\n }\n\n JupyterCommManager.prototype.register_target = function(plot_id, comm_id, msg_handler) {\n if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n comm_manager.register_target(comm_id, function(comm) {\n comm.on_msg(msg_handler);\n });\n } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n window.PyViz.kernels[plot_id].registerCommTarget(comm_id, function(comm) {\n comm.onMsg = msg_handler;\n });\n } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n google.colab.kernel.comms.registerTarget(comm_id, (comm) => {\n var messages = comm.messages[Symbol.asyncIterator]();\n function processIteratorResult(result) {\n var message = result.value;\n console.log(message)\n var content = {data: message.data, comm_id};\n var buffers = []\n for (var buffer of message.buffers || []) {\n buffers.push(new DataView(buffer))\n }\n var metadata = message.metadata || {};\n var msg = {content, buffers, metadata}\n msg_handler(msg);\n return messages.next().then(processIteratorResult);\n }\n return messages.next().then(processIteratorResult);\n })\n }\n }\n\n JupyterCommManager.prototype.get_client_comm = function(plot_id, comm_id, msg_handler) {\n if (comm_id in window.PyViz.comms) {\n return window.PyViz.comms[comm_id];\n } else if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n var comm = comm_manager.new_comm(comm_id, {}, {}, {}, comm_id);\n if (msg_handler) {\n comm.on_msg(msg_handler);\n }\n } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n var comm = window.PyViz.kernels[plot_id].connectToComm(comm_id);\n comm.open();\n if (msg_handler) {\n comm.onMsg = msg_handler;\n }\n } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n var comm_promise = google.colab.kernel.comms.open(comm_id)\n comm_promise.then((comm) => {\n window.PyViz.comms[comm_id] = comm;\n if (msg_handler) {\n var messages = comm.messages[Symbol.asyncIterator]();\n function processIteratorResult(result) {\n var message = result.value;\n var content = {data: message.data};\n var metadata = message.metadata || {comm_id};\n var msg = {content, metadata}\n msg_handler(msg);\n return messages.next().then(processIteratorResult);\n }\n return messages.next().then(processIteratorResult);\n }\n }) \n var sendClosure = (data, metadata, buffers, disposeOnDone) => {\n return comm_promise.then((comm) => {\n comm.send(data, metadata, buffers, disposeOnDone);\n });\n };\n var comm = {\n send: sendClosure\n };\n }\n window.PyViz.comms[comm_id] = comm;\n return comm;\n }\n window.PyViz.comm_manager = new JupyterCommManager();\n \n\n\nvar JS_MIME_TYPE = 'application/javascript';\nvar HTML_MIME_TYPE = 'text/html';\nvar EXEC_MIME_TYPE = 'application/vnd.holoviews_exec.v0+json';\nvar CLASS_NAME = 'output';\n\n/**\n * Render data to the DOM node\n */\nfunction render(props, node) {\n var div = document.createElement(\"div\");\n var script = document.createElement(\"script\");\n node.appendChild(div);\n node.appendChild(script);\n}\n\n/**\n * Handle when a new output is added\n */\nfunction handle_add_output(event, handle) {\n var output_area = handle.output_area;\n var output = handle.output;\n if ((output.data == undefined) || (!output.data.hasOwnProperty(EXEC_MIME_TYPE))) {\n return\n }\n var id = output.metadata[EXEC_MIME_TYPE][\"id\"];\n var toinsert = output_area.element.find(\".\" + CLASS_NAME.split(' ')[0]);\n if (id !== undefined) {\n var nchildren = toinsert.length;\n var html_node = toinsert[nchildren-1].children[0];\n html_node.innerHTML = output.data[HTML_MIME_TYPE];\n var scripts = [];\n var nodelist = html_node.querySelectorAll(\"script\");\n for (var i in nodelist) {\n if (nodelist.hasOwnProperty(i)) {\n scripts.push(nodelist[i])\n }\n }\n\n scripts.forEach( function (oldScript) {\n var newScript = document.createElement(\"script\");\n var attrs = [];\n var nodemap = oldScript.attributes;\n for (var j in nodemap) {\n if (nodemap.hasOwnProperty(j)) {\n attrs.push(nodemap[j])\n }\n }\n attrs.forEach(function(attr) { newScript.setAttribute(attr.name, attr.value) });\n newScript.appendChild(document.createTextNode(oldScript.innerHTML));\n oldScript.parentNode.replaceChild(newScript, oldScript);\n });\n if (JS_MIME_TYPE in output.data) {\n toinsert[nchildren-1].children[1].textContent = output.data[JS_MIME_TYPE];\n }\n output_area._hv_plot_id = id;\n if ((window.Bokeh !== undefined) && (id in Bokeh.index)) {\n window.PyViz.plot_index[id] = Bokeh.index[id];\n } else {\n window.PyViz.plot_index[id] = null;\n }\n } else if (output.metadata[EXEC_MIME_TYPE][\"server_id\"] !== undefined) {\n var bk_div = document.createElement(\"div\");\n bk_div.innerHTML = output.data[HTML_MIME_TYPE];\n var script_attrs = bk_div.children[0].attributes;\n for (var i = 0; i < script_attrs.length; i++) {\n toinsert[toinsert.length - 1].childNodes[1].setAttribute(script_attrs[i].name, script_attrs[i].value);\n }\n // store reference to server id on output_area\n output_area._bokeh_server_id = output.metadata[EXEC_MIME_TYPE][\"server_id\"];\n }\n}\n\n/**\n * Handle when an output is cleared or removed\n */\nfunction handle_clear_output(event, handle) {\n var id = handle.cell.output_area._hv_plot_id;\n var server_id = handle.cell.output_area._bokeh_server_id;\n if (((id === undefined) || !(id in PyViz.plot_index)) && (server_id !== undefined)) { return; }\n var comm = window.PyViz.comm_manager.get_client_comm(\"hv-extension-comm\", \"hv-extension-comm\", function () {});\n if (server_id !== null) {\n comm.send({event_type: 'server_delete', 'id': server_id});\n return;\n } else if (comm !== null) {\n comm.send({event_type: 'delete', 'id': id});\n }\n delete PyViz.plot_index[id];\n if ((window.Bokeh !== undefined) & (id in window.Bokeh.index)) {\n var doc = window.Bokeh.index[id].model.document\n doc.clear();\n const i = window.Bokeh.documents.indexOf(doc);\n if (i > -1) {\n window.Bokeh.documents.splice(i, 1);\n }\n }\n}\n\n/**\n * Handle kernel restart event\n */\nfunction handle_kernel_cleanup(event, handle) {\n delete PyViz.comms[\"hv-extension-comm\"];\n window.PyViz.plot_index = {}\n}\n\n/**\n * Handle update_display_data messages\n */\nfunction handle_update_output(event, handle) {\n handle_clear_output(event, {cell: {output_area: handle.output_area}})\n handle_add_output(event, handle)\n}\n\nfunction register_renderer(events, OutputArea) {\n function append_mime(data, metadata, element) {\n // create a DOM node to render to\n var toinsert = this.create_output_subarea(\n metadata,\n CLASS_NAME,\n EXEC_MIME_TYPE\n );\n this.keyboard_manager.register_events(toinsert);\n // Render to node\n var props = {data: data, metadata: metadata[EXEC_MIME_TYPE]};\n render(props, toinsert[0]);\n element.append(toinsert);\n return toinsert\n }\n\n events.on('output_added.OutputArea', handle_add_output);\n events.on('output_updated.OutputArea', handle_update_output);\n events.on('clear_output.CodeCell', handle_clear_output);\n events.on('delete.Cell', handle_clear_output);\n events.on('kernel_ready.Kernel', handle_kernel_cleanup);\n\n OutputArea.prototype.register_mime_type(EXEC_MIME_TYPE, append_mime, {\n safe: true,\n index: 0\n });\n}\n\nif (window.Jupyter !== undefined) {\n try {\n var events = require('base/js/events');\n var OutputArea = require('notebook/js/outputarea').OutputArea;\n if (OutputArea.prototype.mime_types().indexOf(EXEC_MIME_TYPE) == -1) {\n register_renderer(events, OutputArea);\n }\n } catch(err) {\n }\n}\n" + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ "# conda: gridTools\n", "\n", @@ -37,7 +448,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, "id": "fa2aa824", "metadata": {}, "outputs": [], @@ -49,7 +460,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 3, "id": "d25fb0f1", "metadata": {}, "outputs": [], @@ -60,7 +471,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 4, "id": "cb355fac", "metadata": {}, "outputs": [], @@ -71,7 +482,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 5, "id": "e8c126ae", "metadata": {}, "outputs": [], @@ -81,7 +492,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 6, "id": "1c968a37", "metadata": {}, "outputs": [], @@ -92,7 +503,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 7, "id": "4a258c5a", "metadata": {}, "outputs": [], @@ -103,10 +514,23 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 8, "id": "b232aac6", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/html": [ + "" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ "if useDisplay:\n", " # Need to expand width of cells in Binder\n", @@ -116,10 +540,177 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 9, "id": "7df0478f", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": {}, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.holoviews_exec.v0+json": "", + "text/html": [ + "
\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
\n", + "
\n", + "" + ], + "text/plain": [ + "WidgetBox\n", + " [0] Column(sizing_mode='stretch_width', width_policy='max')\n", + " [0] Row\n", + " [0] Button(button_type='primary', height=50, name='Clear Information', sizing_mode='fixed', width=125)\n", + " [1] TextAreaInput(background='skyblue', height=100, name='Information', sizing_mode='fixed', value='GridUtils application i..., width=900)\n", + " [1] Row\n", + " [0] Tabs\n", + " [0] Tabs\n", + " [0] WidgetBox\n", + " [0] Markdown(str)\n", + " [1] Select(name='Projection', options=['Nearside Perspective', ...], value='Nearside Perspective')\n", + " [2] FloatInput(end=360.0, name='Central Longitude(lon_0) ..., start=0.0, step=1.0, value=230.0, width=100)\n", + " [3] FloatInput(end=90.0, name='Central Latitude(lat_0) (..., start=-90.0, step=1.0, value=40.0, width=100)\n", + " [4] FloatInput(end=90.0, name='First Parallel(lat_1) (..., start=-90.0, step=1.0, value=40.0, width=100)\n", + " [5] FloatInput(end=90.0, name='Second Parallel(lat_2) (..., start=-90.0, step=1.0, value=40.0, width=100)\n", + " [6] FloatInput(end=90.0, name='Latitude of T..., start=-90.0, step=1.0, value=40.0, width=100)\n", + " [7] Button(button_type='primary', name='Plot')\n", + " [1] WidgetBox\n", + " [0] Markdown(str)\n", + " [1] FloatInput(end=180.0, name='Longitude(x0) (..., start=-180.0, step=1.0, value=-160.0, width=100)\n", + " [2] FloatInput(end=180.0, name='Longitude(x1) (..., start=-180.0, step=1.0, value=-100.0, width=100)\n", + " [3] FloatInput(end=90.0, name='Latitude(y0) (..., start=-90.0, step=1.0, value=20.0, width=100)\n", + " [4] FloatInput(end=90.0, name='Latitude(y1) (..., start=-90.0, step=1.0, value=60.0, width=100)\n", + " [5] Checkbox(name='Use global extent (...)\n", + " [6] Button(button_type='primary', name='Plot')\n", + " [2] WidgetBox\n", + " [0] Markdown(str)\n", + " [1] TextInput(name='Plot title', width=250)\n", + " [2] Select(name='Grid Style', options=['Grid Extent', ...], value='Grid Cells')\n", + " [3] Select(name='x Color', options=['Blue', 'Cyan', ...], value='Black')\n", + " [4] Select(name='y Color', options=['Blue', 'Cyan', ...], value='Black')\n", + " [5] FloatInput(end=10.0, name='x Line Width', start=0.01, value=1.0, width=80)\n", + " [6] FloatInput(end=10.0, name='y Line Width', start=0.01, value=1.0, width=80)\n", + " [7] Button(button_type='primary', name='Plot')\n", + " [1] Tabs\n", + " [0] WidgetBox\n", + " [0] Markdown(str)\n", + " [1] FloatInput(end=360.0, name='Grid Center(Longitude o..., start=0.0, value=230.0, width=100)\n", + " [2] FloatInput(end=90.0, name='Grid Center(Latitude o..., start=0.0, value=40.0, width=100)\n", + " [3] Select(name='Grid Center Units', options=['degrees', 'meters'], value='degrees')\n", + " [4] Button(button_type='primary', name='Make Grid')\n", + " [1] WidgetBox\n", + " [0] Markdown(str)\n", + " [1] Select(name='Projection', options=['Mercator', 'Lambert Conf...], value='Lambert Conformal Conic')\n", + " [2] FloatInput(end=360.0, name='Central Longitude(lon_0) ..., start=0.0, step=1.0, value=230.0, width=100)\n", + " [3] FloatInput(end=90.0, name='Central Latitude(lat_0) (..., start=-90.0, step=1.0, value=40.0, width=100)\n", + " [4] FloatInput(end=90.0, name='First Parallel(lat_1) (..., start=-90.0, step=1.0, value=40.0, width=100)\n", + " [5] FloatInput(end=90.0, name='Second Parallel(lat_2) (..., start=-90.0, step=1.0, value=40.0, width=100)\n", + " [6] FloatInput(end=90.0, name='Latitude of T..., start=-90.0, step=1.0, value=40.0, width=100)\n", + " [7] FloatInput(end=90.0, name='Tilt (-90 to 90)', start=-90.0, value=30.0, width=100)\n", + " [8] Button(button_type='primary', name='Make Grid')\n", + " [2] WidgetBox\n", + " [0] Markdown(str)\n", + " [1] FloatInput(end=10000000, name='dx', start=0.0, step=1.0, value=20.0, width=100)\n", + " [2] Select(name='dx Units', options=['degrees', 'meters'], value='degrees')\n", + " [3] FloatInput(end=10000000, name='dy', start=0.0, step=1.0, value=30.0, width=100)\n", + " [4] Select(name='dy Units', options=['degrees', 'meters'], value='degrees')\n", + " [5] FloatInput(end=1000000.0, name='Grid Resolution(X)', start=0.0, value=1.0, width=100)\n", + " [6] Select(name='Grid Resolution U..., options=['degrees', 'meters'], value='degrees')\n", + " [7] FloatInput(end=1000000.0, name='Grid Resolution(Y)', start=0.0, value=1.0, width=100)\n", + " [8] Select(name='Grid Resolution U..., options=['degrees', 'meters'], value='degrees')\n", + " [9] Button(button_type='primary', name='Make Grid')\n", + " [3] WidgetBox\n", + " [0] Markdown(str)\n", + " [1] Select(disabled=True, name='Grid Mode(X)', options=['Left', 'Center', ...], value='Center')\n", + " [2] Select(disabled=True, name='Grid Mode(Y)', options=['Lower', 'Center', ...], value='Center')\n", + " [3] Markdown(str)\n", + " [4] Select(disabled=True, name='Grid Type', options=['MOM6'], value='MOM6')\n", + " [5] Markdown(str)\n", + " [6] IntInput(disabled=True, end=2, name='Grid Mode', start=1, value=2, width=80)\n", + " [2] Tabs\n", + " [0] WidgetBox\n", + " [0] Markdown(str)\n", + " [1] Markdown(str)\n", + " [2] TextInput(name='Log filename', value='logFile.log', width=200)\n", + " [3] Checkbox(name='Enable file logging')\n", + " [4] Button(button_type='danger', height=50, name='Erase log file', sizing_mode='fixed', width=200)\n", + " [5] Select(name='Log level', options=['NOTSET', 'DEBUG', ...], value='WARNING')\n", + " [6] Select(name='Information level', options=['NOTSET', 'DEBUG', ...], value='INFO')\n", + " [7] Select(name='Debug level', options=['OFF', 'MESSAGE', ...], value='OFF')\n", + " [1] WidgetBox\n", + " [0] Markdown(str)\n", + " [1] Checkbox(disabled=True, name='Enable numpypi b...)\n", + " [1] Tabs\n", + " [0] Matplotlib(Figure, height=600, sizing_mode='fixed', width=800)\n", + " [1] Column(width=800)\n", + " [0] HTML(Dataset)\n", + " [2] WidgetBox\n", + " [0] Markdown(str)\n", + " [1] Markdown(str)\n", + " [2] FileInput(accept='.nc')\n", + " [3] Button(button_type='primary', name='Load Local Grid')\n", + " [4] Markdown(str)\n", + " [5] TextInput(name='Grid filename', value='gridFile.nc', width=200)\n", + " [6] FileDownload(button_type='success', callback=" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dashboard.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a418cc30-b77c-40b1-91c4-9ec4125f4a9d", + "metadata": {}, "outputs": [], "source": [] } @@ -150,7 +769,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.4" + "version": "3.7.10" } }, "nbformat": 4, From 8bf3cb09719f96352cecce72adfc3bf30af0cd90 Mon Sep 17 00:00:00 2001 From: Rob Cermak Date: Thu, 20 May 2021 17:14:16 -0800 Subject: [PATCH 02/40] Add netCDF4 to gridTools.yml base packages; xarray needs it to read netcdf version 4 files --- conda/gridTools.yml | 1 + docs/development/CHANGELOG.md | 1 + 2 files changed, 2 insertions(+) diff --git a/conda/gridTools.yml b/conda/gridTools.yml index db01d37..d3595f6 100644 --- a/conda/gridTools.yml +++ b/conda/gridTools.yml @@ -9,6 +9,7 @@ dependencies: - dask - jupyterlab - matplotlib + - netCDF4 - pandas - panel - pip diff --git a/docs/development/CHANGELOG.md b/docs/development/CHANGELOG.md index 94fc10b..a3fedd5 100644 --- a/docs/development/CHANGELOG.md +++ b/docs/development/CHANGELOG.md @@ -2,6 +2,7 @@ # 2021-05-20 + - Add netCDF4 to gridTools.yml base packages; xarray needs it to read netcdf version 4 files - Add a few informational links - Update to push exp/bathyV1 From 124c4a7aca6d6d295216196a5f4689e4339892bc Mon Sep 17 00:00:00 2001 From: Rob Cermak Date: Tue, 25 May 2021 01:07:34 +0000 Subject: [PATCH 03/40] Update TODOs and prepare to add topog generation. --- docs/development/TODO.md | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/docs/development/TODO.md b/docs/development/TODO.md index c23e3fc..746fb28 100644 --- a/docs/development/TODO.md +++ b/docs/development/TODO.md @@ -17,22 +17,24 @@ - [X] Ensure mybinder.org works with the published github commit - [ ] Version 0.2 - [X] Make library installable via pip or setup.py - - [X] Specific installation instructions + - [ ] Create specific installation instructions - [ ] Improve reproducibility of grids produced by the library - [ ] Estabish sphinx document generator and link to readthedocs - [ ] Creation of all needed files to run a MOM6 simulation - [ ] Construct initial bathymetry grid for new grids - [ ] Construct initial grid land mask for new grids - [ ] Verison 0.x + - [ ] Sponge data preparation + - [ ] Subset existing grids and infrastructure - [ ] Leverage dask (expecially for binder.org) - [ ] Explore the extent problem for lon defined as +0,+360 vs -180,+180 - [ ] Enhanced grid/plot projection options - [ ] Allow import of ROMS grid for conversion to MOM6 + - [ ] Allow export of MOM6 grid to ROMS - [ ] Boundery condition support - [ ] Grid filling options (flooding) - [ ] Grid mask editor - [ ] This library is installable via conda - - [ ] Subset existing grids and infrastructure # BUGS - [ ] app:Remote Files does not save the grid in the specified directory @@ -42,6 +44,8 @@ # TASKS + - [ ] Sponge data preparation + - [ ] Current scripts generate u,v fields on h-points; this needs to be changed to C-grid u/v-points instead - [ ] general documentation - [X] grid parameters - [X] plot parameters @@ -73,8 +77,11 @@ - [X] Allow user control - [ ] grid mask editor (land, etc) - [ ] integration of bathymetric sources and apply to grids - - [ ] https://github.com/nikizadehgfdl/ocean_model_topog_generator + - [ ] https://github.com/nikizadehgfdl/ocean\_model\_topog\_generator - [ ] xesmf regridder + - [ ] fix native zero band columns in partitions + - [ ] flexible partitioning + - [ ] implement current hack as --fix-by-overlap-qh-grid-shift - [X] add nbserverproxy/xgcm to conda software stacks; copied to binder environment.yml - [ ] include a dump of conda environment in the grid file (nc) - [ ] Add option to use numpypi package (Alistair) as a configurable option in gridtools From def1ab98dd49b7675140375288f9026e80089aeb Mon Sep 17 00:00:00 2001 From: Rob Cermak Date: Tue, 25 May 2021 13:31:31 -0800 Subject: [PATCH 04/40] Add useful references --- docs/development/ImportantReferences.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/development/ImportantReferences.md b/docs/development/ImportantReferences.md index 58cab0a..ec72fee 100644 --- a/docs/development/ImportantReferences.md +++ b/docs/development/ImportantReferences.md @@ -38,6 +38,7 @@ These are people, references and bookmarks that provided useful information to m * https://www.git-tower.com/learn/git/faq/delete-remote-branch/ * https://github.com/binder-examples/conda * https://github.com/marketplace/actions/setup-miniconda + * https://github.com/pydata/xarray/issues/2899 * https://github.com/SciTools/cartopy/issues/787 * https://math.libretexts.org/Bookshelves/Calculus/Book%3A_Calculus_(OpenStax)/12%3A_Vectors_in_Space/12.7%3A_Cylindrical_and_Spherical_Coordinates#:~:text=In%20the%20Cartesian%20coordinate%20system%2C%20the%20location%20of%20a%20point,an%20angle%20measure%20(%CE%B8). * http://mathworld.wolfram.com @@ -75,6 +76,7 @@ These are people, references and bookmarks that provided useful information to m * https://xarray.pydata.org/en/stable/examples/ROMS_ocean_model.html * https://xarray.pydata.org/en/stable/data-structures.html#dictionary-like-methods * https://xarray.pydata.org/en/stable/dask.html + * http://xarray.pydata.org/en/stable/user-guide/io.html#string-encoding ## Paywall Bookmarks From aeb8f659b6b2df4f150bb310ab6d56721e5f7bf4 Mon Sep 17 00:00:00 2001 From: Rob Cermak Date: Thu, 27 May 2021 05:19:53 +0000 Subject: [PATCH 05/40] Progress on data source integration and bug fixes - Fix remote saving to correct directory as shown in the application - Improve gridtools metadata output; add hashes to certain variables - For pip installs, if jupyterlab<3.0.0 is required, require: jupyter labextension install @pyviz/jupyterlab_pyviz - In gridutils, self.app was overwriting the app() function; changed to self.applicationObj - Add a couple more try blocks on a machine without conda - Add example #7 demonstrating grid generation of bathymetric roughness(h2) and other bathymetric or other general field options. - Add hashlib to gridutils - Add package requirements to setup.py and requirements.txt - Begin construction of topoutils.py based on ocean_model_topog_generator - Begin construction of datasource.py that will manage data sources --- docs/development/CHANGELOG.md | 14 ++ docs/development/ImportantReferences.md | 32 ++++- docs/development/TODO.md | 21 ++- examples/mkGridInteractive.ipynb | 172 ++++++++++-------------- examples/mkGridsExample7.py | 88 ++++++++++++ gridtools/__init__.py | 2 +- gridtools/app.py | 4 +- gridtools/datasource.py | 30 +++++ gridtools/gridutils.py | 130 ++++++++++++++++-- gridtools/topoutils.py | 4 + requirements.txt | 20 +++ setup.py | 13 +- 12 files changed, 402 insertions(+), 128 deletions(-) create mode 100644 examples/mkGridsExample7.py create mode 100644 gridtools/datasource.py create mode 100644 gridtools/topoutils.py create mode 100644 requirements.txt diff --git a/docs/development/CHANGELOG.md b/docs/development/CHANGELOG.md index a3fedd5..7f1b291 100644 --- a/docs/development/CHANGELOG.md +++ b/docs/development/CHANGELOG.md @@ -1,5 +1,19 @@ # Change Log +# 2021-05-26 + + - Fix remote saving to correct directory as shown in the application + - Improve gridtools metadata output; add hashes to certain variables + - For pip installs, if jupyterlab<3.0.0 is required, require: jupyter labextension install @pyviz/jupyterlab_pyviz + - In gridutils, self.app was overwriting the app() function; changed to self.applicationObj + - Add a couple more try blocks on a machine without conda + - Add example #7 demonstrating grid generation of bathymetric roughness(h2) + and other bathymetric or other general field options. + - Add hashlib to gridutils + - Add package requirements to setup.py and requirements.txt + - Begin construction of topoutils.py based on ocean_model_topog_generator + - Begin construction of datasource.py that will manage data sources + # 2021-05-20 - Add netCDF4 to gridTools.yml base packages; xarray needs it to read netcdf version 4 files diff --git a/docs/development/ImportantReferences.md b/docs/development/ImportantReferences.md index ec72fee..495c752 100644 --- a/docs/development/ImportantReferences.md +++ b/docs/development/ImportantReferences.md @@ -5,9 +5,9 @@ These are people, references and bookmarks that provided useful information to m ## Alistair Adcroft * numpypi: https://github.com/adcroft/numpypi -## Raphael Dussin - * Use of pyproj to convert coordinates in 2D array - * https://github.com/raphaeldussin/regrid_weights_bedmachine_gebco/blob/master/create_grids.py +## James Simkins + * Conservative regridding + https://github.com/jsimkins2/esm_lab/blob/main/bathyTools/examples/xesmf_regrid_ex.py ## Mehmet Ilicak; Alistair Adcroft; Matthew Harrison * ROMS to MOM6 grid converter @@ -22,20 +22,27 @@ These are people, references and bookmarks that provided useful information to m Branch: create_spear_grid (generates tri-polar grids) https://github.com/nikizadehgfdl/ocean_model_topog_generator + Adcroft, A., 2013: Representation of topography by porous barriers and objective + interpolation of topographic data. Ocean Modelling, doi:10.1016/j.ocemod.2013.03.002. + (http://dx.doi.org/10.1016/j.ocemod.2013.03.002) + +## Raphael Dussin + * Use of pyproj to convert coordinates in 2D array + * https://github.com/raphaeldussin/regrid_weights_bedmachine_gebco/blob/master/create_grids.py + ## Bookmarks - * https://www.digitalocean.com/community/tutorials/how-to-use-args-and-kwargs-in-python-3 + * https://cfconventions.org/standard-names.html * https://docs.conda.io/projects/conda/en/latest/user-guide/tasks/manage-environments.html * https://docs.github.com/en/actions/guides/about-continuous-integration#skipping-workflow-runs * https://docs.github.com/en/actions/quickstart - * https://pypi.org/classifiers/ * https://docs.github.com/en/github/writing-on-github/autolinked-references-and-urls + * https://docs.python.org/3/reference/compound_stmts.html#function-definitions * https://docs.pytest.org/en/6.2.x/getting-started.html * https://docs.pytest.org/en/6.2.x/skipping.html * https://en.wikipedia.org/wiki/Arakawa_grids * https://en.wikipedia.org/wiki/World_Geodetic_System * https://edbennett.github.io/high-performance-python/11-dask/index.html * https://geohackweek.github.io/nDarrays/09-masking/ - * https://www.git-tower.com/learn/git/faq/delete-remote-branch/ * https://github.com/binder-examples/conda * https://github.com/marketplace/actions/setup-miniconda * https://github.com/pydata/xarray/issues/2899 @@ -52,6 +59,7 @@ These are people, references and bookmarks that provided useful information to m * https://panel.holoviz.org/gallery/index.html * https://pangeo-xesmf.readthedocs.io/en/latest/large_problems_on_HPC.html#technical-point-mpi4py-considerations * https://pangeo-xesmf.readthedocs.io/en/latest/notebooks/Compare_algorithms.html + * https://pypi.org/classifiers/ * https://rabernat.github.io/research_computing/xarray.html * https://rabernat.github.io/research_computing_2018/maps-with-cartopy.html * https://realpython.com/python-bindings-overview/ @@ -64,23 +72,33 @@ These are people, references and bookmarks that provided useful information to m * https://stackoverflow.com/questions/3277367/how-does-pythons-super-work-with-multiple-inheritance * https://stackoverflow.com/questions/6999621/how-to-use-extent-in-matplotlib-pyplot-imshow * https://stackoverflow.com/questions/12575421/convert-a-1d-array-to-a-2d-array-in-numpy + * https://stackoverflow.com/questions/20288711/post-install-script-with-python-setuptools * https://stackoverflow.com/questions/21778118/counting-the-number-of-non-nan-elements-in-a-numpy-ndarray-in-python * https://stackoverflow.com/questions/32234156/how-to-unimport-a-python-module-which-is-already-imported * https://stackoverflow.com/questions/44412432/cartopy-zoom-in-to-a-region * https://stackoverflow.com/questions/51357691/python-logging-only-for-own-imported-modules * https://towardsdatascience.com/plt-subplot-or-plt-subplots-understanding-state-based-vs-object-oriented-programming-in-pyplot-4ba0c7283f5d * https://unidata.github.io/MetPy/latest/examples/Four_Panel_Map.html + * https://www.digitalocean.com/community/tutorials/how-to-use-args-and-kwargs-in-python-3 + * https://www.git-tower.com/learn/git/faq/delete-remote-branch/ * https://www.kite.com/python/answers/how-to-hide-a-figure-from-being-shown-in-matplotlib-in-python * https://www.mathsisfun.com/geometry/interior-angles-polygons.html + * https://www.myroms.org/wiki/Numerical_Solution_Technique * https://www.python.org/dev/peps/pep-0008/#package-and-module-names * https://xarray.pydata.org/en/stable/examples/ROMS_ocean_model.html * https://xarray.pydata.org/en/stable/data-structures.html#dictionary-like-methods * https://xarray.pydata.org/en/stable/dask.html - * http://xarray.pydata.org/en/stable/user-guide/io.html#string-encoding + * https://xarray.pydata.org/en/stable/user-guide/io.html#string-encoding ## Paywall Bookmarks + * https://towardsdatascience.com/10-examples-to-master-args-and-kwargs-in-python-6f1e8cc30749 + ## For Review Later * http://dsrs.atmos.umd.edu/DATA/aosc/greenland/code/MOM4SODA/MOM_TEST/src/tools/make_hgrid/make_hgrid.c * Be aware, this may be Arakawa B grid code + + * https://github.com/nsidc/mapx + * The NSIDC mapx library and associated binary tools for gridding/reprojection. + diff --git a/docs/development/TODO.md b/docs/development/TODO.md index 746fb28..4638875 100644 --- a/docs/development/TODO.md +++ b/docs/development/TODO.md @@ -37,7 +37,7 @@ - [ ] This library is installable via conda # BUGS - - [ ] app:Remote Files does not save the grid in the specified directory + - [X] app:Remote Files does not save the grid in the specified directory - [ ] A nested dictionary will clobber other nested elements instead of updating elements. Recode `setPlotParameters` and `setGridParameters` to recursively update dictionary elements. @@ -63,9 +63,9 @@ - [ ] changing plot parameters lat_1 and lat_2 do not seem to impact the view - [ ] make Mercator grids; needs testing - [ ] issue a warning if tilt is non-zero - disabled - - [ ] Niki might have solved lat lon tilt? - [ ] having tilt may not produce conformal grids - [X] Niki's example added; but it may not be correct + - [ ] Niki might have solved lat lon tilt? - [X] make Stereographic grids; needs testing - [X] using meters; no tilt; based on code from Raphael - [X] using degrees; with tilt; based on code from Niki; may not be correct @@ -76,14 +76,20 @@ - [X] Gridutils initializes with proj GRS80 - [X] Allow user control - [ ] grid mask editor (land, etc) + - [ ] integration of data sources + - [ ] xesmf regridder for bathymetry sources + - [ ] option to create land_mask fraction + - [ ] option to use source grid as a supergrid for coarsening - [ ] integration of bathymetric sources and apply to grids - [ ] https://github.com/nikizadehgfdl/ocean\_model\_topog\_generator - - [ ] xesmf regridder - [ ] fix native zero band columns in partitions - [ ] flexible partitioning - [ ] implement current hack as --fix-by-overlap-qh-grid-shift - [X] add nbserverproxy/xgcm to conda software stacks; copied to binder environment.yml - - [ ] include a dump of conda environment in the grid file (nc) + - [ ] improve reproducibility + - [ ] include a dump of conda environment in the grid file (nc) + - [ ] if conda environment does not exist, do some other snooping + - [X] add sha256 to grid elements - [ ] Add option to use numpypi package (Alistair) as a configurable option in gridtools - [X] turn numpypi into a loadable package via pip - [X] add datashader and numpypi from github sources; see postBuild script @@ -153,7 +159,8 @@ # WISH - - [ ] Add an activity spinner to indicate the notebook is busy + - [ ] app:Save remote files; additional sanity checks + - [ ] app:Add an activity spinner to indicate the notebook is busy - [ ] Compute angle_dy for testing of grid conformality. Theoretically, we can do this check for all grid and supergrid cells. - [ ] tripolar grids: use FRE-NCtools via cython? @@ -176,10 +183,10 @@ - [ ] Add a notebook or two that demonstrates some of the esoteric API features of the library: help, debugging, etc. - [ ] Dask optimizations - - [ ] IBCAO grid is too big for mybinder.org + - [ ] creating the native IBCAO grid is too big for mybinder.org - [ ] Subset any grid for running with MOM6 - [ ] https://github.com/ESMG/regionalMOM6_notebooks/tree/master/creating_obc_input_files - - [ ] May be especially useful for debugging situations + - [ ] May be especially useful for debugging situations; Arctic6 - [ ] Allow gridtools to be used without xesmf and xgcm; enable module detection for available capabilities - [ ] Update setup.py and other files with package dependencies - Create a configuration script that would perform autosetup of gridtools library diff --git a/examples/mkGridInteractive.ipynb b/examples/mkGridInteractive.ipynb index b75b471..97aca4f 100644 --- a/examples/mkGridInteractive.ipynb +++ b/examples/mkGridInteractive.ipynb @@ -3,7 +3,65 @@ { "cell_type": "code", "execution_count": 1, - "id": "a655cdec", + "id": "8b40c15b", + "metadata": {}, + "outputs": [], + "source": [ + "# conda: gridTools\n", + "\n", + "# This should be the minimalist\n", + "# notebook script to launch the\n", + "# gridtools library for interactive\n", + "# mode (Application).\n", + "\n", + "# The source for the application can be\n", + "# found in gridtools/app.py. You need to save\n", + "# any changes and re-run all the cells for\n", + "# changes to be applied.\n", + "\n", + "# Required to access environment variables via os.environ.\n", + "import os\n", + "\n", + "useDisplay = False\n", + "\n", + "# Detect if we are running on mybinder.org\n", + "if os.environ.get('BINDER_LAUNCH_HOST') in ['https://mybinder.org/']:\n", + " useDisplay = True\n", + " \n", + "# Set your username if you need to use display() instead of show()\n", + "if os.environ.get('USER') == 'cermak':\n", + " useDisplay = True\n", + "\n", + "from gridtools.gridutils import GridUtils" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "675ccdcb", + "metadata": {}, + "outputs": [], + "source": [ + "# Disable annoying warnings from python\n", + "import warnings\n", + "warnings.filterwarnings('ignore')" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "ca46b85d", + "metadata": {}, + "outputs": [], + "source": [ + "# If we are successful, we can initialize the grid toolset\n", + "grd = GridUtils()" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "f09feae9", "metadata": {}, "outputs": [ { @@ -127,9 +185,9 @@ " document.body.appendChild(element);\n", " }\n", "\n", - " var js_urls = [\"https://unpkg.com/tabulator-tables@4.9.3/dist/js/tabulator.js\", \"https://unpkg.com/moment@2.27.0/moment.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-2.3.2.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-widgets-2.3.2.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-tables-2.3.2.min.js\", \"https://unpkg.com/@holoviz/panel@^0.11.3/dist/panel.min.js\"];\n", + " var js_urls = [\"https://unpkg.com/tabulator-tables@4.9.3/dist/js/tabulator.js\", \"https://unpkg.com/moment@2.27.0/moment.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-2.3.2.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-widgets-2.3.2.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-tables-2.3.2.min.js\", \"https://unpkg.com/@holoviz/panel@^0.12.0-a.11/dist/panel.js\"];\n", " var js_modules = [];\n", - " var css_urls = [\"https://unpkg.com/tabulator-tables@4.9.3/dist/css/tabulator_simple.min.css\", \"https://unpkg.com/@holoviz/panel@0.11.3/dist/css/card.css\", \"https://unpkg.com/@holoviz/panel@0.11.3/dist/css/widgets.css\", \"https://unpkg.com/@holoviz/panel@0.11.3/dist/css/markdown.css\", \"https://unpkg.com/@holoviz/panel@0.11.3/dist/css/json.css\", \"https://unpkg.com/@holoviz/panel@0.11.3/dist/css/dataframe.css\", \"https://unpkg.com/@holoviz/panel@0.11.3/dist/css/alerts.css\", \"https://unpkg.com/@holoviz/panel@0.11.3/dist/css/loading.css\"];\n", + " var css_urls = [\"https://unpkg.com/tabulator-tables@4.9.3/dist/css/tabulator_simple.min.css\", \"https://unpkg.com/@holoviz/panel@0.12.0-a.11/dist/css/json.css\", \"https://unpkg.com/@holoviz/panel@0.12.0-a.11/dist/css/widgets.css\", \"https://unpkg.com/@holoviz/panel@0.12.0-a.11/dist/css/dataframe.css\", \"https://unpkg.com/@holoviz/panel@0.12.0-a.11/dist/css/alerts.css\", \"https://unpkg.com/@holoviz/panel@0.12.0-a.11/dist/css/markdown.css\", \"https://unpkg.com/@holoviz/panel@0.12.0-a.11/dist/css/card.css\", \"https://unpkg.com/@holoviz/panel@0.12.0-a.11/dist/css/loading.css\"];\n", " var inline_js = [\n", " function(Bokeh) {\n", " inject_raw_css(\"\\n .bk.pn-loading.arcs:before {\\n background-image: url(\\\"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiBzdHlsZT0ibWFyZ2luOiBhdXRvOyBiYWNrZ3JvdW5kOiBub25lOyBkaXNwbGF5OiBibG9jazsgc2hhcGUtcmVuZGVyaW5nOiBhdXRvOyIgdmlld0JveD0iMCAwIDEwMCAxMDAiIHByZXNlcnZlQXNwZWN0UmF0aW89InhNaWRZTWlkIj4gIDxjaXJjbGUgY3g9IjUwIiBjeT0iNTAiIHI9IjMyIiBzdHJva2Utd2lkdGg9IjgiIHN0cm9rZT0iI2MzYzNjMyIgc3Ryb2tlLWRhc2hhcnJheT0iNTAuMjY1NDgyNDU3NDM2NjkgNTAuMjY1NDgyNDU3NDM2NjkiIGZpbGw9Im5vbmUiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCI+ICAgIDxhbmltYXRlVHJhbnNmb3JtIGF0dHJpYnV0ZU5hbWU9InRyYW5zZm9ybSIgdHlwZT0icm90YXRlIiByZXBlYXRDb3VudD0iaW5kZWZpbml0ZSIgZHVyPSIxcyIga2V5VGltZXM9IjA7MSIgdmFsdWVzPSIwIDUwIDUwOzM2MCA1MCA1MCI+PC9hbmltYXRlVHJhbnNmb3JtPiAgPC9jaXJjbGU+PC9zdmc+\\\")\\n }\\n \");\n", @@ -163,7 +221,7 @@ " }\n", "}(window));" ], - "application/vnd.holoviews_load.v0+json": "\n(function(root) {\n function now() {\n return new Date();\n }\n\n var force = true;\n\n if (typeof root._bokeh_onload_callbacks === \"undefined\" || force === true) {\n root._bokeh_onload_callbacks = [];\n root._bokeh_is_loading = undefined;\n }\n\n if (typeof (root._bokeh_timeout) === \"undefined\" || force === true) {\n root._bokeh_timeout = Date.now() + 5000;\n root._bokeh_failed_load = false;\n }\n\n function run_callbacks() {\n try {\n root._bokeh_onload_callbacks.forEach(function(callback) {\n if (callback != null)\n callback();\n });\n } finally {\n delete root._bokeh_onload_callbacks\n }\n console.debug(\"Bokeh: all callbacks have finished\");\n }\n\n function load_libs(css_urls, js_urls, js_modules, callback) {\n if (css_urls == null) css_urls = [];\n if (js_urls == null) js_urls = [];\n if (js_modules == null) js_modules = [];\n\n root._bokeh_onload_callbacks.push(callback);\n if (root._bokeh_is_loading > 0) {\n console.debug(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n return null;\n }\n if (js_urls.length === 0 && js_modules.length === 0) {\n run_callbacks();\n return null;\n }\n console.debug(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n root._bokeh_is_loading = css_urls.length + js_urls.length + js_modules.length;\n\n function on_load() {\n root._bokeh_is_loading--;\n if (root._bokeh_is_loading === 0) {\n console.debug(\"Bokeh: all BokehJS libraries/stylesheets loaded\");\n run_callbacks()\n }\n }\n\n function on_error() {\n console.error(\"failed to load \" + url);\n }\n\n for (var i = 0; i < css_urls.length; i++) {\n var url = css_urls[i];\n const element = document.createElement(\"link\");\n element.onload = on_load;\n element.onerror = on_error;\n element.rel = \"stylesheet\";\n element.type = \"text/css\";\n element.href = url;\n console.debug(\"Bokeh: injecting link tag for BokehJS stylesheet: \", url);\n document.body.appendChild(element);\n }\n\n var skip = [];\n if (window.requirejs) {\n window.requirejs.config({'paths': {'tabulator': 'https://unpkg.com/tabulator-tables@4.9.3/dist/js/tabulator'}});\n require([\"tabulator\"], function(Tabulator,) {\n window.Tabulator = Tabulator;\n })\n }\n if (((window['tabulator'] !== undefined) && (!(window['tabulator'] instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://unpkg.com/tabulator-tables@4.9.3/dist/js/tabulator.js', 'https://unpkg.com/moment@2.27.0/moment.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(urls[i])\n }\n }\n for (var i = 0; i < js_urls.length; i++) {\n var url = js_urls[i];\n if (skip.indexOf(url) >= 0) { on_load(); continue; }\n var element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (var i = 0; i < js_modules.length; i++) {\n var url = js_modules[i];\n if (skip.indexOf(url) >= 0) { on_load(); continue; }\n var element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n if (!js_urls.length && !js_modules.length) {\n on_load()\n }\n };\n\n function inject_raw_css(css) {\n const element = document.createElement(\"style\");\n element.appendChild(document.createTextNode(css));\n document.body.appendChild(element);\n }\n\n var js_urls = [\"https://unpkg.com/tabulator-tables@4.9.3/dist/js/tabulator.js\", \"https://unpkg.com/moment@2.27.0/moment.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-2.3.2.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-widgets-2.3.2.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-tables-2.3.2.min.js\", \"https://unpkg.com/@holoviz/panel@^0.11.3/dist/panel.min.js\"];\n var js_modules = [];\n var css_urls = [\"https://unpkg.com/tabulator-tables@4.9.3/dist/css/tabulator_simple.min.css\", \"https://unpkg.com/@holoviz/panel@0.11.3/dist/css/card.css\", \"https://unpkg.com/@holoviz/panel@0.11.3/dist/css/widgets.css\", \"https://unpkg.com/@holoviz/panel@0.11.3/dist/css/markdown.css\", \"https://unpkg.com/@holoviz/panel@0.11.3/dist/css/json.css\", \"https://unpkg.com/@holoviz/panel@0.11.3/dist/css/dataframe.css\", \"https://unpkg.com/@holoviz/panel@0.11.3/dist/css/alerts.css\", \"https://unpkg.com/@holoviz/panel@0.11.3/dist/css/loading.css\"];\n var inline_js = [\n function(Bokeh) {\n inject_raw_css(\"\\n .bk.pn-loading.arcs:before {\\n background-image: url(\\\"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiBzdHlsZT0ibWFyZ2luOiBhdXRvOyBiYWNrZ3JvdW5kOiBub25lOyBkaXNwbGF5OiBibG9jazsgc2hhcGUtcmVuZGVyaW5nOiBhdXRvOyIgdmlld0JveD0iMCAwIDEwMCAxMDAiIHByZXNlcnZlQXNwZWN0UmF0aW89InhNaWRZTWlkIj4gIDxjaXJjbGUgY3g9IjUwIiBjeT0iNTAiIHI9IjMyIiBzdHJva2Utd2lkdGg9IjgiIHN0cm9rZT0iI2MzYzNjMyIgc3Ryb2tlLWRhc2hhcnJheT0iNTAuMjY1NDgyNDU3NDM2NjkgNTAuMjY1NDgyNDU3NDM2NjkiIGZpbGw9Im5vbmUiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCI+ICAgIDxhbmltYXRlVHJhbnNmb3JtIGF0dHJpYnV0ZU5hbWU9InRyYW5zZm9ybSIgdHlwZT0icm90YXRlIiByZXBlYXRDb3VudD0iaW5kZWZpbml0ZSIgZHVyPSIxcyIga2V5VGltZXM9IjA7MSIgdmFsdWVzPSIwIDUwIDUwOzM2MCA1MCA1MCI+PC9hbmltYXRlVHJhbnNmb3JtPiAgPC9jaXJjbGU+PC9zdmc+\\\")\\n }\\n \");\n },\n function(Bokeh) {\n Bokeh.set_log_level(\"info\");\n },\n function(Bokeh) {} // ensure no trailing comma for IE\n ];\n\n function run_inline_js() {\n if ((root.Bokeh !== undefined) || (force === true)) {\n for (var i = 0; i < inline_js.length; i++) {\n inline_js[i].call(root, root.Bokeh);\n }} else if (Date.now() < root._bokeh_timeout) {\n setTimeout(run_inline_js, 100);\n } else if (!root._bokeh_failed_load) {\n console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n root._bokeh_failed_load = true;\n }\n }\n\n if (root._bokeh_is_loading === 0) {\n console.debug(\"Bokeh: BokehJS loaded, going straight to plotting\");\n run_inline_js();\n } else {\n load_libs(css_urls, js_urls, js_modules, function() {\n console.debug(\"Bokeh: BokehJS plotting callback run at\", now());\n run_inline_js();\n });\n }\n}(window));" + "application/vnd.holoviews_load.v0+json": "\n(function(root) {\n function now() {\n return new Date();\n }\n\n var force = true;\n\n if (typeof root._bokeh_onload_callbacks === \"undefined\" || force === true) {\n root._bokeh_onload_callbacks = [];\n root._bokeh_is_loading = undefined;\n }\n\n if (typeof (root._bokeh_timeout) === \"undefined\" || force === true) {\n root._bokeh_timeout = Date.now() + 5000;\n root._bokeh_failed_load = false;\n }\n\n function run_callbacks() {\n try {\n root._bokeh_onload_callbacks.forEach(function(callback) {\n if (callback != null)\n callback();\n });\n } finally {\n delete root._bokeh_onload_callbacks\n }\n console.debug(\"Bokeh: all callbacks have finished\");\n }\n\n function load_libs(css_urls, js_urls, js_modules, callback) {\n if (css_urls == null) css_urls = [];\n if (js_urls == null) js_urls = [];\n if (js_modules == null) js_modules = [];\n\n root._bokeh_onload_callbacks.push(callback);\n if (root._bokeh_is_loading > 0) {\n console.debug(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n return null;\n }\n if (js_urls.length === 0 && js_modules.length === 0) {\n run_callbacks();\n return null;\n }\n console.debug(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n root._bokeh_is_loading = css_urls.length + js_urls.length + js_modules.length;\n\n function on_load() {\n root._bokeh_is_loading--;\n if (root._bokeh_is_loading === 0) {\n console.debug(\"Bokeh: all BokehJS libraries/stylesheets loaded\");\n run_callbacks()\n }\n }\n\n function on_error() {\n console.error(\"failed to load \" + url);\n }\n\n for (var i = 0; i < css_urls.length; i++) {\n var url = css_urls[i];\n const element = document.createElement(\"link\");\n element.onload = on_load;\n element.onerror = on_error;\n element.rel = \"stylesheet\";\n element.type = \"text/css\";\n element.href = url;\n console.debug(\"Bokeh: injecting link tag for BokehJS stylesheet: \", url);\n document.body.appendChild(element);\n }\n\n var skip = [];\n if (window.requirejs) {\n window.requirejs.config({'paths': {'tabulator': 'https://unpkg.com/tabulator-tables@4.9.3/dist/js/tabulator'}});\n require([\"tabulator\"], function(Tabulator,) {\n window.Tabulator = Tabulator;\n })\n }\n if (((window['tabulator'] !== undefined) && (!(window['tabulator'] instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://unpkg.com/tabulator-tables@4.9.3/dist/js/tabulator.js', 'https://unpkg.com/moment@2.27.0/moment.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(urls[i])\n }\n }\n for (var i = 0; i < js_urls.length; i++) {\n var url = js_urls[i];\n if (skip.indexOf(url) >= 0) { on_load(); continue; }\n var element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (var i = 0; i < js_modules.length; i++) {\n var url = js_modules[i];\n if (skip.indexOf(url) >= 0) { on_load(); continue; }\n var element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n if (!js_urls.length && !js_modules.length) {\n on_load()\n }\n };\n\n function inject_raw_css(css) {\n const element = document.createElement(\"style\");\n element.appendChild(document.createTextNode(css));\n document.body.appendChild(element);\n }\n\n var js_urls = [\"https://unpkg.com/tabulator-tables@4.9.3/dist/js/tabulator.js\", \"https://unpkg.com/moment@2.27.0/moment.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-2.3.2.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-widgets-2.3.2.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-tables-2.3.2.min.js\", \"https://unpkg.com/@holoviz/panel@^0.12.0-a.11/dist/panel.js\"];\n var js_modules = [];\n var css_urls = [\"https://unpkg.com/tabulator-tables@4.9.3/dist/css/tabulator_simple.min.css\", \"https://unpkg.com/@holoviz/panel@0.12.0-a.11/dist/css/json.css\", \"https://unpkg.com/@holoviz/panel@0.12.0-a.11/dist/css/widgets.css\", \"https://unpkg.com/@holoviz/panel@0.12.0-a.11/dist/css/dataframe.css\", \"https://unpkg.com/@holoviz/panel@0.12.0-a.11/dist/css/alerts.css\", \"https://unpkg.com/@holoviz/panel@0.12.0-a.11/dist/css/markdown.css\", \"https://unpkg.com/@holoviz/panel@0.12.0-a.11/dist/css/card.css\", \"https://unpkg.com/@holoviz/panel@0.12.0-a.11/dist/css/loading.css\"];\n var inline_js = [\n function(Bokeh) {\n inject_raw_css(\"\\n .bk.pn-loading.arcs:before {\\n background-image: url(\\\"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiBzdHlsZT0ibWFyZ2luOiBhdXRvOyBiYWNrZ3JvdW5kOiBub25lOyBkaXNwbGF5OiBibG9jazsgc2hhcGUtcmVuZGVyaW5nOiBhdXRvOyIgdmlld0JveD0iMCAwIDEwMCAxMDAiIHByZXNlcnZlQXNwZWN0UmF0aW89InhNaWRZTWlkIj4gIDxjaXJjbGUgY3g9IjUwIiBjeT0iNTAiIHI9IjMyIiBzdHJva2Utd2lkdGg9IjgiIHN0cm9rZT0iI2MzYzNjMyIgc3Ryb2tlLWRhc2hhcnJheT0iNTAuMjY1NDgyNDU3NDM2NjkgNTAuMjY1NDgyNDU3NDM2NjkiIGZpbGw9Im5vbmUiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCI+ICAgIDxhbmltYXRlVHJhbnNmb3JtIGF0dHJpYnV0ZU5hbWU9InRyYW5zZm9ybSIgdHlwZT0icm90YXRlIiByZXBlYXRDb3VudD0iaW5kZWZpbml0ZSIgZHVyPSIxcyIga2V5VGltZXM9IjA7MSIgdmFsdWVzPSIwIDUwIDUwOzM2MCA1MCA1MCI+PC9hbmltYXRlVHJhbnNmb3JtPiAgPC9jaXJjbGU+PC9zdmc+\\\")\\n }\\n \");\n },\n function(Bokeh) {\n Bokeh.set_log_level(\"info\");\n },\n function(Bokeh) {} // ensure no trailing comma for IE\n ];\n\n function run_inline_js() {\n if ((root.Bokeh !== undefined) || (force === true)) {\n for (var i = 0; i < inline_js.length; i++) {\n inline_js[i].call(root, root.Bokeh);\n }} else if (Date.now() < root._bokeh_timeout) {\n setTimeout(run_inline_js, 100);\n } else if (!root._bokeh_failed_load) {\n console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n root._bokeh_failed_load = true;\n }\n }\n\n if (root._bokeh_is_loading === 0) {\n console.debug(\"Bokeh: BokehJS loaded, going straight to plotting\");\n run_inline_js();\n } else {\n load_libs(css_urls, js_urls, js_modules, function() {\n console.debug(\"Bokeh: BokehJS plotting callback run at\", now());\n run_inline_js();\n });\n }\n}(window));" }, "metadata": {}, "output_type": "display_data" @@ -417,64 +475,6 @@ "output_type": "display_data" } ], - "source": [ - "# conda: gridTools\n", - "\n", - "# This should be the minimalist\n", - "# notebook script to launch the\n", - "# gridtools library for interactive\n", - "# mode (Application).\n", - "\n", - "# The source for the application can be\n", - "# found in gridtools/app.py. You need to save\n", - "# any changes and re-run all the cells for\n", - "# changes to be applied.\n", - "\n", - "# Required to access environment variables via os.environ.\n", - "import os\n", - "\n", - "useDisplay = False\n", - "\n", - "# Detect if we are running on mybinder.org\n", - "if os.environ.get('BINDER_LAUNCH_HOST') in ['https://mybinder.org/']:\n", - " useDisplay = True\n", - " \n", - "# Set your username if you need to use display() instead of show()\n", - "if os.environ.get('USER') == 'cermak':\n", - " useDisplay = True\n", - "\n", - "from gridtools.gridutils import GridUtils" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "fa2aa824", - "metadata": {}, - "outputs": [], - "source": [ - "# Disable annoying warnings from python\n", - "import warnings\n", - "warnings.filterwarnings('ignore')" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "d25fb0f1", - "metadata": {}, - "outputs": [], - "source": [ - "# If we are successful, we can initialize the grid toolset\n", - "grd = GridUtils()" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "cb355fac", - "metadata": {}, - "outputs": [], "source": [ "# Initialize the application\n", "dashboard = grd.app()" @@ -483,7 +483,7 @@ { "cell_type": "code", "execution_count": 5, - "id": "e8c126ae", + "id": "49919735", "metadata": {}, "outputs": [], "source": [ @@ -493,7 +493,7 @@ { "cell_type": "code", "execution_count": 6, - "id": "1c968a37", + "id": "c5850262", "metadata": {}, "outputs": [], "source": [ @@ -504,7 +504,7 @@ { "cell_type": "code", "execution_count": 7, - "id": "4a258c5a", + "id": "eb85a3b9", "metadata": {}, "outputs": [], "source": [ @@ -515,7 +515,7 @@ { "cell_type": "code", "execution_count": 8, - "id": "b232aac6", + "id": "2353f696", "metadata": {}, "outputs": [ { @@ -541,7 +541,7 @@ { "cell_type": "code", "execution_count": 9, - "id": "7df0478f", + "id": "4168b709", "metadata": {}, "outputs": [ { @@ -559,12 +559,12 @@ "\n", "\n", "\n", - "
\n", + "
\n", "\n", "