Skip to content

Importing Labels from GeoJSON

Open In Colab

This tutorial explains how to use the kili.append_labels_from_geojson_files function in the Kili SDK to import geometries from GeoJSON files and convert them to annotations in your Kili projects.

Introduction

GeoJSON is a widely-used open standard format for representing simple geographical features along with their non-spatial attributes. Unlike shapefiles, GeoJSON is human-readable, supports web applications natively, and always uses the WGS84 coordinate system (EPSG:4326).

The append_labels_from_geojson_files function provides three flexible modes to convert GeoJSON features into Kili annotations, making it easy to import existing geographic data into your annotation projects.

Prerequisites

Before using this feature, ensure you have:

  • A Kili project of type IMAGE or GEOSPATIAL
  • One or more GeoJSON files (.geojson or .json)
  • Understanding of your project's job structure and categories

Function Structure

The append_labels_from_geojson_files function accepts the following parameters:

Parameter Type
project_id str
asset_external_id str
geojson_file_paths List[str]
job_names Optional[List[str]]
category_names Optional[List[str]]

Supported Geometry Types

The function supports the following GeoJSON geometry types and their Kili annotation mappings:

GeoJSON Geometry Kili Annotation Type Job Tool Required
Point marker marker
LineString polyline polyline
Polygon polygon or semantic polygon/semantic
MultiPolygon semantic semantic

Import Modes

The function supports three different import modes, providing flexibility for various use cases:

Mode 1: GeoJSON with Kili Properties

In this mode, your GeoJSON features contain kili metadata in their properties, specifying the job, annotation type, and categories.

GeoJSON Structure:

{
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "geometry": {
        "type": "Point",
        "coordinates": [2.3522, 48.8566]
      },
      "properties": {
        "name": "Eiffel Tower",
        "kili": {
          "job": "LANDMARKS",
          "type": "marker",
          "categories": [{"name": "TOWER"}]
        }
      }
    }
  ]
}

Python Code:

from kili.client import Kili

kili = Kili(api_key="your_api_key")

# Mode 1: Import with kili properties already in GeoJSON
kili.append_labels_from_geojson_files(
    project_id="your_project_id",
    asset_external_id="paris_satellite.tif",
    geojson_file_paths=["landmarks_with_kili_props.geojson"]
)

Mode 2: Specific Job/Category Mapping

In this mode, you explicitly specify which job and category to use for all compatible geometries in each file.

Python Code:

# Mode 2: Map all features to specific jobs and categories
kili.append_labels_from_geojson_files(
    project_id="your_project_id",
    asset_external_id="urban_area.jp2",
    geojson_file_paths=["roads.geojson", "buildings.geojson", "parks.geojson"],
    job_names=["INFRASTRUCTURE", "BUILDINGS", "VEGETATION"],
    category_names=["ROAD", "RESIDENTIAL", "PARK"]
)

Mode 3: Automatic Mapping

When neither kili properties nor specific mappings are provided, the function automatically maps geometries based on their type and available jobs in your project.

Automatic Mapping Priority:

  • Point → First available job with 'marker' tool
  • LineString → First available job with 'polyline' tool
  • Polygon → First available job with 'polygon' tool (fallback to 'semantic')
  • MultiPolygon → First available job with 'semantic' tool

Python Code:

# Mode 3: Automatic mapping based on geometry types
kili.append_labels_from_geojson_files(
    project_id="your_project_id",
    asset_external_id="geographic_data.tif",
    geojson_file_paths=["mixed_features.geojson"]
)

Detailed Examples

Example 1: Importing Multiple Annotation Types

This example shows how to import a GeoJSON file containing different geometry types with kili properties:

from kili.client import Kili

kili = Kili(api_key="your_api_key")

# Create a sample GeoJSON with mixed geometries
import json

