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 217e019 commit b54f6de
Show file tree
Hide file tree
Showing 26 changed files with 10,991 additions and 396 deletions.
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:
7 changes: 4 additions & 3 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +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
)

setup(
name=release_package,
Expand All @@ -28,4 +29,4 @@
include_package_data=True,
zip_safe=False,
install_requires=dependencies,
)
)
7 changes: 3 additions & 4 deletions tethysapp/earth_engine/app.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
from tethys_sdk.base import TethysAppBase


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 All @@ -15,4 +14,4 @@ class EarthEngine(TethysAppBase):
color = '#524745'
tags = ''
enable_feedback = False
feedback_emails = []
feedback_emails = []
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)
39 changes: 13 additions & 26 deletions tethysapp/earth_engine/gee/methods.py
Original file line number Diff line number Diff line change
@@ -1,34 +1,29 @@
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 params as gee_account
from .products import EE_PRODUCTS
from . import cloud_mask as cm
import geojson
import pandas as pd
import os
import json
import math

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

if gee_account.service_account:
try:
credentials = ee.ServiceAccountCredentials(gee_account.service_account, gee_account.private_key)
ee.Initialize(credentials)
log.info('Successfully initialized GEE using service account.')
except EEException as e:
print(str(e))
log.warning('Unable to initialize GEE using service account. If installing ignore this warning.')
else:
try:
ee.Initialize()
except EEException as e:
from oauth2client.service_account import ServiceAccountCredentials
credentials = ServiceAccountCredentials.from_p12_keyfile(
service_account_email='',
filename='',
private_key_password='notasecret',
scopes=ee.oauth.SCOPE + ' https://www.googleapis.com/auth/drive '
)
ee.Initialize(credentials)
log.warning('Unable to initialize GEE with local credentials. If installing ignore this warning.')


def image_to_map_id(image_name, vis_params={}):
Expand All @@ -44,7 +39,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 @@ -91,7 +85,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 @@ -156,8 +149,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 @@ -185,16 +177,15 @@ 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)
except EEException as e:
# Nothing to delete, so pass
if 'Asset not found' not in str(e):
if 'Asset not found' not in str(e) and 'does not exist' not in str(e):
log.exception('Encountered an unhandled EEException.')
raise e

Expand All @@ -207,7 +198,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 @@ -250,7 +240,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 @@ -265,7 +254,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 @@ -288,7 +276,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 @@ -327,4 +314,4 @@ def get_boundary_fc_props_for_user(user):
'centroid': centroid.get('coordinates')
}

return fc_props
return fc_props
2 changes: 2 additions & 0 deletions tethysapp/earth_engine/gee/params.py
Original file line number Diff line number Diff line change
@@ -1,2 +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 b54f6de

Please sign in to comment.