Skip to content

Commit

Permalink
updates for tethys 4.3
Browse files Browse the repository at this point in the history
  • Loading branch information
jakeymac committed Aug 17, 2024
1 parent 6728d0e commit a5acf3f
Show file tree
Hide file tree
Showing 28 changed files with 10,996 additions and 392 deletions.
4 changes: 2 additions & 2 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Copyright 2023 Tethys Platform
Copyright <YEAR> <COPYRIGHT HOLDER>

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

Expand All @@ -8,4 +8,4 @@ Redistribution and use in source and binary forms, with or without modification,

3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
18 changes: 11 additions & 7 deletions install.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# This file should be committed to your app code.
version: 1.0
version: 1.1
# This should be greater or equal to your tethys-platform in your environment
tethys_version: ">=4.0.0"
# This should match the app - package name in your setup.py
Expand All @@ -10,14 +10,18 @@ requirements:
skip: false
conda:
channels:
- conda-forge
- conda-forge
packages:
- earthengine-api
- oauth2client
- geojson
- pyshp
- earthengine-api
- oauth2client
- geojson
- pandas
- pyshp
- simplejson
- djangorestframework

pip:

npm:

post:
post:
File renamed without changes.
12 changes: 7 additions & 5 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@
dependencies = []

# -- Get Resource File -- #
resource_files = find_all_resource_files(app_package, TethysAppBase.package_namespace)
resource_files = find_all_resource_files(
app_package, TethysAppBase.package_namespace
)

with open('README.md', 'r') as f:
long_description = f.read()
Expand All @@ -20,13 +22,13 @@
version='1.0.0',
description='A Google Earth Engine demonstration Tethys App.',
long_description=long_description,
author='Luke Skywalker',
author_email='lskywalker@example.com',
url='',
author='<YOUR NAME>',
author_email='<YOUR EMAIL>',
url='', # The URL will be set in a future step.
license='BSD-3-Clause',
packages=find_namespace_packages(),
package_data={'': resource_files},
include_package_data=True,
zip_safe=False,
install_requires=dependencies,
)
)
8 changes: 3 additions & 5 deletions tethysapp/earth_engine/app.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
from tethys_sdk.app_settings import CustomSetting
from tethys_sdk.base import TethysAppBase
from tethys_sdk.app_settings import CustomSetting


class EarthEngine(TethysAppBase):
class App(TethysAppBase):
"""
Tethys app class for Earth Engine.
"""

name = 'Google Earth Engine Tutorial'
name = 'Earth Engine'
description = ''
package = 'earth_engine' # WARNING: Do not change this value
index = 'home'
Expand Down
7 changes: 4 additions & 3 deletions tethysapp/earth_engine/controllers/home.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import logging
from django.shortcuts import render
from tethys_sdk.routing import controller

from ..app import App

log = logging.getLogger(f'tethys.apps.{__name__}')


Expand All @@ -11,7 +12,7 @@ def home(request):
Controller for the app home page.
"""
context = {}
return render(request, 'earth_engine/home.html', context)
return App.render(request, 'home.html', context)


@controller
Expand All @@ -20,4 +21,4 @@ def about(request):
Controller for the app about page.
"""
context = {}
return render(request, 'earth_engine/about.html', context)
return App.render(request, 'about.html', context)
16 changes: 10 additions & 6 deletions tethysapp/earth_engine/controllers/rest.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import datetime as dt
import logging
import geojson
from django.http import JsonResponse, HttpResponseBadRequest, HttpResponseServerError
from django.http import JsonResponse, HttpResponseBadRequest
from tethys_sdk.routing import controller
from rest_framework.authentication import TokenAuthentication
from rest_framework.decorators import api_view, authentication_classes
from simplejson import JSONDecodeError
from tethys_sdk.routing import controller
from ..gee.products import EE_PRODUCTS
import datetime as dt
from ..helpers import compute_dates_for_product
import geojson
from simplejson import JSONDecodeError
from django.http import HttpResponseServerError
from ..gee.methods import get_time_series_from_image_collection
from ..gee.products import EE_PRODUCTS

log = logging.getLogger(f'tethys.apps.{__name__}')