geojson_data = {
    "type": "FeatureCollection",
    "features": [
        # Point annotation
        {
            "type": "Feature",
            "geometry": {
                "type": "Point",
                "coordinates": [-73.985428, 40.758896]
            },
            "properties": {
                "kili": {
                    "job": "POI_DETECTION",
                    "type": "marker",
                    "categories": [{"name": "LANDMARK"}]
                }
            }
        },
        # LineString annotation
        {
            "type": "Feature",
            "geometry": {
                "type": "LineString",
                "coordinates": [
                    [-73.985, 40.758],
                    [-73.983, 40.760],
                    [-73.981, 40.762]
                ]
            },
            "properties": {
                "kili": {
                    "job": "ROAD_MAPPING",
                    "type": "polyline",
                    "categories": [{"name": "HIGHWAY"}]
                }
            }
        },
        # Polygon annotation
        {
            "type": "Feature",
            "geometry": {
                "type": "Polygon",
                "coordinates": [[
                    [-73.980, 40.755],
                    [-73.978, 40.755],
                    [-73.978, 40.757],
                    [-73.980, 40.757],
                    [-73.980, 40.755]
                ]]
            },
            "properties": {
                "kili": {
                    "job": "ZONE_DETECTION",
                    "type": "semantic",
                    "categories": [{"name": "COMMERCIAL_AREA"}]
                }
            }
        }
    ]
}

# Save to file
with open("mixed_annotations.geojson", "w") as f:
    json.dump(geojson_data, f)

# Import into Kili
kili.append_labels_from_geojson_files(
    project_id="your_project_id",
    asset_external_id="manhattan_satellite.tif",
    geojson_file_paths=["mixed_annotations.geojson"]
)

Example 2: Batch Import with Specific Mapping

This example demonstrates importing multiple GeoJSON files with specific job/category mappings:

# Import different infrastructure types
kili.append_labels_from_geojson_files(
    project_id="city_planning_project",
    asset_external_id="city_orthophoto_2024.tif",
    geojson_file_paths=[
        "water_infrastructure.geojson",
        "power_lines.geojson",
        "green_spaces.geojson"
    ],
    job_names=[
        "WATER_INFRASTRUCTURE",
        "ELECTRICAL_GRID",
        "URBAN_VEGETATION"
    ],
    category_names=[
        "WATER_PIPELINE",
        "HIGH_VOLTAGE_LINE",
        "PUBLIC_PARK"
    ]
)

Example 3: Working with MultiPolygon Features

MultiPolygon features are useful for representing discontinuous areas:

# Create a GeoJSON with MultiPolygon for forest patches
forest_patches = {
    "type": "FeatureCollection",
    "features": [
        {
            "type": "Feature",
            "geometry": {
                "type": "MultiPolygon",
                "coordinates": [
                    # First forest patch
                    [[
                        [2.10, 48.80],
                        [2.12, 48.80],
                        [2.12, 48.82],
                        [2.10, 48.82],
                        [2.10, 48.80]
                    ]],
                    # Second forest patch
                    [[
                        [2.15, 48.81],
                        [2.17, 48.81],
                        [2.17, 48.83],
                        [2.15, 48.83],
                        [2.15, 48.81]
                    ]]
                ]
            },
            "properties": {
                "kili": {
                    "job": "LAND_COVER",
                    "type": "semantic",
                    "categories": [{"name": "DECIDUOUS_FOREST"}]
                }
            }
        }
    ]
}

# Save and import
with open("forest_patches.geojson", "w") as f:
    json.dump(forest_patches, f)

kili.append_labels_from_geojson_files(
    project_id="environmental_monitoring",
    asset_external_id="sentinel2_composite.tif",
    geojson_file_paths=["forest_patches.geojson"]
)

Best Practices

  1. Validate Your GeoJSON: Use online validators (see geojson.io) or the geojson Python library to ensure your files are valid before import.

  2. Check Job Compatibility: Ensure your Kili project has jobs with the appropriate tools for your geometry types:

    # Check project structure
    project = kili.projects(project_id="your_project_id", fields=["jsonInterface"])[0]
    print(json.dumps(project["jsonInterface"]["jobs"], indent=2))
    

Troubleshooting

Problem: Features Not Appearing

Possible causes and solutions:

  1. Incompatible geometry-job combination:

    # Check which tools are available for each job
    project = kili.projects(project_id="your_project_id", fields=["jsonInterface"])[0]
    for job_name, job_config in project["jsonInterface"]["jobs"].items():
        print(f"{job_name}: {job_config.get('tools', [])}")
    

  2. Coordinates outside image bounds: Verify your coordinates match the geographic extent of your image.

Problem: ValueError for Missing Job or Category

Solution: Verify exact names in your project:

# List all jobs and categories
project = kili.projects(project_id="your_project_id", fields=["jsonInterface"])[0]
for job_name, job_config in project["jsonInterface"]["jobs"].items():
    categories = job_config.get("content", {}).get("categories", {})