├── .gitignore ├── .pre-commit-config.yaml ├── Dockerfile ├── LICENSE ├── Makefile ├── README.md ├── bitbucket-pipelines.yml ├── cfo ├── __init__.py ├── __version__.py ├── data │ └── paths.json ├── tests │ └── test_utils.py └── utils.py ├── demos ├── api-introduction.ipynb ├── cloud-forest-demo.ipynb └── czu-perimeter.geojson ├── environment.yml ├── img ├── cfo-fire.jpg ├── cfo-height.png ├── cfo-logo.png ├── cfo-terrain.jpg ├── cfo-understory.png └── ipyleaflet-example.jpg ├── requirements.txt └── setup.py /.gitignore: -------------------------------------------------------------------------------- 1 | .zedstate 2 | *.pyc 3 | *__pycache__/* 4 | build/* 5 | dist/* 6 | cfo.egg-info/* 7 | .make/* 8 | .gcloudignore 9 | .dockerignore 10 | .coverage 11 | *.tif 12 | demos/.ipynb_checkpoints/* 13 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | # See https://pre-commit.com for more information 2 | # See https://pre-commit.com/hooks.html for more hooks 3 | 4 | default_language_version: 5 | python: python3.7 6 | repos: 7 | - repo: https://github.com/ambv/black 8 | rev: stable 9 | hooks: 10 | - id: black 11 | args: ["cfo", "--line-length=120", "--target-version=py37"] 12 | - repo: https://github.com/pycqa/flake8 13 | rev: master 14 | hooks: 15 | - id: flake8 16 | args: ["--select=C,E,F,W,B,B950", "--max-line-length=88", "--ignore=E203,E501,W503,F401"] 17 | - repo: https://github.com/pre-commit/pre-commit-hooks 18 | rev: v2.4.0 19 | hooks: 20 | - id: check-yaml 21 | - id: check-added-large-files 22 | - id: end-of-file-fixer 23 | - id: requirements-txt-fixer 24 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM continuumio/miniconda:latest 2 | 3 | # create working directory 4 | ENV APP_HOME /app 5 | WORKDIR $APP_HOME 6 | 7 | # install the conda environment 8 | COPY requirements.txt . 9 | COPY environment.yml . 10 | RUN conda env create --file environment.yml 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020+ Salo Sciences 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # SETUP 2 | 3 | # help documentation 4 | .DEFAULT: help 5 | help: 6 | @echo "make init" 7 | @echo " initialize tools for development -- conda, pip, etc" 8 | @echo "make update" 9 | @echo " update tools for development -- conda, pip, etc" 10 | @echo "make docker-build" 11 | @echo " build docker image for salo-data-acquisition service" 12 | @echo "make docker-deploy" 13 | @echo " build and deploy docker image for cfo-api" 14 | @echo "make docker-clean" 15 | @echo " clean all docker containers, images, and data" 16 | @echo "make test" 17 | @echo " run tests" 18 | 19 | # environment variables 20 | CONDA_ENV=cfo 21 | CONDA_RUN=conda run --name ${CONDA_ENV} 22 | DOCKER_IMAGE=us.gcr.io/california-fores-1547767414612/cfo-api 23 | DOCKER_TAG_GIT:=$(shell git rev-parse --short=12 HEAD) 24 | 25 | # create directory for dummy files to indicate when targets need to be rerun 26 | DIR_MAKE=.make 27 | CONDA_UPDATED=${DIR_MAKE}/conda_updated 28 | PIP_UPDATED=${DIR_MAKE}/pip_updated 29 | DOCKER_INITIALIZED=${DIR_MAKE}/docker_initialized 30 | 31 | 32 | # ENTRY POINTS 33 | 34 | # initialize tools 35 | init: conda-init pip-init misc-update 36 | @: 37 | 38 | # update tools 39 | update: conda-update pip-update misc-update 40 | @: 41 | 42 | # run tests 43 | test: 44 | ${CONDA_RUN} pip install . && pytest --cov --no-cov-on-fail --cov-report=term-missing:skip-covered 45 | 46 | 47 | # DETAILED ENTRIES 48 | 49 | # conda 50 | conda-init: 51 | @conda env list | grep -q -w ${CONDA_ENV} || conda env create --file environment.yml 52 | @test -d ${DIR_MAKE} || mkdir ${DIR_MAKE} 53 | @touch ${CONDA_UPDATED} 54 | 55 | conda-update: conda-init ${CONDA_UPDATED} 56 | @: 57 | ${CONDA_UPDATED}: environment.yml 58 | ${CONDA_RUN} conda env update --file environment.yml --prune 59 | @test -d ${DIR_MAKE} || mkdir ${DIR_MAKE} 60 | @touch ${CONDA_UPDATED} 61 | 62 | # pip -- only needed because some packages are not available via conda, need to use the conda version of pip to work correctly 63 | pip-init: ${PIP_UPDATED} 64 | @: 65 | pip-update: ${PIP_UPDATED} 66 | @: 67 | ${PIP_UPDATED}: requirements.txt 68 | ${CONDA_RUN} pip install -r requirements.txt 69 | ${CONDA_RUN} pip install --editable . 70 | @test -d ${DIR_MAKE} || mkdir ${DIR_MAKE} 71 | @touch ${PIP_UPDATED} 72 | 73 | # misc 74 | misc-update: 75 | @${CONDA_RUN} pre-commit install 76 | @test ! -f .gcloudignore || rm .gcloudignore 77 | @cp .gitignore .gcloudignore 78 | 79 | 80 | # docker 81 | docker-init: ${DOCKER_INITIALIZED} 82 | @: 83 | ${DOCKER_INITIALIZED}: 84 | gcloud auth configure-docker 85 | @test -d ${DIR_MAKE} || mkdir ${DIR_MAKE} 86 | @touch ${DOCKER_INITIALIZED} 87 | 88 | docker-build: docker-init docker-clean 89 | @test ! -f .dockerignore || rm .dockerignore 90 | @cp .gitignore .dockerignore 91 | docker build --tag ${DOCKER_IMAGE}:${DOCKER_TAG_GIT} . 92 | docker tag ${DOCKER_IMAGE}:${DOCKER_TAG_GIT} ${DOCKER_IMAGE}:testing 93 | docker tag ${DOCKER_IMAGE}:${DOCKER_TAG_GIT} ${DOCKER_IMAGE}:latest 94 | @docker system prune -f 95 | 96 | docker-clean: 97 | @docker system prune -f 98 | 99 | docker-deploy: docker-build 100 | docker push ${DOCKER_IMAGE}:${DOCKER_TAG_GIT} 101 | gcloud container images add-tag ${DOCKER_IMAGE}:${DOCKER_TAG_GIT} ${DOCKER_IMAGE}:testing -q 102 | gcloud container images add-tag ${DOCKER_IMAGE}:${DOCKER_TAG_GIT} ${DOCKER_IMAGE}:latest -q 103 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | California Forest Observatory 2 | 3 | # Introduction 4 | 5 | The [California Forest Observatory][cfo-web] (CFO) is a data-driven forest monitoring system that maps the drivers of wildfire behavior across the state—including vegetation fuels, weather, topography & infrastructure—from space. 6 | 7 | The `cfo` library was designed to provide easy access to CFO datasets. Each dataset has a unique `asset_id`, and the `search` and `fetch` workflows were designed to query and download these assets. 8 | 9 | - You can search for asset IDs by geography, data type, and time of year 10 | - `forest.search(geography="SantaCruzCounty", metric="CanopyHeight", year=2020)` 11 | - You can download the data to your loacal machine 12 | - `forest.download(asset_id, output_file)` 13 | - If you don't want the file, you can just fetch the download URL 14 | - `forest.fetch(asset_id, dl=True)` 15 | - Or a WMS URL for web mapping 16 | - `forest.fetch(asset_id, wms=True)` 17 | 18 | You can find support for the CFO API at the [community forum][cfo-forum]. 19 | 20 | ## License 21 | 22 | CFO data are available for free for non-commercial use per the [API terms][api-terms]. You must have a CFO account, which you can create by visiting [the web map][cfo-web], clicking the menu in the top right corner and selecting "Create an account." Please keep track of the e-mail address and password you used to create your Forest Observatory account, as you'll need them to authenticate API access. 23 | 24 | The software provided here, the `cfo` python API wrapper, is provided with an MIT license. Please do not confuse the license terms for the wrapper with the [terms of use][api-terms] for the API. 25 | 26 | ## Table of contents 27 | 28 | - [Installation](#installation) 29 | - [Authentication](#authentication) 30 | - [Searching for data](#searching) 31 | - [Downloading data](#downloads) 32 | - [Serving map tiles](#map-tiles) 33 | - [Contact](#contact) 34 | 35 | # Installation 36 | 37 | This library can be installed via `pip` directly from Github. 38 | 39 | ```bash 40 | pip install cfo 41 | ``` 42 | 43 | If you don't have `pip` you could also clone the repository locally and install using python's `setuptools` 44 | 45 | ```bash 46 | git clone https://github.com/forestobservatory/cfo-api.git 47 | cd cfo-api 48 | python setup.py install 49 | ``` 50 | 51 | Once installed, you should be able to load the `cfo` module in python. Instatiate the `api` class to begin working with the Forest Observatory API. 52 | 53 | ```python 54 | import cfo 55 | forest = cfo.api() 56 | ``` 57 | 58 | Canopy Height 59 | 60 | # Authentication 61 | 62 | A Forest Observatory account is required to use the API (sign up free at [forestobservatory.com][cfo-web]). 63 | 64 | There are two authentication methods: entering your CFO account's email/password at runtime or setting environment variables. 65 | 66 | ### Passing your credentials at runtime 67 | 68 | Using any API call (`forest.search()`, `forest.fetch()`, `forest.download()`) will prompt you to enter the following authentication information: 69 | 70 | ```python 71 | >>> CFO E-mail: slug@forest.net 72 | >>> CFO Password: ********** 73 | ``` 74 | 75 | You can also authenticate directly with `forest.authenticate()`. 76 | 77 | This retrieves an authentication token from the API, which is stored as a temp file for future access (this does not store your e-mail/password). The API reads this stored token, which means you won't have to pass your email/password during each session. 78 | 79 | ### Setting environment variables 80 | 81 | You can forego runtime credential entry by setting environment variables. This is the lowest friction, least secure approach. You'll set the following variables in your `.bashrc` profile or elsewhere. 82 | 83 | ```bash 84 | export CFO_EMAIL=slug@forest.net 85 | export CFO_PASS=ari0limax 86 | ``` 87 | 88 | ### Restoring a botched authentication 89 | 90 | The temp file that stores your authentication credentials can sometimes get donked up. To re-authenticate, use the following command to pass your credentials and overwrite the temporary token data. 91 | 92 | ```python 93 | forest.authenticate(ignore_temp=True) 94 | ``` 95 | 96 | Spotting during the Rough Fire 97 | 98 | # Searching 99 | 100 | CFO data are organized by `asset_id`. These IDs contain information on the spatial extent of the data, the category and name of the data, the time of collection, and the spatial resolution. Asset IDs follow this naming format: 101 | 102 | ```python 103 | asset_id = {geography}-{category}-{metric}-{year}-{timeOfYear}-{resolution} 104 | ``` 105 | 106 | Some examples: 107 | 108 | - A statewide vegetation fuels dateset that's rendered in the Layers tab: `California-Vegetation-CanopyHeight-2020-Summer-00010m`. 109 | - A statewide weather dataset queried in the Trends tab: `California-Weather-WindSpeed-2020-0601-03000m`. 110 | - A county-level dataset accessed in the Download tab: `Marin-Vegetation-SurfaceFuels-2020-Spring-00010m`. 111 | 112 | The `forest.search()` function queries the API and returns the assets that match the search terms. 113 | 114 | ```python 115 | >>> import cfo 116 | >>> forest = cfo.api() 117 | >>> forest.search(geography="MendocinoCounty", metric="CanopyCover") 118 | 2020-09-07 13:53:47,028 INFO cfo.utils [authenticate] Loaded cfo token 119 | ['MendocinoCounty-Vegetation-CanopyCover-2020-Fall-00010m'] 120 | ``` 121 | 122 | The default behavior of this function is to return the asset IDs as a list. 123 | 124 | You could instead return the API JSON data, including asset ID, the spatial extent (`bbox`) of the data, the catalog its stored in, etc. by setting `just_assets=False`. 125 | 126 | ```python 127 | >>> forest.search(geography="MendocinoCounty", metric="CanopyCover", just_assets=False) 128 | [{'asset_id': 'MendocinoCounty-Vegetation-CanopyCover-2020-Fall-00010m', 129 | 'attribute_dict': {}, 130 | 'bbox': [-124.022978699284, -122.814767867036, 38.7548320538975, 40.0060478879686], 131 | 'catalog': 'cfo', 132 | 'description': 'CanopyCover', 133 | 'expiration_utc_datetime': '', 134 | 'utc_datetime': '2020-07-09 09:52:42.292286+00:00'}] 135 | ``` 136 | 137 | And to examine the full response from the `requests` library, use `forest.search(raw=True)`. 138 | 139 | But with over 17,000 published assets it's not easy to know just what to search by. So we wrote some functions to simplify your searches. 140 | 141 | ### Convenience functions 142 | 143 | Based on the asset ID naming convention above, we've provided some `list` functions as a guide to what's available. 144 | 145 | - Geography - CFO datasets have been clipped to different spatial extents: statewide, by county, by municipality, by watershed. 146 | - `forest.list_geographies()` - returns the different geographic extents. Use `forest.list_geographies(by="County")` to narrow return just the unique counties. 147 | - `forest.list_geography_types()` - returns the categories of geographical clipping available. 148 | - Category - we currently provide three categories of data. 149 | - `forest.list_categories()` - returns [`Vegetation`, `Weather`, `Wildfire`] 150 | - Metric - each category of data contains a list of different available data types 151 | - `forest.list_metrics()` - returns the unique metrics for each category. 152 | - Run `forest.list_metrics(category="Weather")` to return only weather-specific metrics. 153 | 154 | Use these as keywords when searching for data (e.g. `id_list = forest.search(geography="FresnoCounty", category="Vegetation")`). 155 | 156 | You can also use wildcards: 157 | 158 | ```python 159 | >>> forest.search(geography='Plumas*', metric='CanopyHeight') 160 | ['PlumasCounty-Vegetation-CanopyHeight-2020-Fall-00010m', 161 | 'PlumasEurekaMunicipality-Vegetation-CanopyHeight-2020-Fall-00010m', 162 | 'PlumasLakeMunicipality-Vegetation-CanopyHeight-2020-Fall-00010m'] 163 | ``` 164 | 165 | ### A note on availabile datasets 166 | 167 | Even though we have a range of geographic extents, resolutions, and metrics, it is **not** the case that we provide all permutations of extent/resolution/metric. For example, we clip all `Vegetation` data to the county level, but we do not clip any `Weather` data that fine. All weather data are only available at the state level. 168 | 169 | This means you don't really need to specify the geographic extent if you search for weather data. You'll get pretty far with `wind_ids = forest.search(metric="WindSpeed")`. 170 | 171 | Redwood understory 172 | 173 | # Downloads 174 | 175 | Once you've generated a list of asset IDs, you can then download the files to your local machine. The `forest.download()` function requires an asset_id string so you'll have to iterate over search results, which are often returned as lists. 176 | 177 | Here's how to search for and download all data from Mendocino County. 178 | 179 | ```python 180 | import cfo 181 | forest = cfo.api() 182 | asset_ids = forest.search(geography="MendocinoCounty") 183 | for asset in asset_ids: 184 | forest.download(asset) 185 | ``` 186 | 187 | Which generates the following output as it downloads each file. 188 | 189 | ``` 190 | 2020-09-07 16:19:24,542 INFO cfo.utils [download] Beginning download for: MendocinoCounty-Vegetation-CanopyHeight-2020-Fall-00010m 191 | 2020-09-07 16:19:28,853 INFO cfo.utils [download] Successfully downloaded MendocinoCounty-Vegetation-CanopyHeight-2020-Fall-00010m to file: /home/slug/MendocinoCounty-Vegetation-CanopyHeight-2020-Fall-00010m.tif 192 | 2020-09-07 16:19:29,359 INFO cfo.utils [download] Beginning download for: MendocinoCounty-Vegetation-CanopyBaseHeight-2020-Fall-00010m 193 | 2020-09-07 16:19:32,321 INFO cfo.utils [download] Successfully downloaded MendocinoCounty-Vegetation-CanopyBaseHeight-2020-Fall-00010m to file: /home/slug/MendocinoCounty-Vegetation-CanopyBaseHeight-2020-Fall-00010m.tif 194 | ... 195 | ``` 196 | 197 | This function uses the `fetch()` command under the hood to retrieve a URL for where the file is hosted on google cloud storage. It then performs a `GET` call to download the file locally. 198 | 199 | The function will download the file to your current working directory if you don't specify an output file path. You can set a custom output path with `forest.download(asset_id, path)`. This may be tricky if you're downloading multiple datasets, but you could parse the asset_id to generate useful names for output files. 200 | 201 | ```python 202 | asset_ids = forest.search(geography="MendocinoCounty") 203 | for asset in asset_ids: 204 | geo, category, metric, year, timeOfYear, res = asset.split("-") 205 | output_path = f"/external/downloads/CFO-{metric}-{year}.tif" 206 | forest.download(asset, output_path) 207 | ``` 208 | 209 | Which generates the following output: 210 | 211 | ``` 212 | 2020-09-07 23:10:02,312 INFO cfo.utils [download] Beginning download for: MendocinoCounty-Vegetation-CanopyHeight-2020-Fall-00010m 213 | 2020-09-07 23:10:25,163 INFO cfo.utils [download] Successfully downloaded MendocinoCounty-Vegetation-CanopyHeight-2020-Fall-00010m to file: /external/downloads/CFO-CanopyHeight-2020.tif 214 | 2020-09-07 23:10:25,596 INFO cfo.utils [download] Beginning download for: MendocinoCounty-Vegetation-CanopyBaseHeight-2020-Fall-00010m 215 | 2020-09-07 23:10:47,965 INFO cfo.utils [download] Successfully downloaded MendocinoCounty-Vegetation-CanopyBaseHeight-2020-Fall-00010m to file: /external/downloads/CFO-CanopyBaseHeight-2020.tif 216 | ... 217 | ``` 218 | Mono Lake 219 | 220 | # Map tiles 221 | 222 | The `fetch` function also returns URLs for displaying CFO data in web mapping applications as WMS tile layers. 223 | 224 | ```python 225 | forest.fetch("MendocinoCounty-Vegetation-CanopyHeight-2020-Fall-00010m", wms=True) 226 | 'https://maps.salo.ai/geoserver/cfo/wms?layers=cfo:MendocinoCounty-Vegetation-CanopyHeight-2020-Fall-00010m&format="image/png"&styles=vegetation&p0=0.0&p2=1.44&p25=18.0&p30=21.599999999999998&p50=36.0&p60=43.199999999999996&p75=54.0&p90=64.8&p98=70.56&p100=72.0' 227 | 228 | ``` 229 | 230 | WMS URLs don't always easily plug and play with different rendering services, but they should work with a little nudging. Here's how to use the above URL to visualize these data in a jupyter notebook with `ipyleaflet`. 231 | 232 | ```python 233 | from ipyleaflet import Map, WMSLayer, LayersControl, basemaps 234 | wms = WMSLayer( 235 | url='https://maps.salo.ai/geoserver/cfo/wms?p0=0.0&p2=1.44&p25=18.0&p30=21.599999999999998&p50=36.0&p60=43.199999999999996&p75=54.0&p90=64.8&p98=70.56&p100=72.0', 236 | layers="cfo:MendocinoCounty-Vegetation-CanopyHeight-2020-Fall-00010m", 237 | name="Mendocino Canopy Height", 238 | styles="vegetation", 239 | format="image/png8", 240 | transparent=True, 241 | attribution="Forest Observatory © Salo Sciences", 242 | ) 243 | m = Map(basemap=basemaps.Stamen.Terrain, center=(39.39,-123.33), zoom=10) 244 | m.add_layer(wms) 245 | control = LayersControl(position='topright') 246 | m.add_control(control) 247 | m 248 | ``` 249 | 250 | This code, executed in `jupyter-lab`, should look something like this. 251 | 252 | CFO WMS example 253 | 254 | The URL has a lot of useful information. Here's a quick breakdown of what's encoded in the string returned from `fetch`. 255 | 256 | - The base URL (`https://maps.salo.ai/geoserver/cfo/wms`) is our map server address. 257 | - Each component following the `?` is a parameter passed to the map server. 258 | - `layers` specifies which asset to show (and is defined based on `{catalog}:{asset_id}` naming). 259 | - `format` defines the image format the data are rendered in (use `image/png8` for best performance). 260 | - `styles` defines the color palette (which you can retrieve with `forest.list_styles()`). 261 | - the long list of `p0, p2, p25, ..., p100` are parameters we use to render custom raster styles on the fly. These numbers are based on the min/max raster values of a dataset and can be altered on the fly to dynamically scale the data. 262 | 263 | # Contact 264 | 265 | Issue tracking isn't set up for this repository yet. Please visit the [Forest Observatory Community Forum][cfo-forum] for technical support. To get in touch directly or to inquire about commercial API access, contact [tech@forestobservatory.com](mailto:tech@forestobservatory.com). 266 | 267 | The California Forest Observatory API is developed and maintained by [Salo Sciences][salo-web]. 268 | 269 | 270 | [api-terms]: https://forestobservatory.com/api.html 271 | [cfo-web]: https://forestobservatory.com 272 | [cfo-forum]: https://groups.google.com/a/forestobservatory.com/g/community 273 | [salo-web]: https://salo.ai 274 | -------------------------------------------------------------------------------- /bitbucket-pipelines.yml: -------------------------------------------------------------------------------- 1 | definitions: 2 | steps: 3 | - step: &unit-tests 4 | name: Run unit tests 5 | script: 6 | - export PYTHONPATH=$PYTHONPATH:/opt/atlassian/pipelines/agent/build 7 | - conda run --name cfo pytest --cov --cov-report=xml:test-results/results.xml --cov-report=term-missing:skip-covered 8 | images: 9 | - image: &testing 10 | name: us.gcr.io/california-fores-1547767414612/cfo-api:testing 11 | username: _json_key 12 | password: '$GCR_JSON_KEY' 13 | 14 | pipelines: 15 | pull-requests: 16 | '**': 17 | - step: 18 | <<: *unit-tests 19 | image: *testing 20 | branches: 21 | master: 22 | - step: 23 | <<: *unit-tests 24 | image: *testing 25 | -------------------------------------------------------------------------------- /cfo/__init__.py: -------------------------------------------------------------------------------- 1 | from .utils import API as api 2 | -------------------------------------------------------------------------------- /cfo/__version__.py: -------------------------------------------------------------------------------- 1 | "1.0.1" 2 | -------------------------------------------------------------------------------- /cfo/data/paths.json: -------------------------------------------------------------------------------- 1 | {"category":["Vegetation","Wildfire","Weather"],"metric":{"Vegetation":["CanopyHeight","CanopyCover","CanopyBaseHeight","CanopyBulkDensity","CanopyLayerCount","LadderFuelDensity","SurfaceFuels"],"Wildfire":["Hazard","Exposure"],"Weather":["Temperature","Humidity","WindDirection","WindSpeed"]},"geography":{"State":["California"],"County":["AlamedaCounty","AlpineCounty","AmadorCounty","ButteCounty","CalaverasCounty","ColusaCounty","ContraCostaCounty","DelNorteCounty","ElDoradoCounty","FresnoCounty","GlennCounty","HumboldtCounty","ImperialCounty","InyoCounty","KernCounty","KingsCounty","LakeCounty","LassenCounty","LosAngelesCounty","MaderaCounty","MarinCounty","MariposaCounty","MendocinoCounty","MercedCounty","ModocCounty","MonoCounty","MontereyCounty","NapaCounty","NevadaCounty","OrangeCounty","PlacerCounty","PlumasCounty","RiversideCounty","SacramentoCounty","SanBenitoCounty","SanBernardinoCounty","SanDiegoCounty","SanFranciscoCounty","SanJoaquinCounty","SanLuisObispoCounty","SanMateoCounty","SantaBarbaraCounty","SantaClaraCounty","SantaCruzCounty","ShastaCounty","SierraCounty","SiskiyouCounty","SolanoCounty","SonomaCounty","StanislausCounty","SutterCounty","TehamaCounty","TrinityCounty","TulareCounty","TuolumneCounty","VenturaCounty","YoloCounty","YubaCounty"],"Municipality":["AcalanesRidgeMunicipality","AcampoMunicipality","ActonMunicipality","AdelantoMunicipality","AdinMunicipality","AgouraHillsMunicipality","AguaDulceMunicipality","AguangaMunicipality","AhwahneeMunicipality","AirportMunicipality","AlamedaMunicipality","AlamoMunicipality","AlbanyMunicipality","AlbionMunicipality","AlderpointMunicipality","AlhambraMunicipality","AlhambraValleyMunicipality","AlisoViejoMunicipality","AlleghanyMunicipality","AllendaleMunicipality","AllensworthMunicipality","AlmanorMunicipality","AlondraParkMunicipality","AlpaughMunicipality","AlpineMunicipality","AlpineVillageMunicipality","AltaMunicipality","AltaSierraMunicipality","AltadenaMunicipality","AltoMunicipality","AlturasMunicipality","AlumRockMunicipality","AmadorCityMunicipality","AmericanCanyonMunicipality","AmestiMunicipality","AnaheimMunicipality","AnchorBayMunicipality","AndersonMunicipality","AngelsMunicipality","AngwinMunicipality","AntelopeMunicipality","AntiochMunicipality","AnzaMunicipality","AppleValleyMunicipality","AptosMunicipality","AptosHillsLarkinValleyMunicipality","ArbuckleMunicipality","ArcadiaMunicipality","ArcataMunicipality","ArdenArcadeMunicipality","ArmonaMunicipality","ArnoldMunicipality","AromasMunicipality","ArroyoGrandeMunicipality","ArtesiaMunicipality","ArtoisMunicipality","ArvinMunicipality","AshlandMunicipality","AspenSpringsMunicipality","AtascaderoMunicipality","AthertonMunicipality","AtwaterMunicipality","AuberryMunicipality","AuburnMunicipality","AuburnLakeTrailsMunicipality","AugustMunicipality","AvalonMunicipality","AvenalMunicipality","AveryMunicipality","AvilaBeachMunicipality","AvocadoHeightsMunicipality","AzusaMunicipality","BakerMunicipality","BakersfieldMunicipality","BaldwinParkMunicipality","BallardMunicipality","BallicoMunicipality","BangorMunicipality","BanningMunicipality","BarstowMunicipality","BassLakeMunicipality","BayPointMunicipality","BayviewMunicipality","BealeAFBMunicipality","BearCreekMunicipality","BearValleyMunicipality","BearValleySpringsMunicipality","BeaumontMunicipality","BeckwourthMunicipality","BeldenMunicipality","BellMunicipality","BellCanyonMunicipality","BellGardensMunicipality","BellaVistaMunicipality","BellflowerMunicipality","BelmontMunicipality","BelvedereMunicipality","BenLomondMunicipality","BenbowMunicipality","BendMunicipality","BeniciaMunicipality","BentonMunicipality","BerkeleyMunicipality","BermudaDunesMunicipality","BerryCreekMunicipality","BertschOceanviewMunicipality","BethelIslandMunicipality","BeverlyHillsMunicipality","BieberMunicipality","BigBearCityMunicipality","BigBearLakeMunicipality","BigBendMunicipality","BigCreekMunicipality","BigLagoonMunicipality","BigPineMunicipality","BigRiverMunicipality","BiggsMunicipality","BiolaMunicipality","BishopMunicipality","BlackPointGreenPointMunicipality","BlackhawkMunicipality","BlacklakeMunicipality","BlairsdenMunicipality","BloomfieldMunicipality","BloomingtonMunicipality","BlueLakeMunicipality","BluewaterMunicipality","BlytheMunicipality","BodegaMunicipality","BodegaBayMunicipality","BodfishMunicipality","BolinasMunicipality","BombayBeachMunicipality","BonadelleRanchosMaderaRanchosMunicipality","BonitaMunicipality","BonnyDoonMunicipality","BonsallMunicipality","BoonvilleMunicipality","BootjackMunicipality","BoronMunicipality","BorondaMunicipality","BorregoSpringsMunicipality","BostoniaMunicipality","BoulderCreekMunicipality","BoulevardMunicipality","BowlesMunicipality","BoyesHotSpringsMunicipality","BradburyMunicipality","BradleyMunicipality","BrawleyMunicipality","BreaMunicipality","BrentwoodMunicipality","BretHarteMunicipality","BridgeportMunicipality","BrisbaneMunicipality","BroadmoorMunicipality","BrookdaleMunicipality","BrooktrailsMunicipality","BuckMeadowsMunicipality","BuckhornMunicipality","BucksLakeMunicipality","BuelltonMunicipality","BuenaParkMunicipality","BuenaVistaMunicipality","BurbankMunicipality","BurlingameMunicipality","BurneyMunicipality","BurntRanchMunicipality","ButteCreekCanyonMunicipality","ButteMeadowsMunicipality","ButteValleyMunicipality","ButtonwillowMunicipality","ByronMunicipality","BystromMunicipality","CRoadMunicipality","CabazonMunicipality","CalabasasMunicipality","CalexicoMunicipality","CaliforniaCityMunicipality","CaliforniaHotSpringsMunicipality","CaliforniaPinesMunicipality","CalimesaMunicipality","CalipatriaMunicipality","CalistogaMunicipality","CallenderMunicipality","CalpellaMunicipality","CalpineMunicipality","CalwaMunicipality","CamancheNorthShoreMunicipality","CamancheVillageMunicipality","CamarilloMunicipality","CambriaMunicipality","CambrianParkMunicipality","CameronParkMunicipality","CaminoMunicipality","CaminoTassajaraMunicipality","CampNelsonMunicipality","CampPendletonNorthMunicipality","CampPendletonSouthMunicipality","CampbellMunicipality","CampoMunicipality","CamptonvilleMunicipality","CanbyMunicipality","CantuaCreekMunicipality","CanyonLakeMunicipality","CanyondamMunicipality","CapitolaMunicipality","CaribouMunicipality","CarlsbadMunicipality","CarmelValleyVillageMunicipality","CarmelbytheSeaMunicipality","CarmetMunicipality","CarmichaelMunicipality","CarnelianBayMunicipality","CarpinteriaMunicipality","CarrickMunicipality","CarsonMunicipality","CartagoMunicipality","CaruthersMunicipality","CasaConejoMunicipality","CasadeOroMountHelixMunicipality","CasmaliaMunicipality","CasparMunicipality","CasselMunicipality","CastaicMunicipality","CastleHillMunicipality","CastroValleyMunicipality","CastrovilleMunicipality","CathedralCityMunicipality","CatheysValleyMunicipality","CayucosMunicipality","CazaderoMunicipality","CedarRidgeMunicipality","CedarSlopeMunicipality","CedarvilleMunicipality","CentervilleMunicipality","CeresMunicipality","CerritosMunicipality","ChalfantMunicipality","ChallengeBrownsvilleMunicipality","ChannelIslandsBeachMunicipality","CharterOakMunicipality","CherokeeMunicipality","CherokeeStripMunicipality","CherryValleyMunicipality","CherrylandMunicipality","ChesterMunicipality","ChicoMunicipality","ChilcootVintonMunicipality","ChinaLakeAcresMunicipality","ChineseCampMunicipality","ChinoMunicipality","ChinoHillsMunicipality","ChowchillaMunicipality","ChualarMunicipality","ChulaVistaMunicipality","CitrusMunicipality","CitrusHeightsMunicipality","ClaremontMunicipality","ClarksburgMunicipality","ClayMunicipality","ClaytonMunicipality","ClearCreekMunicipality","ClearlakeMunicipality","ClearlakeOaksMunicipality","ClearlakeRivieraMunicipality","CleoneMunicipality","ClioMunicipality","ClipperMillsMunicipality","CloverdaleMunicipality","ClovisMunicipality","ClydeMunicipality","CoachellaMunicipality","CoalingaMunicipality","CoarsegoldMunicipality","CobbMunicipality","CoffeeCreekMunicipality","CohassetMunicipality","ColdSpringsMunicipality","ColevilleMunicipality","ColfaxMunicipality","CollegeCityMunicipality","ColliervilleMunicipality","ColmaMunicipality","ColomaMunicipality","ColtonMunicipality","ColumbiaMunicipality","ColusaMunicipality","CommerceMunicipality","ComptcheMunicipality","ComptonMunicipality","ConcordMunicipality","ConcowMunicipality","ContraCostaCentreMunicipality","CopperopolisMunicipality","CorcoranMunicipality","CorningMunicipality","CoronaMunicipality","CoronadoMunicipality","CoronitaMunicipality","CorralitosMunicipality","CorteMaderaMunicipality","CostaMesaMunicipality","CotatiMunicipality","CotodeCazaMunicipality","CottonwoodMunicipality","CoultervilleMunicipality","CountryClubMunicipality","CourtlandMunicipality","CoveloMunicipality","CovinaMunicipality","CowanMunicipality","CrescentCityMunicipality","CrescentMillsMunicipality","CresseyMunicipality","CrestMunicipality","CrestlineMunicipality","CrestonMunicipality","CrockettMunicipality","CrombergMunicipality","CrowleyLakeMunicipality","CrowsLandingMunicipality","CudahyMunicipality","CulverCityMunicipality","CupertinoMunicipality","CutlerMunicipality","CuttenMunicipality","CuyamaMunicipality","CypressMunicipality","DalyCityMunicipality","DanaPointMunicipality","DanvilleMunicipality","DaphnedaleParkMunicipality","DarwinMunicipality","DavenportMunicipality","DavisMunicipality","DayValleyMunicipality","DeerParkMunicipality","DelAireMunicipality","DelMarMunicipality","DelMonteForestMunicipality","DelReyMunicipality","DelReyOaksMunicipality","DelRioMunicipality","DelanoMunicipality","DelftColonyMunicipality","DelhiMunicipality","DellekerMunicipality","DenairMunicipality","DerbyAcresMunicipality","DescansoMunicipality","DesertCenterMunicipality","DesertEdgeMunicipality","DesertHotSpringsMunicipality","DesertPalmsMunicipality","DesertShoresMunicipality","DesertViewHighlandsMunicipality","DiabloMunicipality","DiabloGrandeMunicipality","DiamondBarMunicipality","DiamondSpringsMunicipality","DillonBeachMunicipality","DinubaMunicipality","DiscoveryBayMunicipality","DixonMunicipality","DixonLaneMeadowCreekMunicipality","DobbinsMunicipality","DogtownMunicipality","DollarPointMunicipality","DorringtonMunicipality","DorrisMunicipality","DosPalosMunicipality","DosPalosYMunicipality","DouglasCityMunicipality","DowneyMunicipality","DownievilleMunicipality","DoyleMunicipality","DrytownMunicipality","DuarteMunicipality","DublinMunicipality","DucorMunicipality","DunniganMunicipality","DunsmuirMunicipality","DurhamMunicipality","DustinAcresMunicipality","DutchFlatMunicipality","EaglevilleMunicipality","EarlimartMunicipality","EastFoothillsMunicipality","EastHemetMunicipality","EastLosAngelesMunicipality","EastNicolausMunicipality","EastOakdaleMunicipality","EastOrosiMunicipality","EastPaloAltoMunicipality","EastPasadenaMunicipality","EastPortervilleMunicipality","EastQuincyMunicipality","EastRanchoDominguezMunicipality","EastRichmondHeightsMunicipality","EastSanGabrielMunicipality","EastShoreMunicipality","EastSonoraMunicipality","EastTulareVillaMunicipality","EastWhittierMunicipality","EastonMunicipality","EastvaleMunicipality","EdgewoodMunicipality","EdmundsonAcresMunicipality","EdnaMunicipality","EdwardsAFBMunicipality","ElCajonMunicipality","ElCentroMunicipality","ElCerritoMunicipality","ElDoradoHillsMunicipality","ElGranadaMunicipality","ElMonteMunicipality","ElNidoMunicipality","ElPasodeRoblesMunicipality","ElPortalMunicipality","ElRanchoMunicipality","ElRioMunicipality","ElSegundoMunicipality","ElSobranteMunicipality","ElVeranoMunicipality","EldridgeMunicipality","ElizabethLakeMunicipality","ElkCreekMunicipality","ElkGroveMunicipality","ElkhornMunicipality","ElmiraMunicipality","ElvertaMunicipality","EmeraldLakeHillsMunicipality","EmeryvilleMunicipality","EmpireMunicipality","EncinitasMunicipality","EscalonMunicipality","EscondidoMunicipality","EspartoMunicipality","EtnaMunicipality","EucalyptusHillsMunicipality","EurekaMunicipality","ExeterMunicipality","FairOaksMunicipality","FairbanksRanchMunicipality","FairfaxMunicipality","FairfieldMunicipality","FairhavenMunicipality","FairmeadMunicipality","FairviewMunicipality","FallRiverMillsMunicipality","FallbrookMunicipality","FarmersvilleMunicipality","FarmingtonMunicipality","FellowsMunicipality","FeltonMunicipality","FerndaleMunicipality","FettersHotSpringsAguaCalienteMunicipality","FiddletownMunicipality","FieldbrookMunicipality","FieldsLandingMunicipality","FillmoreMunicipality","FirebaughMunicipality","FishCampMunicipality","FlorenceGrahamMunicipality","FlorinMunicipality","FloristonMunicipality","FlournoyMunicipality","FolsomMunicipality","FontanaMunicipality","FoothillFarmsMunicipality","ForbestownMunicipality","FordCityMunicipality","ForestMeadowsMunicipality","ForestRanchMunicipality","ForesthillMunicipality","ForestvilleMunicipality","FortBidwellMunicipality","FortBraggMunicipality","FortDickMunicipality","FortIrwinMunicipality","FortJonesMunicipality","FortWashingtonMunicipality","FortunaMunicipality","FosterCityMunicipality","FountainValleyMunicipality","FowlerMunicipality","FranklinMunicipality","FrazierParkMunicipality","FreedomMunicipality","FreeportMunicipality","FremontMunicipality","FrenchCampMunicipality","FrenchGulchMunicipality","FrenchValleyMunicipality","FresnoMunicipality","FriantMunicipality","FruitdaleMunicipality","FruitridgePocketMunicipality","FullerAcresMunicipality","FullertonMunicipality","FultonMunicipality","FurnaceCreekMunicipality","GaltMunicipality","GarbervilleMunicipality","GardenAcresMunicipality","GardenFarmsMunicipality","GardenGroveMunicipality","GardenaMunicipality","GareyMunicipality","GarnetMunicipality","GasquetMunicipality","GazelleMunicipality","GeorgetownMunicipality","GerberMunicipality","GeyservilleMunicipality","GilroyMunicipality","GlenEllenMunicipality","GlendaleMunicipality","GlendoraMunicipality","GoldMountainMunicipality","GoldRiverMunicipality","GoldenHillsMunicipality","GoletaMunicipality","GonzalesMunicipality","GoodHopeMunicipality","GoodyearsBarMunicipality","GoshenMunicipality","GraeagleMunicipality","GrandTerraceMunicipality","GrangevilleMunicipality","GraniteBayMunicipality","GraniteHillsMunicipality","GranitevilleMunicipality","GrassValleyMunicipality","GratonMunicipality","GraysonMunicipality","GreeleyHillMunicipality","GreenAcresMunicipality","GreenValleyMunicipality","GreenacresMunicipality","GreenfieldMunicipality","GreenhornMunicipality","GreenviewMunicipality","GreenvilleMunicipality","GrenadaMunicipality","GridleyMunicipality","GrimesMunicipality","GrizzlyFlatsMunicipality","GrovelandMunicipality","GroverBeachMunicipality","GuadalupeMunicipality","GuernevilleMunicipality","GuindaMunicipality","GustineMunicipality","HaciendaHeightsMunicipality","HalfMoonBayMunicipality","HamiltonBranchMunicipality","HamiltonCityMunicipality","HanfordMunicipality","HappyCampMunicipality","HarbisonCanyonMunicipality","HardwickMunicipality","HartlandMunicipality","HartleyMunicipality","HasleyCanyonMunicipality","HatCreekMunicipality","HawaiianGardensMunicipality","HawthorneMunicipality","HayforkMunicipality","HaywardMunicipality","HealdsburgMunicipality","HeberMunicipality","HemetMunicipality","HeraldMunicipality","HerculesMunicipality","HerlongMunicipality","HermosaBeachMunicipality","HesperiaMunicipality","HickmanMunicipality","HiddenHillsMunicipality","HiddenMeadowsMunicipality","HiddenValleyLakeMunicipality","HighgroveMunicipality","HighlandMunicipality","HighlandsBaywoodParkMunicipality","HillsboroughMunicipality","HilmarIrwinMunicipality","HiouchiMunicipality","HollisterMunicipality","HoltvilleMunicipality","HomeGardenMunicipality","HomeGardensMunicipality","HomelandMunicipality","HomesteadValleyMunicipality","HomewoodCanyonMunicipality","HoncutMunicipality","HoodMunicipality","HoopaMunicipality","HoplandMunicipality","HornbrookMunicipality","HornitosMunicipality","HughsonMunicipality","HumboldtHillMunicipality","HuntingtonBeachMunicipality","HuntingtonParkMunicipality","HuronMunicipality","HyampomMunicipality","HydesvilleMunicipality","IdlewildMunicipality","IdyllwildPineCoveMunicipality","ImperialMunicipality","ImperialBeachMunicipality","IndependenceMunicipality","IndianFallsMunicipality","IndianWellsMunicipality","IndianolaMunicipality","IndioMunicipality","IndioHillsMunicipality","IndustryMunicipality","InglewoodMunicipality","InterlakenMunicipality","InvernessMunicipality","InyokernMunicipality","IoneMunicipality","IronHorseMunicipality","IrvineMunicipality","IrwindaleMunicipality","IslaVistaMunicipality","IsletonMunicipality","IvanhoeMunicipality","JacksonMunicipality","JacumbaMunicipality","JamestownMunicipality","JamulMunicipality","JanesvilleMunicipality","JennerMunicipality","JohannesburgMunicipality","JohnstonvilleMunicipality","JohnsvilleMunicipality","JoshuaTreeMunicipality","JulianMunicipality","JunctionCityMunicipality","JuneLakeMunicipality","JurupaValleyMunicipality","KeddieMunicipality","KeelerMunicipality","KeeneMunicipality","KellyRidgeMunicipality","KelseyvilleMunicipality","KennedyMunicipality","KennedyMeadowsMunicipality","KensingtonMunicipality","KentfieldMunicipality","KenwoodMunicipality","KermanMunicipality","KernvilleMunicipality","KeswickMunicipality","KettlemanCityMunicipality","KeyesMunicipality","KingCityMunicipality","KingsBeachMunicipality","KingsburgMunicipality","KingvaleMunicipality","KirkwoodMunicipality","KlamathMunicipality","KnightsLandingMunicipality","KnightsenMunicipality","LaCanadaFlintridgeMunicipality","LaCrescentaMontroseMunicipality","LaHabraMunicipality","LaHabraHeightsMunicipality","LaHondaMunicipality","LaMesaMunicipality","LaMiradaMunicipality","LaPalmaMunicipality","LaPorteMunicipality","LaPresaMunicipality","LaPuenteMunicipality","LaQuintaMunicipality","LaRivieraMunicipality","LaSelvaBeachMunicipality","LaVerneMunicipality","LaVinaMunicipality","LaderaMunicipality","LaderaHeightsMunicipality","LaderaRanchMunicipality","LafayetteMunicipality","LagunaBeachMunicipality","LagunaHillsMunicipality","LagunaNiguelMunicipality","LagunaWoodsMunicipality","LagunitasForestKnollsMunicipality","LakeAlmanorCountryClubMunicipality","LakeAlmanorPeninsulaMunicipality","LakeAlmanorWestMunicipality","LakeArrowheadMunicipality","LakeCaliforniaMunicipality","LakeCityMunicipality","LakeDavisMunicipality","LakeDonPedroMunicipality","LakeElsinoreMunicipality","LakeForestMunicipality","LakeHughesMunicipality","LakeIsabellaMunicipality","LakeLosAngelesMunicipality","LakeMathewsMunicipality","LakeNacimientoMunicipality","LakeRiversideMunicipality","LakeSanMarcosMunicipality","LakeSherwoodMunicipality","LakeWildwoodMunicipality","LakeheadMunicipality","LakelandVillageMunicipality","LakeofthePinesMunicipality","LakeoftheWoodsMunicipality","LakeportMunicipality","LakesideMunicipality","LakeviewMunicipality","LakewoodMunicipality","LamontMunicipality","LanareMunicipality","LancasterMunicipality","LarkfieldWikiupMunicipality","LarkspurMunicipality","LasFloresMunicipality","LasLomasMunicipality","LathropMunicipality","LatonMunicipality","LawndaleMunicipality","LaytonvilleMunicipality","LeGrandMunicipality","LebecMunicipality","LeeViningMunicipality","LeggettMunicipality","LemonCoveMunicipality","LemonGroveMunicipality","LemonHillMunicipality","LemooreMunicipality","LemooreStationMunicipality","LennoxMunicipality","LenwoodMunicipality","LeonaValleyMunicipality","LewistonMunicipality","LexingtonHillsMunicipality","LikelyMunicipality","LincolnMunicipality","LincolnVillageMunicipality","LindaMunicipality","LindcoveMunicipality","LindenMunicipality","LindsayMunicipality","LinnellCampMunicipality","LitchfieldMunicipality","LittleGrassValleyMunicipality","LittleRiverMunicipality","LittleValleyMunicipality","LittlerockMunicipality","LiveOakMunicipality","LivermoreMunicipality","LivingstonMunicipality","LockefordMunicipality","LockwoodMunicipality","LodiMunicipality","LodogaMunicipality","LoletaMunicipality","LomaLindaMunicipality","LomaMarMunicipality","LomaRicaMunicipality","LomitaMunicipality","LompicoMunicipality","LompocMunicipality","LondonMunicipality","LonePineMunicipality","LongBarnMunicipality","LongBeachMunicipality","LookoutMunicipality","LoomisMunicipality","LosAlamitosMunicipality","LosAlamosMunicipality","LosAltosMunicipality","LosAltosHillsMunicipality","LosAngelesMunicipality","LosBanosMunicipality","LosBerrosMunicipality","LosGatosMunicipality","LosMolinosMunicipality","LosOlivosMunicipality","LosOsosMunicipality","LosRanchosMunicipality","LostHillsMunicipality","LowerLakeMunicipality","LoyaltonMunicipality","LoyolaMunicipality","LucasValleyMarinwoodMunicipality","LucerneMunicipality","LucerneValleyMunicipality","LynwoodMunicipality","LytleCreekMunicipality","MabieMunicipality","MacdoelMunicipality","MadRiverMunicipality","MaderaMunicipality","MaderaAcresMunicipality","MadisonMunicipality","MagaliaMunicipality","MalagaMunicipality","MalibuMunicipality","MammothLakesMunicipality","ManchesterMunicipality","ManhattanBeachMunicipality","ManilaMunicipality","MantecaMunicipality","MantonMunicipality","MarchARBMunicipality","MaricopaMunicipality","MarinCityMunicipality","MarinaMunicipality","MarinadelReyMunicipality","MariposaMunicipality","MarkleevilleMunicipality","MartellMunicipality","MartinezMunicipality","MarysvilleMunicipality","MathenyMunicipality","MatherMunicipality","MaxwellMunicipality","MayfairMunicipality","MayflowerVillageMunicipality","MaywoodMunicipality","McArthurMunicipality","McClellanParkMunicipality","McClenneyTractMunicipality","McCloudMunicipality","McFarlandMunicipality","McGeeCreekMunicipality","McKinleyvilleMunicipality","McKittrickMunicipality","McSwainMunicipality","MeadValleyMunicipality","MeadowValleyMunicipality","MeadowVistaMunicipality","MeadowbrookMunicipality","MeccaMunicipality","MeinersOaksMunicipality","MendocinoMunicipality","MendotaMunicipality","MenifeeMunicipality","MenloParkMunicipality","MentoneMunicipality","MercedMunicipality","MeridianMunicipality","MesaMunicipality","MesaVerdeMunicipality","MesaVistaMunicipality","MettlerMunicipality","MexicanColonyMunicipality","MiWukVillageMunicipality","MiddletownMunicipality","MidpinesMunicipality","MidwayCityMunicipality","MilfordMunicipality","MillValleyMunicipality","MillbraeMunicipality","MillvilleMunicipality","MilpitasMunicipality","MineralMunicipality","MinklerMunicipality","MiraMonteMunicipality","MirandaMunicipality","MissionCanyonMunicipality","MissionHillsMunicipality","MissionViejoMunicipality","ModestoMunicipality","MohawkVistaMunicipality","MojaveMunicipality","MokelumneHillMunicipality","MonmouthMunicipality","MonoCityMunicipality","MonoVistaMunicipality","MonroviaMunicipality","MonsonMunicipality","MontagueMunicipality","MontalvinManorMunicipality","MontaraMunicipality","MontclairMunicipality","MonteRioMunicipality","MonteSerenoMunicipality","MontebelloMunicipality","MontecitoMunicipality","MontereyMunicipality","MontereyParkMunicipality","MontereyParkTractMunicipality","MontgomeryCreekMunicipality","MonumentHillsMunicipality","MoorparkMunicipality","MoradaMunicipality","MoragaMunicipality","MorenoValleyMunicipality","MorganHillMunicipality","MorongoValleyMunicipality","MorroBayMunicipality","MoskowiteCornerMunicipality","MossBeachMunicipality","MossLandingMunicipality","MountHebronMunicipality","MountHermonMunicipality","MountLagunaMunicipality","MountShastaMunicipality","MountainCenterMunicipality","MountainGateMunicipality","MountainHouseMunicipality","MountainMesaMunicipality","MountainRanchMunicipality","MountainViewMunicipality","MountainViewAcresMunicipality","MuirBeachMunicipality","MurphysMunicipality","MurrietaMunicipality","MuscoyMunicipality","MyersFlatMunicipality","MyrtletownMunicipality","NapaMunicipality","NationalCityMunicipality","NeedlesMunicipality","NevadaCityMunicipality","NewCuyamaMunicipality","NewPineCreekMunicipality","NewarkMunicipality","NewcastleMunicipality","NewellMunicipality","NewmanMunicipality","NewportBeachMunicipality","NicasioMunicipality","NiceMunicipality","NicolausMunicipality","NilandMunicipality","NipinnawaseeMunicipality","NipomoMunicipality","NorcoMunicipality","NordMunicipality","NorrisCanyonMunicipality","NorthAuburnMunicipality","NorthEdwardsMunicipality","NorthElMonteMunicipality","NorthFairOaksMunicipality","NorthGateMunicipality","NorthHighlandsMunicipality","NorthLakeportMunicipality","NorthRichmondMunicipality","NorthSanJuanMunicipality","NorthShoreMunicipality","NorthTustinMunicipality","NorwalkMunicipality","NovatoMunicipality","NubieberMunicipality","NuevoMunicipality","OakGlenMunicipality","OakHillsMunicipality","OakParkMunicipality","OakShoresMunicipality","OakViewMunicipality","OakdaleMunicipality","OakhurstMunicipality","OaklandMunicipality","OakleyMunicipality","OakvilleMunicipality","OasisMunicipality","OccidentalMunicipality","OceanoMunicipality","OceansideMunicipality","OcotilloMunicipality","OildaleMunicipality","OjaiMunicipality","OlanchaMunicipality","OldFigGardenMunicipality","OldStationMunicipality","OlivehurstMunicipality","OntarioMunicipality","OnyxMunicipality","OrangeMunicipality","OrangeCoveMunicipality","OrangevaleMunicipality","OrcuttMunicipality","OrickMunicipality","OrindaMunicipality","OrlandMunicipality","OrosiMunicipality","OrovilleMunicipality","OrovilleEastMunicipality","OxnardMunicipality","PachecoMunicipality","PacificGroveMunicipality","PacificaMunicipality","PajaroMunicipality","PajaroDunesMunicipality","PalaMunicipality","PalermoMunicipality","PalmDesertMunicipality","PalmSpringsMunicipality","PalmdaleMunicipality","PaloAltoMunicipality","PaloCedroMunicipality","PaloVerdeMunicipality","PalosVerdesEstatesMunicipality","PanoramaHeightsMunicipality","ParadiseMunicipality","ParadiseParkMunicipality","ParamountMunicipality","ParklawnMunicipality","ParksdaleMunicipality","ParkwayMunicipality","ParkwoodMunicipality","ParlierMunicipality","PasadenaMunicipality","PasatiempoMunicipality","PaskentaMunicipality","PattersonMunicipality","PattersonTractMunicipality","PattonVillageMunicipality","PaxtonMunicipality","PaynesCreekMunicipality","PearsonvilleMunicipality","PennValleyMunicipality","PenngroveMunicipality","PenrynMunicipality","PerrisMunicipality","PescaderoMunicipality","PetalumaMunicipality","PetersMunicipality","PhelanMunicipality","PhillipsvilleMunicipality","PhiloMunicipality","PhoenixLakeMunicipality","PicoRiveraMunicipality","PiedmontMunicipality","PierpointMunicipality","PikeMunicipality","PineCanyonMunicipality","PineFlatMunicipality","PineGroveMunicipality","PineHillsMunicipality","PineMountainClubMunicipality","PineMountainLakeMunicipality","PineValleyMunicipality","PinoleMunicipality","PinonHillsMunicipality","PioneerMunicipality","PiruMunicipality","PismoBeachMunicipality","PittsburgMunicipality","PixleyMunicipality","PlacentiaMunicipality","PlacervilleMunicipality","PlainviewMunicipality","PlanadaMunicipality","PleasantHillMunicipality","PleasantonMunicipality","PleasurePointMunicipality","PlumasEurekaMunicipality","PlumasLakeMunicipality","PlymouthMunicipality","PointArenaMunicipality","PointReyesStationMunicipality","PollockPinesMunicipality","PomonaMunicipality","PonderosaMunicipality","PoplarCottonCenterMunicipality","PortCostaMunicipality","PortHuenemeMunicipality","PortervilleMunicipality","PortolaMunicipality","PortolaValleyMunicipality","PoseyMunicipality","PosoParkMunicipality","PotreroMunicipality","PotterValleyMunicipality","PowayMunicipality","PrattvilleMunicipality","PrincetonMunicipality","ProbertaMunicipality","PrunedaleMunicipality","QuartzHillMunicipality","QuincyMunicipality","RackerbyMunicipality","RailRoadFlatMunicipality","RainbowMunicipality","RaisinCityMunicipality","RamonaMunicipality","RanchoCalaverasMunicipality","RanchoCordovaMunicipality","RanchoCucamongaMunicipality","RanchoMirageMunicipality","RanchoMurietaMunicipality","RanchoPalosVerdesMunicipality","RanchoSanDiegoMunicipality","RanchoSantaFeMunicipality","RanchoSantaMargaritaMunicipality","RanchoTehamaReserveMunicipality","RandsburgMunicipality","RedBluffMunicipality","RedCorralMunicipality","RedcrestMunicipality","ReddingMunicipality","RedlandsMunicipality","RedondoBeachMunicipality","RedwayMunicipality","RedwoodCityMunicipality","RedwoodValleyMunicipality","ReedleyMunicipality","ReliezValleyMunicipality","RialtoMunicipality","RichfieldMunicipality","RichgroveMunicipality","RichmondMunicipality","RichvaleMunicipality","RidgecrestMunicipality","RidgemarkMunicipality","RioDellMunicipality","RioLindaMunicipality","RioOsoMunicipality","RioVistaMunicipality","RiodelMarMunicipality","RipleyMunicipality","RiponMunicipality","RiverPinesMunicipality","RiverbankMunicipality","RiverdaleMunicipality","RiverdaleParkMunicipality","RiversideMunicipality","RobbinsMunicipality","RobinsonMillMunicipality","RocklinMunicipality","RodeoMunicipality","RodriguezCampMunicipality","RohnertParkMunicipality","RollingHillsMunicipality","RollingHillsEstatesMunicipality","RollingwoodMunicipality","RomolandMunicipality","RosamondMunicipality","RoseHillsMunicipality","RosedaleMunicipality","RoselandMunicipality","RosemeadMunicipality","RosemontMunicipality","RosevilleMunicipality","RossMunicipality","RossmoorMunicipality","RoughandReadyMunicipality","RoundMountainMunicipality","RoundValleyMunicipality","RouseMunicipality","RowlandHeightsMunicipality","RunningSpringsMunicipality","RuthMunicipality","RutherfordMunicipality","SacramentoMunicipality","SalidaMunicipality","SalinasMunicipality","SalmonCreekMunicipality","SaltonCityMunicipality","SaltonSeaBeachMunicipality","SamoaMunicipality","SanAndreasMunicipality","SanAnselmoMunicipality","SanAntonioHeightsMunicipality","SanArdoMunicipality","SanBernardinoMunicipality","SanBrunoMunicipality","SanBuenaventuraMunicipality","SanCarlosMunicipality","SanClementeMunicipality","SanDiegoMunicipality","SanDiegoCountryEstatesMunicipality","SanDimasMunicipality","SanFernandoMunicipality","SanFranciscoMunicipality","SanGabrielMunicipality","SanGeronimoMunicipality","SanJacintoMunicipality","SanJoaquinMunicipality","SanJoseMunicipality","SanJuanBautistaMunicipality","SanJuanCapistranoMunicipality","SanLeandroMunicipality","SanLorenzoMunicipality","SanLucasMunicipality","SanLuisObispoMunicipality","SanMarcosMunicipality","SanMarinoMunicipality","SanMartinMunicipality","SanMateoMunicipality","SanMiguelMunicipality","SanPabloMunicipality","SanPasqualMunicipality","SanRafaelMunicipality","SanRamonMunicipality","SanSimeonMunicipality","SandCityMunicipality","SangerMunicipality","SantaAnaMunicipality","SantaBarbaraMunicipality","SantaClaraMunicipality","SantaClaritaMunicipality","SantaCruzMunicipality","SantaFeSpringsMunicipality","SantaMargaritaMunicipality","SantaMariaMunicipality","SantaMonicaMunicipality","SantaNellaMunicipality","SantaPaulaMunicipality","SantaRosaMunicipality","SantaRosaValleyMunicipality","SantaSusanaMunicipality","SantaVenetiaMunicipality","SantaYnezMunicipality","SanteeMunicipality","SaranapMunicipality","SaratogaMunicipality","SaticoyMunicipality","SattleyMunicipality","SausalitoMunicipality","ScotiaMunicipality","ScottsValleyMunicipality","SeaRanchMunicipality","SeacliffMunicipality","SealBeachMunicipality","SearlesValleyMunicipality","SeasideMunicipality","SebastopolMunicipality","SeeleyMunicipality","SelmaMunicipality","SequoiaCrestMunicipality","SerenodelMarMunicipality","SevilleMunicipality","ShafterMunicipality","ShandonMunicipality","ShastaMunicipality","ShastaLakeMunicipality","ShaverLakeMunicipality","ShellRidgeMunicipality","ShelterCoveMunicipality","SheridanMunicipality","ShingleSpringsMunicipality","ShingletownMunicipality","ShoshoneMunicipality","SierraBrooksMunicipality","SierraCityMunicipality","SierraMadreMunicipality","SierraVillageMunicipality","SierravilleMunicipality","SignalHillMunicipality","SilverCityMunicipality","SilverLakesMunicipality","SilveradoResortMunicipality","SimiValleyMunicipality","SisquocMunicipality","SkyValleyMunicipality","SleepyHollowMunicipality","SmartsvilleMunicipality","SmithCornerMunicipality","SmithRiverMunicipality","SnellingMunicipality","SodaBayMunicipality","SodaSpringsMunicipality","SolanaBeachMunicipality","SoledadMunicipality","SolvangMunicipality","SonomaMunicipality","SonoraMunicipality","SoquelMunicipality","SoulsbyvilleMunicipality","SouthDosPalosMunicipality","SouthElMonteMunicipality","SouthGateMunicipality","SouthLakeTahoeMunicipality","SouthMonroviaIslandMunicipality","SouthOrovilleMunicipality","SouthPasadenaMunicipality","SouthSanFranciscoMunicipality","SouthSanGabrielMunicipality","SouthSanJoseHillsMunicipality","SouthTaftMunicipality","SouthWhittierMunicipality","SpauldingMunicipality","SpreckelsMunicipality","SpringGardenMunicipality","SpringValleyMunicipality","SpringValleyLakeMunicipality","SpringvilleMunicipality","SquawValleyMunicipality","SquirrelMountainValleyMunicipality","St.HelenaMunicipality","StallionSpringsMunicipality","StanfordMunicipality","StantonMunicipality","StevensonRanchMunicipality","StevinsonMunicipality","StinsonBeachMunicipality","StirlingCityMunicipality","StocktonMunicipality","StonyfordMunicipality","StorrieMunicipality","StratfordMunicipality","StrathmoreMunicipality","StrawberryMunicipality","SugarloafMountainParkMunicipality","SugarloafSawMillMunicipality","SugarloafVillageMunicipality","SuisunCityMunicipality","SultanaMunicipality","SummerlandMunicipality","SunVillageMunicipality","SunnySlopesMunicipality","SunnysideMunicipality","SunnysideTahoeCityMunicipality","SunnyvaleMunicipality","SunolMunicipality","SusanvilleMunicipality","SutterMunicipality","SutterCreekMunicipality","SwallMeadowsMunicipality","TaftMunicipality","TaftHeightsMunicipality","TaftMosswoodMunicipality","TahoeVistaMunicipality","TahomaMunicipality","TalmageMunicipality","TamalpaisHomesteadValleyMunicipality","TaraHillsMunicipality","TarpeyVillageMunicipality","TaylorsvilleMunicipality","TecopaMunicipality","TehachapiMunicipality","TehamaMunicipality","TemeculaMunicipality","TemelecMunicipality","TemescalValleyMunicipality","TempleCityMunicipality","TempletonMunicipality","TennantMunicipality","TerminousMunicipality","TerraBellaMunicipality","TevistonMunicipality","ThermalMunicipality","ThermalitoMunicipality","ThorntonMunicipality","ThousandOaksMunicipality","ThousandPalmsMunicipality","ThreeRiversMunicipality","ThreeRocksMunicipality","TiburonMunicipality","TimberCoveMunicipality","TiptonMunicipality","TobinMunicipality","TomalesMunicipality","TonyvilleMunicipality","ToolevilleMunicipality","TopangaMunicipality","TopazMunicipality","ToroCanyonMunicipality","TorranceMunicipality","TracyMunicipality","TranquillityMunicipality","TraverMunicipality","TresPinosMunicipality","TrinidadMunicipality","TrinityCenterMunicipality","TrinityVillageMunicipality","TronaMunicipality","TrowbridgeMunicipality","TruckeeMunicipality","TulareMunicipality","TulelakeMunicipality","TuolumneCityMunicipality","TupmanMunicipality","TurlockMunicipality","TustinMunicipality","TuttleMunicipality","TuttletownMunicipality","TwainMunicipality","TwainHarteMunicipality","TwentyninePalmsMunicipality","TwinLakesMunicipality","UkiahMunicipality","UnionCityMunicipality","UniversityofCaliforniaDavisMunicipality","UniversityofCaliforniaMercedMunicipality","UplandMunicipality","UpperLakeMunicipality","VacavilleMunicipality","ValVerdeMunicipality","ValindaMunicipality","ValleVistaMunicipality","VallecitoMunicipality","VallejoMunicipality","ValleyAcresMunicipality","ValleyCenterMunicipality","ValleyFordMunicipality","ValleyHomeMunicipality","ValleyRanchMunicipality","ValleySpringsMunicipality","ValleyWellsMunicipality","VandenbergAFBMunicipality","VandenbergVillageMunicipality","VerdiMunicipality","VernonMunicipality","VictorMunicipality","VictorvilleMunicipality","ViewParkWindsorHillsMunicipality","VillaParkMunicipality","VinaMunicipality","VincentMunicipality","VineHillMunicipality","VineyardMunicipality","VisaliaMunicipality","VistaMunicipality","VistaSantaRosaMunicipality","VolcanoMunicipality","VoltaMunicipality","WalkerMunicipality","WallaceMunicipality","WalnutMunicipality","WalnutCreekMunicipality","WalnutGroveMunicipality","WalnutParkMunicipality","WarmSpringsMunicipality","WarnerValleyMunicipality","WascoMunicipality","WashingtonMunicipality","WaterfordMunicipality","WaterlooMunicipality","WatsonvilleMunicipality","WaukenaMunicipality","WawonaMunicipality","WeavervilleMunicipality","WeedMunicipality","WeedpatchMunicipality","WeldonMunicipality","WeottMunicipality","WestAthensMunicipality","WestBishopMunicipality","WestCarsonMunicipality","WestCovinaMunicipality","WestGoshenMunicipality","WestHollywoodMunicipality","WestMenloParkMunicipality","WestModestoMunicipality","WestParkMunicipality","WestPointMunicipality","WestPuenteValleyMunicipality","WestRanchoDominguezMunicipality","WestSacramentoMunicipality","WestWhittierLosNietosMunicipality","WesthavenMoonstoneMunicipality","WestlakeVillageMunicipality","WestleyMunicipality","WestminsterMunicipality","WestmontMunicipality","WestmorlandMunicipality","WestsideMunicipality","WestwoodMunicipality","WheatlandMunicipality","WhitehawkMunicipality","WhitewaterMunicipality","WhitleyGardensMunicipality","WhittierMunicipality","WildomarMunicipality","WilkersonMunicipality","WilliamsMunicipality","WillitsMunicipality","WillowCreekMunicipality","WillowbrookMunicipality","WillowsMunicipality","WilsoniaMunicipality","WiltonMunicipality","WinchesterMunicipality","WindsorMunicipality","WinterGardensMunicipality","WinterhavenMunicipality","WintersMunicipality","WintonMunicipality","WoffordHeightsMunicipality","WoodacreMunicipality","WoodbridgeMunicipality","WoodcrestMunicipality","WoodlakeMunicipality","WoodlandMunicipality","WoodlandsMunicipality","WoodsideMunicipality","WoodvilleMunicipality","WrightwoodMunicipality","YankeeHillMunicipality","YettemMunicipality","YoloMunicipality","YorbaLindaMunicipality","YosemiteLakesMunicipality","YosemiteValleyMunicipality","YountvilleMunicipality","YrekaMunicipality","YubaCityMunicipality","YucaipaMunicipality","YuccaValleyMunicipality","ZayanteMunicipality"],"Watershed":["AbbottsLagoonFrontalPacificOceanWatershed","AdobeValleyWatershed","AguaCalienteCreekFrontalSanFranciscoBayEstuariesWatershed","AirportLakeWatershed","AlamedaCreekWatershed","AlamitosBaySanPedroBayWatershed","AlamoCreekWatershed","AlamoPintadoCreekSantaYnezRiverWatershed","AlamoRiverWatershed","AlbionRiverFrontalPacificOceanWatershed","AlderCreekFrontalPacificOceanWatershed","AlgodonesDunesWatershed","AlgodonesDunesChocolateMountainWatershed","AlisoCreekFrontalGulfofSantaCatalinaWatershed","AlkaliValleyFrontalMonoLakeWatershed","AmargosaCreekWatershed","AmboyCraterWatershed","AmericanRiverWatershed","AngelSloughWatershed","AntelopeCreekWatershed","AntelopePlainWatershed","AntelopeValleyAntelopePlainWatershed","AnvilSpringCanyonWatershed","AppleValleyDryLakeWatershed","ArrastreCreekMellvilleLakeWatershed","ArroyoDoblegadoFrontalTulareLakeBedWatershed","ArroyoGrandeCreekWatershed","ArroyoHondoWatershed","ArroyoHondoFresnoSloughWatershed","ArroyoLasPositasWatershed","ArroyoMochoWatershed","ArroyoRamosoElRinconWatershed","ArroyoSaladaFrontalSaltonSeaWatershed","ArroyoSecoWatershed","ArroyoSecoUpperMilpitasWashWatershed","ArroyoTorcidoFrontalTulareLakeBedWatershed","ArroyoTozoHaciendaSpillwayWatershed","ArroyoValleWatershed","ArroyodelaLagunaWatershed","AshCreekWatershed","AshCreekSacramentoRiverWatershed","AuburnRavineWatershed","AustinCreekWatershed","AvenalCreekAlamoSoloSpringWatershed","BadWaterBasinAmargosaRiverWatershed","BadgerBasinWillowCreekWatershed","BallonaCreekWatershed","BasinCreekEelRiverWatershed","BattleCreekWatershed","BaxterCreekFrontalHoneyLakeWatershed","BaxterWashMojaveRiverWatershed","BearCreekWatershed","BearCreekMercedRiverWatershed","BearRiverWatershed","BeaverCreekWatershed","BeegumCreekWatershed","BellMountainWashMojaveRiverWatershed","BigChicoCreekWatershed","BigCreekWatershed","BigCreekFrontalPacificOceanWatershed","BigCreekTuolumneRiverWatershed","BigFrenchCreekTrinityRiverWatershed","BigLagoonFrontalPacificOceanWatershed","BigPineCreekOwensRiverWatershed","BigRiverWatershed","BigRockCreekBigRockWashWatershed","BigSageReservoirRattlesnakeCreekWatershed","BigSandyCreekWatershed","BigSandyCreekSanJoaquinRiverWatershed","BigSulphurCreekWatershed","BigSycamoreCanyonFrontalSantaMonicaBayWatershed","BigTujungaCreekWatershed","BigWashWatershed","BishopCreekWatershed","BissellHillsWatershed","BitterwaterCreekWatershed","BlackButteRiverWatershed","BlackCanyonWatershed","BlackHillsWatershed","BlackRascalCreekWatershed","BlackRockSpringCoyoteWellWatershed","BlackSulphurSpringCarrizoPlainWatershed","BlackhawkCanyonCougarButtesWatershed","BlacksCanyonPitRiverWatershed","BlueCreekWatershed","BluffCreekKlamathRiverWatershed","BogusCreekKlamathRiverWatershed","BolsaChicaChannelFrontalHuningtonHarbourWatershed","BorregoValleyBorregoSinkWashWatershed","BouquetCanyonWatershed","BristolLakeWatershed","BroadwellLakeWatershed","BrownsCanyonWatershed","BrownsCreekWatershed","BrownsWashCadizLakeWatershed","BrushCreekKernRiverWatershed","BucknellCreekEelRiverWatershed","BuckthornWashMojaveRiverWatershed","BuckwheatWashAmargosaRiverWatershed","BuenaVistaCreekWatershed","BuenaVistaLakeBedWatershed","BullRunCreekKernRiverWatershed","BurchCreekWatershed","BurneyCreekWatershed","BurnsCreekWatershed","BurroCanyonDryLakesWatershed","ButtCreekWatershed","ButteCreekWatershed","ButteCreekAshCreekWatershed","ButteCreekLostCreekWatershed","ButteValleyWatershed","CacheSloughWatershed","CadizValleyWatershed","CalaverasRiverWatershed","CalienteCreekWatershed","CaliforniaValleyWatershed","CalleguasCreekWatershed","CampCreekWatershed","CanebrakeCreekWatershed","CantuaCreekFresnoSloughWatershed","CanyonCreekWatershed","CanyonCreekScottRiverWatershed","CaparellCreekFrontalKernLakeBedWatershed","CapeMendicinoFrontalPacificOceanWatershed","CarmelBayFrontalPacificOceanWatershed","CarmelRiverWatershed","CarnerosCreekFrontalSanPabloBayEstuariesWatershed","CarrizoPlainSodaLakeWatershed","CastaicCreekWatershed","CastleCreekSacramentoRiverWatershed","CedarCreekWatershed","CentennialFlatWatershed","ChaloneCreekWatershed","ChamiseCreekEelRiverWatershed","CherryCreekWatershed","ChicagoValleyWatershed","ChimneyCreekWatershed","ChinaLakeWatershed","ChinoCreekWatershed","ChiquitoCreekWatershed","CholameCreekWatershed","ChurnCreekSacramentoRiverWatershed","ClaiborneCreekMcCloudRiverWatershed","ClarkForkWatershed","ClarkValleyWatershed","ClaveyRiverWatershed","ClearCreekWatershed","CleghornLakesWatershed","CleghornPassWatershed","ClipperValleyWashWatershed","ClipperWashWatershed","CloverSwaleCreekWatershed","CoarseGoldCreekWatershed","CoffeeCreekWatershed","ColdForkWatershed","ColdSpringCreekMadelinePlainsWatershed","ColeSloughKingsRiverWatershed","ColusaBasinDrainageCanalWatershed","ColusaDrainWatershed","ColusaTroughWatershed","ConnCreekWatershed","CooksieCreekFrontalPacificOceanWatershed","CoonCreekWatershed","CopicBayWatershed","CorbinCreekEelRiverWatershed","CorralHollowCreekWatershed","CorteMaderaCreekFrontalSanFransiscoBayEstuariesWatershed","CosoWashWatershed","CottonwoodCreekWatershed","CottonwoodCreekAshCreekWatershed","CottonwoodCreekKernRiverWatershed","CottonwoodCreekSanJoaquinRiverWatershed","CottonwoodCreekTylerhorseCanyonWatershed","CowCreekWatershed","CoyoteCreekWatershed","CoyoteLakeWatershed","CoyoteWashWatershed","CroniseValleyWatershed","CrowCreekSanJoaquinRiverWatershed","CruceroHillWatershed","CrystalCreekLucerneLakeWatershed","CuddebackLakeWatershed","CurryCreekSacramentoRiverWatershed","DaggettWashMojaveRiverWatershed","DaleLakeWatershed","DarwinWashWatershed","DeadmanCreekWatershed","DeepCanyonWatershed","DeepCreekWatershed","DeepCreekSecretCreekWatershed","DeepSpringsLakeWatershed","DeerCreekWatershed","DeerPeakWatershed","DelPuertoCreekWatershed","DevilCanyonFrontalIvanpahLakeWatershed","DevilsPlaygroundWashWatershed","DibbleCreekSacramentoRiverWatershed","DillonCreekWatershed","DinkeyCreekWatershed","DobbynCreekWatershed","DogCreekFishSloughWatershed","DominguezChannelWatershed","DoveSpringCanyonRedRockCanyonWatershed","DownieRiverWatershed","DrakesBayFrontalPacificOceanWatershed","DryCreekWatershed","DryCreekFrontalGooseLakeWatershed","DryCreekFrontalMonoLakeWatershed","DryCreekSouthForkPitRiverWatershed","DryValleyCreekWatershed","DryValleyGrasshopperValleyWatershed","DuckSloughWatershed","DutchmanCreekWatershed","DyerCreekLakeWoollomesWatershed","EastBranchNorthForkFeatherRiverWatershed","EastBranchSouthForkEelRiverWatershed","EastForkKaweahRiverWatershed","EastForkRussianRiverWatershed","EastForkScottRiverWatershed","EastForkTrinityRiverWatershed","ElPasoCreekWatershed","ElToroCreekSalinasRiverWatershed","ElderCreekWatershed","EleanorCreekWatershed","ElkBayouWatershed","ElkCreekWatershed","EmigrantWashWatershed","EricksenDryLakeWatershed","EscondidoCreekWatershed","EstrellaRiverWatershed","EticueraCreekWatershed","FallRiverWatershed","FallsCreekTuolumneRiverWatershed","FancherCreekFancherCreekCanalWatershed","FarallonIslandsWatershed","FiddlerGulchGolerGulchWatershed","FineGoldCreekWatershed","FishCanyonPanamintValleyWatershed","FishCreekWatershed","FishCreekWashWatershed","FivemileCreekSanJoaquinRiverWatershed","FletcherCreekBolesCreekWatershed","FoothillDitchOutsideCreekWatershed","FordWellWatershed","FortyninePalmsCanyonShortzLakeWatershed","FrenchCampSloughWatershed","FrenchCreekScottRiverWatershed","FreshwaterCreekWatershed","FrontalSantaMonicaBaySanPedroBayWatershed","FurnaceCreekFrontalFishLakeValleyWatershed","FurnaceCreekWashWatershed","GarapitoCreekFrontalSantaMonicaBayWatershed","GarciaRiverWatershed","GeneralCreekFrontalLakeTahoeWatershed","GilsizerSloughSnakeRiverWatershed","GoatMountainKeysLakeWatershed","GoldenTroutCreekKernRiverWatershed","GoldstoneLakeWatershed","GooseLakeWatershed","GooseLakeCanalWatershed","GooseLakeSloughJerrySloughWatershed","GraniteCreekWatershed","GrapevineCanyonWatershed","GrapevineCreekWatershed","GreenhornCreekWatershed","GreenwaterCanyonAmargosaRiverWatershed","GreenwaterValleyWatershed","GrindstoneCreekWatershed","GriswoldCreekWatershed","GuadalupeRiverFrontalSanFranciscoBayEstuariesWatershed","GualalaRiverWatershed","HaiweeReservoirsWatershed","HalloranWashWatershed","HamiltonBranchWatershed","HarperLakeWatershed","HatCreekWatershed","HayfieldLakeLakeTamariskWatershed","HeadwatersApplegateRiverWatershed","HeadwatersCuyamaRiverWatershed","HeadwatersEastWalkerRiverWatershed","HeadwatersMercedRiverWatershed","HeadwatersNorthForkFeatherRiverWatershed","HeadwatersPosoCreekWatershed","HeadwatersRussianRiverWatershed","HeadwatersSantaAnaRiverWatershed","HeadwatersSantaClaraRiverWatershed","HeadwatersSantaYnezRiverWatershed","HeadwatersSouthForkKernRiverWatershed","HeadwatersTuolumneRiverWatershed","HeadwatersWhitewaterRiverWatershed","HiddenSpringsCanyonFrontalSaltonSeaWatershed","HoncutCreekWatershed","HoneyLakeWatershed","HoneyLakeValleyFrontalHoneyLakeWatershed","HorseCreekWatershed","HorseCreekKaweahRiverWatershed","HorseCreekKlamathRiverWatershed","HorseLakeWillowCreekWatershed","HorseLintoCreekTrinityRiverWatershed","HortonCreekOwensRiverWatershed","HotCreekOwensRiverWatershed","HuasnaRiverWatershed","HuerhueroCreekWatershed","HumboldtBayFrontalPacificOceanWatershed","HumbugCreekKlamathRiverWatershed","HuntoonValleyWatershed","HutchinsonCreekReedsCreekWatershed","ImperialValleyFrontalSaltonSeaWatershed","IndainWashAmericanGirlWashWatershed","IndianCreekWatershed","IndianCreekScottRiverWatershed","IndianValleySalinasRiverWatershed","IngalsbeSloughMercedRiverWatershed","IngramCreekSanJoaquinRiverWatershed","InscriptionCanyonWatershed","IronGateReservoirKlamathRiverWatershed","IronMountainTunnelSandDrawWatershed","IronRidgeGalwayLakeWatershed","IronwoodWashDanbyLakeWatershed","IvanpahLakeWatershed","JacalitosCreekWatershed","JacksonCreekWatershed","JacobsSloughFrontalTulareLakeBedWatershed","JailCanyonWarmSulphurSpringsWatershed","JalamaCreekFrontalSantaBarbaraChannelWatershed","JamesBypassWatershed","JawboneCanyonWatershed","JessValleySouthForkPitRiverWatershed","JewettCreekSacramentoRiverWatershed","JubileeWashAmargosaRiverWatershed","JuniperCreekWatershed","KaiserCreekSanJoaquinRiverWatershed","KelloggCreekBigBreakWatershed","KelseyCreekClearLakeWatershed","KelsoCreekWatershed","KennedyPondFresnoSloughWatershed","KidderCreekScottRiverWatershed","KingstonPeakWatershed","KnightsLandingRidgeCutTuleCanalWatershed","KoehnLakeWatershed","KoskCreekPitRiverWatershed","LaBreaCreekWatershed","LagunaWatershed","LagunitasCreekWatershed","LakePalmdalePiutePondsWatershed","LakePaulinaComancheCreekWatershed","LakeShastinaShastaRiverWatershed","LakeTahoeWatershed","LangfordWellLakeWatershed","LarabeeCreekWatershed","LariousCreekSilverCreekWatershed","LastChanceCreekWatershed","LavaHillsWatershed","LeMontaineCreekEllerSloughWatershed","LeachLakeWatershed","LeeViningCreekFrontalMonoLakeWatershed","LeeWashWatershed","LewisCreekWatershed","LightsCreekWatershed","LittleCowCreekWatershed","LittleDixieWashWatershed","LittleDryCreekWatershed","LittleKernRiverWatershed","LittleLastChanceCreekWatershed","LittleMorongoCreekMorongoWashWatershed","LittlePanocheCreekWatershed","LittleRockWashWatershed","LittleShastaRiverWatershed","LittleStonyCreekWatershed","LittleTruckeeRiverWatershed","LittlejohnsCreekWatershed","LiveoakCanyonPastoriaCreekWatershed","LlagasCreekWatershed","LoganCreekWatershed","LonePineCreekOwensRiverWatershed","LoneTreeCreekWatershed","LoneTreeCreekSanJoaquinRiverWatershed","LosGatosCreekWatershed","LowerAlkaliLakeWatershed","LowerBearCreekWatershed","LowerBearRiverWatershed","LowerBorregoValleyWatershed","LowerButteCreekWatershed","LowerCacheCreekWatershed","LowerCarrizoCreekWatershed","LowerChemehueviWashWatershed","LowerChowchillaRiverWatershed","LowerCosumnesRiverWatershed","LowerCottonwoodCreekWatershed","LowerCoyoteCreekFrontalSanFranciscoBayEstuariesWatershed","LowerCrossCreekWatershed","LowerCuyamaRiverWatershed","LowerDeathValleyWashWatershed","LowerDeerCreekWatershed","LowerDryCreekWatershed","LowerEastForkCarsonRiverWatershed","LowerEurekaValleyWatershed","LowerFeatherRiverWatershed","LowerFremontWashWatershed","LowerFresnoRiverWatershed","LowerHayforkCreekWatershed","LowerHomerWashWatershed","LowerIndianCreekWatershed","LowerKelsoWashWatershed","LowerKernRiverFloodCanalKernRiverChannelWatershed","LowerKingstonWashWatershed","LowerKlamathLakeWatershed","LowerLongValleyCreekFrontalHoneyLakeWatershed","LowerLosAngelesRiverWatershed","LowerLosBanosCreekWatershed","LowerMadRiverWatershed","LowerMiddleForkAmericanRiverWatershed","LowerMiddleForkEelRiverWatershed","LowerMiddleForkFeatherRiverWatershed","LowerMiddleForkStanislausRiverWatershed","LowerMilpitasWashWatershed","LowerMokelumneRiverWatershed","LowerNorthForkAmericanRiverWatershed","LowerNorthForkFeatherRiverWatershed","LowerNorthForkMokelumneRiverWatershed","LowerNorthYubaRiverWatershed","LowerPanocheCreekWatershed","LowerPineCreekEagleLakeWatershed","LowerPintoWashWatershed","LowerPiruCreekWatershed","LowerPiuteWashWatershed","LowerPosoCreekWatershed","LowerPutahCreekWatershed","LowerRussianRiverWatershed","LowerSaltCreekWatershed","LowerSanBenitoRiverWatershed","LowerSanDiegoRiverWatershed","LowerSanFelipeCreekWatershed","LowerSanGabrielRiverWatershed","LowerSanJacintoRiverWatershed","LowerSanJuanCreekWatershed","LowerSanLuisReyRiverWatershed","LowerSantaAnaRiverWatershed","LowerSantaClaraRiverWatershed","LowerSantaYsabelCreekWatershed","LowerSisquocRiverWatershed","LowerSouthForkAmericanRiverWatershed","LowerSouthForkCottonwoodCreekWatershed","LowerSouthForkEelRiverWatershed","LowerSouthForkKernRiverWatershed","LowerSouthForkKingsRiverWatershed","LowerSouthForkSanJoaquinRiverWatershed","LowerSouthForkTrinityRiverWatershed","LowerSouthYubaRiverWatershed","LowerSpringCanyonCreekWatershed","LowerStanislausRiverWatershed","LowerStonyCreekWatershed","LowerSusanRiverFrontalHoneyLakeWatershed","LowerSweetwaterRiverWatershed","LowerTemeculaCreekWatershed","LowerThomesCreekWatershed","LowerTuleRiverWatershed","LowerVanDuzenRiverWatershed","LowerWarmSpringsFrontalSaltLakeWatershed","LowerWatsonWashWatershed","LowerWhiteRiverWatershed","LowerWhitewaterRiverWatershed","LucyGrayMountainsFrontalIvanpahLakeWatershed","LytleCreekWatershed","MalibuCreekWatershed","ManixWashMojaveRiverWatershed","MarbleCanyonWatershed","MarbleForkKaweahRiverKaweahRiverWatershed","MarbleMountainsWatershed","MarkWestCreekWatershed","MarletteLakeFrontalLakeTahoeWatershed","MarshCreekWatershed","MartinsWellDanbyLakeWatershed","MattoleRiverWatershed","MaxwellCreekMercedRiverWatershed","McAfeeCanyonFrontalFishLakeValleyWatershed","McCloudRiverArmShastaLakeWatershed","McCoySpringWatershed","McCoyWashWatershed","McGrathLakeFrontalPacificOceanWatershed","MeansLakeEmersonLakeWatershed","MedicineLakePaynesCreekWatershed","MescalCreekRockyButtesWatershed","MesquiteFlatWatershed","MesquiteLakeWatershed","MesquiteSpringWatershed","MesquiteValleyWatershed","MesquitoSpringWatershed","MiddleAlkaliLakeWatershed","MiddleBearRiverWatershed","MiddleBranchCrossCreekWatershed","MiddleButteCreekWatershed","MiddleCottonwoodCreekWatershed","MiddleCreekWatershed","MiddleCrossCreekWatershed","MiddleCuyamaRiverWatershed","MiddleDeathValleyWashWatershed","MiddleDeerCreekWatershed","MiddleEastForkCarsonRiverWatershed","MiddleForkCosumnesRiverWatershed","MiddleForkCottonwoodCreekWatershed","MiddleForkKaweahRiverWatershed","MiddleForkKingsRiverWatershed","MiddleForkMokelumneRiverWatershed","MiddleForkSanJoaquinRiverWatershed","MiddleForkSmithRiverWatershed","MiddleForkTuleRiverWatershed","MiddleFresnoRiverWatershed","MiddleMadRiverWatershed","MiddleMiddleForkFeatherRiverWatershed","MiddleNorthForkFeatherRiverWatershed","MiddleNorthYubaRiverWatershed","MiddlePineCreekWatershed","MiddlePintoWashWatershed","MiddlePosoCreekWatershed","MiddlePutahCreekWatershed","MiddleRiverSanJoaquinRiverWatershed","MiddleRussianRiverWatershed","MiddleSanFelipeCreekWatershed","MiddleSanJacintoRiverWatershed","MiddleSanLuisReyRiverWatershed","MiddleSantaAnaRiverWatershed","MiddleSantaClaraRiverWatershed","MiddleSisquocRiverWatershed","MiddleSouthForkAmericanRiverWatershed","MiddleSouthForkEelRiverWatershed","MiddleSouthForkKernRiverWatershed","MiddleSouthForkTrinityRiverWatershed","MiddleStonyCreekWatershed","MiddleTuolumneRiverWatershed","MiddleWestWalkerRiverWatershed","MiddleWhitewaterRiverWatershed","MiddleYubaRiverWatershed","MillCanyonPanamintValleyWatershed","MillCreekWatershed","MillFlatCreekKingsRiverWatershed","MissionBayWatershed","MissionBeachFrontalPacificOceanWatershed","MoccasinCreekTuolumneRiverWatershed","MoffettCreekWatershed","MonoCreekWatershed","MonoLakeWatershed","MontereyBayWatershed","MormonSloughWatershed","MorrisonCreekWatershed","MorroBayFrontalEsteroBayWatershed","MountDiabloCreekFrontalSuisunBayEstuariesWatershed","MountGeneralWatershed","MowitzCreekClearLakeWatershed","MudCreekWatershed","MudCreekMcCloudRiverWatershed","MudSloughWatershed","MudSloughSanJoaquinRiverWatershed","MurphySloughFresnoSloughWatershed","MurrietaCreekWatershed","MyrickSpringWatershed","NacimientoRiverWatershed","NapaRiverWatershed","NavarroRiverWatershed","NelsonLakeBicycleLakeWatershed","NewRiverWatershed","NewportBayFrontalPacificOceanWatershed","NinemileCanyonWatershed","NorthForkBattleCreekWatershed","NorthForkCacheCreekWatershed","NorthForkCalaverasRiverWatershed","NorthForkCosumnesRiverWatershed","NorthForkCottonwoodCreekWatershed","NorthForkEelRiverWatershed","NorthForkKaweahRiverWatershed","NorthForkKingsRiverWatershed","NorthForkKingsRiverKingsRiverWatershed","NorthForkMercedRiverWatershed","NorthForkMiddleForkAmericanRiverWatershed","NorthForkPitRiverWatershed","NorthForkSalmonRiverWatershed","NorthForkSmithRiverWatershed","NorthForkStanislausRiverWatershed","NorthForkStonyCreekWatershed","NorthForkTrinityRiverWatershed","NorthForkTuleRiverWatershed","NorthForkTuolumneRiverWatershed","NorthForkWillowCreekWillowCreekWatershed","NorthLucerneValleyWatershed","NoyoRiverWatershed","OatCreekSacramentoRiverWatershed","OldChannelPosoCreekAlpaughIrrigationDistrictCanalWatershed","OldCowCreekWatershed","OldRiverWatershed","OrangeBlossomWashWatershed","OrcuttCreekCorralitosCanyonWatershed","OrestimbaCreekWatershed","OtayRiverWatershed","OutletCreekWatershed","OwensCreekWatershed","OwensLakeWatershed","OwlLakeWatershed","PachecoCreekWatershed","PackardWellWatershed","PajaroRiverWatershed","PalenLakeWatershed","PalmCanyonWashWatershed","PalmettoWashFrontalFishLakeValleyWatershed","PaloVerdeValleyWatershed","PanchoRicoCreekSalinasRiverWatershed","ParkerCreekWatershed","ParksCreekShastaRiverWatershed","PasoRoblesCreekSalinasRiverWatershed","PaynesCreekWatershed","PeasleeCreekTuolumneRiverWatershed","PeerlessValleyWatershed","PescaderoCreekWatershed","PetalumaRiverFrontalSanPabloBayEstuariesWatershed","PicachoWashColoradoRiverWatershed","PilotKnobValleyWatershed","PineCreekWatershed","PineCreekSouthForkPitRiverWatershed","PineFlatReservoirKingsRiverWatershed","PineTreeCanyonWatershed","PineValleyCreekWatershed","PinkhamWashBoxCanyonWashWatershed","PipesWashWatershed","PismoCreekFrontalPacificOceanWatershed","PitRiverArmShastaLakeWatershed","PleasantGroveCreekCrossCanalWatershed","PleititoCreekKernLakeBedWatershed","PointSaintGeorgeFrontalPacificOceanWatershed","PoisonCanyonWatershed","PopeCreekWatershed","PowayCreekWatershed","PriceCreekEelRiverWatershed","ProsserCreekTruckeeRiverWatershed","PuddingCreekFrontalPacificOceanWatershed","QuackenbushLakeBullionWashWatershed","QuailWashWatershed","RacetrackValleyWatershed","RagGulchWatershed","RancheriaCreekWatershed","RattlesnakeCanyonWatershed","RattlesnakeCreekKernRiverWatershed","RedBankCreekWatershed","RedCloverCreekWatershed","RedPassLakeSaltCreekWatershed","RedRockValleyAntelopeCreekWatershed","RedrockCanyonSantaYnezRiverWatershed","RedwoodCreekWatershed","ReedsCreekWatershed","RiceForkWatershed","RiggsWashSaltCreekWatershed","RinconCreekFrontalPacificOceanWatershed","RioHondoWatershed","RoaringCreekPitRiverWatershed","RoaringRiverWatershed","RockCreekWatershed","RockCreekBuckhornLakeWatershed","RockCreekKernRiverWatershed","RockCreekKlamathRiverWatershed","RogersLakeWatershed","RootCreekSanJoaquinRiverWatershed","RosamondLakeWatershed","RoseValleyWatershed","RubiconRiverWatershed","RushCreekWatershed","RushCreekAshCreekWatershed","SacataraCreekKingsCanyonWatershed","SacramentoRiverWatershed","SacramentoRiverArmShastaLakeWatershed","SacramentoWashWatershed","SaddlePeakHillsAmargosaRiverWatershed","SaladoCreekSanJoaquinRiverWatershed","SalmonCreekFrontalPacificOceanWatershed","SalmonRiverWatershed","SalsipuedesCreekSantaYnezRiverWatershed","SaltCreekWatershed","SaltLakeWatershed","SaltRiverEelRiverWatershed","SaltSloughWatershed","SaltonSeaWatershed","SanAntonioCreekWatershed","SanAntonioCreekSouthForkCalaverasRiverWatershed","SanAntonioRiverWatershed","SanDiegoBayWatershed","SanDiegoCreekWatershed","SanDieguitoRiverWatershed","SanEmigdioCreekFrontalBuenaVistaLakeBedWatershed","SanFranciscoBayWatershed","SanGorgonioRiverWatershed","SanGregorioCreekFrontalPacificOceanWatershed","SanJoseCreekWatershed","SanJuanCreekWatershed","SanLorenzoCreekWatershed","SanLorenzoCreekFrontalSanFranciscoBayEstuariesWatershed","SanLorenzoRiverWatershed","SanLuisCreekWatershed","SanMarcosCreekFrontalGulfofSantaCatalinaWatershed","SanMateoCreekWatershed","SanMateoCreekFrontalSanFranciscoBayEstuariesWatershed","SanMiguelIslandSantaRosaIslandWatershed","SanNicholasIslandSantaCatalinaIslandWatershed","SanOnofreCreekFrontalGulfofSantaCatalinaWatershed","SanPabloBayWatershed","SanPabloCreekFrontalSanPabloBayEstuariesWatershed","SanPedroCreekFrontalSantaBarbaraChannelWatershed","SanTimoteoWashWatershed","SanVicenteCreekWatershed","SandCreekWatershed","SandyCreekFrontalBuenaVistaLakeBedWatershed","SantaCruzCreekWatershed","SantaCruzIslandWatershed","SantaMargaritaCreekSalinasRiverWatershed","SantaMargaritaLakeSalinasRiverWatershed","SantaMargaritaRiverWatershed","SantaMariaRiverWatershed","SantaRosaCreekFrontalPacificOceanWatershed","SantaRosaWashWatershed","SantiagoCreekWatershed","SaratogaCreekFrontalSanFranciscoBayEstuariesWatershed","SchulylerWashWatershed","ScottsCreekWatershed","SearlesLakeWatershed","SearlesValleyWatershed","SeiadCreekKlamathRiverWatershed","SespeCreekWatershed","SheepCreekElMirageLakeWatershed","SheepHoleMountainsWatershed","ShepherdCreekOwensRiverWatershed","ShermanLakeSacramentoRiverWatershed","ShipCreekFordDryLakeWatershed","ShumanCanyonFrontalPacificOceanWatershed","SidneyPeakWatershed","SierraValleyWatershed","SilverCreekWatershed","SilverCreekRabbitLakeWatershed","SilverForkAmericanRiverWatershed","SilverLakeWatershed","SkedaddleCreekWatershed","SlateCreekSacramentoRiverWatershed","SmithRiverWatershed","SmithneckCreekWatershed","SnodgrassSloughWatershed","SodaLakeWatershed","SonomaCreekFrontalSanPabloBayEstuariesWatershed","SouthCowCreekWatershed","SouthForkBattleCreekWatershed","SouthForkCosumnesRiverWatershed","SouthForkFeatherRiverWatershed","SouthForkKaweahRiverWatershed","SouthForkMercedRiverWatershed","SouthForkMokelumneRiverWatershed","SouthForkSalmonRiverWatershed","SouthForkSmithRiverWatershed","SouthForkStanislausRiverWatershed","SouthForkTuleRiverWatershed","SouthForkTuolumneRiverWatershed","SouthForkWillowCreekWatershed","SouthForkWillowSloughWatershed","SpanishCreekWatershed","SquawCreekWatershed","SquawValleyCreekWatershed","SteelheadCreekWatershed","StevensonCreekSanJoaquinRiverWatershed","StillwaterCreekWatershed","StoddardValleyWatershed","StoneCorralCreekWatershed","StonewallCreekSalinasRiverWatershed","StuartForkWatershed","SuisunBayWatershed","SunshinePeakLavicLakeWatershed","SuperiorLakeWatershed","SuperstitionHillsFrontalSaltonSeaWatershed","SurpriseCanyonPanamintValleyWatershed","SurpriseSpringsDeadmanLakeWatershed","SutterBasinWatershed","SutterCreekWatershed","SwiftCreekTrinityRiverWatershed","SycamoreSloughWatershed","TangleBlueCreekTrinityRiverWatershed","TankSpringRiceValleyWatershed","TaylorReservoirWatershed","TeagleWashWatershed","TecateCreekWatershed","TecopaHotSpringsAmargosaRiverWatershed","TectahCreekKlamathRiverWatershed","TecuyaCreekFrontalKernLakeBedWatershed","TehachapiCreekWatershed","TejonCreekWatershed","TembladeroSloughWatershed","TemescalWashWatershed","TenMileRiverWatershed","TequisquitaSloughWatershed","TheButtesWatershed","ThirdCreekFrontalLakeTahoeWatershed","ThompsonCreekKlamathRiverWatershed","TinemahaCreekOwensRiverWatershed","TomalesBayBodegaBayWatershed","TomkiCreekWatershed","ToomesCreekWatershed","TownofIvanpahFrontalIvanpahLakeWatershed","TownofKramerJunctionTownofJimgreyWatershed","TownofMendotaFresnoSloughWatershed","TownofOldDaleDogWashWatershed","TownofPearblossomWatershed","TownofPittvillePitRiverWatershed","TownofPoplarFrontalTulareLakeBedWatershed","TownofRichgroveTownofAllensworthWatershed","TresPinosCreekWatershed","TropicoHillOakCreekWatershed","TroyLakeWatershed","TulareLakeBedWatershed","TuleLakeWatershed","TulucayCreekFrontalSanPabloBayEstuariesWatershed","TumeyGulchFresnoSloughWatershed","TurnerCreekWatershed","TurwarCreekKlamathRiverWatershed","TwentymileCreekWatershed","UbehebePeakWatershed","UkonomCreekKlamathRiverWatershed","UlatisCreekWatershed","UpperAlkaliLakeWatershed","UpperBearCreekWatershed","UpperBearRiverWatershed","UpperButteCreekWatershed","UpperCacheCreekWatershed","UpperCarrizoCreekWatershed","UpperChemehueviWashWatershed","UpperChowchillaRiverWatershed","UpperCosumnesRiverWatershed","UpperCottonwoodCreekWatershed","UpperCoyoteCreekWatershed","UpperCrossCreekWatershed","UpperCuyamaRiverWatershed","UpperDeathValleyWashWatershed","UpperDeerCreekWatershed","UpperDryCreekWatershed","UpperEastForkCarsonRiverWatershed","UpperEastWalkerRiverWatershed","UpperEurekaValleyWatershed","UpperFeatherRiverWatershed","UpperFremontWashWatershed","UpperFresnoRiverWatershed","UpperHayforkCreekWatershed","UpperHomerWashWatershed","UpperIndianCreekWatershed","UpperKelsoWashWatershed","UpperKernRiverFloodCanalWatershed","UpperKingstonWashWatershed","UpperLongValleyCreekWatershed","UpperLosAngelesRiverWatershed","UpperLosBanosCreekWatershed","UpperMadRiverWatershed","UpperMiddleForkAmericanRiverWatershed","UpperMiddleForkEelRiverWatershed","UpperMiddleForkFeatherRiverWatershed","UpperMiddleForkStanislausRiverWatershed","UpperMokelumneRiverWatershed","UpperNorthForkAmericanRiverWatershed","UpperNorthForkFeatherRiverWatershed","UpperNorthForkMokelumneRiverWatershed","UpperNorthYubaRiverWatershed","UpperPanocheCreekWatershed","UpperPineCreekWatershed","UpperPintoWashWatershed","UpperPiruCreekWatershed","UpperPosoCreekWatershed","UpperPutahCreekWatershed","UpperRussianRiverWatershed","UpperSaltCreekWatershed","UpperSanBenitoRiverWatershed","UpperSanDiegoRiverWatershed","UpperSanFelipeCreekWatershed","UpperSanGabrielRiverWatershed","UpperSanJacintoRiverWatershed","UpperSanJuanCreekWatershed","UpperSanLuisReyRiverWatershed","UpperSantaAnaRiverWatershed","UpperSantaClaraRiverWatershed","UpperSantaYsabelCreekWatershed","UpperSisquocRiverWatershed","UpperSouthForkAmericanRiverWatershed","UpperSouthForkCottonwoodCreekWatershed","UpperSouthForkEelRiverWatershed","UpperSouthForkKernRiverWatershed","UpperSouthForkKingsRiverWatershed","UpperSouthForkSanJoaquinRiverWatershed","UpperSouthForkTrinityRiverWatershed","UpperSouthYubaRiverWatershed","UpperSpringCanyonCreekWatershed","UpperStanislausRiverWatershed","UpperStonyCreekWatershed","UpperSusanRiverWatershed","UpperSweetwaterRiverWatershed","UpperTemeculaCreekWatershed","UpperThomesCreekWatershed","UpperTruckeeRiverFrontalLakeTahoeWatershed","UpperTuleRiverWatershed","UpperVanDuzenRiverWatershed","UpperWatsonWashWatershed","UpperWestWalkerRiverWatershed","UpperWhiteRiverWatershed","UpperWhitewaterRiverWatershed","UsalCreekFrontalPacificOceanWatershed","UvasCreekWatershed","VallecitoCreekWatershed","ValleyMountainWatershed","VanLoanCreekMadelinePlainsWatershed","VenturaRiverWatershed","VidalWashWatershed","WaddellCreekFrontalAnoNuevoBayWatershed","WagonCreekSacramentoRiverWatershed","WalkerBasinCreekWatershed","WalkerCreekWatershed","WallStreetCanyonWatershed","WalnutCreekWatershed","WalnutCreekFrontalSuisinBayEstuariesWatershed","WarmSpringsValleyPitRiverWatershed","WarthanCreekWatershed","WaterCanyonPanamintValleyWatershed","WaucobaWashWatershed","WeaverCreekTrinityRiverWatershed","WeberCreekWatershed","WestBranchFeatherRiverWatershed","WestForkCarsonRiverWatershed","WestForkMojaveRiverWatershed","WestForkSanGabrielRiverWatershed","WestSideCanalWatershed","WidowValleyCreekPitRiverWatershed","WildWashWatershed","WildroseWashWatershed","WillowCreekWatershed","WillowCreekFrontalGooseLakeWatershed","WillowSloughWatershed","WillowWashWatershed","WilsonCreekWatershed","WingateWashWatershed","WolfCreekWatershed","WoodenValleyCreekFrontalSuisunBayEstuariesWatershed","WoodmanCreekEelRiverWatershed","WoodsCreekWatershed","WooleyCreekWatershed","YagerCreekWatershed","YellowCreekWatershed","YokohlCreekWatershed","YosemiteCreekMercedRiverWatershed","YrekaCreekShastaRiverWatershed","YubaRiverWatershed","ZacaCreekSantaYnezRiverWatershed","ZapatoChinoCreekWatershed"]}} 2 | -------------------------------------------------------------------------------- /cfo/tests/test_utils.py: -------------------------------------------------------------------------------- 1 | import os 2 | import builtins 3 | import mock 4 | import requests 5 | 6 | from cfo import utils 7 | 8 | # get authentication inputs 9 | try: 10 | email = os.environ["CFO_EMAIL"] 11 | password = os.environ["CFO_PASS"] 12 | except KeyError: 13 | email = "bad@example.com" 14 | password = "badpassword" 15 | 16 | 17 | def test_connection(): 18 | """Test internet connectivity""" 19 | url = "http://httpbin.org/get" 20 | body = {"content": "testing"} 21 | response = requests.get(url, body) 22 | assert response.status_code == 200 23 | assert response.json()["args"] == body 24 | 25 | 26 | def test_endpoints(): 27 | """Tests connections to API endpoints""" 28 | entries = list(utils.ENDPOINTS.keys()) 29 | for entry in entries: 30 | url = "{host}{endpoint}".format(host=utils.URL, endpoint=utils.ENDPOINTS[entry]) 31 | response = requests.get(url) 32 | assert response.status_code != 404 33 | 34 | 35 | def test_get_input(): 36 | """Tests user input""" 37 | with mock.patch.object(builtins, "input", lambda _: email): 38 | assert utils.get_input(email) == email 39 | assert utils.get_input(email) != password 40 | 41 | 42 | def test_API(): 43 | """Tests creation/functions of the CFO API class""" 44 | firetower = utils.API() 45 | methods = dir(firetower) 46 | assert "authenticate" in methods 47 | assert "help" in methods 48 | assert "list_categories" in methods 49 | assert "list_geographies" in methods 50 | assert "list_geography_types" in methods 51 | assert "list_metrics" in methods 52 | assert "search" in methods 53 | -------------------------------------------------------------------------------- /cfo/utils.py: -------------------------------------------------------------------------------- 1 | """Convenience functions for interacting with the CFO catalog in the Salo Sciences REST API""" 2 | from functools import wraps 3 | import re 4 | import logging 5 | import tempfile 6 | import json 7 | import gzip 8 | import os 9 | import sys 10 | from getpass import getpass 11 | 12 | import requests 13 | from retrying import retry 14 | 15 | # global parameters 16 | URL = "https://api.salo.ai" 17 | CATALOG = "cfo" 18 | 19 | # logging setup 20 | logging.basicConfig( 21 | level=logging.WARNING, 22 | format=("%(asctime)s %(levelname)s %(name)s [%(funcName)s] | %(message)s"), 23 | stream=sys.stdout, 24 | ) 25 | LOGGER = logging.getLogger(__name__) 26 | 27 | # define the endpoints 28 | ENDPOINTS = { 29 | "auth": "/users/auth", 30 | "refresh": "/users/auth/refresh", 31 | "search": "/data/search", 32 | "fetch": "/data/fetch", 33 | "pixel_pick": "/data/pixel_pick", 34 | "public_key": "/data/public_key", 35 | "styles": "/data/styles", 36 | } 37 | 38 | # set the path to package data 39 | package_path = os.path.realpath(__file__) 40 | package_dir = os.path.dirname(package_path) 41 | json_path = os.path.join(package_dir, "data", "paths.json") 42 | with open(json_path, "r+") as f: 43 | PATHS = json.loads(f.read()) 44 | 45 | # create a temp directory to store the authentication data 46 | TMP_DIR = os.path.join(tempfile.gettempdir(), "cfo") 47 | if not os.path.exists(TMP_DIR): 48 | os.mkdir(TMP_DIR) 49 | TMP_KEY = tempfile.NamedTemporaryFile(mode="w+", dir=TMP_DIR, delete=True) 50 | TMP_FILE = os.path.join(TMP_DIR, "token") 51 | 52 | 53 | def auth_required(): 54 | """Decorator to require authorization before an API request is made""" 55 | 56 | def decorator(view): 57 | @wraps(view) 58 | def wrapper(*args, **kwargs): 59 | 60 | self = args[0] 61 | name = view.__name__ 62 | warning = f"Authentication is required for function .{name}()" 63 | 64 | # first run auth 65 | if "Authorization" not in self._session.headers: 66 | status = self.authenticate(ignore_temp=False) 67 | if status != 200: 68 | LOGGER.warning(warning) 69 | return None 70 | 71 | if not self._session.headers["Authorization"].startswith("Bearer "): 72 | LOGGER.warning("Authorization header is not a bearer type") 73 | LOGGER.warning(warning) 74 | return None 75 | 76 | matches = re.match(r"^Bearer (\S+)$", self._session.headers["Authorization"]) 77 | if not matches: 78 | LOGGER.warning("Invalid bearer token format") 79 | LOGGER.warning(warning) 80 | return None 81 | 82 | return view(*args, **kwargs) 83 | 84 | return wrapper 85 | 86 | return decorator 87 | 88 | 89 | def get_input(data_type: str): 90 | """ 91 | Gets command line user input 92 | :param data_type: the data type to prompt the user to request 93 | :return user_input: the user entered content 94 | """ 95 | prompt = f"CFO {data_type}: " 96 | try: 97 | if data_type.lower() == "password": 98 | user_input = getpass(prompt) 99 | else: 100 | user_input = input(prompt) 101 | 102 | return user_input 103 | 104 | except Exception as error: 105 | LOGGER.exception(error) 106 | 107 | 108 | def get_email_pass(): 109 | """ 110 | Gets CFO email/password from environment variables or user input 111 | :return (email, password): tuple of strings for the users input email/password 112 | """ 113 | 114 | # check environment variables first 115 | email = os.getenv("CFO_EMAIL") 116 | password = os.getenv("CFO_PASS") 117 | 118 | # get user input otherwise 119 | if email is None: 120 | email = get_input("E-mail") 121 | 122 | if password is None: 123 | password = get_input("Password") 124 | 125 | return email, password 126 | 127 | 128 | def construct_asset_id( 129 | geography: str = None, 130 | category: str = None, 131 | metric: str = None, 132 | year: int = None, 133 | timeOfYear: str = None, 134 | resolution: int = None, 135 | ): 136 | """ 137 | Constructs a CFO-format asset id string 138 | :param geography: see list from API.list_geographies() 139 | :param category: see list from API.list_categories() 140 | :param metric: see list from API.list_metrics() 141 | :param year: julian year 142 | :param timeOfYear: can be a date ('0825') or more general ('Fall') 143 | :param resolution: the spatial resolution in meters 144 | :return asset_id: a formatted string 145 | """ 146 | # handle None 147 | if geography is None: 148 | geography = "*" 149 | if category is None: 150 | category = "*" 151 | if metric is None: 152 | metric = "*" 153 | if timeOfYear is None: 154 | timeOfYear = "*" 155 | 156 | # handle numerical cases 157 | if year is None: 158 | year = "*" 159 | else: 160 | year = f"{year:04d}" 161 | 162 | if resolution is None: 163 | resolution = "*" 164 | else: 165 | resolution = f"{resolution:05d}m" 166 | 167 | # join everything together 168 | asset_id = "-".join([geography, category, metric, year, timeOfYear, resolution]) 169 | 170 | # replace common wildcards with the sql format wildcard 171 | wildcard = "%" 172 | finders = ["*", "?"] 173 | for finder in finders: 174 | asset_id = asset_id.replace(finder, wildcard) 175 | 176 | return asset_id 177 | 178 | 179 | def check(response: object): 180 | """ 181 | Evaluates the response code and message returned by a search request 182 | :return [success, msg]: a boolean success/fail on the request and the response message 183 | """ 184 | if response.status_code == 200: 185 | success = True 186 | msg = "slugs rule" 187 | else: 188 | success = False 189 | msg = response.content 190 | 191 | return [success, msg] 192 | 193 | 194 | def read_token_file(path: str): 195 | """ 196 | Reads a gzipped token tempfile 197 | :param path: the path to the gzipped file 198 | :return token: a token string 199 | """ 200 | with gzip.open(path, "rb") as f: 201 | return f.read().decode() 202 | 203 | 204 | def write_token_file(token: str, path: str): 205 | """ 206 | Writes token data to a gzipped tempfile 207 | :param token: a string containing the token data 208 | :param path: the path to the output tempfile 209 | :return: 210 | """ 211 | with gzip.open(path, "wb") as f: 212 | f.write(token.encode("utf-8")) 213 | 214 | 215 | def write_public_key(tf, data: dict): 216 | """ 217 | Writes json key data to a temporary file 218 | :param tf: the tempfile NamedTemporaryFile object 219 | :param data: the public key auth data 220 | :return none: no object returned; an environment variable is updated 221 | """ 222 | # write the json data 223 | tf.file.write(json.dumps(data, indent=2) + "\n") 224 | tf.file.flush() 225 | 226 | # point the google auth to this file path 227 | global os 228 | os.environ["GOOGLE_APPLICATION_CREDENTIALS"] = tf.name 229 | 230 | 231 | def validate_geography(lon: float, lat: float): 232 | """ 233 | Verifies that latitude and longitude values are valid 234 | :param lon: longitude value in degrees 235 | :param lat: latitude value in degrees 236 | :return valid: boolean for whether the lon/lat values are valid 237 | """ 238 | lon_valid = lon >= -180 and lon <= 180 239 | lat_valid = lat >= -90 and lat <= 90 240 | valid = lon_valid and lat_valid 241 | if not valid: 242 | return False 243 | else: 244 | return True 245 | 246 | 247 | class API(object): 248 | """Utility class for Salo API requests""" 249 | 250 | def __init__(self): 251 | """API class constructor""" 252 | 253 | # create the REST session 254 | self._session = requests.Session() 255 | 256 | def help(self): 257 | """Returns the docstring for the main class""" 258 | return self.__doc__ 259 | 260 | def list_categories(self): 261 | """ 262 | Lists the different categories of data available 263 | :return categories: list 264 | """ 265 | return PATHS["category"] 266 | 267 | def list_metrics(self, category: str = None): 268 | """ 269 | Lists the metrics available by category 270 | :param category: the category of data for each metric (see .list_categories()) 271 | :return metrics: a list if category is specified, a dictionary with each metric if not 272 | """ 273 | if category is None: 274 | return PATHS["metric"] 275 | else: 276 | try: 277 | return PATHS["metric"][category] 278 | except KeyError: 279 | LOGGER.warning(f"Unsupported category: {category}") 280 | LOGGER.warning(f"Must be one of {', '.join(self.list_categories())}") 281 | return None 282 | 283 | def list_fuel_metrics(self): 284 | """ 285 | Lists the veg metrics needed to create a landscape file 286 | :return metrics: a list of "Vegetation" metrics used to generate landscape files 287 | """ 288 | return [ 289 | "SurfaceFuels", 290 | "CanopyCover", 291 | "CanopyHeight", 292 | "CanopyBaseHeight", 293 | "CanopyBulkDensity", 294 | ] 295 | 296 | def list_geography_types(self): 297 | """ 298 | Lists the broad geography classes (state, watershed, etc.) 299 | :return types: list 300 | """ 301 | return list(PATHS["geography"].keys()) 302 | 303 | def list_geographies(self, by: str = None): 304 | """ 305 | Lists the specific geographic areas available 306 | :param by: the type of geography to list (see .list_geography_types()) 307 | :return geographies: a list if type is specified, a dictionary with each geography if not 308 | """ 309 | if type is None: 310 | return PATHS["geography"] 311 | else: 312 | try: 313 | return PATHS["geography"][by] 314 | except KeyError: 315 | LOGGER.warning(f"Unsupported category: {by}") 316 | LOGGER.warning(f"Must be one of {', '.join(self.list_geography_types())}") 317 | return None 318 | 319 | def list_fetch_types(self): 320 | """ 321 | Lists the different link types that can be retrieved from the fetch() routine 322 | :returns fetch_types: list of strings 323 | """ 324 | return ["wms", "signed_url", "uri", "url", "wms_preview"] 325 | 326 | def list_styles(self): 327 | """ 328 | Lists the WMS styles available 329 | :returns styles: list of style strings 330 | """ 331 | response = self._styles_request() 332 | success, msg = check(response) 333 | if success: 334 | styles = response.json()["styles"] 335 | return styles 336 | else: 337 | LOGGER.warning(msg) 338 | raise 339 | 340 | def authenticate(self, ignore_temp: bool = True): 341 | """ 342 | Retrieves a JWT authentication token. Requires a forestobservatory.com account. 343 | :return status_code: the API response status code 344 | """ 345 | # check for a stored token 346 | login = True 347 | if not ignore_temp: 348 | if os.path.exists(TMP_FILE): 349 | try: 350 | token = read_token_file(TMP_FILE) 351 | LOGGER.info("Loaded cfo token") 352 | auth = {"Authorization": f"Bearer {token}"} 353 | self._session.headers.update(auth) 354 | login = False 355 | status = 200 356 | 357 | # get the public auth key 358 | response = self._public_key_request() 359 | if response.status_code == 200: 360 | write_public_key(TMP_KEY, response.json()) 361 | 362 | except PermissionError: 363 | LOGGER.warning("Unable to read token from temp file") 364 | 365 | # otherwise 366 | if login: 367 | email, password = get_email_pass() 368 | token, status = self._auth_request(email, password) 369 | del password 370 | if status == 200: 371 | LOGGER.info("Authentication successful") 372 | auth = {"Authorization": f"Bearer {token}"} 373 | self._session.headers.update(auth) 374 | 375 | # write it to a temp file for convenience 376 | try: 377 | write_token_file(token, TMP_FILE) 378 | except PermissionError: 379 | pass 380 | 381 | # get the public auth key 382 | response = self._public_key_request() 383 | if response.status_code == 200: 384 | write_public_key(TMP_KEY, response.json()) 385 | 386 | else: 387 | LOGGER.warning(f"Authentication failed with status code {status}") 388 | 389 | return status 390 | 391 | def search( 392 | self, 393 | geography: str = None, 394 | category: str = None, 395 | metric: str = None, 396 | year: int = None, 397 | timeOfYear: str = None, 398 | resolution: int = None, 399 | asset_id: str = None, 400 | bbox: list = None, 401 | description: str = None, 402 | raw: bool = False, 403 | just_assets: bool = True, 404 | ): 405 | """ 406 | Queries the CFO API for datasets. 407 | :param geography: see list from API.list_geographies() 408 | :param category: see list from API.list_categories() 409 | :param metric: see list from API.list_metrics() 410 | :param year: julian year 411 | :param timeOfYear: can be a date ('0825') or more general ('Fall') 412 | :param resolution: the spatial resolution in meters 413 | :param asset_id: an asset id to search by. this is constructed by the above if not passed 414 | :param bbox: returns only results that intersect this box [xmin, ymin, xmax, ymax] (in lat/lon) 415 | :param description: a string that may match the dataset description 416 | :param raw: specifies whether to return the full response object. default is just json 417 | :param just_assets: specified whether to return just the asset IDs of the search result. 418 | :return response: the api search result 419 | """ 420 | # construct an asset ID if not explicitly passed 421 | if asset_id is None: 422 | asset_id = construct_asset_id( 423 | geography=geography, 424 | category=category, 425 | metric=metric, 426 | year=year, 427 | timeOfYear=timeOfYear, 428 | resolution=resolution, 429 | ) 430 | 431 | # send the request 432 | response = self._search_request(asset_id=asset_id, bbox=bbox, description=description) 433 | 434 | # check for failures 435 | success, msg = check(response) 436 | 437 | # return the data on a success 438 | if success: 439 | if raw: 440 | return response 441 | elif just_assets: 442 | features = response.json()["features"] 443 | asset_ids = [feature["asset_id"] for feature in features] 444 | return asset_ids 445 | else: 446 | return response.json()["features"] 447 | 448 | # otherwise, debug 449 | else: 450 | LOGGER.warning(msg) 451 | return msg 452 | 453 | def download(self, asset_id: str, path: str = None): 454 | """ 455 | Downloads a CFO asset to your local machine 456 | :param asset_id: a CFO asset ID string (often returned from search()) 457 | :param path: the output file path. Set to ./{asset_id}.tif by default. Appends '.tif' if not set. 458 | :return: 459 | """ 460 | if path is None: 461 | path = os.path.join(os.getcwd(), f"{asset_id}.tif") 462 | else: 463 | if ".tif" not in path.lower(): 464 | path = f"{path}.tif" 465 | 466 | # fetch the url by asset ID 467 | url = self.fetch(asset_id, dl=True) 468 | 469 | # then stream the file to disk 470 | r = requests.get(url, stream=True) 471 | if r.ok: 472 | LOGGER.info(f"Beginning download for: {asset_id}") 473 | with open(path, "wb") as f: 474 | for chunk in r.iter_content(chunk_size=128): 475 | f.write(chunk) 476 | 477 | # check that it worked 478 | if os.stat(path).st_size > 0: 479 | LOGGER.info(f"Successfully downloaded {asset_id} to file: {path}") 480 | 481 | def fetch( 482 | self, 483 | asset_id: str, 484 | dl: bool = False, 485 | wms: bool = False, 486 | gdal: bool = False, 487 | bucket: bool = False, 488 | fetch_types: list = [], 489 | ): 490 | """ 491 | Fetches the download / map / file url for an asset 492 | :param asset_id: a CFO asset ID string (often returned from search() ) 493 | :param dl: returns the asset download url (a google cloud signed url) 494 | :param wms: returns a wms url (for web mapping applications) 495 | :param gdal: returns a vsicurl address to read the data using GDAL 496 | :param bucket: returns a google cloud bucket url to the asset id 497 | :param fetch_types: the full range of fetch options accepted by the API (from get_fetch_types()) 498 | :return response: the api fetch result. returns a string if only one boolean parameter passed, otherwise a dict. 499 | """ 500 | # handle multiple pathways of parameter setting 501 | responses = dict() 502 | params = list() 503 | n_params = 0 504 | link = "link" 505 | 506 | # make sure something is set 507 | if True not in [dl, wms, bucket, gdal] and len(fetch_types) == 0: 508 | # set a default option 509 | dl = True 510 | 511 | # check each fetch type 512 | if dl: 513 | param = "dl" 514 | response = self._fetch_request(asset_id, fetch_type="signed_url") 515 | success, msg = check(response) 516 | if success: 517 | responses[param] = response.json()[link] 518 | params.append(param) 519 | n_params += 1 520 | else: 521 | LOGGER.warning(msg) 522 | raise 523 | if wms: 524 | param = "wms" 525 | response = self._fetch_request(asset_id, fetch_type="wms") 526 | success, msg = check(response) 527 | if success: 528 | responses[param] = response.json()[link] 529 | params.append(param) 530 | n_params += 1 531 | else: 532 | LOGGER.warning(msg) 533 | raise 534 | if gdal: 535 | param = "gdal" 536 | response = self._fetch_request(asset_id, fetch_type="uri") 537 | success, msg = check(response) 538 | if success: 539 | uri = response.json()[link] 540 | vsi = f"/vsigs/{uri[5:]}" 541 | responses[param] = vsi 542 | params.append(param) 543 | n_params += 1 544 | else: 545 | LOGGER.warning(msg) 546 | raise 547 | if bucket: 548 | param = "bucket" 549 | response = self._fetch_request(asset_id, fetch_type="uri") 550 | success, msg = check(response) 551 | if success: 552 | responses[param] = response.json()[link] 553 | params.append(param) 554 | n_params += 1 555 | else: 556 | LOGGER.warning(msg) 557 | raise 558 | 559 | # run through types last 560 | if len(fetch_types) != 0: 561 | supported = set(self.list_fetch_types()) 562 | if supported.intersection(set(fetch_types)) != supported: 563 | LOGGER.warning(f"Unsupported type parameter passed: [{', '.join(fetch_types)}]") 564 | LOGGER.warning(f"Supported type parameters: [{', '.join(supported)}]") 565 | return None 566 | else: 567 | for fetch_type in fetch_types: 568 | response = self._fetch_request(asset_id, fetch_type) 569 | success, msg = check(response) 570 | if success: 571 | responses[fetch_type] = response.json()[link] 572 | n_params += 1 573 | else: 574 | LOGGER.warning(msg) 575 | raise 576 | 577 | # determine what you return based on the number of passed options 578 | if n_params == 1: 579 | return responses[params[0]] # just the link url 580 | else: 581 | return responses # the multi-param dictionary 582 | 583 | def pixel_pick(self, asset_id: str, lon: float, lat: float): 584 | """ 585 | Returns the pixel value at a point coordinate from a CFO asset 586 | :param asset_id: a CFO asset ID string (often returned from search()) 587 | :param lon: the longitude (x) location in decimal degrees 588 | :param lat: the latitude (y) location in decimal degrees 589 | :return response: the pixel_pick api response. 590 | """ 591 | # verify the geometry is valid 592 | if not validate_geography(lon, lat): 593 | LOGGER.warning(f"Invalid longitude/latidude values: {lat:0.2f}/{lon:0.2f}") 594 | LOGGER.warning("Must be in range [-180, 180] and [-90, 90], respectively.") 595 | return None 596 | 597 | # verify the asset ID is valid 598 | response = self._search_request(asset_id=asset_id) 599 | success, msg = check(response) 600 | if not success: 601 | LOGGER.warning(f"Invalid asset_id: {asset_id}") 602 | LOGGER.warning(msg) 603 | return None 604 | 605 | # then get the dang pixel value 606 | response = self._pixel_pick_request(asset_id, lon, lat) 607 | if not success: 608 | LOGGER.warning(msg) 609 | else: 610 | return response.json()["val"] 611 | 612 | @retry(wait_exponential_multiplier=1000, wait_exponential_max=10000) 613 | def _auth_request(self, email: str, password: str): 614 | """ 615 | Retrieves a JWT token for the email/password combo 616 | :param email: registered email address 617 | :param password: CFO account password 618 | :return: (token, status_code) 619 | """ 620 | endpoint = ENDPOINTS["auth"] 621 | request_url = f"{URL}{endpoint}" 622 | body = {"email": email, "password": password} 623 | response = self._session.post(request_url, json=body) 624 | 625 | # hope for success 626 | if response.status_code == 200: 627 | token = response.json()["token"] 628 | 629 | else: 630 | token = None 631 | LOGGER.warning("Authentication failed. Try and run .authenticate(ignore_temp=True)") 632 | LOGGER.warning(response.content) 633 | 634 | return token, response.status_code 635 | 636 | @auth_required() 637 | @retry(wait_exponential_multiplier=1000, wait_exponential_max=10000) 638 | def _search_request( 639 | self, 640 | catalog: str = CATALOG, 641 | asset_id: str = None, 642 | bbox: list = None, 643 | date: str = None, 644 | description: str = None, 645 | ): 646 | """ 647 | Submits the POST request to the search endpoint 648 | :param catalog: the data catalog to query 649 | :param asset_id: a partial/full cfo asset id to search for 650 | :param bbox: a lat/lon bounding box of [xmin, ymin, xmax, ymax] extent 651 | :param date: a utc datetime to query by 652 | :param description: a partial/full dataset description to search by 653 | :return response: the request response 654 | """ 655 | endpoint = ENDPOINTS["search"] 656 | request_url = f"{URL}{endpoint}" 657 | body = { 658 | "catalog_list": catalog, 659 | "asset_id": asset_id, 660 | "bounding_box": bbox, 661 | "datetime": date, 662 | "description": description, 663 | } 664 | response = self._session.post(request_url, json=body) 665 | 666 | return response 667 | 668 | @auth_required() 669 | @retry(wait_exponential_multiplier=1000, wait_exponential_max=10000) 670 | def _fetch_request(self, asset_id: str, fetch_type: str, catalog: str = CATALOG): 671 | """ 672 | Submits the POST request to the search endpoint 673 | :param asset_id: a full cfo asset id to fetch 674 | :param fetch_type: the type of url to return 675 | :param catalog: the data catalog to query 676 | :return response: the request response 677 | """ 678 | endpoint = ENDPOINTS["fetch"] 679 | request_url = f"{URL}{endpoint}" 680 | body = { 681 | "catalog": catalog, 682 | "asset_id": asset_id, 683 | "type": fetch_type, 684 | } 685 | response = self._session.post(request_url, json=body) 686 | 687 | return response 688 | 689 | @retry(wait_exponential_multiplier=1000, wait_exponential_max=10000) 690 | def _styles_request(self): 691 | """ 692 | Submits the GET request to the styles endpoint 693 | :return response: the request response 694 | """ 695 | endpoint = ENDPOINTS["styles"] 696 | request_url = f"{URL}{endpoint}" 697 | response = self._session.get(request_url) 698 | 699 | return response 700 | 701 | @auth_required() 702 | @retry(wait_exponential_multiplier=1000, wait_exponential_max=10000) 703 | def _public_key_request(self): 704 | """ 705 | Submits the GET request to the public_key endpoint 706 | :return response: the request response 707 | """ 708 | endpoint = ENDPOINTS["public_key"] 709 | request_url = f"{URL}{endpoint}" 710 | response = self._session.get(request_url) 711 | 712 | return response 713 | 714 | def _pixel_pick_request(self, asset_id: str, lon: float, lat: float, catalog: str = CATALOG): 715 | """ 716 | Submits the POST request to the pixel_pick endpoint 717 | :param asset_id: a full cfo asset id to request pixel values from 718 | :param lon: the longitude location to request pixel values from 719 | :param lat: the latitude location to request pixel values from 720 | :param catalog: the data catalog to query 721 | :return response: the request response 722 | """ 723 | endpoint = ENDPOINTS["pixel_pick"] 724 | request_url = f"{URL}{endpoint}" 725 | body = { 726 | "catalog": catalog, 727 | "asset_id": asset_id, 728 | "lng": lon, 729 | "lat": lat, 730 | } 731 | response = self._session.post(request_url, json=body) 732 | 733 | return response 734 | -------------------------------------------------------------------------------- /demos/api-introduction.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Forest Observatory Webinar API demo\n", 8 | "\n", 9 | "This notebook walks through the central `cfo` Python API functions and demonstrates some potential applications. This includes searching for data, downloading it locally, rendering map tiles & clipping data using other spatial datasets.\n", 10 | "\n", 11 | "This notebook is running in the cfo `conda` environment. We created this simple environment to include a series of useful geospatial/data science packages we use on a regular basis (`gdal`, `otb`, `geopandas`, `sklearn`, etc.). If you have conda [installed](https://docs.conda.io/projects/conda/en/latest/user-guide/install/), you can run the following to run this notebook:\n", 12 | "\n", 13 | "```bash\n", 14 | "git clone https://github.com/forestobservatory/cfo-api.git\n", 15 | "cd cfo-api\n", 16 | "conda env update\n", 17 | "conda activate cfo\n", 18 | "jupyter notebook\n", 19 | "```\n", 20 | "\n", 21 | "### What we'll cover\n", 22 | "\n", 23 | "The `cfo` package is pretty simple. We designed it to make it easy for users to access and use CFO data. This notebook will address the following topics:\n", 24 | "\n", 25 | "- Searching for data\n", 26 | "- Downloading data\n", 27 | "- Loading web maps\n", 28 | "\n", 29 | "You'll need a CFO account to run everything in this notebook. Sign up at [forestobservatory.com](https://forestobservatory.com).\n", 30 | "\n", 31 | "### A note on cloud data storage\n", 32 | "\n", 33 | "This notebook review how to download the data using Salo Science's API. But if you want to skip the middle man (erm, the middle alien) you can find the data on our publicly-accessible Google Cloud Storage Bucket ([link here](https://console.cloud.google.com/storage/browser/cfo-public)). If you use `gsutil`, you can access the data via the `gs://cfo-public` bucket)" 34 | ] 35 | }, 36 | { 37 | "cell_type": "code", 38 | "execution_count": null, 39 | "metadata": {}, 40 | "outputs": [], 41 | "source": [ 42 | "# !!!!!!!!!!!!!!!!!\n", 43 | "# change this to a directory on your local machine to determine where downloads will go\n", 44 | "output_directory = '/home/cba/cfo'" 45 | ] 46 | }, 47 | { 48 | "cell_type": "code", 49 | "execution_count": null, 50 | "metadata": {}, 51 | "outputs": [], 52 | "source": [ 53 | "# package prep\n", 54 | "import os\n", 55 | "import cfo\n", 56 | "import gdal\n", 57 | "import ipyleaflet\n", 58 | "import rasterio\n", 59 | "import numpy as np\n", 60 | "from matplotlib import pyplot as plt\n", 61 | "from ipyleaflet import Map, WMSLayer, LayersControl, basemaps\n", 62 | "\n", 63 | "# set plotting style\n", 64 | "%matplotlib notebook\n", 65 | "\n", 66 | "# create the output directory if it doesn't exist\n", 67 | "if not os.path.exists(output_directory):\n", 68 | " os.mkdir(output_directory)" 69 | ] 70 | }, 71 | { 72 | "cell_type": "markdown", 73 | "metadata": {}, 74 | "source": [ 75 | "# Searching for data\n", 76 | "\n", 77 | "Forest Observatory data are organized by `asset_id`, and you'll need to acquire these IDs before you can do anything else. We built the `search` function to facilitate this. It helps to understand the asset ID format:\n", 78 | "\n", 79 | "```python\n", 80 | "{geography}-{category}-{metric}-{year}-{timeOfYear}-{resolution}\n", 81 | "```\n", 82 | "\n", 83 | "We'll explore these in more detail below.\n", 84 | "\n", 85 | "When you run a `search` command it returns a `list` of asset IDs" 86 | ] 87 | }, 88 | { 89 | "cell_type": "code", 90 | "execution_count": null, 91 | "metadata": {}, 92 | "outputs": [], 93 | "source": [ 94 | "# first, we'll create an api class instance\n", 95 | "forest = cfo.api()" 96 | ] 97 | }, 98 | { 99 | "cell_type": "code", 100 | "execution_count": null, 101 | "metadata": {}, 102 | "outputs": [], 103 | "source": [ 104 | "# search for all California-wide vegetation datasets\n", 105 | "ca = forest.search(geography='California', category='Vegetation')\n", 106 | "\n", 107 | "# list the results\n", 108 | "ca.sort()\n", 109 | "for asset in ca:\n", 110 | " print(asset)" 111 | ] 112 | }, 113 | { 114 | "cell_type": "code", 115 | "execution_count": null, 116 | "metadata": {}, 117 | "outputs": [], 118 | "source": [ 119 | "# you can search the daily weather datasets we produce, which are deleted from the api after two weeks\n", 120 | "\n", 121 | "# list the wind speed assets\n", 122 | "wind = forest.search(metric='WindSpeed')\n", 123 | "wind.sort()\n", 124 | "for asset in wind:\n", 125 | " print(asset)" 126 | ] 127 | }, 128 | { 129 | "cell_type": "code", 130 | "execution_count": null, 131 | "metadata": {}, 132 | "outputs": [], 133 | "source": [ 134 | "# all the CFO data on the website have been clipped by County, Watershed and Municipality. \n", 135 | "# you can search those, too. Try it using wildcards\n", 136 | "\n", 137 | "# we'll search an ambiguous area\n", 138 | "sc = forest.search(geography='santacruz*')\n", 139 | "sc.sort()\n", 140 | "for asset in sc:\n", 141 | " print(asset)" 142 | ] 143 | }, 144 | { 145 | "cell_type": "markdown", 146 | "metadata": {}, 147 | "source": [ 148 | "### Cool! But, what if I don't already know what to enter into those fancy category=\"blah blah blah\" fields?\n", 149 | "\n", 150 | "We've built some convenience functions to help you out! The search function accepts keywords that match the `asset_id` formatting above. So, `forest.search(geography=str, category=str, metric=str, year=int, timeOfYear=str, resolution=int)`.\n", 151 | "\n", 152 | "The convenience functions (under `forest.list_*` can guide some suitable inputs for each." 153 | ] 154 | }, 155 | { 156 | "cell_type": "code", 157 | "execution_count": null, 158 | "metadata": {}, 159 | "outputs": [], 160 | "source": [ 161 | "# list the categories of data we generate\n", 162 | "forest.list_categories()" 163 | ] 164 | }, 165 | { 166 | "cell_type": "code", 167 | "execution_count": null, 168 | "metadata": {}, 169 | "outputs": [], 170 | "source": [ 171 | "# list the metrics in the Vegetation category\n", 172 | "forest.list_metrics('Vegetation')" 173 | ] 174 | }, 175 | { 176 | "cell_type": "code", 177 | "execution_count": null, 178 | "metadata": {}, 179 | "outputs": [], 180 | "source": [ 181 | "# and the weather metrics\n", 182 | "forest.list_metrics('Weather')" 183 | ] 184 | }, 185 | { 186 | "cell_type": "code", 187 | "execution_count": null, 188 | "metadata": {}, 189 | "outputs": [], 190 | "source": [ 191 | "# list the different types of geography we slice data by\n", 192 | "forest.list_geography_types()" 193 | ] 194 | }, 195 | { 196 | "cell_type": "code", 197 | "execution_count": null, 198 | "metadata": {}, 199 | "outputs": [], 200 | "source": [ 201 | "# list the first few county names\n", 202 | "forest.list_geographies('County')[:5]" 203 | ] 204 | }, 205 | { 206 | "cell_type": "code", 207 | "execution_count": null, 208 | "metadata": {}, 209 | "outputs": [], 210 | "source": [ 211 | "# which states do we cover?\n", 212 | "forest.list_geographies('State')" 213 | ] 214 | }, 215 | { 216 | "cell_type": "markdown", 217 | "metadata": {}, 218 | "source": [ 219 | ":sunglasses:" 220 | ] 221 | }, 222 | { 223 | "cell_type": "code", 224 | "execution_count": null, 225 | "metadata": {}, 226 | "outputs": [], 227 | "source": [ 228 | "# wanna be a rebel and just get every dang asset we've published?\n", 229 | "thewholeshebang = forest.search()\n", 230 | "print(f\"Number of CFO assets: {len(thewholeshebang)}\")" 231 | ] 232 | }, 233 | { 234 | "cell_type": "markdown", 235 | "metadata": {}, 236 | "source": [ 237 | ":astonished:" 238 | ] 239 | }, 240 | { 241 | "cell_type": "code", 242 | "execution_count": null, 243 | "metadata": { 244 | "scrolled": false 245 | }, 246 | "outputs": [], 247 | "source": [ 248 | "# for more help, run\n", 249 | "forest.search?" 250 | ] 251 | }, 252 | { 253 | "cell_type": "markdown", 254 | "metadata": {}, 255 | "source": [ 256 | "### Gimme the highest resolution data you have!\n", 257 | "\n", 258 | "Thanks for asking nicely. We're still in the process of publishing our 3m datasets, and we appreciate your patience as we do so. Here's how you would search for the statewide datasets at 10m and 3m resolution." 259 | ] 260 | }, 261 | { 262 | "cell_type": "code", 263 | "execution_count": null, 264 | "metadata": {}, 265 | "outputs": [], 266 | "source": [ 267 | "ca3 = forest.search(geography='california', resolution=3)\n", 268 | "ca10 = forest.search(geography='california', resolution=10)\n", 269 | "print(ca3)" 270 | ] 271 | }, 272 | { 273 | "cell_type": "markdown", 274 | "metadata": {}, 275 | "source": [ 276 | "# Downloading data\n", 277 | "\n", 278 | "Though `search` returns a list of asset IDs, the `download` function requires string inputs. This is to reduce the risk of downloading a huge list of files by accident." 279 | ] 280 | }, 281 | { 282 | "cell_type": "code", 283 | "execution_count": null, 284 | "metadata": {}, 285 | "outputs": [], 286 | "source": [ 287 | "# grab the most recent tree height data from grass valley\n", 288 | "gv = forest.search(geography=\"GrassValley*\", metric='CanopyHeight', year=2020)\n", 289 | "print(f\"Number of files found: {len(gv)}\")\n", 290 | "\n", 291 | "# iterate over the list to pass the asset id as a string\n", 292 | "for asset in gv:\n", 293 | " filename = os.path.join(output_directory, asset + '.tif')\n", 294 | " forest.download(asset, filename)" 295 | ] 296 | }, 297 | { 298 | "cell_type": "code", 299 | "execution_count": null, 300 | "metadata": {}, 301 | "outputs": [], 302 | "source": [ 303 | "# to get all the veg metrics, just iterate over the list\n", 304 | "gv_time_series = forest.search(geography=\"GrassValley*\", category=\"Vegetation\")\n", 305 | "for asset in gv_time_series:\n", 306 | " filename = os.path.join(output_directory, asset + '.tif')\n", 307 | " forest.download(asset, filename)" 308 | ] 309 | }, 310 | { 311 | "cell_type": "markdown", 312 | "metadata": {}, 313 | "source": [ 314 | "### What's happening under the hood?\n", 315 | "\n", 316 | "Great segue. Thanks for asking. The `download` function calls another routine, `fetch()` to get a URL to where the file is stored on our Google Cloud Storage Bucket. The fetch function is used to retrieve a series of different asset-specific URLs.\n", 317 | "\n", 318 | "Downloads use a \"signed url\", which means you can just directly download the file without needing to authenticate with Google first. We then make a `GET` request using this url to stream the file to disk." 319 | ] 320 | }, 321 | { 322 | "cell_type": "code", 323 | "execution_count": null, 324 | "metadata": {}, 325 | "outputs": [], 326 | "source": [ 327 | "# print out the long and convoluted signed url\n", 328 | "for asset in gv:\n", 329 | " print(forest.fetch(asset, dl=True))" 330 | ] 331 | }, 332 | { 333 | "cell_type": "code", 334 | "execution_count": null, 335 | "metadata": {}, 336 | "outputs": [], 337 | "source": [ 338 | "# alternatively you can just get the direct bucket uri\n", 339 | "for asset in gv:\n", 340 | " print(forest.fetch(asset, bucket=True))" 341 | ] 342 | }, 343 | { 344 | "cell_type": "code", 345 | "execution_count": null, 346 | "metadata": {}, 347 | "outputs": [], 348 | "source": [ 349 | "# set multiple flags to return a dictionary of urls\n", 350 | "for asset in gv:\n", 351 | " urls = forest.fetch(asset, dl=True, bucket=True, wms=True, gdal=True)\n", 352 | " for key in list(urls.keys()):\n", 353 | " print(f\"{key}: {urls[key]}\")\n", 354 | " print(\"\")" 355 | ] 356 | }, 357 | { 358 | "cell_type": "markdown", 359 | "metadata": {}, 360 | "source": [ 361 | "# Custom data clipping\n", 362 | "\n", 363 | "We clipped all of the 2020 10-meter Vegetation data by County, Municipality & Watershed based on feedback from the community that these were the most relevant areas and datasets of interest. You're welcome.\n", 364 | "\n", 365 | "But we imagine many people are going to be interested in analyzing custom areas of interest. How do you download data from an AOI vector file?\n", 366 | "\n", 367 | "The best way to do this with the API is through `gdal`, referencing the statewide datasets.\n", 368 | "\n", 369 | "`gdalwarp` has a really nice driver for handling [cloud datasets](https://gdal.org/user/virtual_file_systems.html) that allows you to clip rasters on Google Cloud Storage. \n", 370 | "\n", 371 | "We'll run through an example now to use a `geojson` file to download canopy height data from the perimeter of the CZU fire in the Santa Cruz Mountains. This will use `gdal`'s python bindings, but we'll also show what the command line version would look like." 372 | ] 373 | }, 374 | { 375 | "cell_type": "code", 376 | "execution_count": null, 377 | "metadata": {}, 378 | "outputs": [], 379 | "source": [ 380 | "# this vector is in cfo-api/demos\n", 381 | "vector = os.path.join(os.getcwd(), \"czu-perimeter.geojson\")\n", 382 | "\n", 383 | "# get the 2020 10m canopy height asset id\n", 384 | "czu_search = forest.search(geography='California', metric='CanopyHeight', year=2020, resolution=10)\n", 385 | "czu = czu_search[0]\n", 386 | "\n", 387 | "# and get the gdal file path reference\n", 388 | "input_file = forest.fetch(czu, gdal=True)\n", 389 | "print(f\"We'll download from: {input_file}\")" 390 | ] 391 | }, 392 | { 393 | "cell_type": "code", 394 | "execution_count": null, 395 | "metadata": {}, 396 | "outputs": [], 397 | "source": [ 398 | "# set the output raster file\n", 399 | "output_file = os.path.join(output_directory, \"CZU-perimeter-CanopyHeight-2020.tif\")\n", 400 | "\n", 401 | "# set the gdalwarp options\n", 402 | "options = gdal.WarpOptions(\n", 403 | " creationOptions = [\"COMPRESS=DEFLATE\", \"TILED=YES\", \"BIGTIFF=YES\", \"NUM_THREADS=ALL_CPUS\"],\n", 404 | " cutlineDSName = vector,\n", 405 | " cropToCutline = True\n", 406 | ")\n", 407 | "\n", 408 | "# and run the command\n", 409 | "warp = gdal.Warp(output_file, input_file, options=options)\n", 410 | "warp.FlushCache()" 411 | ] 412 | }, 413 | { 414 | "cell_type": "markdown", 415 | "metadata": {}, 416 | "source": [ 417 | "The above is akin to running something like this at the command line:\n", 418 | "\n", 419 | "```\n", 420 | "gdalwarp /vsigs/cfo-public/vegetation/California-Vegetation-CanopyHeight-2020-Summer-00010m.tif /home/cba/cfo/California-Vegetation-CanopyHeight-2020-Summer-00010m.tif -cutline /home/cba/src/cfo-api/demos/czu-perimeter.geojson -crop_to_cutline\n", 421 | "```" 422 | ] 423 | }, 424 | { 425 | "cell_type": "code", 426 | "execution_count": null, 427 | "metadata": {}, 428 | "outputs": [], 429 | "source": [ 430 | "# read and mask the data\n", 431 | "source = rasterio.open(output_file)\n", 432 | "height = source.read(1).astype(float)\n", 433 | "height[height == source.nodata] = np.nan\n", 434 | "\n", 435 | "# get the range to show\n", 436 | "vmin = np.nanpercentile(height, 5)\n", 437 | "vmax = np.nanpercentile(height, 95)\n", 438 | "\n", 439 | "# and plot\n", 440 | "plt.plot(figsize=(15,15), dpi=100)\n", 441 | "height_map = plt.imshow(height, vmin=vmin, vmax=vmax, cmap=plt.cm.cividis)\n", 442 | "plt.title(\"Canopy height inside the\\nburn perimeter of the CZU fire\")\n", 443 | "colorbar = plt.colorbar(height_map)\n", 444 | "colorbar.set_label(\"Canopy Height (m)\")\n", 445 | "plt.tight_layout()" 446 | ] 447 | }, 448 | { 449 | "cell_type": "markdown", 450 | "metadata": {}, 451 | "source": [ 452 | "# Web mapping" 453 | ] 454 | }, 455 | { 456 | "cell_type": "code", 457 | "execution_count": null, 458 | "metadata": {}, 459 | "outputs": [], 460 | "source": [ 461 | "forest.fetch(\"MendocinoCounty-Vegetation-CanopyHeight-2020-Summer-00010m\", wms=True)" 462 | ] 463 | }, 464 | { 465 | "cell_type": "markdown", 466 | "metadata": {}, 467 | "source": [ 468 | "WMS URLs don't always easily plug and play with different rendering services, but they should work with a little nudging. Here's how to use the above URL to visualize these data with `ipyleaflet`." 469 | ] 470 | }, 471 | { 472 | "cell_type": "code", 473 | "execution_count": null, 474 | "metadata": {}, 475 | "outputs": [], 476 | "source": [ 477 | "wms = WMSLayer(\n", 478 | " url='https://maps.salo.ai/geoserver/cfo/wms?p0=0.0&p2=1.44&p25=18.0&p30=21.599999999999998&p50=36.0&p60=43.199999999999996&p75=54.0&p90=64.8&p98=70.56&p100=72.0',\n", 479 | " layers=\"cfo:MendocinoCounty-Vegetation-CanopyHeight-2020-Summer-00010m\",\n", 480 | " name=\"Mendocino Canopy Height\",\n", 481 | " styles=\"vegetation\",\n", 482 | " format=\"image/png8\",\n", 483 | " transparent=True,\n", 484 | " attribution=\"Forest Observatory © Salo Sciences\",\n", 485 | ")\n", 486 | "m = Map(basemap=basemaps.Stamen.Terrain, center=(39.39,-123.33), zoom=10)\n", 487 | "m.add_layer(wms)\n", 488 | "control = LayersControl(position='topright')\n", 489 | "m.add_control(control)\n", 490 | "m" 491 | ] 492 | } 493 | ], 494 | "metadata": { 495 | "kernelspec": { 496 | "display_name": "Python 3", 497 | "language": "python", 498 | "name": "python3" 499 | }, 500 | "language_info": { 501 | "codemirror_mode": { 502 | "name": "ipython", 503 | "version": 3 504 | }, 505 | "file_extension": ".py", 506 | "mimetype": "text/x-python", 507 | "name": "python", 508 | "nbconvert_exporter": "python", 509 | "pygments_lexer": "ipython3", 510 | "version": "3.7.8" 511 | } 512 | }, 513 | "nbformat": 4, 514 | "nbformat_minor": 4 515 | } 516 | -------------------------------------------------------------------------------- /demos/czu-perimeter.geojson: -------------------------------------------------------------------------------- 1 | { 2 | "type": "FeatureCollection", 3 | "name": "czu-perimeter", 4 | "crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:OGC:1.3:CRS84" } }, 5 | "features": [ 6 | { "type": "Feature", "properties": { "AREA": 485725.65567214595, "PERIMETER": 2795.3435221367599 }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -122.297970184044004, 37.270360380625078 ], [ -122.281358893870419, 37.270989317353958 ], [ -122.280873707307137, 37.273605976855023 ], [ -122.273962497020079, 37.273765676257788 ], [ -122.273078936485149, 37.270757775240092 ], [ -122.271970868366623, 37.270803132927192 ], [ -122.271430824428265, 37.26926462362227 ], [ -122.25692814635255, 37.269120828825983 ], [ -122.256845678930759, 37.268803175987351 ], [ -122.253874698899565, 37.269056922760186 ], [ -122.253236740897421, 37.264364074727638 ], [ -122.250423740191763, 37.264030233559922 ], [ -122.250812750067141, 37.26206573036383 ], [ -122.23963469250856, 37.261837096489181 ], [ -122.236147282295079, 37.25695192093184 ], [ -122.23203865952037, 37.256803910600446 ], [ -122.23115994999057, 37.252949258648833 ], [ -122.222812191223483, 37.252714044268721 ], [ -122.22255885932185, 37.252358987595386 ], [ -122.220997977220463, 37.252315825593726 ], [ -122.21955277050975, 37.250418675521573 ], [ -122.217062811411267, 37.250587586212596 ], [ -122.217023088603355, 37.250297096696542 ], [ -122.214043917777332, 37.250478478749748 ], [ -122.213591283438646, 37.246364575452723 ], [ -122.208575598700435, 37.246024250795081 ], [ -122.208251572188274, 37.243652578374835 ], [ -122.205993770232723, 37.243588634601309 ], [ -122.205687726663513, 37.243159472240336 ], [ -122.203991031218536, 37.243097939428303 ], [ -122.203987392589397, 37.243065856875909 ], [ -122.20035499322212, 37.243286612558869 ], [ -122.200067276466143, 37.237150712383453 ], [ -122.197529318643731, 37.237015121641875 ], [ -122.196185210798106, 37.235129738490102 ], [ -122.187090341331995, 37.235744529028459 ], [ -122.18700380683417, 37.227681583440749 ], [ -122.185890784278698, 37.227548813726585 ], [ -122.186073458281996, 37.221532434705971 ], [ -122.17638808523273, 37.222353820863852 ], [ -122.175541414083369, 37.216074435533628 ], [ -122.178054404565387, 37.215711561122106 ], [ -122.177951850551551, 37.214337142107041 ], [ -122.175836092883145, 37.214533430692015 ], [ -122.174784395545274, 37.21093371763299 ], [ -122.166672650856228, 37.211301082080496 ], [ -122.16663600426358, 37.209697947708889 ], [ -122.163754860477127, 37.209571791841597 ], [ -122.163569185394437, 37.202612000165026 ], [ -122.160801304893695, 37.20222789676054 ], [ -122.160773780019127, 37.196129962891149 ], [ -122.158062733123629, 37.195805794295786 ], [ -122.158239914805137, 37.191862826024995 ], [ -122.150344818663754, 37.191685010751023 ], [ -122.150283334051139, 37.191368075493507 ], [ -122.147755199661859, 37.191767841492833 ], [ -122.146889475618494, 37.188410543466944 ], [ -122.144389025581418, 37.188607579232297 ], [ -122.144477516606216, 37.186972159665459 ], [ -122.141111282159272, 37.186436485398382 ], [ -122.141113794738473, 37.184312911655482 ], [ -122.138554845128311, 37.184154296012011 ], [ -122.138551222975707, 37.181930259788729 ], [ -122.138424176937548, 37.181910038631223 ], [ -122.138434772125905, 37.173206560762587 ], [ -122.135539463623147, 37.172621504507084 ], [ -122.135577735922524, 37.168580886691359 ], [ -122.132830339801416, 37.167963513259046 ], [ -122.132909568646767, 37.160828627907499 ], [ -122.132903735490913, 37.160827180843441 ], [ -122.132910488907328, 37.160745754635869 ], [ -122.132949074240386, 37.157270985738663 ], [ -122.132940862931406, 37.157271288242377 ], [ -122.13264656485056, 37.156666389305997 ], [ -122.132151585132036, 37.156655162820911 ], [ -122.131827856439074, 37.154983619761964 ], [ -122.131782946239809, 37.154891311542727 ], [ -122.130114483413166, 37.154554007345524 ], [ -122.130132774547619, 37.152713430219855 ], [ -122.108404370845562, 37.151469393017642 ], [ -122.108378607395167, 37.139061221377062 ], [ -122.103026658678957, 37.138067883593813 ], [ -122.102855966714458, 37.130005626573997 ], [ -122.09761651217012, 37.129164645095642 ], [ -122.097578419128695, 37.122805987442838 ], [ -122.106449914053727, 37.12222405350105 ], [ -122.112976576079092, 37.130983184753262 ], [ -122.119212000097306, 37.131340425252233 ], [ -122.119261200271978, 37.119372835586454 ], [ -122.117244074786427, 37.119263565578407 ], [ -122.116543469834269, 37.114979236843489 ], [ -122.115329150044602, 37.114785508784408 ], [ -122.114404811361609, 37.114735411753408 ], [ -122.11438846720921, 37.114635435746429 ], [ -122.111054435166196, 37.11410353668483 ], [ -122.111082801238013, 37.109920254650874 ], [ -122.108122643363558, 37.109320894290988 ], [ -122.108295071257174, 37.09285249261282 ], [ -122.106009000926548, 37.092968570372648 ], [ -122.106413070180267, 37.087318461634673 ], [ -122.105898313815388, 37.087256599202711 ], [ -122.105868043154288, 37.084307944738327 ], [ -122.105681400282236, 37.084270138239518 ], [ -122.105693661329468, 37.083093969553182 ], [ -122.10315827902582, 37.082835487407131 ], [ -122.103102808487364, 37.081163089854002 ], [ -122.092693091974695, 37.08141512507104 ], [ -122.092807449220345, 37.055088683724634 ], [ -122.087323013541393, 37.054211937745364 ], [ -122.087325743568414, 37.052738131724318 ], [ -122.083790556104432, 37.052326823691686 ], [ -122.083861441690331, 37.048059452213693 ], [ -122.083615271226591, 37.048045637057719 ], [ -122.083773447457091, 37.045917355117126 ], [ -122.08361671951937, 37.045904807837147 ], [ -122.083953843285201, 37.042496799024818 ], [ -122.083977792612203, 37.041055029536203 ], [ -122.08193243762976, 37.040769235391728 ], [ -122.08270102945167, 37.034438322284828 ], [ -122.090283305542243, 37.034555967059632 ], [ -122.090677870973394, 37.032970002082529 ], [ -122.095255858666633, 37.033076921857266 ], [ -122.095860794897078, 37.024216415460742 ], [ -122.101077609698166, 37.024200995070025 ], [ -122.101101138410883, 37.020384996085056 ], [ -122.10508746903686, 37.019726955307803 ], [ -122.10525504783422, 37.016650593246254 ], [ -122.107331929355553, 37.016763586722604 ], [ -122.107752406149629, 37.015071450814034 ], [ -122.115566683934688, 37.015861705991014 ], [ -122.115551285776064, 37.022148138937979 ], [ -122.117619655626115, 37.022142739672482 ], [ -122.11871140157885, 37.017746724846909 ], [ -122.121676045322928, 37.017961346414189 ], [ -122.121760797921965, 37.017692388636142 ], [ -122.128644273187632, 37.0179450240094 ], [ -122.129344778330776, 37.022229347942343 ], [ -122.134213299701869, 37.022492841832104 ], [ -122.13454608277965, 37.024527127917523 ], [ -122.14361992934785, 37.025206518047419 ], [ -122.143344903838255, 37.030855280728012 ], [ -122.140373947877592, 37.031167858832944 ], [ -122.140370627894882, 37.031669578988506 ], [ -122.14316548510223, 37.032058789380528 ], [ -122.143119404549054, 37.053878938380976 ], [ -122.154474574378099, 37.053960314232718 ], [ -122.154562616761524, 37.051273796122537 ], [ -122.155337871166836, 37.051121391237523 ], [ -122.155338427864322, 37.051111459537367 ], [ -122.155428179217139, 37.051103637854986 ], [ -122.156699692005716, 37.050853675056956 ], [ -122.157091220427205, 37.036551776040966 ], [ -122.160422416035175, 37.03648499443991 ], [ -122.160436254063811, 37.036134228546821 ], [ -122.166156121738155, 37.036128585542308 ], [ -122.166152676762607, 37.035982830008599 ], [ -122.168754746574947, 37.035748649764962 ], [ -122.169441085058068, 37.033566476683283 ], [ -122.169514421830598, 37.033566862377604 ], [ -122.169532215523404, 37.03350342352207 ], [ -122.177629811275636, 37.033604741980845 ], [ -122.178170734391443, 37.030699161616141 ], [ -122.18018286479014, 37.030654072890037 ], [ -122.180753838872121, 37.027128455449493 ], [ -122.209516480300394, 37.027323551824338 ], [ -122.210780793275816, 37.036320131196291 ], [ -122.223155680370809, 37.036863438268803 ], [ -122.229758997099935, 37.036751768293847 ], [ -122.229799694373639, 37.037155137075416 ], [ -122.233130620926048, 37.037301378082709 ], [ -122.23287131579616, 37.047582475886209 ], [ -122.232710849286391, 37.047590223544198 ], [ -122.23283873724975, 37.050801647887845 ], [ -122.237101868242817, 37.051379518126183 ], [ -122.237366331446424, 37.056556689961326 ], [ -122.243114309613716, 37.056626912277416 ], [ -122.243972311826639, 37.05994259536147 ], [ -122.253572630913382, 37.060248525155934 ], [ -122.253771171320622, 37.06128978755099 ], [ -122.254621117171993, 37.061308271847331 ], [ -122.257263944314147, 37.064964445473194 ], [ -122.259796627920124, 37.065498280759833 ], [ -122.259832730911029, 37.068518188983738 ], [ -122.261050553359368, 37.070202964444682 ], [ -122.266384610341575, 37.070836997295089 ], [ -122.266554917748365, 37.073534138527393 ], [ -122.269749830510747, 37.073598414625131 ], [ -122.27021331425172, 37.075104858238689 ], [ -122.271868156076195, 37.07527126763857 ], [ -122.271968804513534, 37.078115245804341 ], [ -122.276334825258843, 37.078809829158374 ], [ -122.27646184564604, 37.082274642045221 ], [ -122.280412298193269, 37.082668264403132 ], [ -122.280411081739075, 37.086679965686194 ], [ -122.282776772687598, 37.086661873082242 ], [ -122.283148062632009, 37.093815198327434 ], [ -122.283253601569001, 37.093834105926817 ], [ -122.283252809339928, 37.095833263404003 ], [ -122.283271608736101, 37.0961954552631 ], [ -122.287138473029472, 37.096630272208778 ], [ -122.293344991532805, 37.105153475599181 ], [ -122.304212000334431, 37.106018968228469 ], [ -122.304401254342253, 37.111129201850915 ], [ -122.304631383276444, 37.111132880971311 ], [ -122.305241148762008, 37.113816755472044 ], [ -122.31098915748467, 37.114165437235194 ], [ -122.311035885235157, 37.120597168296982 ], [ -122.311141450188899, 37.123536569224399 ], [ -122.315581665166761, 37.124591558240986 ], [ -122.315584436733346, 37.125376868237325 ], [ -122.316726208266545, 37.125581000219341 ], [ -122.316726467458622, 37.132561017934627 ], [ -122.319499132476906, 37.133143404916645 ], [ -122.320172765637693, 37.133199278013173 ], [ -122.320182523380538, 37.133286948389539 ], [ -122.321056491873847, 37.133470521908102 ], [ -122.321060404112615, 37.133777195396064 ], [ -122.338952571656009, 37.134362394984123 ], [ -122.339107157425033, 37.140514562278277 ], [ -122.339181479439901, 37.14076721920555 ], [ -122.344675235953815, 37.141632398805676 ], [ -122.344700577120548, 37.148241278640796 ], [ -122.344733841052403, 37.148799294135024 ], [ -122.34470274193913, 37.148805855087325 ], [ -122.344712292510039, 37.151296607631231 ], [ -122.33907952085066, 37.152484905862167 ], [ -122.338621901272376, 37.161002041662023 ], [ -122.333370009981053, 37.161466952709588 ], [ -122.33335698366092, 37.162949547810392 ], [ -122.333352974162494, 37.163406048646827 ], [ -122.334731763527827, 37.163303388686757 ], [ -122.335022205819882, 37.168927286830893 ], [ -122.3374235130442, 37.169307591961953 ], [ -122.337449986237971, 37.169779288127629 ], [ -122.337981296323761, 37.169774483352761 ], [ -122.338114510790035, 37.170544594848053 ], [ -122.338792719394604, 37.170651398213479 ], [ -122.338788043109602, 37.174438278441514 ], [ -122.339053666491154, 37.175973844549809 ], [ -122.338786091796521, 37.176018462060512 ], [ -122.338782431922667, 37.178982247186767 ], [ -122.340952952324756, 37.178943619135666 ], [ -122.341522525553927, 37.184498967625466 ], [ -122.340287445034065, 37.184645667699563 ], [ -122.344382903309707, 37.190373194285627 ], [ -122.349628259472482, 37.19089644110776 ], [ -122.349931139802933, 37.196526633759078 ], [ -122.349806417830038, 37.196538015027762 ], [ -122.349913908512804, 37.198536111223461 ], [ -122.344419006508915, 37.199037522453033 ], [ -122.344528250187693, 37.202653705179152 ], [ -122.337703644499825, 37.203025679487517 ], [ -122.33743087484234, 37.20400402390289 ], [ -122.336678893519007, 37.204004133843 ], [ -122.336545837616654, 37.214973649002872 ], [ -122.33803468247504, 37.215014295187366 ], [ -122.338727545374596, 37.220781882886968 ], [ -122.336469615351405, 37.221257634000636 ], [ -122.336454520450388, 37.222502101495401 ], [ -122.333047397624767, 37.223069779537099 ], [ -122.332590947761389, 37.234993564686221 ], [ -122.330712959132214, 37.235068114049795 ], [ -122.330699459064334, 37.23599058968616 ], [ -122.325127150294634, 37.236918560149853 ], [ -122.32453837187326, 37.240105492501357 ], [ -122.32465885931822, 37.240103367516561 ], [ -122.324714949167131, 37.240651217330722 ], [ -122.326925060602221, 37.240612196649501 ], [ -122.327493998369945, 37.246167549441793 ], [ -122.326165475565674, 37.246325046675551 ], [ -122.326171764172656, 37.24638646173004 ], [ -122.323974458553494, 37.246646927820748 ], [ -122.324061597094158, 37.247498152580654 ], [ -122.321307066505099, 37.247824616039779 ], [ -122.321278496241575, 37.250449449103129 ], [ -122.318354431876486, 37.250999364760446 ], [ -122.318120572408063, 37.268712669844497 ], [ -122.311684430796262, 37.269156791576897 ], [ -122.309861350096952, 37.269499468723055 ], [ -122.309832554046494, 37.272654145015863 ], [ -122.302323258572486, 37.273955691057537 ], [ -122.301903815670158, 37.272681520657905 ], [ -122.297918893937421, 37.27271661382246 ], [ -122.297970184044004, 37.270360380625078 ] ], [ [ -122.127690430225087, 37.136049881195632 ], [ -122.127620404218533, 37.133959791324656 ], [ -122.12541365888228, 37.134133417161003 ], [ -122.126799574028098, 37.136043345255942 ], [ -122.127690430225087, 37.136049881195632 ] ] ] } } 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /environment.yml: -------------------------------------------------------------------------------- 1 | name: cfo 2 | 3 | channels: 4 | - conda-forge 5 | 6 | dependencies: 7 | - python=3.7 8 | - jupyter=1.0.0 9 | - matplotlib=3.2.1 10 | - black 11 | - earthengine-api 12 | - flake8 13 | - folium 14 | - gdal>=3.0 15 | - geopandas 16 | - ipython 17 | - ipyleaflet 18 | - isort 19 | - mock 20 | - pandas 21 | - pre-commit 22 | - pytest 23 | - pytest-cov 24 | - rasterio 25 | - rtree 26 | - scikit-learn 27 | - shapely 28 | - pip 29 | - pip: 30 | - . 31 | - -r file:requirements.txt 32 | - pystac 33 | -------------------------------------------------------------------------------- /img/cfo-fire.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/forestobservatory/cfo-api/fd3a8156f02226937e2a2b1f783ceb39fb22ff15/img/cfo-fire.jpg -------------------------------------------------------------------------------- /img/cfo-height.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/forestobservatory/cfo-api/fd3a8156f02226937e2a2b1f783ceb39fb22ff15/img/cfo-height.png -------------------------------------------------------------------------------- /img/cfo-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/forestobservatory/cfo-api/fd3a8156f02226937e2a2b1f783ceb39fb22ff15/img/cfo-logo.png -------------------------------------------------------------------------------- /img/cfo-terrain.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/forestobservatory/cfo-api/fd3a8156f02226937e2a2b1f783ceb39fb22ff15/img/cfo-terrain.jpg -------------------------------------------------------------------------------- /img/cfo-understory.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/forestobservatory/cfo-api/fd3a8156f02226937e2a2b1f783ceb39fb22ff15/img/cfo-understory.png -------------------------------------------------------------------------------- /img/ipyleaflet-example.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/forestobservatory/cfo-api/fd3a8156f02226937e2a2b1f783ceb39fb22ff15/img/ipyleaflet-example.jpg -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | requests>=2.23 2 | retrying>=1.3.3 3 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import find_packages, setup 2 | 3 | version = open("cfo/__version__.py").read().strip('"\n') 4 | long_description = open("README.md", "r", encoding="utf-8").read() 5 | 6 | setup( 7 | name="cfo", 8 | url="https://github.com/forestobservatory/cfo-api", 9 | license="MIT", 10 | description="Python wrappers for accessing Forest Observatory data via the Salo API", 11 | long_description=long_description, 12 | long_description_content_type="text/markdown", 13 | keywords=[ 14 | "ecology", 15 | "conservation", 16 | "remote sensing", 17 | "wildfire", 18 | "california", 19 | ], 20 | packages=find_packages(exclude="tests"), 21 | version=version, 22 | python_requires=">=3.0", 23 | platforms="any", 24 | install_requires=["requests", "retrying"], 25 | author="Salo Sciences", 26 | author_email="cba@salo.ai", 27 | include_package_data=True, 28 | package_data={"cfo": ["data/paths.json", "data/public.json"]}, 29 | classifiers=[ 30 | "Programming Language :: Python :: 3", 31 | "License :: OSI Approved :: MIT License", 32 | "Operating System :: OS Independent", 33 | ], 34 | ) 35 | --------------------------------------------------------------------------------