Skip to content

Commit

Permalink
initial documentation updates
Browse files Browse the repository at this point in the history
  • Loading branch information
jmjohnson1578 authored and jakeymac committed Jul 29, 2024
1 parent 23b13f5 commit bf23aa8
Show file tree
Hide file tree
Showing 7 changed files with 109 additions and 40 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ In this step, you'll define a variable that will effectively contain a list of a
The metadata parameters for each dataset were derived from the examples of each dataset that can be found in the `Earth Engine Data Catalog <https://developers.google.com/earth-engine/datasets>`_ or the `Earth Engine Code Editor <https://code.earthengine.google.com/>`_ example scripts. Additional datasets can be easily added to the app by following this pattern.

Create a new package (a folder with an empty :file:`__init__.py`) called :file:``gee`` to house Google Earth Engine related logic in the :file:`earth_engine` directory. Add a Python module called :file:`products.py` to this package with the following contents:
Create a new package (a folder with an empty :file:`__init__.py`) called :file:`gee` to house Google Earth Engine related logic in the :file:`earth_engine` directory. Add a Python module called :file:`products.py` to this package with the following contents:

.. code-block:: python
Expand Down
4 changes: 2 additions & 2 deletions docs/tutorials/google_earth_engine/part_1/gee_primer.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
Part 1 Primer: Google Earth Engine for Tethys Developers
********************************************************

**Last Updated:** January 2023
**Last Updated:** July 2024

This tutorial provides links to Google Earth Engine tutorials and resources that can be used to learn what you need to know for this Tethys tutorial. This is by no means exhaustive and we encourage you familiarize yourself with everything Google Earth Engine has to offer by visiting their documentation: `<https://developers.google.com/earth-engine/>`_. You will need an active `Google Earth Engine account <https://signup.earthengine.google.com>`_ to complete this tutorial.
This tutorial provides links to Google Earth Engine tutorials and resources that can be used to learn what you need to know for this Tethys tutorial. This is by no means exhaustive and we encourage you to familiarize yourself with everything Google Earth Engine has to offer by visiting their documentation: `<https://developers.google.com/earth-engine/>`_. You will need an active `Google Earth Engine account <https://signup.earthengine.google.com>`_ to complete this tutorial.