Expand Down Expand Up @@ -145,6 +146,8 @@ def get_time_series(request):
f'The "scale" parameter must be a valid number, but "{scale_str}" was given.'
)



# geometry
bad_geometry_msg = 'The "geometry" parameter is required and must be a valid geojson string.'
if not geometry_str:
Expand Down Expand Up @@ -192,3 +195,4 @@ def get_time_series(request):
}

return JsonResponse(response_data)

24 changes: 13 additions & 11 deletions tethysapp/earth_engine/controllers/viewer.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,23 @@
from simplejson.errors import JSONDecodeError

from django.http import JsonResponse, HttpResponseNotAllowed, HttpResponseRedirect
from django.shortcuts import render
from tethys_sdk.routing import controller
from tethys_sdk.gizmos import SelectInput, DatePicker, Button, MapView, MVView, PlotlyView, MVDraw

from ..app import App

from ..helpers import generate_figure, handle_shapefile_upload, compute_dates_for_product
from ..gee.methods import get_image_collection_asset, get_time_series_from_image_collection, \
get_boundary_fc_props_for_user
from ..gee.products import EE_PRODUCTS

log = logging.getLogger(f'tethys.apps.{__name__}')

log = logging.getLogger(f'tethys.apps.{__name__}')

@controller(user_workspace=True, url='viewer')
def viewer(request, user_workspace):
@controller(user_media=True, url='viewer')
def viewer(request, user_media):
"""
Controller for the app viewer page.
Controller for the app home page.
"""
default_platform = 'modis'
default_sensors = EE_PRODUCTS[default_platform]
Expand Down Expand Up @@ -115,7 +116,7 @@ def viewer(request, user_workspace):
style='outline-secondary',
attributes={'id': 'load_map'}
)

# Get bounding box from user boundary if it exists
boundary_props = get_boundary_fc_props_for_user(request.user)

Expand Down Expand Up @@ -143,7 +144,7 @@ def viewer(request, user_workspace):
maxZoom=18,
minZoom=2
),
draw=MVDraw(
draw = MVDraw(
controls=['Pan', 'Modify', 'Delete', 'Move', 'Point', 'Polygon', 'Box'],
initial='Pan',
output_format='GeoJSON'
Expand Down Expand Up @@ -176,11 +177,10 @@ def viewer(request, user_workspace):
'data-bs-target': '#set-boundary-modal', # ID of the Set Boundary Modal
}
)

# Handle Set Boundary Form
set_boundary_error = ''
if request.POST and request.FILES:
set_boundary_error = handle_shapefile_upload(request, user_workspace)
set_boundary_error = handle_shapefile_upload(request, user_media)

if not set_boundary_error:
# Redirect back to this page to clear form
Expand All @@ -202,8 +202,8 @@ def viewer(request, user_workspace):
'map_view': map_view
}

return render(request, 'earth_engine/viewer.html', context)

return App.render(request, 'viewer.html', context)

@controller(url='viewer/get-image-collection')
def get_image_collection(request):
Expand Down Expand Up @@ -316,4 +316,6 @@ def get_time_series_plot(request):
context['error'] = f'An unexpected error has occurred. Please try again.'
log.exception('An unexpected error occurred.')

return render(request, 'earth_engine/plot.html', context)
print(context)
return App.render(request, 'plot.html', context)

6 changes: 3 additions & 3 deletions tethysapp/earth_engine/gee/cloud_mask.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ def mask_l8_sr(image):
cloudsBitMask = (1 << 5)

# Get the pixel QA band.
qa = image.select('pixel_qa')
qa = image.select('QA_PIXEL')

# Both flags should be set to zero, indicating clear conditions.
mask = qa.bitwiseAnd(cloudShadowBitMask).eq(0).And(qa.bitwiseAnd(cloudsBitMask).eq(0))
Expand All @@ -21,7 +21,7 @@ def cloud_mask_l457(image):
"""
Cloud Mask for Landsat 7 surface reflectance. Derived From: https://developers.google.com/earth-engine/datasets/catalog/LANDSAT_LE07_C01_T1_SR
"""
qa = image.select('pixel_qa')
qa = image.select('QA_PIXEL')

