Skip to content

Geographic Data API

The Geographic API handles location-based data and provides endpoints for retrieving geographic information and regional data.

Router Implementation

Geographic API endpoints for the CulicidaeLab server.

This module provides FastAPI router endpoints for retrieving geographic data and spatial information related to arthropod vectors and vector-borne diseases. The endpoints support various layer types and filtering options for spatial analysis and mapping applications.

The module includes the following endpoints: - GET /geo/{layer_type}: Retrieve geographic features for a specific layer type with optional spatial, temporal, and species-based filtering

All endpoints return GeoJSON-compliant data structures suitable for mapping applications and geographic information systems (GIS). The endpoints support bounding box filtering, date range filtering, and species-specific queries.

VALID_LAYER_TYPES = ['distribution', 'observations', 'modeled', 'breeding_sites'] module-attribute

Built-in mutable sequence.

If no argument is given, the constructor creates a new empty list. The argument must be an iterable if specified.

GeoJSONFeatureCollection

GeoJSON FeatureCollection model.

Represents a collection of GeoJSON Features for batch operations and API responses containing multiple geographic features.

model_config = {} class-attribute

dict() -> new empty dictionary dict(mapping) -> new dictionary initialized from a mapping object's (key, value) pairs dict(iterable) -> new dictionary initialized as if via: d = {} for k, v in iterable: d[k] = v dict(**kwargs) -> new dictionary initialized with the name=value pairs in the keyword argument list. For example: dict(one=1, two=2)

get_geographic_layer(layer_type: str = Path(PydanticUndefined), db: DBConnection = Depends(get_db), species: str | None = Query(None), bbox: str | None = Query(None), start_date: str | None = Query(None), end_date: str | None = Query(None)) async

Retrieve geographic features for a specific layer type with optional filtering.

This endpoint provides access to various geographic data layers related to arthropod vectors and vector-borne diseases. Currently supports observation data with spatial, temporal, and species-based filtering capabilities.

The endpoint returns GeoJSON FeatureCollection data that can be directly consumed by mapping libraries and GIS applications for visualization and spatial analysis.

Parameters:

Name Type Description Default
layer_type str

The type of geographic layer to retrieve. Must be one of: 'distribution', 'observations', 'modeled', 'breeding_sites'.

Path(PydanticUndefined)
db DBConnection

Database connection for querying geographic data.

Depends(get_db)
species str | None

Comma-separated list of species scientific names to filter by. If provided, only features for the specified species will be returned. Example: "Aedes aegypti,Anopheles gambiae,Culex quinquefasciatus".

Query(None)
bbox str | None

Bounding box filter in the format "min_lon,min_lat,max_lon,max_lat". Filters features to only include those within the specified geographic bounds. Example: "-122.4194,37.7749,-122.0808,37.9128" (San Francisco area).

Query(None)
start_date str | None

Start date for temporal filtering in YYYY-MM-DD format. Only features observed on or after this date will be included. Example: "2023-01-01".

Query(None)
end_date str | None

End date for temporal filtering in YYYY-MM-DD format. Only features observed on or before this date will be included. Example: "2023-12-31".

Query(None)

Returns:

Name Type Description
GeoJSONFeatureCollection

A GeoJSON FeatureCollection containing the requested geographic features. Each feature includes geometry (Point) and properties with observation metadata such as species information, observation dates, and location details.

Raises:

Type Description
HTTPException

If layer_type is invalid (400) or if bbox format is incorrect (400).

Examples:

Basic usage - retrieve all observation features:

GET /geo/observations

Filter by species:

GET /geo/observations?species=Aedes%20aegypti,Anopheles%20gambiae

Filter by geographic bounds (San Francisco):

GET /geo/observations?bbox=-122.4194,37.7749,-122.0808,37.9128

Filter by date range:

GET /geo/observations?start_date=2023-01-01&end_date=2023-06-30

Combined filters - species and location:

GET /geo/observations?species=Aedes%20aegypti&bbox=-74.0,40.7,-71.0,45.0

Combined filters - all parameters:

GET /geo/observations?species=Culex%20quinquefasciatus
                    &bbox=-118.5,34.0,-118.1,34.3
                    &start_date=2023-03-01&end_date=2023-09-30

