diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile deleted file mode 100644 index b36e815e..00000000 --- a/.devcontainer/Dockerfile +++ /dev/null @@ -1 +0,0 @@ -FROM mcr.microsoft.com/planetary-computer/python:latest diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json deleted file mode 100644 index e83f006c..00000000 --- a/.devcontainer/devcontainer.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "name": "Planetary Computer (Python)", - "build": { - "dockerfile": "Dockerfile", - "context": "..", - }, - - // Set *default* container specific settings.json values on container create. - "settings": { - "python.pythonPath": "/srv/conda/envs/notebook/bin/python", - "python.languageServer": "Pylance", - "python.linting.enabled": true, - }, - - // Add the IDs of extensions you want installed when the container is created. - "extensions": [ - "ms-python.python", - "ms-python.vscode-pylance", - "ms-toolsai.jupyter" - ], - - // Use 'forwardPorts' to make a list of ports inside the container available locally. - // "forwardPorts": [], - - // Use 'postCreateCommand' to run commands after the container is created. - // "postCreateCommand": "pip3 install --user -r requirements.txt", - - // Comment out connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root. - "remoteUser": "jovyan", - "containerEnv": { - "DASK_GATEWAY__ADDRESS": "https://pccompute.westeurope.cloudapp.azure.com/compute/services/dask-gateway", - "DASK_GATEWAY__AUTH__TYPE": "jupyterhub", - "DASK_GATEWAY__PROXY_ADDRESS": "gateway://pccompute-dask.westeurope.cloudapp.azure.com:80", - "DASK_GATEWAY__CLUSTER__OPTIONS__IMAGE": "pcccr.azurecr.io/public/planetary-computer/python:latest", - } -} diff --git a/.flake8 b/.flake8 deleted file mode 100644 index 92129e91..00000000 --- a/.flake8 +++ /dev/null @@ -1,3 +0,0 @@ -[flake8] -ignore = E402,W503 -max-line-length = 90 diff --git a/.github/workflows/diff.yml b/.github/workflows/diff.yml index 5dc5d126..a1a652bc 100644 --- a/.github/workflows/diff.yml +++ b/.github/workflows/diff.yml @@ -18,17 +18,17 @@ jobs: - uses: actions/checkout@a37ce9120846195fa4ece8f58b268e6043cb2f26 # v3.7.0 with: fetch-depth: 0 - - name: Set up Python 3.9 + - name: Set up Python 3.12 uses: actions/setup-python@3542bca2639a428e1796aaa6a2ffef0c0f575566 # v3.1.4 with: - python-version: "3.9.13" + python-version: "3.12" - name: Install dependencies run: | python -m pip install --upgrade pip pip install nbdime ipython_genutils - name: Configure nbdime run: | - /opt/hostedtoolcache/Python/3.9.13/x64/bin/nbdime config-git --enable --global + nbdime config-git --enable --global - name: git diff run: | git diff HEAD^ HEAD diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 6f248df6..d079799e 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -21,5 +21,5 @@ jobs: - uses: actions/checkout@a37ce9120846195fa4ece8f58b268e6043cb2f26 # v3.7.0 - uses: actions/setup-python@3542bca2639a428e1796aaa6a2ffef0c0f575566 # v3.1.4 with: - python-version: "3.11" + python-version: "3.12" - uses: pre-commit/action@2c7b3805fd2a0fd8c1884dcaebf91fc102a13ecd # v3.0.1 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index ade9a3da..7974bc85 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,12 +1,11 @@ repos: - repo: https://github.com/nbQA-dev/nbQA - rev: 1.7.0 + rev: 1.9.1 hooks: - - id: nbqa-black - additional_dependencies: [black==22.3.0] - args: [--nbqa-mutate] - - id: nbqa-flake8 - additional_dependencies: [flake8==6.1.0] + - id: nbqa-ruff-check + additional_dependencies: [ruff==0.17.3] + - id: nbqa-ruff-format + additional_dependencies: [ruff==0.17.3] - repo: local hooks: - id: check-headers diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 0a3ed09b..ac5d845f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -4,51 +4,78 @@ This repository contains Jupyter Notebooks that serve as examples of using the [ ## Getting Started -This project uses Docker to encapsulate the development environment. To set up your development -environment, have Docker installed and run: +Follow the [setup instructions in README.md](README.md#getting-started). +Microsoft employees must use +. Other contributors can use +. Set `UV_DEFAULT_INDEX` to your required index before +installing packages or updating requirements. Keep any feed credentials outside +the repository. + +The minimum supported Python version is 3.12. The installer creates a local +`.venv` using Python 3.12, matching CI. uv downloads +Python if needed. Common dependencies are declared in +[pyproject.toml](pyproject.toml). [requirements.txt](requirements.txt) records exact +versions of direct and transitive dependencies. It is generated with +uv and contains no index URLs, so it works with either package index. + +Start JupyterLab with: ```sh -> scripts/setup +uv run jupyter lab ``` -If you need to rebuild the images at any point, you -can run: +Open the URL printed in the terminal. In VS Code, select `.venv/bin/python` as the +Python interpreter and notebook kernel. On Windows, use `.venv/Scripts/python.exe` +and run `scripts/install` from a Bash shell. -```sh -> scripts/update -``` +The shared environment covers common Python notebook dependencies. Specialized +examples may need extra packages, credentials, or remote services. R notebooks +need a separate R environment. -To run the jupyter notebook server, you can use: +To regenerate requirements after editing `pyproject.toml`, run: ```sh -> scripts/server +uv pip compile pyproject.toml --extra dev --universal --python-version 3.12 \ + --output-file requirements.txt +./scripts/install ``` -And browse to the URL printed in the terminal output. - -From there you'll be able to run all Jupyter Notebook examples. +The installer only installs requirements; it does not regenerate them. Add +`--upgrade-package package` to the compile command to update a specific package, +or `--upgrade` to update all packages. Commit both dependency files. Use `uv pip` +commands for this environment; automatic project syncing is disabled so `uv run` +cannot replace the compiled requirements with a different resolution. ### Linting -Notebooks are linted using [nbqa](https://nbqa.readthedocs.io/en/latest/) with flake8 and black. -We include a [pre-commit](https://pre-commit.com/) file for running the checks. +Notebooks are linted and formatted using +[nbQA](https://nbqa.readthedocs.io/en/latest/) with +[Ruff](https://docs.astral.sh/ruff/). The +[pre-commit configuration](.pre-commit-config.yaml) pins both tools. +```sh +uv run pre-commit install +./scripts/test --lint ``` -> pre-commit install -``` + +The test script runs every pre-commit hook over all tracked files, regardless of +the current directory. Formatters may modify files; review those changes and +rerun the command until it passes. + +Ruff formats at 88 columns and checks line lengths at 94 columns. Imports may +appear after other notebook code. The R quickstart is excluded from both Ruff +hooks. Notebook header checks remain unchanged. + +Hook environments install packages with pip. Microsoft employees must set +`PIP_INDEX_URL=https://packagefeedproxy.microsoft.io/pypi/simple` before running +pre-commit. Other contributors can use `PIP_INDEX_URL=https://pypi.org/simple`. Notebooks should start with an H2-level header (`## `) and should have no H1-level headers. ### Integration with Data Catalog site -Running the `./scripts/server` script also starts a local webserver that can -source notebook files to the Planetary Computer docs site development -environment. That project is pre-configured to integrate with this server. -After running `./scripts/server` from within this project, run -`./scripts/update --devdocs` from the Planetary Computer website project and -it will treat this local instance as the source for external docs notebooks. -See that project's ETL readme for more information. +The notebooks from this repository are consumed by the Planetary Computer Data Catalog (the website): <https://planetarycomputer.microsoft.com>, but the code for the website is now managed privately by Microsoft. ## Contributing diff --git a/README.md b/README.md index 2e7f8e62..47ebb33e 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,34 @@ <img src="https://ai4edatasetspublicassets.blob.core.windows.net/assets/aod_images/planetary_computer_header_800w.png" alt="Planetary Computer"/> -# Planetary Computer Hub +This repository contains [Jupyter](https://jupyter.org/) notebooks showcasing various analysis possible with geospatial data from [Microsoft Planetary Computer](https://planetarycomputer.microsoft.com/). -Welcome to the [Planetary Computer Hub](http://planetarycomputer.microsoft.com/compute), a development environment that makes our data and APIs accessible through familiar, open-source tools, and allows users to easily scale their analyses. +## Getting started -If you're viewing this repository from GitHub, you might want to browse the rendered examples on [nbviewer](https://nbviewer.org/github/Microsoft/PlanetaryComputerExamples/tree/main/), including our [quickstarts](https://nbviewer.org/github/microsoft/PlanetaryComputerExamples/tree/main/quickstarts/), [dataset examples](https://nbviewer.org/github/microsoft/PlanetaryComputerExamples/tree/main/datasets/), and [tutorials](https://nbviewer.org/github/microsoft/PlanetaryComputerExamples/tree/main/tutorials/). +Install [uv](https://docs.astral.sh/uv/getting-started/installation/). -## Quickstarts +**Microsoft employees must use the Microsoft package feed proxy:** + +```sh +UV_DEFAULT_INDEX=https://packagefeedproxy.microsoft.io/pypi/simple ./scripts/install +``` + +**Other contributors can use PyPI:** + +```sh +UV_DEFAULT_INDEX=https://pypi.org/simple ./scripts/install +``` -These quickstarts give high-level introductions to a single topic. +Python 3.12 is the minimum supported version. The installer creates `.venv` with +Python 3.12 and installs the exact package +versions in `requirements.txt`. uv downloads Python if needed. Start JupyterLab: + +```sh +uv run jupyter lab +``` + +See [CONTRIBUTING.md](CONTRIBUTING.md) for environment and development details. + +## Quickstarts * [Reading from the STAC API](quickstarts/reading-stac.ipynb) * [Reading from the STAC API with R](quickstarts/reading-stac-r.ipynb) diff --git a/competitions/cloud-cover/benchmark-tutorial.ipynb b/competitions/cloud-cover/benchmark-tutorial.ipynb index ed5a75cf..63ca38ce 100644 --- a/competitions/cloud-cover/benchmark-tutorial.ipynb +++ b/competitions/cloud-cover/benchmark-tutorial.ipynb @@ -1088,8 +1088,7 @@ "source": [ "left, bottom, right, top = lat_long_bounds(example_chip[\"B04_path\"])\n", "print(\n", - " f\"Image coordinates (lat, long):\\nStart: ({left}, {bottom})\"\n", - " f\"\\nEnd: ({right}, {top})\"\n", + " f\"Image coordinates (lat, long):\\nStart: ({left}, {bottom})\\nEnd: ({right}, {top})\"\n", ")" ] }, diff --git a/competitions/s1floods/generate_auxiliary_input.ipynb b/competitions/s1floods/generate_auxiliary_input.ipynb index 2ed61c35..2b371c1c 100755 --- a/competitions/s1floods/generate_auxiliary_input.ipynb +++ b/competitions/s1floods/generate_auxiliary_input.ipynb @@ -341,7 +341,7 @@ "# Iterate over the chips and generate all aux input files.\n", "count = len(chip_paths)\n", "for i, chip_path in enumerate(chip_paths):\n", - " print(f\"({i+1} of {count}) {chip_path}\")\n", + " print(f\"({i + 1} of {count}) {chip_path}\")\n", " chip_info = get_chip_info(chip_path)\n", " for collection_id, asset_key, file_name, resampling_method in aux_file_params:\n", " print(f\" ... Creating chip data for {collection_id} {asset_key}\")\n", diff --git a/datasets/ai4good/colombia-earthquake.ipynb b/datasets/ai4good/colombia-earthquake.ipynb index d404fc81..94749b39 100644 --- a/datasets/ai4good/colombia-earthquake.ipynb +++ b/datasets/ai4good/colombia-earthquake.ipynb @@ -47,7 +47,7 @@ "import planetary_computer\n", "import pystac_client\n", "import rasterio\n", - "import rasterio.windows\n" + "import rasterio.windows" ] }, { @@ -157,7 +157,7 @@ " }\n", " for item in items\n", " ]\n", - ")\n" + ")" ] }, { @@ -197,7 +197,7 @@ " collections=[\"predicted-damage-colombia-2026\"],\n", " bbox=[-75.79, 4.77, -75.69, 4.85],\n", ")\n", - "[item.id for item in pereira_search.items()]\n" + "[item.id for item in pereira_search.items()]" ] }, { @@ -400,7 +400,7 @@ " for item in items\n", " for key, asset in item.assets.items()\n", " ]\n", - ")\n" + ")" ] }, { @@ -585,7 +585,7 @@ "\n", "print(f\"{len(gdf):,} building footprints\")\n", "print(\"CRS:\", gdf.crs)\n", - "gdf.head()\n" + "gdf.head()" ] }, { @@ -647,7 +647,7 @@ } ], "source": [ - "gdf.info()\n" + "gdf.info()" ] }, { @@ -743,7 +743,7 @@ " partly_obscured=(\"unknown_pct\", lambda s: (s > 0).sum()),\n", ")\n", "summary[\"percent damaged\"] = (summary[\"damaged\"] / summary[\"buildings\"] * 100).round(2)\n", - "summary\n" + "summary" ] }, { @@ -817,7 +817,7 @@ " ],\n", " loc=\"lower left\",\n", ")\n", - "fig.suptitle(\"Predicted building damage — Colombia earthquake, August 2026\", y=0.93)\n" + "fig.suptitle(\"Predicted building damage — Colombia earthquake, August 2026\", y=0.93)" ] }, { @@ -953,7 +953,7 @@ " {\"value\": value, \"class\": label, \"RGBA\": color_table[value]}\n", " for value, label in CLASS_LABELS.items()\n", " ]\n", - ")\n" + ")" ] }, { @@ -1004,7 +1004,7 @@ " predictions = src.read(1, window=window)\n", " left, bottom, right, top = rasterio.windows.bounds(window, src.transform)\n", "\n", - "predictions.shape\n" + "predictions.shape" ] }, { @@ -1072,7 +1072,7 @@ " labelcolor=\"white\",\n", ")\n", "ax.set_title(\"Model predictions, Pereira — 600 m across\")\n", - "ax.set_axis_off()\n" + "ax.set_axis_off()" ] } ], diff --git a/datasets/aster-l1t/aster-l1t-example.ipynb b/datasets/aster-l1t/aster-l1t-example.ipynb index ea3e1ae4..ba0c9faf 100644 --- a/datasets/aster-l1t/aster-l1t-example.ipynb +++ b/datasets/aster-l1t/aster-l1t-example.ipynb @@ -353,7 +353,6 @@ "image_data = []\n", "\n", "with rasterio.open(swir_asset.href, \"r\") as src:\n", - "\n", " h = int(src.height // dsfactor)\n", " w = int(src.width // dsfactor)\n", "\n", diff --git a/datasets/daymet/daymet-example.ipynb b/datasets/daymet/daymet-example.ipynb index 5eec228b..c638010f 100755 --- a/datasets/daymet/daymet-example.ipynb +++ b/datasets/daymet/daymet-example.ipynb @@ -3573,8 +3573,7 @@ ], "source": [ "na_url = (\n", - " \"https://planetarycomputer.microsoft.com/api/stac/v1/collections/\"\n", - " \"daymet-monthly-na\"\n", + " \"https://planetarycomputer.microsoft.com/api/stac/v1/collections/daymet-monthly-na\"\n", ")\n", "na_collection = pystac.read_file(na_url)\n", "na_asset = na_collection.assets[\"zarr-https\"]\n", diff --git a/datasets/gridmet/gridmet-example.ipynb b/datasets/gridmet/gridmet-example.ipynb index 8308c8d0..6eff0f92 100755 --- a/datasets/gridmet/gridmet-example.ipynb +++ b/datasets/gridmet/gridmet-example.ipynb @@ -1897,7 +1897,7 @@ "ds = xr.open_zarr(\n", " asset.href,\n", " storage_options=asset.extra_fields[\"xarray:storage_options\"],\n", - " **asset.extra_fields[\"xarray:open_kwargs\"]\n", + " **asset.extra_fields[\"xarray:open_kwargs\"],\n", ")\n", "ds" ] diff --git a/datasets/hls2/hls2-example.ipynb b/datasets/hls2/hls2-example.ipynb index f141e9a2..927b3a8b 100644 --- a/datasets/hls2/hls2-example.ipynb +++ b/datasets/hls2/hls2-example.ipynb @@ -1145,7 +1145,7 @@ "frames = []\n", "for i, item in enumerate(items):\n", " if (i + 1) % 10 == 0 or i == len(items) - 1:\n", - " print(f\"Rendering frame {i+1}/{len(items)}\")\n", + " print(f\"Rendering frame {i + 1}/{len(items)}\")\n", " frame = visualize_item_rgb_ndvi(\n", " collection_id, item, band_name_map[collection_id], timelapse_bbox_of_interest\n", " )\n", diff --git a/datasets/jrc-gsw/jrc-gsw-example.ipynb b/datasets/jrc-gsw/jrc-gsw-example.ipynb index f98be777..380d6984 100755 --- a/datasets/jrc-gsw/jrc-gsw-example.ipynb +++ b/datasets/jrc-gsw/jrc-gsw-example.ipynb @@ -199,13 +199,12 @@ "fig = plt.figure(frameon=False, dpi=dpi)\n", "\n", "for i, asset_key in enumerate(cog_assets):\n", - "\n", " with rasterio.open(item.assets[asset_key].href) as src:\n", " asset_data, _ = rasterio.mask.mask(\n", " src, [area_of_interest], crop=True, nodata=255\n", " )\n", "\n", - " ax1 = fig.add_subplot(int(f\"23{i+1}\"))\n", + " ax1 = fig.add_subplot(int(f\"23{i + 1}\"))\n", " ax1.set_title(asset_key, fontdict={\"fontsize\": 5})\n", " ax1.set_axis_off()\n", " plt.imshow(asset_data[0], norm=Normalize(0, 255), cmap=cmaps[asset_key])" diff --git a/datasets/nested-eagle/nested-eagle-conus.ipynb b/datasets/nested-eagle/nested-eagle-conus.ipynb index 80dca70b..22e498d4 100644 --- a/datasets/nested-eagle/nested-eagle-conus.ipynb +++ b/datasets/nested-eagle/nested-eagle-conus.ipynb @@ -157,11 +157,14 @@ "asset_href = item.assets[\"conus\"].href\n", "store = HTTPStore.from_url(asset_href)\n", "\n", - "with BlockStoreReader(store, \"\") as remote_file, xr.open_dataset(\n", - " remote_file,\n", - " engine=\"h5netcdf\",\n", - " chunks={},\n", - ") as full_ds:\n", + "with (\n", + " BlockStoreReader(store, \"\") as remote_file,\n", + " xr.open_dataset(\n", + " remote_file,\n", + " engine=\"h5netcdf\",\n", + " chunks={},\n", + " ) as full_ds,\n", + "):\n", " ds = (\n", " full_ds[variables_to_load]\n", " .sel(\n", diff --git a/datasets/nested-eagle/nested-eagle-global.ipynb b/datasets/nested-eagle/nested-eagle-global.ipynb index c931d447..841fb4f1 100644 --- a/datasets/nested-eagle/nested-eagle-global.ipynb +++ b/datasets/nested-eagle/nested-eagle-global.ipynb @@ -888,11 +888,14 @@ "asset_href = item.assets[\"global\"].href\n", "store = HTTPStore.from_url(asset_href)\n", "\n", - "with BlockStoreReader(store, \"\") as remote_file, xr.open_dataset(\n", - " remote_file,\n", - " engine=\"h5netcdf\",\n", - " chunks={},\n", - ") as full_ds:\n", + "with (\n", + " BlockStoreReader(store, \"\") as remote_file,\n", + " xr.open_dataset(\n", + " remote_file,\n", + " engine=\"h5netcdf\",\n", + " chunks={},\n", + " ) as full_ds,\n", + "):\n", " ds = (\n", " full_ds[variables_to_load].sel(time=slice(forecast_start, forecast_stop)).load()\n", " )\n", diff --git a/docker-compose.yml b/docker-compose.yml deleted file mode 100644 index c14e361c..00000000 --- a/docker-compose.yml +++ /dev/null @@ -1,18 +0,0 @@ -services: - hub: - image: mcr.microsoft.com/planetary-computer/python:latest - ports: - - "8888:8888" - volumes: - - .:/home/jovyan - command: jupyter lab --ip 0.0.0.0 - - localserver: - image: python:3.9-alpine - ports: - - "8889:8889" - volumes: - - ./datasets:/opt/src/datasets - - ./quickstarts:/opt/src/quickstarts - - ./tutorials:/opt/src/tutorials - command: python3 -m "http.server" 8889 -d /opt/src diff --git a/pyproject.toml b/pyproject.toml index c5e56437..42f46576 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,8 +1,61 @@ -[tool.nbqa.addopts] -flake8 = [ - "--max-line-length=94" +[project] +name = "planetary-computer-examples" +version = "0.0.0" +requires-python = ">=3.12" +dependencies = [ + "adlfs", + "cartopy", + "contextily", + "dask-geopandas", + "dask[array,dataframe,distributed]", + "datashader", + "fsspec", + "geogif", + "geopandas", + "hvplot", + "ipykernel", + "ipython", + "jupyterlab", + "matplotlib", + "numpy", + "odc-stac", + "pandas", + "pillow", + "planetary-computer", + "pyarrow<26", + "pyproj", + "pystac", + "pystac-client", + "rasterio", + "requests", + "rich", + "rioxarray", + "scipy", + "seaborn", + "shapely", + "stackstac", + "xarray-spatial", + "xarray[io]", + "zarr", ] +[project.optional-dependencies] +dev = ["pre-commit"] + +[tool.uv] +managed = false + [tool.nbqa.exclude] -black = "reading-stac-r.ipynb" -flake8 = "reading-stac-r.ipynb" +"ruff check" = "reading-stac-r.ipynb" +"ruff format" = "reading-stac-r.ipynb" + +[tool.ruff] +target-version = "py312" +line-length = 88 + +[tool.ruff.lint] +select = ["E", "F", "W"] +ignore = ["E402"] + +[tool.ruff.lint.pycodestyle] +max-line-length = 94 diff --git a/quickstarts/reading-zarr-data.ipynb b/quickstarts/reading-zarr-data.ipynb index 8bb4cd5f..30eb7e6f 100755 --- a/quickstarts/reading-zarr-data.ipynb +++ b/quickstarts/reading-zarr-data.ipynb @@ -1590,7 +1590,7 @@ "ds = xr.open_zarr(\n", " asset.href,\n", " **asset.extra_fields[\"xarray:open_kwargs\"],\n", - " storage_options=asset.extra_fields[\"xarray:storage_options\"]\n", + " storage_options=asset.extra_fields[\"xarray:storage_options\"],\n", ")\n", "ds" ] diff --git a/quickstarts/scale-with-dask.ipynb b/quickstarts/scale-with-dask.ipynb index f60e0cd6..56959ef8 100755 --- a/quickstarts/scale-with-dask.ipynb +++ b/quickstarts/scale-with-dask.ipynb @@ -1389,7 +1389,7 @@ "ds = xr.open_zarr(\n", " asset.href,\n", " **asset.extra_fields[\"xarray:open_kwargs\"],\n", - " storage_options=asset.extra_fields[\"xarray:storage_options\"]\n", + " storage_options=asset.extra_fields[\"xarray:storage_options\"],\n", ")\n", "ds" ] diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 00000000..bced1b50 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,881 @@ +# This file was autogenerated by uv via the following command: +# uv pip compile pyproject.toml --extra dev --universal --python-version 3.12 --output-file requirements.txt +adlfs==2026.8.0 + # via planetary-computer-examples (pyproject.toml) +affine==3.0.1 + # via + # odc-geo + # odc-stac + # rasterio +aiohappyeyeballs==2.7.1 + # via aiohttp +aiohttp==3.14.5 + # via azure-core +aiosignal==1.4.0 + # via aiohttp +annotated-types==0.8.0 + # via pydantic +anyio==4.15.1 + # via + # httpx + # jupyter-server +appnope==1.0.0 ; sys_platform == 'darwin' + # via ipykernel +argon2-cffi==25.1.0 + # via jupyter-server +argon2-cffi-bindings==26.1.0 + # via argon2-cffi +arrow==1.4.0 + # via isoduration +asttokens==3.0.2 + # via stack-data +async-lru==2.4.0 + # via jupyterlab +attrs==26.1.0 + # via + # affine + # aiohttp + # cattrs + # jsonschema + # rasterio + # referencing + # requests-cache +azure-core==1.41.0 + # via + # adlfs + # azure-identity + # azure-storage-blob +azure-identity==1.27.0 + # via adlfs +azure-storage-blob==12.31.1 + # via adlfs +babel==2.18.0 + # via jupyterlab-server +beautifulsoup4==4.15.0 + # via + # nbconvert + # pydap +bleach==6.4.0 + # via nbconvert +bokeh==3.10.1 + # via + # holoviews + # hvplot + # panel + # panel-material-ui +cachetools==7.2.7 + # via odc-geo +cartopy==0.26.0 + # via planetary-computer-examples (pyproject.toml) +cattrs==26.2.1 + # via requests-cache +certifi==2026.10.23 + # via + # httpcore + # httpx + # netcdf4 + # pyogrio + # pyproj + # rasterio + # requests +cffi==2.1.1 + # via + # argon2-cffi-bindings + # cryptography + # pyzmq +cfgv==3.5.0 + # via pre-commit +cftime==1.6.6.1 + # via + # netcdf4 + # xarray +charset-normalizer==3.5.2 + # via requests +click==8.5.0 + # via + # click-plugins + # cligj + # dask + # distributed + # mercantile + # planetary-computer + # rasterio +click-plugins==1.1.1.2 + # via rasterio +cligj==0.7.2 + # via rasterio +cloudpickle==3.1.2 + # via + # dask + # distributed + # joblib +colorama==0.4.6 ; sys_platform == 'win32' + # via + # ipython + # tqdm +colorcet==3.2.1 + # via + # datashader + # holoviews + # hvplot +comm==0.2.3 + # via ipykernel +contextily==1.7.1 + # via planetary-computer-examples (pyproject.toml) +contourpy==1.3.3 + # via matplotlib +cryptography==50.0.2 + # via + # azure-identity + # azure-storage-blob + # msal + # pyjwt +cycler==0.12.1 + # via matplotlib +dask==2026.8.0 + # via + # planetary-computer-examples (pyproject.toml) + # dask-geopandas + # distributed + # geogif + # odc-loader + # odc-stac + # stackstac +dask-geopandas==0.5.0 + # via planetary-computer-examples (pyproject.toml) +datashader==0.19.1 + # via planetary-computer-examples (pyproject.toml) +debugpy==1.8.22 + # via ipykernel +defusedxml==0.7.1 + # via nbconvert +distlib==0.4.4 + # via virtualenv +distributed==2026.8.0 + # via dask +donfig==0.8.1.post1 + # via zarr +executing==2.3.0 + # via stack-data +fastjsonschema==2.22.3 + # via nbformat +filelock==4.2.5 + # via + # python-discovery + # virtualenv +fonttools==4.68.0 + # via matplotlib +fqdn==1.6.0 + # via jsonschema +frozenlist==1.8.0 + # via + # aiohttp + # aiosignal +fsspec==2026.9.0 + # via + # planetary-computer-examples (pyproject.toml) + # adlfs + # dask + # xarray +geogif==0.3 + # via planetary-computer-examples (pyproject.toml) +geographiclib==2.1 + # via geopy +geopandas==1.1.4 + # via + # planetary-computer-examples (pyproject.toml) + # dask-geopandas +geopy==2.5.0 + # via contextily +google-crc32c==1.9.0 + # via zarr +h11==0.16.0 + # via httpcore +h5netcdf==1.8.2 + # via xarray +h5py==3.16.0 + # via h5netcdf +holoviews==1.23.2 + # via hvplot +httpcore==1.0.9 + # via httpx +httpx==0.28.1 + # via jupyterlab +hvplot==0.12.2 + # via planetary-computer-examples (pyproject.toml) +identify==2.6.20 + # via pre-commit +idna==3.20 + # via + # anyio + # httpx + # jsonschema + # requests + # url-normalize + # yarl +ipykernel==7.4.0 + # via + # planetary-computer-examples (pyproject.toml) + # jupyterlab +ipython==9.18.1 + # via + # planetary-computer-examples (pyproject.toml) + # ipykernel +ipython-pygments-lexers==1.1.1 + # via ipython +isodate==0.7.2 + # via azure-storage-blob +isoduration==20.11.0 + # via jsonschema +jedi==0.20.1 + # via ipython +jinja2==3.1.6 + # via + # bokeh + # distributed + # jupyter-server + # jupyterlab + # jupyterlab-server + # nbconvert + # pydap +joblib==1.6.0 + # via contextily +json5==0.17.3 + # via jupyterlab-server +jsonpointer==3.6 + # via jsonschema +jsonschema==4.26.0 + # via + # jupyter-events + # jupyterlab-server + # nbformat +jsonschema-specifications==2025.9.1 + # via jsonschema +jupyter-builder==1.2.4 + # via jupyterlab +jupyter-client==8.10.0 + # via + # ipykernel + # jupyter-server + # nbclient +jupyter-core==5.9.1 + # via + # ipykernel + # jupyter-builder + # jupyter-client + # jupyter-server + # jupyterlab + # nbclient + # nbconvert + # nbformat +jupyter-events==0.12.1 + # via jupyter-server +jupyter-lsp==2.3.1 + # via jupyterlab +jupyter-server==2.21.1 + # via + # jupyter-lsp + # jupyterlab + # jupyterlab-server + # notebook-shim +jupyter-server-terminals==0.5.4 + # via jupyter-server +jupyterlab==4.6.5 + # via planetary-computer-examples (pyproject.toml) +jupyterlab-pygments==0.3.0 + # via nbconvert +jupyterlab-server==2.28.1 + # via jupyterlab +kiwisolver==1.5.1 + # via matplotlib +lark==1.3.1 + # via rfc3987-syntax +legacy-cgi==2.6.4 ; python_full_version >= '3.13' + # via webob +linkify-it-py==2.2.0 + # via panel +llvmlite==0.50.0 + # via numba +locket==1.0.0 + # via + # distributed + # partd +lxml==6.1.3 + # via pydap +markdown==3.11.2 + # via panel +markdown-it-py==4.2.0 + # via + # mdit-py-plugins + # panel + # rich +markupsafe==3.0.4 + # via + # jinja2 + # nbconvert +matplotlib==3.11.2 + # via + # planetary-computer-examples (pyproject.toml) + # cartopy + # contextily + # geogif + # seaborn +matplotlib-inline==0.2.2 + # via + # ipykernel + # ipython +mdit-py-plugins==0.6.1 + # via panel +mdurl==0.1.2 + # via markdown-it-py +mercantile==1.2.1 + # via contextily +mistune==3.4.0 + # via nbconvert +msal==1.39.0 + # via + # azure-identity + # msal-extensions +msal-extensions==1.3.1 + # via azure-identity +msgpack==1.2.4 + # via distributed +multidict==7.2.1 + # via + # aiohttp + # yarl +multipledispatch==1.0.0 + # via datashader +narwhals==2.28.0 + # via + # bokeh + # holoviews + # panel +nbclient==0.11.0 + # via nbconvert +nbconvert==7.17.2 + # via jupyter-server +nbformat==5.11.1 + # via + # jupyter-server + # nbclient + # nbconvert +nest-asyncio2==1.7.4 + # via ipykernel +netcdf4==1.7.5.1.post1 + # via xarray +nh3==0.3.7 + # via panel +nodeenv==1.11.1 + # via pre-commit +notebook-shim==0.2.4 + # via jupyterlab +numba==0.68.1 + # via + # datashader + # xarray-spatial +numcodecs==0.16.6 + # via zarr +numpy==1.26.4 + # via + # planetary-computer-examples (pyproject.toml) + # bokeh + # cartopy + # cftime + # contourpy + # dask + # datashader + # geogif + # geopandas + # h5netcdf + # h5py + # holoviews + # hvplot + # matplotlib + # netcdf4 + # numba + # numcodecs + # odc-geo + # odc-loader + # odc-stac + # pandas + # pydap + # pyogrio + # rasterio + # rioxarray + # scipy + # seaborn + # shapely + # stackstac + # xarray + # xarray-spatial + # zarr +odc-geo==0.5.3 + # via + # odc-loader + # odc-stac +odc-loader==0.6.5 + # via odc-stac +odc-stac==0.5.3 + # via planetary-computer-examples (pyproject.toml) +packaging==26.3 + # via + # bokeh + # cartopy + # dask + # dask-geopandas + # datashader + # distributed + # geopandas + # h5netcdf + # hvplot + # ipykernel + # jupyter-events + # jupyter-server + # jupyterlab + # jupyterlab-server + # matplotlib + # nbconvert + # netcdf4 + # panel + # panel-material-ui + # planetary-computer + # pooch + # pyogrio + # rioxarray + # virtualenv + # xarray + # zarr +pandas==2.3.3 + # via + # planetary-computer-examples (pyproject.toml) + # dask + # datashader + # geopandas + # holoviews + # hvplot + # odc-stac + # panel + # seaborn + # stackstac + # xarray + # xarray-spatial +pandocfilters==1.5.1 + # via nbconvert +panel==1.10.0 + # via + # holoviews + # hvplot + # panel-material-ui +panel-material-ui==0.16.6 + # via panel +param==2.4.2 + # via + # datashader + # holoviews + # hvplot + # panel + # pyct + # pyviz-comms +parso==0.8.7 + # via jedi +partd==1.4.2 + # via dask +pexpect==4.9.0 ; sys_platform != 'emscripten' and sys_platform != 'win32' + # via ipython +pillow==10.4.0 + # via + # planetary-computer-examples (pyproject.toml) + # bokeh + # contextily + # geogif + # matplotlib +planetary-computer==1.0.0 + # via planetary-computer-examples (pyproject.toml) +platformdirs==4.14.0 + # via + # jupyter-core + # pooch + # requests-cache + # virtualenv +pooch==1.9.0 + # via xarray +pre-commit==4.7.0 + # via planetary-computer-examples (pyproject.toml) +prometheus-client==0.26.0 + # via jupyter-server +prompt-toolkit==3.0.53 + # via ipython +propcache==0.5.4 + # via + # aiohttp + # yarl +psutil==7.2.2 + # via + # distributed + # ipython +ptyprocess==0.7.0 ; os_name != 'nt' or (sys_platform != 'emscripten' and sys_platform != 'win32') + # via + # pexpect + # terminado +pure-eval==0.2.4 + # via stack-data +pyarrow==25.0.1 + # via + # planetary-computer-examples (pyproject.toml) + # dask +pycparser==3.12 ; implementation_name != 'PyPy' + # via cffi +pyct==0.6.0 + # via datashader +pydantic==2.14.2 + # via planetary-computer +pydantic-core==2.50.2 + # via pydantic +pydap==3.5.11 + # via xarray +pygments==2.21.0 + # via + # ipython + # ipython-pygments-lexers + # nbconvert + # rich +pyjwt==2.15.1 + # via msal +pyogrio==0.13.0 + # via geopandas +pyparsing==3.3.3 + # via + # matplotlib + # rasterio +pyproj==3.8.0 + # via + # planetary-computer-examples (pyproject.toml) + # cartopy + # geopandas + # odc-geo + # rioxarray + # stackstac +pyshp==3.1.6 + # via cartopy +pystac==1.15.2 + # via + # planetary-computer-examples (pyproject.toml) + # odc-stac + # planetary-computer + # pystac-client +pystac-client==0.9.1 + # via + # planetary-computer-examples (pyproject.toml) + # planetary-computer +pystac-core==1.15.2 + # via + # pystac + # pystac-ext-classification + # pystac-ext-datacube + # pystac-ext-eo + # pystac-ext-file + # pystac-ext-grid + # pystac-ext-item-assets + # pystac-ext-label + # pystac-ext-mgrs + # pystac-ext-mlm + # pystac-ext-pointcloud + # pystac-ext-projection + # pystac-ext-raster + # pystac-ext-render + # pystac-ext-sar + # pystac-ext-sat + # pystac-ext-scientific + # pystac-ext-storage + # pystac-ext-table + # pystac-ext-timestamps + # pystac-ext-version + # pystac-ext-view + # pystac-ext-xarray-assets +pystac-ext-classification==2.0.1 + # via + # pystac + # pystac-ext-mlm +pystac-ext-datacube==2.2.1 + # via pystac +pystac-ext-eo==1.1.2 + # via pystac +pystac-ext-file==2.1.1 + # via pystac +pystac-ext-grid==1.1.1 + # via pystac +pystac-ext-item-assets==1.0.1 + # via pystac +pystac-ext-label==1.0.2 + # via pystac +pystac-ext-mgrs==1.0.1 + # via pystac +pystac-ext-mlm==1.4.1 + # via pystac +pystac-ext-pointcloud==1.0.1 + # via pystac +pystac-ext-projection==2.0.1 + # via + # pystac + # pystac-ext-eo +pystac-ext-raster==1.1.1 + # via + # pystac + # pystac-ext-classification + # pystac-ext-mlm +pystac-ext-render==2.0.0 + # via pystac +pystac-ext-sar==1.0.1 + # via pystac +pystac-ext-sat==1.0.1 + # via pystac +pystac-ext-scientific==1.0.1 + # via pystac +pystac-ext-storage==2.0.1 + # via pystac +pystac-ext-table==1.2.1 + # via pystac +pystac-ext-timestamps==1.1.1 + # via pystac +pystac-ext-version==1.2.1 + # via pystac +pystac-ext-view==1.0.1 + # via + # pystac + # pystac-ext-eo +pystac-ext-xarray-assets==1.0.1 + # via pystac +python-dateutil==3.0.0 + # via + # arrow + # holoviews + # jupyter-client + # matplotlib + # pandas + # pystac-client + # pystac-core +python-discovery==1.9.1 + # via virtualenv +python-dotenv==1.2.4 + # via planetary-computer +python-json-logger==4.2.0 + # via jupyter-events +pytz==2026.6 + # via + # pandas + # planetary-computer +pyviz-comms==3.0.6 + # via + # holoviews + # panel +pywinpty==3.1.2 ; os_name == 'nt' + # via + # jupyter-server + # jupyter-server-terminals + # terminado +pyyaml==6.0.3 + # via + # bokeh + # dask + # distributed + # donfig + # jupyter-events + # pre-commit +pyzmq==27.2.0 + # via + # ipykernel + # jupyter-client + # jupyter-server +rasterio==1.4.4 + # via + # planetary-computer-examples (pyproject.toml) + # contextily + # odc-loader + # odc-stac + # rioxarray + # stackstac +referencing==0.37.0 + # via + # jsonschema + # jsonschema-specifications + # jupyter-events +requests==2.34.2 + # via + # planetary-computer-examples (pyproject.toml) + # azure-core + # contextily + # datashader + # jupyterlab-server + # msal + # panel + # planetary-computer + # pooch + # pydap + # pystac-client + # requests-cache +requests-cache==1.3.3 + # via pydap +rfc3339-validator==0.1.4 + # via + # jsonschema + # jupyter-events +rfc3986-validator==0.1.1 + # via + # jsonschema + # jupyter-events +rfc3987-syntax==1.1.0 + # via jsonschema +rich==15.0.0 + # via planetary-computer-examples (pyproject.toml) +rioxarray==0.19.0 + # via planetary-computer-examples (pyproject.toml) +rpds-py==2026.9.1 + # via + # jsonschema + # referencing +scipy==1.17.1 + # via + # planetary-computer-examples (pyproject.toml) + # datashader + # pydap + # xarray + # xarray-spatial +seaborn==0.13.2 + # via planetary-computer-examples (pyproject.toml) +send2trash==2.1.0 + # via jupyter-server +shapely==2.2.0 + # via + # planetary-computer-examples (pyproject.toml) + # cartopy + # dask-geopandas + # geopandas + # odc-geo +six==1.17.0 + # via + # python-dateutil + # rfc3339-validator +sortedcontainers==2.4.0 + # via distributed +soupsieve==3.0.4 + # via beautifulsoup4 +stack-data==0.6.3 + # via ipython +stackstac==0.5.1 + # via planetary-computer-examples (pyproject.toml) +tblib==3.2.2 + # via distributed +terminado==0.18.1 + # via + # jupyter-server + # jupyter-server-terminals +tinycss2==1.5.1 + # via bleach +toolz==1.2.0 + # via + # dask + # datashader + # distributed + # odc-stac + # partd +tornado==6.6 + # via + # bokeh + # distributed + # ipykernel + # jupyter-client + # jupyter-server + # jupyterlab + # terminado +tqdm==4.70.1 + # via panel +traitlets==5.16.1 + # via + # ipykernel + # ipython + # jupyter-builder + # jupyter-client + # jupyter-core + # jupyter-events + # jupyter-server + # jupyterlab + # matplotlib-inline + # nbclient + # nbconvert + # nbformat +typing-extensions==4.16.0 + # via + # aiohttp + # aiosignal + # anyio + # azure-core + # azure-identity + # azure-storage-blob + # beautifulsoup4 + # cattrs + # jupyter-client + # numcodecs + # odc-loader + # odc-stac + # panel + # pydantic + # pydantic-core + # referencing + # typing-inspection + # zarr +typing-inspection==0.4.4 + # via pydantic +tzdata==2026.6 + # via + # arrow + # pandas + # python-dateutil +uri-template==1.3.0 + # via jsonschema +url-normalize==3.1.0 + # via requests-cache +urllib3==2.8.0 + # via + # requests + # requests-cache + # xarray-spatial +virtualenv==21.15.5 + # via pre-commit +wcwidth==0.9.4 + # via prompt-toolkit +webcolors==25.10.0 + # via jsonschema +webencodings==0.6.1 + # via + # bleach + # tinycss2 +webob==1.8.11 + # via pydap +websocket-client==1.9.2 + # via jupyter-server +xarray==2026.9.0 + # via + # planetary-computer-examples (pyproject.toml) + # datashader + # geogif + # odc-geo + # odc-loader + # odc-stac + # rioxarray + # stackstac + # xarray-spatial +xarray-spatial==0.10.19 + # via planetary-computer-examples (pyproject.toml) +xyzservices==2026.9.1 + # via + # bokeh + # contextily +yarl==1.25.1 + # via aiohttp +zarr==3.1.5 + # via + # planetary-computer-examples (pyproject.toml) + # xarray +zict==3.0.0 + # via distributed diff --git a/scripts/install b/scripts/install new file mode 100755 index 00000000..f7e29010 --- /dev/null +++ b/scripts/install @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +set -euo pipefail + +if ! command -v uv >/dev/null 2>&1; then + printf '%s\n' \ + 'uv is required. See https://docs.astral.sh/uv/getting-started/installation/.' >&2 + exit 1 +fi + +cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." +uv venv --allow-existing --python 3.12 .venv +exec uv pip sync --python .venv requirements.txt diff --git a/scripts/server b/scripts/server deleted file mode 100755 index 382e335f..00000000 --- a/scripts/server +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/bash - -set -e - -function usage() { - echo -n \ - "Usage: $(basename "$0") -Runs the jupyter notebooks server -" -} - -if [ "${BASH_SOURCE[0]}" = "${0}" ]; then - - docker-compose up - -fi diff --git a/scripts/setup b/scripts/setup deleted file mode 100755 index 0d337788..00000000 --- a/scripts/setup +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/bash - -set -e - -function usage() { - echo -n \ - "Usage: $(basename "$0") -Setup the development environment -" -} - -if [ "${BASH_SOURCE[0]}" = "${0}" ]; then - - scripts/setup - -fi diff --git a/scripts/test b/scripts/test new file mode 100755 index 00000000..cb5b17b2 --- /dev/null +++ b/scripts/test @@ -0,0 +1,28 @@ +#!/usr/bin/env bash +set -euo pipefail + +if [[ $# -ne 1 ]]; then + printf '%s\n' 'Usage: scripts/test --lint' >&2 + exit 2 +fi + +case "$1" in + --lint) ;; + --help|-h) + printf '%s\n' 'Usage: scripts/test --lint' + exit 0 + ;; + *) + printf 'Unknown option: %s\nUsage: scripts/test --lint\n' "$1" >&2 + exit 2 + ;; +esac + +if ! command -v uv >/dev/null 2>&1; then + printf '%s\n' \ + 'uv is required. See https://docs.astral.sh/uv/getting-started/installation/.' >&2 + exit 1 +fi + +cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." +exec uv run pre-commit run --all-files diff --git a/scripts/update b/scripts/update deleted file mode 100755 index adc855d2..00000000 --- a/scripts/update +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/bash - -set -e - -function usage() { - echo -n \ - "Usage: $(basename "$0") -Updates the docker containers for this project. -" -} - -if [ "${BASH_SOURCE[0]}" = "${0}" ]; then - - echo "==Building image..." - docker-compose build - -fi diff --git a/tutorials/coregistration.ipynb b/tutorials/coregistration.ipynb index dd94e92a..4ada3d4d 100755 --- a/tutorials/coregistration.ipynb +++ b/tutorials/coregistration.ipynb @@ -240,9 +240,7 @@ " bounds=sentinel_data.spec.bounds, # set bounds to match Sentinel data\n", " assets=[\"blue\", \"green\", \"red\", \"nir08\"],\n", " resampling=rasterio.enums.Resampling.bilinear,\n", - " ).where(\n", - " lambda x: x > 0, other=np.nan\n", - " ) # landsat-c2-l2 uses 0 as nodata\n", + " ).where(lambda x: x > 0, other=np.nan) # landsat-c2-l2 uses 0 as nodata\n", " )\n", " .median(dim=\"time\", keep_attrs=True)\n", " .persist()\n", diff --git a/tutorials/model_training.ipynb b/tutorials/model_training.ipynb index da258b06..c7016d21 100644 --- a/tutorials/model_training.ipynb +++ b/tutorials/model_training.ipynb @@ -1776,7 +1776,6 @@ "MILE = 1609 # 1 mile is 1609 meters\n", "\n", "for i in range(len(grids_df)): # Query each grid saved in grids.csv for OSM objects\n", - "\n", " if len(grids_df) > 10000:\n", " print(\n", " \"Too many queries! The API for OpenStreetMap, OverPass, has a limit\"\n", diff --git a/tutorials/mosaiks.ipynb b/tutorials/mosaiks.ipynb index 2531f6a2..0b30a644 100755 --- a/tutorials/mosaiks.ipynb +++ b/tutorials/mosaiks.ipynb @@ -942,7 +942,6 @@ "i = 0\n", "for images in dataloader:\n", " for image in images:\n", - "\n", " if image is not None:\n", " # A full image should be ~101x101 pixels (i.e. ~1km^2 at a 10m/px spatial\n", " # resolution), however we can receive smaller images if an input point\n", @@ -965,7 +964,7 @@ " if i % 1000 == 0:\n", " print(\n", " f\"{i}/{points.shape[0]} -- {i / points.shape[0] * 100:0.2f}%\"\n", - " + f\" -- {time.time()-tic:0.2f} seconds\"\n", + " + f\" -- {time.time() - tic:0.2f} seconds\"\n", " )\n", " tic = time.time()\n", " i += 1"