# If the cloud bit (5) is set and the cloud confidence (7) is high
# or the cloud shadow bit is set (3), then it's a bad pixel.
Expand All @@ -46,4 +46,4 @@ def mask_s2_clouds(image):
# Both flags should be set to zero, indicating clear conditions.
mask = qa.bitwiseAnd(cloudBitMask).eq(0).And(qa.bitwiseAnd(cirrusBitMask).eq(0))

return image.updateMask(mask).divide(10000)
return image.updateMask(mask).divide(10000)
30 changes: 12 additions & 18 deletions tethysapp/earth_engine/gee/methods.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
import math
import os
import logging
import ee
from ee.ee_exception import EEException
import geojson
import pandas as pd
from .products import EE_PRODUCTS
from . import cloud_mask as cm
from ..app import EarthEngine as app
import geojson
import pandas as pd
import os
import json
import math

from ..app import App

log = logging.getLogger(f'tethys.apps.{__name__}')

service_account = app.get_custom_setting('service_account_email')
private_key_path = app.get_custom_setting('private_key_file')
service_account = App.get_custom_setting('service_account_email')
private_key_path = App.get_custom_setting('private_key_file')

if service_account and private_key_path and os.path.isfile(private_key_path):
try:
Expand Down Expand Up @@ -41,7 +43,6 @@ def image_to_map_id(image_name, vis_params={}):
except EEException:
log.exception('An error occurred while attempting to retrieve the map id.')


def get_image_collection_asset(request, platform, sensor, product, date_from=None, date_to=None, reducer='median'):
"""
Get tile url for image collection asset.
Expand Down Expand Up @@ -88,7 +89,6 @@ def get_image_collection_asset(request, platform, sensor, product, date_from=Non
except EEException:
log.exception('An error occurred while attempting to retrieve the image collection asset.')


def get_time_series_from_image_collection(platform, sensor, product, index_name, scale=30, geometry=None,
date_from=None, date_to=None, reducer='median', orient='df'):
"""
Expand Down Expand Up @@ -153,8 +153,7 @@ def get_index(image):

log.debug(f'Time Series: {time_series}')
return time_series



def upload_shapefile_to_gee(user, shp_file):
"""
Upload a shapefile to Google Earth Engine as an asset.
Expand Down Expand Up @@ -182,10 +181,9 @@ def upload_shapefile_to_gee(user, shp_file):
features.append(ee.Feature(geojson_feature))

feature_collection = ee.FeatureCollection(features)

# Get unique folder for each user to story boundary asset
user_boundary_asset_path = get_user_boundary_path(user)

# Overwrite an existing asset with this name by deleting it first
try:
ee.batch.data.deleteAsset(user_boundary_asset_path)
Expand All @@ -204,7 +202,6 @@ def upload_shapefile_to_gee(user, shp_file):

task.start()


def get_asset_dir_for_user(user):
"""
Get a unique asset directory for given user.
Expand Down Expand Up @@ -247,7 +244,6 @@ def get_asset_dir_for_user(user):

return user_root_dir


def get_user_boundary_path(user):
"""
Get a unique path for the user boundary asset.
Expand All @@ -262,7 +258,6 @@ def get_user_boundary_path(user):
user_boundary_asset_path = os.path.join(user_asset_dir, 'boundary')
return user_boundary_asset_path


def get_boundary_fc_for_user(user):
"""
Get the boundary FeatureClass for the given user if it exists.
Expand All @@ -285,7 +280,6 @@ def get_boundary_fc_for_user(user):

return None


def get_boundary_fc_props_for_user(user):
"""
Get various properties of the boundary FeatureCollection.
Expand Down Expand Up @@ -324,4 +318,4 @@ def get_boundary_fc_props_for_user(user):
'centroid': centroid.get('coordinates')
}

return fc_props
return fc_props
4 changes: 4 additions & 0 deletions tethysapp/earth_engine/gee/params.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from pathlib import Path

service_account = '' # your google service account
private_key = '' # path to the json private key for the service account
Loading

0 comments on commit a5acf3f

Please sign in to comment.