Skip to content

Runnable Examples

The examples/ directory contains focused scripts for the common UavPy workflows. Run them from the repository root so the shared paths in examples/common.py resolve consistently.

1
uv run python examples/demo.py

Shared Demo Paths

Each example imports the same dataset paths and output folders:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
"""Shared paths and settings for the UavPy examples."""

from pathlib import Path

DATA_FOLDER = Path("../data/Stephenville_Peanut_Images")
MULTISPECTRAL_ORTHOMOSAIC = (
    DATA_FOLDER / "Multispectral/ms_orthomosaic_Y2025_20250819_cog.tif"
)
RGB_ORTHOMOSAIC = DATA_FOLDER / "RGB/rgb_orthomosaic_Y2025_20250819.tif"
PLOT_BOUNDARY = DATA_FOLDER / "plot_boundary/plots_shapefile.shp"

TILE_DIR = Path("examples/.uavpy_tiles")
PLOT_EXPORT_DIR = Path("examples/.uavpy_plots")

Update these constants for your local project before running the scripts.

Load An Orthomosaic

Use this first to validate the input path, inspect shape and dtype, and confirm the available bands.

1
uv run python examples/load_orthomosaic.py
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
"""Load an orthomosaic and inspect its raster metadata."""

import asyncio

from dotenv import find_dotenv, load_dotenv

from common import MULTISPECTRAL_ORTHOMOSAIC
from uavpy.artifacts import Orthomosaic


async def main() -> None:
    """Load the demo orthomosaic and print metadata used by later examples."""
    load_dotenv(find_dotenv())

    orthomosaic = Orthomosaic.from_path(MULTISPECTRAL_ORTHOMOSAIC)
    await orthomosaic.load()

    print("Path:", MULTISPECTRAL_ORTHOMOSAIC)
    print("Shape:", orthomosaic.shape)
    print("Dtype:", orthomosaic.dtype)
    print("Band info:", orthomosaic.band_info)


if __name__ == "__main__":
    asyncio.run(main())

Extract Plot ROIs

This workflow loads a plot shapefile, crops the orthomosaic by each feature, and saves one sample plot as both GeoTIFF and PNG.

1
uv run python examples/extract_plot_rois.py
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
"""Extract plot-level regions of interest from an orthomosaic."""

import asyncio

import matplotlib.pyplot as plt
from dotenv import find_dotenv, load_dotenv

from common import MULTISPECTRAL_ORTHOMOSAIC, PLOT_BOUNDARY, PLOT_EXPORT_DIR
from uavpy.artifacts import Orthomosaic, ShapeFile


async def main() -> None:
    """Crop the demo orthomosaic by plot polygons and save one sample plot."""
    load_dotenv(find_dotenv())

    shape_file = ShapeFile(PLOT_BOUNDARY, target_crs="EPSG:4326")
    await shape_file.load()
    print("Shape fields:", list(shape_file.gdf.columns))

    orthomosaic = Orthomosaic.from_path(MULTISPECTRAL_ORTHOMOSAIC)
    await orthomosaic.load()

    plots = await orthomosaic.extract_plots(shape_file, plot_id_field="Plot No")
    PLOT_EXPORT_DIR.mkdir(parents=True, exist_ok=True)

    for plot in plots[:1]:
        plot_id = str(plot.attrs["plot_id"])
        print("Plot:", plot_id, plot.shape)

        fig, _ = plot.plot(
            rgb=(6, 4, 2),
            title=f"Plot {plot_id}",
            show=False,
        )
        plot.save(PLOT_EXPORT_DIR / f"{plot_id}.tif", overwrite=True)
        fig.savefig(PLOT_EXPORT_DIR / f"{plot_id}.png")
        plt.close(fig)


if __name__ == "__main__":
    asyncio.run(main())

Compute Spectral Indices

This example computes NDVI and NDRE with one-based band numbers and saves the derived rasters for downstream analysis or map display.

1
uv run python examples/compute_spectral_indices.py
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
"""Compute spectral indices from a multispectral orthomosaic."""

import asyncio

from dotenv import find_dotenv, load_dotenv

from common import MULTISPECTRAL_ORTHOMOSAIC, PLOT_EXPORT_DIR
from uavpy.artifacts import Orthomosaic
from uavpy.tools import SpectralIndex


async def main() -> None:
    """Compute NDVI and NDRE rasters from the demo multispectral orthomosaic."""
    load_dotenv(find_dotenv())

    orthomosaic = Orthomosaic.from_path(MULTISPECTRAL_ORTHOMOSAIC)
    await orthomosaic.load()

    ndvi = await SpectralIndex.ndvi(nir=6, red=4)(orthomosaic)
    ndre = await SpectralIndex.ndre(nir=6, red_edge=5)(orthomosaic)

    PLOT_EXPORT_DIR.mkdir(parents=True, exist_ok=True)
    ndvi_path = PLOT_EXPORT_DIR / "ndvi.tif"
    ndre_path = PLOT_EXPORT_DIR / "ndre.tif"

    ndvi.save(ndvi_path, overwrite=True, dtype="float32")
    ndre.save(ndre_path, overwrite=True, dtype="float32")

    print("NDVI:", ndvi.shape, ndvi_path)
    print("NDRE:", ndre.shape, ndre_path)


if __name__ == "__main__":
    asyncio.run(main())

Show An Interactive Map

This example uses mapwidgets to generate raster tiles with the Python backend and display them with plot boundaries in a desktop map.

1
uv run python examples/show_interactive_map.py
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
"""Display raster and vector layers in a mapwidgets desktop map."""

import asyncio
import sys

from dotenv import find_dotenv, load_dotenv
from mapwidgets import MapViewer, RasterLayer, VectorLayer
from PySide6.QtWidgets import QApplication

from common import MULTISPECTRAL_ORTHOMOSAIC, PLOT_BOUNDARY, TILE_DIR


async def main() -> None:
    """Generate tiles for the demo raster and display them with plot boundaries."""
    load_dotenv(find_dotenv())

    tile_layer = RasterLayer.from_tiled_geotiff(
        MULTISPECTRAL_ORTHOMOSAIC,
        output_dir=TILE_DIR / "false_color",
        bands=(6, 4, 2),
        zoom_levels=range(18, 23),
        backend="python",
        max_tiles=5000,
        overwrite=True,
        opacity=0.85,
        transparent_values=(0,),
        transparent_match="any",
    )

    app = QApplication.instance() or QApplication(sys.argv[:1])
    viewer = MapViewer(backend="maplibre").resize(1200, 800).show()
    viewer.add_layer(tile_layer, zoom_to=True)
    viewer.add_layer(
        VectorLayer.from_shapefile(PLOT_BOUNDARY, id="plots", name="Plot boundaries"),
    )
    viewer.wait_for_map_ready()
    app.exec()


if __name__ == "__main__":
    asyncio.run(main())