Source code in backend\routers\geo.py
@router.get("/geo/{layer_type}", response_model=GeoJSONFeatureCollection)
async def get_geographic_layer(
    layer_type: str = Path(..., description=f"Type of geographic layer. Valid types: {', '.join(VALID_LAYER_TYPES)}"),
    db: lancedb.DBConnection = Depends(database.get_db),
    species: str | None = Query(None, description="Comma-separated list of species scientific names to filter by"),
    bbox: str | None = Query(None, description="Bounding box filter: min_lon,min_lat,max_lon,max_lat"),
    start_date: str | None = Query(None, description="Start date for filtering (YYYY-MM-DD)"),
    end_date: str | None = Query(None, description="End date for filtering (YYYY-MM-DD)"),
):
    """
    Retrieve geographic features for a specific layer type with optional filtering.

    This endpoint provides access to various geographic data layers related to arthropod
    vectors and vector-borne diseases. Currently supports observation data with spatial,
    temporal, and species-based filtering capabilities.

    The endpoint returns GeoJSON FeatureCollection data that can be directly consumed
    by mapping libraries and GIS applications for visualization and spatial analysis.

    Args:
        layer_type (str): The type of geographic layer to retrieve. Must be one of:
            'distribution', 'observations', 'modeled', 'breeding_sites'.
        db (lancedb.DBConnection): Database connection for querying geographic data.
        species (str | None): Comma-separated list of species scientific names to filter by.
            If provided, only features for the specified species will be returned.
            Example: "Aedes aegypti,Anopheles gambiae,Culex quinquefasciatus".
        bbox (str | None): Bounding box filter in the format "min_lon,min_lat,max_lon,max_lat".
            Filters features to only include those within the specified geographic bounds.
            Example: "-122.4194,37.7749,-122.0808,37.9128" (San Francisco area).
        start_date (str | None): Start date for temporal filtering in YYYY-MM-DD format.
            Only features observed on or after this date will be included.
            Example: "2023-01-01".
        end_date (str | None): End date for temporal filtering in YYYY-MM-DD format.
            Only features observed on or before this date will be included.
            Example: "2023-12-31".

    Returns:
        GeoJSONFeatureCollection: A GeoJSON FeatureCollection containing the requested
            geographic features. Each feature includes geometry (Point) and properties
            with observation metadata such as species information, observation dates,
            and location details.

    Raises:
        HTTPException: If layer_type is invalid (400) or if bbox format is incorrect (400).

    Examples:
        Basic usage - retrieve all observation features:
        ```
        GET /geo/observations
        ```

        Filter by species:
        ```
        GET /geo/observations?species=Aedes%20aegypti,Anopheles%20gambiae
        ```

        Filter by geographic bounds (San Francisco):
        ```
        GET /geo/observations?bbox=-122.4194,37.7749,-122.0808,37.9128
        ```

        Filter by date range:
        ```
        GET /geo/observations?start_date=2023-01-01&end_date=2023-06-30
        ```

        Combined filters - species and location:
        ```
        GET /geo/observations?species=Aedes%20aegypti&bbox=-74.0,40.7,-71.0,45.0
        ```

        Combined filters - all parameters:
        ```
        GET /geo/observations?species=Culex%20quinquefasciatus
                            &bbox=-118.5,34.0,-118.1,34.3
                            &start_date=2023-03-01&end_date=2023-09-30
        ```
    """
    if layer_type not in VALID_LAYER_TYPES:
        raise HTTPException(
            status_code=400,
            detail=f"Invalid layer type. Valid types are: {', '.join(VALID_LAYER_TYPES)}",
        )

    species_list: list[str] | None = None
    if species:
        species_list = [s.strip() for s in species.split(",") if s.strip()]

    bbox_filter: tuple[float, float, float, float] | None = None
    if bbox:
        try:
            coords = [float(c.strip()) for c in bbox.split(",")]
            if len(coords) == 4:
                bbox_filter = (coords[0], coords[1], coords[2], coords[3])
            else:
                raise ValueError("Bounding box must have 4 coordinates.")
        except ValueError as e:
            raise HTTPException(
                status_code=400,
                detail=f"Invalid bbox format: {e}. Use min_lon,min_lat,max_lon,max_lat",
            )

    if start_date and not geo_service.is_valid_date_str(start_date):
        raise HTTPException(status_code=400, detail="Invalid start_date format. Use YYYY-MM-DD")
    if end_date and not geo_service.is_valid_date_str(end_date):
        raise HTTPException(status_code=400, detail="Invalid end_date format. Use YYYY-MM-DD")

    geojson_collection = geo_service.get_geo_layer(
        db=db,
        layer_type=layer_type,
        species_list=species_list,
        bbox_filter=bbox_filter,
        start_date_str=start_date,
        end_date_str=end_date,
    )
    return geojson_collection