1. What is Google Earth Engine?
===============================
Expand Down
4 changes: 3 additions & 1 deletion docs/tutorials/thredds/additional_exercises.rst
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,10 @@ The current implementation uses hard-coded values for the color scale range of t
update_layer = function() {
...
var proxyWMSURL = `getWMSImageFromServer?main_url=${encodeURIComponent(m_curr_wms_url)}`;
// Layer
m_layer = L.tileLayer.wms(m_curr_wms_url, {
m_layer = L.tileLayer.wms(proxyWMSURL, {
layers: m_curr_variable,
format: 'image/png',
transparent: true,
Expand Down
2 changes: 1 addition & 1 deletion docs/tutorials/thredds/new_app_project.rst
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ Download this :download:`Unidata App Icon <./resources/unidata_logo.png>` or fin
name = 'THREDDS Tutorial'
index = 'thredds_tutorial:home'
icon = 'thredds_tutorial/images/unidata_logo.png'
icon = f'{package}/images/unidata_logo.png'
package = 'thredds_tutorial'
root_url = 'thredds-tutorial'
color = '#008e8d'
Expand Down
13 changes: 9 additions & 4 deletions docs/tutorials/thredds/plot_at_location.rst
Original file line number Diff line number Diff line change
Expand Up @@ -126,22 +126,25 @@ In this step you'll learn to use another Leaflet plugin: `Leaflet.Draw <http://l

In this step you will create a new controller that will query the dataset at the given location using the NCSS service and then build a plotly plot with the results.

1. The Plotly View gizmo requires the `plotly` Python package. Install `plotly` as follows running the following command in the terminal:
1. The Plotly View gizmo requires the `plotly` Python package. We'll also need `geojson` to handle the geometry data. Install `plotly` as follows running the following command in the terminal:

.. code-block::
# with conda
conda install plotly
conda install geojson
# with pip
pip install plotly
pip install geojson
2. The app now depends on `plotly`, so add it to the `install.yml` file:
2. The app now depends on `plotly` and `geojson`, so add them to the `install.yml` file:

.. code-block:: yaml
dependencies:
- plotly
- goejson
3. Create New Plot Controller
=============================
Expand Down Expand Up @@ -356,7 +359,7 @@ In this step you will create a new controller that will query the dataset at the
end_time = datetime.fromtimestamp(e)
# Retrieve the connection to the THREDDS server
catalog = app.get_spatial_dataset_service(app.THREDDS_SERVICE_NAME, as_engine=True)
catalog = App.get_spatial_dataset_service(App.THREDDS_SERVICE_NAME, as_engine=True)
time_series = extract_time_series_at_location(
catalog=catalog,
Expand Down Expand Up @@ -632,9 +635,11 @@ The `JQuery.load() <https://api.jquery.com/load/>`_ method is used to call a URL
if (m_drawn_features) {
m_drawn_features.clearLayers();
}
var proxyWMSURL = `getWMSImageFromServer?main_url=${encodeURIComponent(m_curr_wms_url)}`;
// Layer
m_layer = L.tileLayer.wms(m_curr_wms_url, {
m_layer = L.tileLayer.wms(proxyWMSURL, {
layers: m_curr_variable,
format: 'image/png',
transparent: true,
Expand Down
2 changes: 1 addition & 1 deletion docs/tutorials/thredds/thredds_primer.rst
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ The TDS Configuration File (:file:`threddsConfig.xml`) is used to control the be
5. NetCDF Data Exercise
=======================

1. Download this :download:`National Water Model Short Range Forecast <https://drive.google.com/open?id=1TIGAe-03ju_sOEpjTJMxvPUBXYpzWkjI>` data and extract it. The archive should contain the **first 3** of 18 NetCDF files each representing a 1-hour increment in an 18 hour forecast produced by the `National Water Model <https://water.noaa.gov/about/nwm>`_. Each file contains over 2.7 million forecast points where each point is associated a different stream reach on the `National Hydrogrophy Dataset <https://nhd.usgs.gov/>`_.
1. Download this :download:`National Water Model Short Range Forecast <https://drive.google.com/file/d/1Mrv54RoIlesWILria8fpSTRwS6StPhgU>` data and extract it. The archive should contain the **first 3** of 18 NetCDF files each representing a 1-hour increment in an 18 hour forecast produced by the `National Water Model <https://water.noaa.gov/about/nwm>`_. Each file contains over 2.7 million forecast points where each point is associated a different stream reach on the `National Hydrogrophy Dataset <https://nhd.usgs.gov/>`_.

2. Create a new :file:`nwm` directory in the :file:`public` directory of the TDS Content Directory (i.e.: :file:`<TDS_CONTENT_DIRECTORY>/public/nwm`).

Expand Down
122 changes: 92 additions & 30 deletions docs/tutorials/thredds/visualize_leaflet.rst
Original file line number Diff line number Diff line change
Expand Up @@ -46,16 +46,16 @@ Leaflet is not officially supported by Tethys Platform as a Gizmo, but it can ea

{% block styles %}
{{ block.super }}
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.8.0/dist/leaflet.css"
integrity_no="sha512-hoalWLoI8r4UszCkZ5kL8vayOGVae1oxXe/2A4AO6J9+580uKHDO3JdHb7NzwwzK5xr/Fs0W40kiNHxM9vyTtQ=="
crossorigin=""/>
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css"
integrity_no="sha512-Zcn6bjR/8RZbLEpLIeOwNtzREBAJnUKESxces60Mpoj+2okopSAcSUIUOseddDm0cxnGQzxIR7vJgsLZbdLE3w=="
crossorigin=""/>
{% endblock %}

{% block global_scripts %}
{{ block.super }}
<script src="https://unpkg.com/leaflet@1.8.0/dist/leaflet.js"
integrity_no="sha512-BB3hKbKWOc9Ez/TAwyWxNXeoV9c1v6FIeYiBieIWkpLjauysF18NzgR1MBNBXf8/KABdlkX68nAhlwcDFLGPCQ=="
crossorigin=""></script>
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"
integrity_no="sha512-BwHfrr4c9kmRkLw6iXFdzcdWV/PGkVgiIyIWLLlTSXzWQzxuSg4DiQUCpauz/EWjgk5TYQqX/kvn9pG1NpYfqg=="
crossorigin=""></script>
{% endblock %}

{% block header_buttons %}
Expand Down Expand Up @@ -174,17 +174,17 @@ Leaflet is not officially supported by Tethys Platform as a Gizmo, but it can ea

{% block styles %}
{{ block.super }}
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.8.0/dist/leaflet.css"
integrity_no="sha512-hoalWLoI8r4UszCkZ5kL8vayOGVae1oxXe/2A4AO6J9+580uKHDO3JdHb7NzwwzK5xr/Fs0W40kiNHxM9vyTtQ=="
crossorigin=""/>
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css"
integrity_no="sha512-Zcn6bjR/8RZbLEpLIeOwNtzREBAJnUKESxces60Mpoj+2okopSAcSUIUOseddDm0cxnGQzxIR7vJgsLZbdLE3w=="
crossorigin=""/>
<link rel="stylesheet" href="{% static tethys_app|public:'css/leaflet_map.css' %}"/>
{% endblock %}

{% block global_scripts %}
{{ block.super }}
<script src="https://unpkg.com/leaflet@1.8.0/dist/leaflet.js"
integrity_no="sha512-BB3hKbKWOc9Ez/TAwyWxNXeoV9c1v6FIeYiBieIWkpLjauysF18NzgR1MBNBXf8/KABdlkX68nAhlwcDFLGPCQ=="
crossorigin=""></script>
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"
integrity_no="sha512-BwHfrr4c9kmRkLw6iXFdzcdWV/PGkVgiIyIWLLlTSXzWQzxuSg4DiQUCpauz/EWjgk5TYQqX/kvn9pG1NpYfqg=="
crossorigin=""></script>
{% endblock %}

{% block scripts %}
Expand Down Expand Up @@ -217,6 +217,7 @@ In this step, you'll create controls to allow the user to search for and select
from tethys_sdk.routing import controller
from tethys_sdk.gizmos import SelectInput
from .app import App
@controller
def home(request):
Expand Down Expand Up @@ -396,7 +397,7 @@ At this point the select controls are empty and don't do anything. In this step,
"""
Controller for the app home page.
"""
catalog = App.get_spatial_dataset_service(app.THREDDS_SERVICE_NAME, as_engine=True)
catalog = App.get_spatial_dataset_service(App.THREDDS_SERVICE_NAME, as_engine=True)
# Retrieve dataset options from the THREDDS service
print('Retrieving Datasets...')
Expand Down Expand Up @@ -446,6 +447,8 @@ Each time a new dataset is selected, the options in the variable and style contr
.. code-block:: python
from owslib.wms import WebMapService
import requests
import chardet
.. code-block:: python
Expand All @@ -459,7 +462,21 @@ Each time a new dataset is selected, the options in the variable and style contr
Returns:
dict<layer_name:dict<styles,bbox>>: A dictionary with a key for each WMS layer available and a dictionary value containing metadata about the layer.
"""
wms = WebMapService(wms_url)
params = {
'service': 'WMS',
'version': '1.1.1',
'request': 'GetCapabilities'
}
request_url = f"{wms_url}?{'&'.join(f'{key}={value}' for key, value in params.items())}"
response = requests.get(request_url)
encoding = chardet.detect(response.content)['encoding']
response_content = response.content.decode(encoding)
utf8_content = response_content.encode('utf-8')
wms = WebMapService(None, xml=utf8_content)
layers = wms.contents
from pprint import pprint
print('WMS Contents:')
Expand Down Expand Up @@ -705,18 +722,18 @@ Many of the datasets hosted on THREDDS servers have time as a dimension. In this

{% block styles %}
{{ block.super }}
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.8.0/dist/leaflet.css"
integrity_no="sha512-hoalWLoI8r4UszCkZ5kL8vayOGVae1oxXe/2A4AO6J9+580uKHDO3JdHb7NzwwzK5xr/Fs0W40kiNHxM9vyTtQ=="
crossorigin=""/>
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css"
integrity_no="sha512-Zcn6bjR/8RZbLEpLIeOwNtzREBAJnUKESxces60Mpoj+2okopSAcSUIUOseddDm0cxnGQzxIR7vJgsLZbdLE3w=="
crossorigin=""/>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/leaflet.timedimension.control.min.css" />
<link rel="stylesheet" href="{% static tethys_app|public:'css/leaflet_map.css' %}"/>
{% endblock %}

{% block global_scripts %}
{{ block.super }}
<script src="https://unpkg.com/leaflet@1.8.0/dist/leaflet.js"
integrity_no="sha512-BB3hKbKWOc9Ez/TAwyWxNXeoV9c1v6FIeYiBieIWkpLjauysF18NzgR1MBNBXf8/KABdlkX68nAhlwcDFLGPCQ=="
crossorigin=""></script>
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"
integrity_no="sha512-BwHfrr4c9kmRkLw6iXFdzcdWV/PGkVgiIyIWLLlTSXzWQzxuSg4DiQUCpauz/EWjgk5TYQqX/kvn9pG1NpYfqg=="
crossorigin=""></script>
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/[email protected]/iso8601.min.js"></script>
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/[email protected]/dist/leaflet.timedimension.min.js"></script>
{% endblock %}
Expand Down Expand Up @@ -761,17 +778,49 @@ In this step, you'll create the ``update_layer`` method that will add the THREDD
var update_layer;
3. **Insert** the ``update_layer`` method just after the ``init_map`` method in :file:`public/js/leaflet_map.js`:
3. Add proxy controller to :file:`controllers.py` to allow the JavaScript to access the WMS service:

First, add the necessary imports

.. code-block:: python
from django.http import HttpResponseNotAllowed, JsonResponse, HttpResponse # new import: HttpResponse
import requests
Then, add the new controller

.. code-block:: python
@controller(name='getWMSImageFromServer', url='getWMSImageFromServer/')
def wms_image_from_server(request):
try:
if 'main_url' in request.GET:
request_url = request.GET.get('main_url')
query_params = request.GET.dict()
query_params.pop('main_url', None)
r = requests.get(request_url, params=query_params)
return HttpResponse(r.content, content_type="image/png")
else:
return JsonResponse({})
except Exception as e:
print(e)
return JsonResponse({'error': e})
This controller will act as a proxy to the WMS service. It will take a URL and any query parameters and return the image data from the WMS service. This is necessary because the WMS service does not have CORS enabled, so the JavaScript cannot access it directly.

4. **Insert** the ``update_layer`` method just after the ``init_map`` method in :file:`public/js/leaflet_map.js`:

.. code-block:: javascript
update_layer = function() {
if (m_td_layer) {
m_map.removeLayer(m_td_layer);
}
var proxyWMSURL = `getWMSImageFromServer?main_url=${encodeURIComponent(m_curr_wms_url)}`;
// Layer
m_layer = L.tileLayer.wms(m_curr_wms_url, {
m_layer = L.tileLayer.wms(proxyWMSURL, {
layers: m_curr_variable,
format: 'image/png',
transparent: true,
Expand All @@ -791,7 +840,7 @@ In this step, you'll create the ``update_layer`` method that will add the THREDD
m_td_layer.addTo(m_map);
};
4. Call the ``update_layer`` method when the style changes. **Replace** the on-change handler for the *style control* (i.e. ``$('#style').on('change', ...);``) defined in the ``init_controls`` method in :file:`public/js/leaflet_map.js` with this updated implementation:
5. Call the ``update_layer`` method when the style changes. **Replace** the on-change handler for the *style control* (i.e. ``$('#style').on('change', ...);``) defined in the ``init_controls`` method in :file:`public/js/leaflet_map.js` with this updated implementation:

.. code-block:: javascript
Expand All @@ -807,7 +856,7 @@ In this step, you'll create the ``update_layer`` method that will add the THREDD
The style is changed not only when the user selects a new style, but also whenever the dataset or variable changes. Consequently, the ``update_layer`` method will be called anytime the dataset, variable, or style controls changes.
5. Use the bounding box retrieved from the WMS service to automatically frame the selected layer on the map. **Replace** the on-change handler for the *variable control* (i.e. ``$('#variable').on('change', ...);``) defined in the ``init_controls`` method with this updated implementation:
6. Use the bounding box retrieved from the WMS service to automatically frame the selected layer on the map. **Replace** the on-change handler for the *variable control* (i.e. ``$('#variable').on('change', ...);``) defined in the ``init_controls`` method with this updated implementation:

.. code-block:: javascript
Expand All @@ -822,7 +871,7 @@ In this step, you'll create the ``update_layer`` method that will add the THREDD
m_map.fitBounds(bbox);
});
5. Verify that the layers show up on the map. Browse to `<http://localhost:8000/apps/thredds-tutorial>`_ in a web browser and login if necessary. Select the "Best GFS Half Degree Forecast Time Series" dataset using the **Dataset** control to test a time-varying layer. Press the **Play** button on the Time-Dimension control to animate the layer.
7. Verify that the layers show up on the map. Browse to `<http://localhost:8000/apps/thredds-tutorial>`_ in a web browser and login if necessary. Select the "Best GFS Half Degree Forecast Time Series" dataset using the **Dataset** control to test a time-varying layer. Press the **Play** button on the Time-Dimension control to animate the layer.

9. Implement Legend for Layers
==============================
Expand Down Expand Up @@ -942,9 +991,9 @@ Depending on the speed of the THREDDS server and the user's internet connection,

{% block styles %}
{{ block.super }}
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.8.0/dist/leaflet.css"
integrity_no="sha512-hoalWLoI8r4UszCkZ5kL8vayOGVae1oxXe/2A4AO6J9+580uKHDO3JdHb7NzwwzK5xr/Fs0W40kiNHxM9vyTtQ=="
crossorigin=""/>
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css"
integrity_no="sha512-Zcn6bjR/8RZbLEpLIeOwNtzREBAJnUKESxces60Mpoj+2okopSAcSUIUOseddDm0cxnGQzxIR7vJgsLZbdLE3w=="
crossorigin=""/>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/leaflet.timedimension.control.min.css" />
<link rel="stylesheet" href="{% static tethys_app|public:'css/leaflet_map.css' %}"/>
<link rel="stylesheet" href="{% static tethys_app|public:'css/loader.css' %}" />
Expand Down Expand Up @@ -1096,7 +1145,7 @@ During development it is common to use print statements. Rather than delete thes
"""
Controller for the app home page.
"""
catalog = app.get_spatial_dataset_service(app.THREDDS_SERVICE_NAME, as_engine=True)
catalog = app.get_spatial_dataset_service(App.THREDDS_SERVICE_NAME, as_engine=True)
# Retrieve dataset options from the THREDDS service
log.info('Retrieving Datasets...')
Expand Down Expand Up @@ -1143,7 +1192,20 @@ During development it is common to use print statements. Rather than delete thes
Returns:
dict<layer_name:dict<styles,bbox>>: A dictionary with a key for each WMS layer available and a dictionary value containing metadata about the layer.
"""
wms = WebMapService(wms_url)
params = {
'service': 'WMS',
'version': '1.1.1',
'request': 'GetCapabilities'
}
request_url = f"{wms_url}?{'&'.join(f'{key}={value}' for key, value in params.items())}"
response = requests.get(request_url)
encoding = chardet.detect(response.content)['encoding']
response_content = response.content.decode(encoding)
utf8_content = response_content.encode('utf-8')
wms = WebMapService(None, xml=utf8_content)
layers = wms.contents
log.debug('WMS Contents:')
log.debug(layers)
Expand Down

0 comments on commit bf23aa8

Please sign in to comment.