Data Schemas

The Geographic API uses Pydantic schemas for geographic data validation:

backend.schemas.geo_schemas

Pydantic models for geographic data and GeoJSON structures.

This module defines the schema models used for handling geographic data, GeoJSON structures, and map layer responses.

GeoJSONGeometry

GeoJSON geometry model.

Represents the geometry component of a GeoJSON Feature, containing type and coordinates information.

model_config = {} class-attribute

dict() -> new empty dictionary dict(mapping) -> new dictionary initialized from a mapping object's (key, value) pairs dict(iterable) -> new dictionary initialized as if via: d = {} for k, v in iterable: d[k] = v dict(**kwargs) -> new dictionary initialized with the name=value pairs in the keyword argument list. For example: dict(one=1, two=2)

GeoJSONFeature

GeoJSON Feature model.

Represents a complete GeoJSON Feature with type, properties, and geometry. Used for representing geographic features with associated data.

model_config = {} class-attribute

dict() -> new empty dictionary dict(mapping) -> new dictionary initialized from a mapping object's (key, value) pairs dict(iterable) -> new dictionary initialized as if via: d = {} for k, v in iterable: d[k] = v dict(**kwargs) -> new dictionary initialized with the name=value pairs in the keyword argument list. For example: dict(one=1, two=2)

GeoJSONFeatureCollection

GeoJSON FeatureCollection model.

Represents a collection of GeoJSON Features for batch operations and API responses containing multiple geographic features.

model_config = {} class-attribute

dict() -> new empty dictionary dict(mapping) -> new dictionary initialized from a mapping object's (key, value) pairs dict(iterable) -> new dictionary initialized as if via: d = {} for k, v in iterable: d[k] = v dict(**kwargs) -> new dictionary initialized with the name=value pairs in the keyword argument list. For example: dict(one=1, two=2)

MapLayerResponse

Response model for map layer data.

Contains layer metadata and GeoJSON data for rendering map layers in the frontend application.

model_config = {} class-attribute

dict() -> new empty dictionary dict(mapping) -> new dictionary initialized from a mapping object's (key, value) pairs dict(iterable) -> new dictionary initialized as if via: d = {} for k, v in iterable: d[k] = v dict(**kwargs) -> new dictionary initialized with the name=value pairs in the keyword argument list. For example: dict(one=1, two=2)

Service Layer

The Geographic API integrates with geographic service layers:

backend.services.geo_service

Geographic data service for handling spatial queries and filtering.

This module provides functionality for querying and filtering geographic data, particularly observation data with spatial and temporal filtering capabilities. It supports bounding box filtering, date range filtering, and species-based filtering for geographic visualization.

Example

from backend.services.geo_service import get_geo_layer from backend.services.database import get_db db = get_db() features = get_geo_layer(db, "observations", species_list=["Aedes aegypti"])

GeoJSONFeature

GeoJSON Feature model.

Represents a complete GeoJSON Feature with type, properties, and geometry. Used for representing geographic features with associated data.

model_config = {} class-attribute

dict() -> new empty dictionary dict(mapping) -> new dictionary initialized from a mapping object's (key, value) pairs dict(iterable) -> new dictionary initialized as if via: d = {} for k, v in iterable: d[k] = v dict(**kwargs) -> new dictionary initialized with the name=value pairs in the keyword argument list. For example: dict(one=1, two=2)

GeoJSONFeatureCollection

GeoJSON FeatureCollection model.

Represents a collection of GeoJSON Features for batch operations and API responses containing multiple geographic features.

model_config = {} class-attribute

dict() -> new empty dictionary dict(mapping) -> new dictionary initialized from a mapping object's (key, value) pairs dict(iterable) -> new dictionary initialized as if via: d = {} for k, v in iterable: d[k] = v dict(**kwargs) -> new dictionary initialized with the name=value pairs in the keyword argument list. For example: dict(one=1, two=2)

GeoJSONGeometry

GeoJSON geometry model.

Represents the geometry component of a GeoJSON Feature, containing type and coordinates information.

model_config = {} class-attribute

dict() -> new empty dictionary dict(mapping) -> new dictionary initialized from a mapping object's (key, value) pairs dict(iterable) -> new dictionary initialized as if via: d = {} for k, v in iterable: d[k] = v dict(**kwargs) -> new dictionary initialized with the name=value pairs in the keyword argument list. For example: dict(one=1, two=2)

is_valid_date_str(date_str: str) -> bool

Validate if a string represents a valid YYYY-MM-DD date format.

This helper function checks if the provided string can be parsed as a date in the expected format used throughout the application.

Parameters:

Name Type Description Default
date_str str

The date string to validate.

required

Returns:

Name Type Description
bool bool

True if the string is a valid YYYY-MM-DD date, False otherwise.

Example

is_valid_date_str("2023-12-25") True is_valid_date_str("invalid-date") False

get_geo_layer(db: DBConnection, layer_type: str, species_list: list[str] | None = None, bbox_filter: tuple[float, float, float, float] | None = None, start_date_str: str | None = None, end_date_str: str | None = None, limit: int = 10000) -> GeoJSONFeatureCollection

Retrieve geographic features for a specific layer with optional filtering.

This function queries observation data and applies multiple filters including species, bounding box, and date range filters. It returns GeoJSON formatted features suitable for mapping applications.

Parameters:

Name Type Description Default
db DBConnection

The database connection object.

required
layer_type str

The type of layer to retrieve. Currently supports "observations". Other types return empty collections.

required
species_list list[str] | None

List of species scientific names to filter by. If None, no species filtering is applied.

None
bbox_filter tuple[float, float, float, float] | None

A bounding box as (min_lon, min_lat, max_lon, max_lat). If None, no spatial filtering is applied.

None
start_date_str str | None

Start date in YYYY-MM-DD format. If None, no start date filtering is applied.

None
end_date_str str | None

End date in YYYY-MM-DD format. If None, no end date filtering is applied.

None
limit int

Maximum number of records to return. Defaults to 10000.

10000

Returns:

Name Type Description
GeoJSONFeatureCollection GeoJSONFeatureCollection

A GeoJSON FeatureCollection containing the filtered observation features with their properties and geometry.

Example

from backend.services.database import get_db db = get_db()

Get all Aedes aegypti observations in a specific region

features = get_geo_layer( ... db, ... "observations", ... species_list=["Aedes aegypti"], ... bbox_filter=(-74.1, 40.6, -71.9, 41.3), # NYC area ... start_date_str="2023-01-01", ... end_date_str="2023-12-31" ... ) print(len(features.features)) # Number of observations

get_table(db: DBConnection, table_name: str)

Retrieve a specific table from the LanceDB database.

Opens and returns a reference to the specified table in the database. This function validates that the table exists and is accessible.

Parameters:

Name Type Description Default
db DBConnection

The database connection object.

required
table_name str

The name of the table to retrieve.

required

Returns:

Type Description

lancedb.table.Table: A table object for the specified table name.

Raises:

Type Description
ValueError

If the table is not found or cannot be opened.

Example

db = get_db() observations_table = get_table(db, "observations") results = observations_table.search().limit(10).to_list()

Example Usage

Geographic Data Retrieval

import httpx

async with httpx.AsyncClient() as client:
    # Get regional data
    response = await client.get(
        "http://localhost:8000/api/v1/regions",
        params={"lang": "en"}
    )
    regions = response.json()

    # Get country information
    response = await client.get(
        "http://localhost:8000/api/v1/countries",
        params={"lang": "en"}
    )
    countries = response.json()