diff --git a/examples/prediction_upload/geospatial_predictions.ipynb b/examples/prediction_upload/geospatial_predictions.ipynb
new file mode 100644
index 000000000..527f5fb29
--- /dev/null
+++ b/examples/prediction_upload/geospatial_predictions.ipynb
@@ -0,0 +1,1559 @@
+{
+ "nbformat": 4,
+ "nbformat_minor": 0,
+ "metadata": {
+ "colab": {
+ "provenance": [],
+ "collapsed_sections": [
+ "RgBYFUxa-VGT",
+ "6FZyvnrqSGuc",
+ "viFHCnBeTD1Y",
+ "T-ZHWWI3JgmX"
+ ]
+ },
+ "kernelspec": {
+ "name": "python3",
+ "display_name": "Python 3"
+ },
+ "language_info": {
+ "name": "python"
+ }
+ },
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "a6a048e8-b5fe-418b-aec4-829b5b6802e5"
+ },
+ "source": [
+ "
\n",
+ " \n",
+ " | "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "51cf1362-1cde-4749-aac7-5fb94473baa7"
+ },
+ "source": [
+ "\n",
+ " \n",
+ " | \n",
+ "\n",
+ "\n",
+ " \n",
+ " | "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "source": [
+ "# Geospatial Prediction Import \n",
+ "* This notebook walks you through the process of uploading model predictions to a Model Run. This notebook provides an example for each supported prediction type for tiled imagery assets.\n",
+ "\n",
+ "A Model Run is a container for the predictions, annotations and metrics of a specific experiment in your ML model development cycle.\n",
+ "\n",
+ "**Supported annotations that can be uploaded through the SDK**\n",
+ "- Bounding box\n",
+ "- Point\n",
+ "- Polygons \n",
+ "- Polyline\n",
+ "- Free form text classifications\n",
+ "- Classification - radio\n",
+ "- Classification - checklist\n",
+ "\n",
+ "**NOT** supported:\n",
+ "- Segmentation masks\n",
+ "\n",
+ "\n",
+ "Please note that this list of unsupported annotations only refers to limitations for importing annotations. For example, when using the Labelbox editor, segmentation masks can be created and edited on video assets.\n"
+ ],
+ "metadata": {
+ "id": "9znxMjDYGi0Y"
+ }
+ },
+ {
+ "cell_type": "markdown",
+ "source": [
+ "## Setup"
+ ],
+ "metadata": {
+ "id": "UtJHIuE8HDRI"
+ }
+ },
+ {
+ "cell_type": "code",
+ "source": [
+ "!pip install -q 'labelbox[data]'"
+ ],
+ "metadata": {
+ "id": "cm8xMaLbGb7v",
+ "colab": {
+ "base_uri": "https://localhost:8080/"
+ },
+ "outputId": "213df0ab-7b5c-4915-e814-688f17646de6"
+ },
+ "execution_count": 2,
+ "outputs": [
+ {
+ "output_type": "stream",
+ "name": "stdout",
+ "text": [
+ "\u001b[?25l \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m0.0/185.5 KB\u001b[0m \u001b[31m?\u001b[0m eta \u001b[36m-:--:--\u001b[0m\r\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m185.5/185.5 KB\u001b[0m \u001b[31m14.4 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+ "\u001b[?25h Preparing metadata (setup.py) ... \u001b[?25l\u001b[?25hdone\n",
+ "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m7.8/7.8 MB\u001b[0m \u001b[31m60.0 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+ "\u001b[?25h Building wheel for pygeotile (setup.py) ... \u001b[?25l\u001b[?25hdone\n"
+ ]
+ }
+ ]
+ },
+ {
+ "cell_type": "code",
+ "source": [
+ "import os\n",
+ "\n",
+ "import uuid\n",
+ "import numpy as np\n",
+ "from PIL import Image\n",
+ "import cv2\n",
+ "import ndjson\n",
+ "\n",
+ "import labelbox as lb\n",
+ "import labelbox.data.annotation_types as lb_types\n",
+ "import labelbox.schema.queue_mode as lb_queue_mode\n",
+ "\n",
+ "from labelbox.data.serialization.ndjson.converter import NDJsonConverter\n",
+ "from labelbox.data.annotation_types.data.tiled_image import TiledBounds, TiledImageData, TileLayer, EPSG, EPSGTransformer"
+ ],
+ "metadata": {
+ "id": "NIq-6M9kHKSs"
+ },
+ "execution_count": 26,
+ "outputs": []
+ },
+ {
+ "cell_type": "markdown",
+ "source": [
+ "## Replace with your API Key \n",
+ "Guides on [Create an API key](https://docs.labelbox.com/docs/create-an-api-key)"
+ ],
+ "metadata": {
+ "id": "pZ2rBqY8HQoe"
+ }
+ },
+ {
+ "cell_type": "code",
+ "source": [
+ "API_KEY = None\n",
+ "client = lb.Client(API_KEY)"
+ ],
+ "metadata": {
+ "id": "z7ZLKLYLHP__"
+ },
+ "execution_count": 4,
+ "outputs": []
+ },
+ {
+ "cell_type": "markdown",
+ "source": [
+ "## Supported Predictions\n",
+ "- Each cell shows the python annotation and the NDJson annotation for each annotation type."
+ ],
+ "metadata": {
+ "id": "RgBYFUxa-VGT"
+ }
+ },
+ {
+ "cell_type": "code",
+ "source": [
+ "####### Point #######\n",
+ "\n",
+ "# Python Annotation\n",
+ "point_prediction = lb_types.ObjectAnnotation(\n",
+ " name = \"point_geo\",\n",
+ " confidence = 0.5,\n",
+ " value = lb_types.Point(x=-122.31741025134123, y=37.87355669249922),\n",
+ ")\n",
+ "\n",
+ "# NDJSON\n",
+ "point_prediction_ndjson = {\n",
+ " \"name\": \"point_geo\",\n",
+ " \"confidence\": 0.5,\n",
+ " \"point\": {\n",
+ " \"x\": -122.31741025134123,\n",
+ " \"y\": 37.87355669249922\n",
+ " }\n",
+ "}"
+ ],
+ "metadata": {
+ "id": "3mQh-yQ2TLmd"
+ },
+ "execution_count": 21,
+ "outputs": []
+ },
+ {
+ "cell_type": "code",
+ "source": [
+ "####### Polyline #######\n",
+ "# Coordinates\n",
+ "coords = [ \n",
+ " [\n",
+ " -122.31757789012927,\n",
+ " 37.87396317833991\n",
+ " ],\n",
+ " [\n",
+ " -122.31639782443663,\n",
+ " 37.87396741226917\n",
+ " ],\n",
+ " [\n",
+ " -122.31638977853417,\n",
+ " 37.87277872707839\n",
+ " ]\n",
+ " ]\n",
+ "\n",
+ "line_points = []\n",
+ "line_points_ndjson = []\n",
+ "\n",
+ "for sub in coords: \n",
+ " line_points.append(lb_types.Point(x=sub[0], y=sub[1]))\n",
+ " line_points_ndjson.append({\"x\":sub[0], \"y\":sub[1]})\n",
+ "\n",
+ "# Python Annotation \n",
+ "polyline_prediction = lb_types.ObjectAnnotation(\n",
+ " name = \"polyline_geo\",\n",
+ " confidence = 0.5,\n",
+ " value = lb_types.Line(points=line_points),\n",
+ ")\n",
+ "\n",
+ "\n",
+ "# NDJSON \n",
+ "polyline_prediction_ndjson = {\n",
+ " \"name\": \"polyline_geo\",\n",
+ " \"confidence\": 0.5,\n",
+ " \"line\": line_points_ndjson\n",
+ "}"
+ ],
+ "metadata": {
+ "id": "f3OoBByTTYda"
+ },
+ "execution_count": 5,
+ "outputs": []
+ },
+ {
+ "cell_type": "code",
+ "source": [
+ "####### Polygon #######\n",
+ "# Coordinates in the desired EPSG coordinate system\n",
+ "coords_polygon = [\n",
+ " [\n",
+ " -122.31691812612837,\n",
+ " 37.873289980495024\n",
+ " ],\n",
+ " [\n",
+ " -122.31710184090099,\n",
+ " 37.87304335144298\n",
+ " ],\n",
+ " [\n",
+ " -122.31680146054286,\n",
+ " 37.87303594197371\n",
+ " ],\n",
+ " [\n",
+ " -122.31691812612837,\n",
+ " 37.873289980495024\n",
+ " ]\n",
+ "]\n",
+ "\n",
+ "polygon_points = []\n",
+ "polygon_points_ndjson = []\n",
+ "\n",
+ "for sub in coords_polygon: \n",
+ " polygon_points.append(lb_types.Point(x=sub[0], y=sub[1]))\n",
+ " polygon_points_ndjson.append({\"x\":sub[0], \"y\":sub[1]})\n",
+ "\n",
+ "# Python Annotation \n",
+ "polygon_prediction = lb_types.ObjectAnnotation(\n",
+ " name = \"polygon_geo\",\n",
+ " confidence = 0.5,\n",
+ " value = lb_types.Polygon(points=polygon_points),\n",
+ ")\n",
+ "\n",
+ "# NDJSON \n",
+ "polygon_prediction_ndjson = {\n",
+ " \"name\": \"polygon_geo\",\n",
+ " \"confidence\": 0.5,\n",
+ " \"polygon\": polygon_points_ndjson\n",
+ "}"
+ ],
+ "metadata": {
+ "id": "BSjRhlFvTdfS"
+ },
+ "execution_count": 6,
+ "outputs": []
+ },
+ {
+ "cell_type": "code",
+ "source": [
+ "####### Bounding Box #######\n",
+ "coord_object = {\n",
+ " \"coordinates\": [\n",
+ " [\n",
+ " [\n",
+ " -122.31734455895823,\n",
+ " 37.873713376083884\n",
+ " ],\n",
+ " [\n",
+ " -122.31734455895823,\n",
+ " 37.87385944699745\n",
+ " ],\n",
+ " [\n",
+ " -122.31673038840458,\n",
+ " 37.87385944699745\n",
+ " ],\n",
+ " [\n",
+ " -122.31673038840458,\n",
+ " 37.873713376083884\n",
+ " ],\n",
+ " [\n",
+ " -122.31734455895823,\n",
+ " 37.873713376083884\n",
+ " ]\n",
+ " ]\n",
+ " ] \n",
+ " }\n",
+ "\n",
+ "\n",
+ "bbox_top_left = lb_types.Point(x=-122.31734455895823, y=37.873713376083884)\n",
+ "bbox_bottom_right = lb_types.Point(x=-122.31673038840458, y=37.87385944699745)\n",
+ "\n",
+ "# Python Annotation\n",
+ "bbox_prediction = lb_types.ObjectAnnotation(\n",
+ " name = \"bbox_geo\",\n",
+ " confidence = 0.5,\n",
+ " value = lb_types.Rectangle(start=bbox_top_left, end=bbox_bottom_right)\n",
+ ")\n",
+ "\n",
+ "\n",
+ "# NDJSON\n",
+ "bbox_prediction_ndjson = {\n",
+ " \"name\" : \"bbox_geo\",\n",
+ " \"confidence\": 0.5,\n",
+ " \"bbox\" : {\n",
+ " 'top': coord_object[\"coordinates\"][0][1][1],\n",
+ " 'left': coord_object[\"coordinates\"][0][1][0],\n",
+ " 'height': coord_object[\"coordinates\"][0][3][1] - coord_object[\"coordinates\"][0][1][1], \n",
+ " 'width': coord_object[\"coordinates\"][0][3][0] - coord_object[\"coordinates\"][0][1][0]\n",
+ " }\n",
+ "}\n"
+ ],
+ "metadata": {
+ "id": "oLX3adDOTmYS"
+ },
+ "execution_count": 7,
+ "outputs": []
+ },
+ {
+ "cell_type": "code",
+ "source": [
+ "####### Classification - radio (single choice) #######\n",
+ "\n",
+ "# Python Annotation \n",
+ "radio_prediction = lb_types.ClassificationAnnotation(\n",
+ " name=\"radio_question_geo\", \n",
+ " confidence = 0.5,\n",
+ " value=lb_types.Radio(answer=lb_types.ClassificationAnswer(name=\"first_radio_answer\"))\n",
+ ")\n",
+ "\n",
+ "# NDJSON \n",
+ "radio_prediction_ndjson = {\n",
+ " \"name\": \"radio_question_geo\",\n",
+ " \"confidence\": 0.5,\n",
+ " \"answer\": { \"name\": \"first_radio_answer\"}\n",
+ "}"
+ ],
+ "metadata": {
+ "id": "OsWf8Y_mTxLm"
+ },
+ "execution_count": 8,
+ "outputs": []
+ },
+ {
+ "cell_type": "code",
+ "source": [
+ "####### Classification - Checklist (multi-choice) #######\n",
+ "\n",
+ "coord_object_checklist = {\n",
+ " \"coordinates\": [\n",
+ " [\n",
+ " [\n",
+ " -122.31711256877092,\n",
+ " 37.87340218056304\n",
+ " ],\n",
+ " [\n",
+ " -122.31711256877092,\n",
+ " 37.87360752741479\n",
+ " ],\n",
+ " [\n",
+ " -122.31665529331502,\n",
+ " 37.87360752741479\n",
+ " ],\n",
+ " [\n",
+ " -122.31665529331502,\n",
+ " 37.87340218056304\n",
+ " ],\n",
+ " [\n",
+ " -122.31711256877092,\n",
+ " 37.87340218056304\n",
+ " ]\n",
+ " ]\n",
+ " ] \n",
+ "}\n",
+ "\n",
+ "# Python Annotation\n",
+ "bbox_with_checklist_subclass = lb_types.ObjectAnnotation(\n",
+ " name=\"bbox_checklist_geo\",\n",
+ " confidence = 0.5,\n",
+ " value=lb_types.Rectangle(\n",
+ " start=lb_types.Point(x=-122.31711256877092, y=37.87340218056304), # Top left\n",
+ " end=lb_types.Point(x=-122.31665529331502, y=37.87360752741479), # Bottom right\n",
+ " ),\n",
+ " classifications=[\n",
+ " lb_types.ClassificationAnnotation(\n",
+ " name=\"checklist_class_name\",\n",
+ " value=lb_types.Checklist(\n",
+ " answer=[lb_types.ClassificationAnswer(name=\"first_checklist_answer\", confidence = 0.5)]\n",
+ " )\n",
+ " )\n",
+ " ]\n",
+ ")\n",
+ "\n",
+ "\n",
+ "# NDJSON \n",
+ "bbox_with_checklist_subclass_ndjson = {\n",
+ " \"name\": \"bbox_checklist_geo\", \n",
+ " \"confidence\": 0.5,\n",
+ " \"classifications\": [{\n",
+ " \"name\": \"checklist_class_name\",\n",
+ " \"answer\": [\n",
+ " { \"name\":\"first_checklist_answer\", \"confidence\": 0.5 }\n",
+ " ] \n",
+ " }],\n",
+ " \"bbox\": {\n",
+ " 'top': coord_object_checklist[\"coordinates\"][0][1][1],\n",
+ " 'left': coord_object_checklist[\"coordinates\"][0][1][0],\n",
+ " 'height': coord_object_checklist[\"coordinates\"][0][3][1] - coord_object_checklist[\"coordinates\"][0][1][1], \n",
+ " 'width': coord_object_checklist[\"coordinates\"][0][3][0] - coord_object_checklist[\"coordinates\"][0][1][0]\n",
+ " }\n",
+ "}"
+ ],
+ "metadata": {
+ "id": "2IZXIWP2UcOJ"
+ },
+ "execution_count": 9,
+ "outputs": []
+ },
+ {
+ "cell_type": "code",
+ "source": [
+ "####### Classification free form text with bbox #######\n",
+ "\n",
+ "coord_object_text ={\n",
+ " \"coordinates\": [\n",
+ " [\n",
+ " [\n",
+ " -122.31750814315438,\n",
+ " 37.87318201423049\n",
+ " ],\n",
+ " [\n",
+ " -122.31750814315438,\n",
+ " 37.87337992476082\n",
+ " ],\n",
+ " [\n",
+ " -122.31710049991725,\n",
+ " 37.87337992476082\n",
+ " ],\n",
+ " [\n",
+ " -122.31710049991725,\n",
+ " 37.87318201423049\n",
+ " ],\n",
+ " [\n",
+ " -122.31750814315438,\n",
+ " 37.87318201423049\n",
+ " ]\n",
+ " ]\n",
+ " ]\n",
+ "}\n",
+ "# Python Annotation\n",
+ "bbox_with_free_text_subclass = lb_types.ObjectAnnotation(\n",
+ " name=\"bbox_text_geo\",\n",
+ " value=lb_types.Rectangle(\n",
+ " start=lb_types.Point(x=-122.31750814315438, y=37.87318201423049), # Top left\n",
+ " end=lb_types.Point(x=-122.31710049991725, y=37.87337992476082), # Bottom right\n",
+ " ),\n",
+ " classifications=[\n",
+ " lb_types.ClassificationAnnotation(\n",
+ " name=\"free_text_geo\",\n",
+ " value=lb_types.Text(answer=\"sample text\")\n",
+ " )\n",
+ " ]\n",
+ ")\n",
+ "\n",
+ "# NDJSON \n",
+ "bbox_with_free_text_subclass_ndjson = {\n",
+ " \"name\":\"bbox_text_geo\",\n",
+ " \"classifications\": [{\n",
+ " \"name\": \"free_text_geo\",\n",
+ " \"answer\": \"sample text\"\n",
+ " }],\n",
+ " \"bbox\": {\n",
+ " 'top': coord_object_text[\"coordinates\"][0][1][1],\n",
+ " 'left': coord_object_text[\"coordinates\"][0][1][0],\n",
+ " 'height': coord_object_text[\"coordinates\"][0][3][1] - coord_object_text[\"coordinates\"][0][1][1], \n",
+ " 'width': coord_object_text[\"coordinates\"][0][3][0] - coord_object_text[\"coordinates\"][0][1][0]\n",
+ " }\n",
+ "}"
+ ],
+ "metadata": {
+ "id": "bnjcIB7FU21R"
+ },
+ "execution_count": 10,
+ "outputs": []
+ },
+ {
+ "cell_type": "code",
+ "source": [
+ "####### Classification - Checklist (multi-choice) #######\n",
+ "\n",
+ "# Python Annotation\n",
+ "checklist_prediction = lb_types.ClassificationAnnotation(\n",
+ " name=\"checklist_question_geo\",\n",
+ " confidence = 0.5,\n",
+ " value=lb_types.Checklist(answer = [\n",
+ " lb_types.ClassificationAnswer(name = \"first_checklist_answer\", confidence = 0.5),\n",
+ " lb_types.ClassificationAnswer(name = \"second_checklist_answer\", confidence = 0.5),\n",
+ " lb_types.ClassificationAnswer(name = \"third_checklist_answer\", confidence = 0.5)\n",
+ " ])\n",
+ " )\n",
+ "\n",
+ "\n",
+ "# NDJSON\n",
+ "checklist_prediction_ndjson = {\n",
+ " 'name': 'checklist_question_geo',\n",
+ " \"confidence\": 0.5,\n",
+ " 'answer': [\n",
+ " {'name': 'first_checklist_answer', \"confidence\": 0.5},\n",
+ " {'name': 'second_checklist_answer', \"confidence\": 0.5},\n",
+ " {'name': 'third_checklist_answer', \"confidence\": 0.5},\n",
+ " ]\n",
+ "}"
+ ],
+ "metadata": {
+ "id": "hIkLI1q7glMi"
+ },
+ "execution_count": 11,
+ "outputs": []
+ },
+ {
+ "cell_type": "markdown",
+ "source": [
+ "## Step 1: Import data rows into Catalog"
+ ],
+ "metadata": {
+ "id": "U-o15yu9IPDo"
+ }
+ },
+ {
+ "cell_type": "code",
+ "source": [
+ "top_left_bound = lb_types.Point(x=-122.31764674186705, y=37.87276155898985)\n",
+ "bottom_right_bound = lb_types.Point(x=-122.31635199317932, y=37.87398109727749)\n",
+ "\n",
+ "epsg = EPSG.EPSG4326\n",
+ "bounds = TiledBounds(epsg=epsg, bounds=[top_left_bound, bottom_right_bound])\n",
+ "\n",
+ "tile_layer = TileLayer(\n",
+ " url=\"https://api.mapbox.com/styles/v1/mapbox/satellite-streets-v11/tiles/{z}/{x}/{y}?access_token=pk.eyJ1IjoibWFwYm94IiwiYSI6ImNpejY4NXVycTA2emYycXBndHRqcmZ3N3gifQ.rJcFIG214AriISLbB6B5aw\"\n",
+ ")\n",
+ "\n",
+ "tiled_image_data = TiledImageData(tile_layer=tile_layer,\n",
+ " tile_bounds=bounds,\n",
+ " zoom_levels=[17, 23])\n",
+ "\n",
+ "asset = {\n",
+ " \"row_data\": tiled_image_data.asdict(),\n",
+ " \"global_key\": str(uuid.uuid4()),\n",
+ " \"media_type\": \"TMS_GEO\"\n",
+ "}\n",
+ "\n",
+ "dataset = client.create_dataset(name=\"geo_demo_dataset\")\n",
+ "data_row = dataset.create_data_row(asset)\n",
+ "print(data_row)"
+ ],
+ "metadata": {
+ "id": "HjH9gTV8IBG9",
+ "colab": {
+ "base_uri": "https://localhost:8080/"
+ },
+ "outputId": "29abe6b9-b699-4f47-8dc1-0702df392fee"
+ },
+ "execution_count": 14,
+ "outputs": [
+ {
+ "output_type": "stream",
+ "name": "stdout",
+ "text": [
+ "\n"
+ ]
+ }
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "source": [
+ "## Step 2: Create/select an Ontology for your model predictions\n",
+ "Your project should have the correct ontology setup with all the tools and classifications supported for your annotations, and the tool names and classification instructions should match the name/instructions fields in your annotations to ensure the correct feature schemas are matched.\n"
+ ],
+ "metadata": {
+ "id": "oy0umzuNIceP"
+ }
+ },
+ {
+ "cell_type": "code",
+ "source": [
+ "ontology_builder = lb.OntologyBuilder(\n",
+ " tools=[\n",
+ " lb.Tool(tool=lb.Tool.Type.POINT, name=\"point_geo\"),\n",
+ " lb.Tool(tool=lb.Tool.Type.LINE, name=\"polyline_geo\"),\n",
+ " lb.Tool(tool=lb.Tool.Type.POLYGON, name=\"polygon_geo\"),\n",
+ " lb.Tool(tool=lb.Tool.Type.POLYGON, name=\"polygon_geo_2\"),\n",
+ " lb.Tool(tool=lb.Tool.Type.BBOX, name=\"bbox_geo\"), \n",
+ " lb.Tool( \n",
+ " tool=lb.Tool.Type.BBOX, \n",
+ " name=\"bbox_checklist_geo\",\n",
+ " classifications=[\n",
+ " lb.Classification(\n",
+ " class_type=lb.Classification.Type.CHECKLIST,\n",
+ " instructions=\"checklist_class_name\",\n",
+ " options=[\n",
+ " lb.Option(value=\"first_checklist_answer\")\n",
+ " ]\n",
+ " ),\n",
+ " ]\n",
+ " ),\n",
+ " lb.Tool( \n",
+ " tool=lb.Tool.Type.BBOX, \n",
+ " name=\"bbox_text_geo\",\n",
+ " classifications=[\n",
+ " lb.Classification(\n",
+ " class_type=lb.Classification.Type.TEXT,\n",
+ " instructions=\"free_text_geo\"\n",
+ " ),\n",
+ " ]\n",
+ " ) \n",
+ " ],\n",
+ " classifications = [\n",
+ " lb.Classification(\n",
+ " class_type=lb.Classification.Type.CHECKLIST, \n",
+ " instructions=\"checklist_question_geo\",\n",
+ " options=[\n",
+ " lb.Option(value=\"first_checklist_answer\"),\n",
+ " lb.Option(value=\"second_checklist_answer\"), \n",
+ " lb.Option(value=\"third_checklist_answer\")\n",
+ " ]\n",
+ " ), \n",
+ " lb.Classification(\n",
+ " class_type=lb.Classification.Type.RADIO, \n",
+ " instructions=\"radio_question_geo\",\n",
+ " options=[\n",
+ " lb.Option(value=\"first_radio_answer\")\n",
+ " ]\n",
+ " )\n",
+ " \n",
+ " ]\n",
+ ")\n",
+ "\n",
+ "ontology = client.create_ontology(\"Ontology Geospatial Annotations\", ontology_builder.asdict())"
+ ],
+ "metadata": {
+ "id": "Kt4XWWqgIiWk"
+ },
+ "execution_count": 16,
+ "outputs": []
+ },
+ {
+ "cell_type": "markdown",
+ "source": [
+ "## Step 3: Create a Model and Model Run"
+ ],
+ "metadata": {
+ "id": "ZjN8jxHvIvHP"
+ }
+ },
+ {
+ "cell_type": "code",
+ "source": [
+ "# create Model\n",
+ "model = client.create_model(name=\"geospatial_model_run_\" + str(uuid.uuid4()), \n",
+ " ontology_id=ontology.uid)\n",
+ "# create Model Run\n",
+ "model_run = model.create_model_run(\"iteration 1\")"
+ ],
+ "metadata": {
+ "id": "8n-AvzdiOR6d"
+ },
+ "execution_count": 17,
+ "outputs": []
+ },
+ {
+ "cell_type": "markdown",
+ "source": [
+ "## Step 4: Send data rows to the Model Run"
+ ],
+ "metadata": {
+ "id": "NX6L0axRJN5J"
+ }
+ },
+ {
+ "cell_type": "code",
+ "source": [
+ "model_run.upsert_data_rows([data_row.uid])"
+ ],
+ "metadata": {
+ "id": "6sngCgIwJSae",
+ "colab": {
+ "base_uri": "https://localhost:8080/"
+ },
+ "outputId": "6a1f9ed0-9f77-4ceb-f463-fa9e4b34f6ba"
+ },
+ "execution_count": 18,
+ "outputs": [
+ {
+ "output_type": "execute_result",
+ "data": {
+ "text/plain": [
+ "True"
+ ]
+ },
+ "metadata": {},
+ "execution_count": 18
+ }
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "source": [
+ "## Step 5. Create the predictions payload\n",
+ "\n",
+ "Create the annotations payload using the snippets in the **Supported Predictions Section**. \n",
+ "\n",
+ "The resulting label_ndjson should have exactly the same content for annotations that are supported by both (with exception of the uuid strings that are generated)"
+ ],
+ "metadata": {
+ "id": "6FZyvnrqSGuc"
+ }
+ },
+ {
+ "cell_type": "code",
+ "source": [
+ " ## Lets create another polygon annotation with python annotation tools that draws the image using cv2 and PIL python libraries\n",
+ "\n",
+ "hsv = cv2.cvtColor(tiled_image_data.value, cv2.COLOR_RGB2HSV)\n",
+ "mask = cv2.inRange(hsv, (10, 25, 25), (100, 150, 255))\n",
+ "kernel = np.ones((15, 20), np.uint8)\n",
+ "mask = cv2.erode(mask, kernel)\n",
+ "mask = cv2.dilate(mask, kernel)\n",
+ "mask_annotation = lb_types.MaskData.from_2D_arr(mask)\n",
+ "mask_data = lb_types.Mask(mask=mask_annotation, color=[255, 255, 255])\n",
+ "h, w, _ = tiled_image_data.value.shape\n",
+ "pixel_bounds = TiledBounds(epsg=EPSG.SIMPLEPIXEL,\n",
+ " bounds=[lb_types.Point(x=0, y=0),\n",
+ " lb_types.Point(x=w, y=h)])\n",
+ "transformer = EPSGTransformer.create_pixel_to_geo_transformer(\n",
+ " src_epsg=pixel_bounds.epsg,\n",
+ " pixel_bounds=pixel_bounds,\n",
+ " geo_bounds=tiled_image_data.tile_bounds,\n",
+ " zoom=23)\n",
+ "pixel_polygons = mask_data.shapely.simplify(3)\n",
+ "list_of_polygons = [transformer(lb_types.Polygon.from_shapely(p)) for p in pixel_polygons.geoms]\n",
+ "polygon_prediction_two = lb_types.ObjectAnnotation(value=list_of_polygons[0], name=\"polygon_geo_2\", confidence=0.5)\n",
+ "\n",
+ "\n",
+ "# Here is the NDJSON representation of the resulting polygon:\n",
+ "polygon_prediction_two_ndjson = {\n",
+ " \"name\": \"polygon_geo_2\",\n",
+ " \"confidence\": 0.5,\n",
+ " \"polygon\": [\n",
+ " {'x': -122.31703039689702, 'y': 37.87397804081582},\n",
+ " {'x': -122.31702351036107, 'y': 37.87393525033866},\n",
+ " {'x': -122.31698907768116, 'y': 37.87389857276706},\n",
+ " {'x': -122.3169787478772, 'y': 37.87385883871054},\n",
+ " {'x': -122.31695808826926, 'y': 37.87385578224377},\n",
+ " {'x': -122.31695464500127, 'y': 37.873816048164166},\n",
+ " {'x': -122.31692021232138, 'y': 37.873779370533214},\n",
+ " {'x': -122.31690988251741, 'y': 37.87373352346883},\n",
+ " {'x': -122.3168857796415, 'y': 37.873696845796786},\n",
+ " {'x': -122.3168547902296, 'y': 37.873684619902065},\n",
+ " {'x': -122.31682035754969, 'y': 37.873611264491025},\n",
+ " {'x': -122.31676526526188, 'y': 37.87355013492598},\n",
+ " {'x': -122.3167583787259, 'y': 37.87351651364362},\n",
+ " {'x': -122.31671017297403, 'y': 37.87348900531027},\n",
+ " {'x': -122.31671017297403, 'y': 37.873452327516496},\n",
+ " {'x': -122.31667918356217, 'y': 37.87344010158117},\n",
+ " {'x': -122.31663442107829, 'y': 37.87335451997715},\n",
+ " {'x': -122.31660343166638, 'y': 37.87334840700161},\n",
+ " {'x': -122.31659998839841, 'y': 37.873320898605485},\n",
+ " {'x': -122.31654489611057, 'y': 37.87329033370888},\n",
+ " {'x': -122.31652767977064, 'y': 37.87319863894286},\n",
+ " {'x': -122.31648980382273, 'y': 37.8731833564708},\n",
+ " {'x': -122.31648980382273, 'y': 37.873161961004534},\n",
+ " {'x': -122.31641749519497, 'y': 37.87309166157168},\n",
+ " {'x': -122.316410608659, 'y': 37.873054983580076},\n",
+ " {'x': -122.31639683558704, 'y': 37.873039701078184},\n",
+ " {'x': -122.31635551637117, 'y': 37.873039701078184},\n",
+ " {'x': -122.31635551637117, 'y': 37.87398109727749},\n",
+ " {'x': -122.31703039689702, 'y': 37.87397804081582}\n",
+ " ]\n",
+ "}"
+ ],
+ "metadata": {
+ "colab": {
+ "base_uri": "https://localhost:8080/"
+ },
+ "id": "dr1dEPzM_tHW",
+ "outputId": "e367b87f-f8cb-4f2f-f74e-5df5aaf60efa"
+ },
+ "execution_count": 34,
+ "outputs": [
+ {
+ "output_type": "stream",
+ "name": "stderr",
+ "text": [
+ "WARNING:labelbox.data.annotation_types.data.tiled_image:Unexpected tile size (512, 512, 3).\n",
+ "WARNING:labelbox.data.annotation_types.data.tiled_image:Unexpected tile size (512, 512, 3).\n"
+ ]
+ }
+ ]
+ },
+ {
+ "cell_type": "code",
+ "source": [
+ "\n",
+ "tiled_image_data_row_id = next(dataset.export_data_rows()).uid\n",
+ "\n",
+ "label = lb_types.Label(\n",
+ " data=TiledImageData(\n",
+ " uid=tiled_image_data_row_id ,\n",
+ " tile_layer=tile_layer,\n",
+ " tile_bounds=bounds,\n",
+ " zoom_levels=[17, 23]\n",
+ " ),\n",
+ " annotations = [\n",
+ " point_prediction,\n",
+ " polyline_prediction,\n",
+ " polygon_prediction,\n",
+ " bbox_prediction,\n",
+ " radio_prediction,\n",
+ " bbox_with_checklist_subclass, \n",
+ " bbox_with_free_text_subclass,\n",
+ " checklist_prediction,\n",
+ " polygon_prediction_two\n",
+ " ]\n",
+ ")\n",
+ "# Convert our label from a Labelbox class object to the underlying NDJSON format required for upload \n",
+ "label_ndjson = list(NDJsonConverter.serialize([label]))\n",
+ "label_ndjson"
+ ],
+ "metadata": {
+ "id": "F-Y7sSyAV3tn",
+ "colab": {
+ "base_uri": "https://localhost:8080/"
+ },
+ "outputId": "a3da2fa9-3611-436d-91f2-b26dbffb133d"
+ },
+ "execution_count": 24,
+ "outputs": [
+ {
+ "output_type": "execute_result",
+ "data": {
+ "text/plain": [
+ "[{'confidence': 0.5,\n",
+ " 'uuid': '9fcc2949-4636-43de-8574-12088b71b480',\n",
+ " 'dataRow': {'id': 'cldnb9fqj02rz07284krw8s8e'},\n",
+ " 'name': 'point_geo',\n",
+ " 'classifications': [],\n",
+ " 'point': {'x': -122.31741025134123, 'y': 37.87355669249922}},\n",
+ " {'confidence': 0.5,\n",
+ " 'uuid': 'ddf8a5c9-c01e-4236-840a-c2c699b5b51f',\n",
+ " 'dataRow': {'id': 'cldnb9fqj02rz07284krw8s8e'},\n",
+ " 'name': 'polyline_geo',\n",
+ " 'classifications': [],\n",
+ " 'line': [{'x': -122.31757789012927, 'y': 37.87396317833991},\n",
+ " {'x': -122.31639782443663, 'y': 37.87396741226917},\n",
+ " {'x': -122.31638977853417, 'y': 37.87277872707839}]},\n",
+ " {'confidence': 0.5,\n",
+ " 'uuid': 'b0a101bd-e376-4c27-87cd-24460ae32c13',\n",
+ " 'dataRow': {'id': 'cldnb9fqj02rz07284krw8s8e'},\n",
+ " 'name': 'polygon_geo',\n",
+ " 'classifications': [],\n",
+ " 'polygon': [{'x': -122.31691812612837, 'y': 37.873289980495024},\n",
+ " {'x': -122.31710184090099, 'y': 37.87304335144298},\n",
+ " {'x': -122.31680146054286, 'y': 37.87303594197371},\n",
+ " {'x': -122.31691812612837, 'y': 37.873289980495024}]},\n",
+ " {'confidence': 0.5,\n",
+ " 'uuid': '5f79cb0d-b48b-4f2f-9532-72db6805fa1e',\n",
+ " 'dataRow': {'id': 'cldnb9fqj02rz07284krw8s8e'},\n",
+ " 'name': 'bbox_geo',\n",
+ " 'classifications': [],\n",
+ " 'bbox': {'top': 37.873713376083884,\n",
+ " 'left': -122.31734455895823,\n",
+ " 'height': 0.0001460709135656657,\n",
+ " 'width': 0.0006141705536464315}},\n",
+ " {'name': 'radio_question_geo',\n",
+ " 'answer': {'name': 'first_radio_answer'},\n",
+ " 'uuid': '912917fa-5c99-4c3b-981e-1825155ff8db',\n",
+ " 'dataRow': {'id': 'cldnb9fqj02rz07284krw8s8e'}},\n",
+ " {'confidence': 0.5,\n",
+ " 'uuid': '553377cb-9347-45ca-b8b9-c6ddcd145a0a',\n",
+ " 'dataRow': {'id': 'cldnb9fqj02rz07284krw8s8e'},\n",
+ " 'name': 'bbox_checklist_geo',\n",
+ " 'classifications': [{'name': 'checklist_class_name',\n",
+ " 'answer': [{'confidence': 0.5, 'name': 'first_checklist_answer'}]}],\n",
+ " 'bbox': {'top': 37.87340218056304,\n",
+ " 'left': -122.31711256877092,\n",
+ " 'height': 0.00020534685175022105,\n",
+ " 'width': 0.0004572754559006853}},\n",
+ " {'uuid': '67f9337f-61dd-4488-bbc2-fb45b6a85cff',\n",
+ " 'dataRow': {'id': 'cldnb9fqj02rz07284krw8s8e'},\n",
+ " 'name': 'bbox_text_geo',\n",
+ " 'classifications': [{'name': 'free_text_geo', 'answer': 'sample text'}],\n",
+ " 'bbox': {'top': 37.87318201423049,\n",
+ " 'left': -122.31750814315438,\n",
+ " 'height': 0.00019791053033202388,\n",
+ " 'width': 0.00040764323713915473}},\n",
+ " {'name': 'checklist_question_geo',\n",
+ " 'uuid': 'dfab5e8a-a290-4809-a87d-9b4288ddb7cd',\n",
+ " 'dataRow': {'id': 'cldnb9fqj02rz07284krw8s8e'},\n",
+ " 'answer': [{'confidence': 0.5, 'name': 'first_checklist_answer'},\n",
+ " {'confidence': 0.5, 'name': 'second_checklist_answer'},\n",
+ " {'confidence': 0.5, 'name': 'third_checklist_answer'}]},\n",
+ " {'confidence': 0.5,\n",
+ " 'uuid': 'ba93e801-b49c-45ac-bd94-df2f8d94cb1d',\n",
+ " 'dataRow': {'id': 'cldnb9fqj02rz07284krw8s8e'},\n",
+ " 'name': 'polygon_geo',\n",
+ " 'classifications': [],\n",
+ " 'polygon': [{'x': -122.31703039689702, 'y': 37.87397804081582},\n",
+ " {'x': -122.31702351036107, 'y': 37.87393525033866},\n",
+ " {'x': -122.31698907768116, 'y': 37.87389857276706},\n",
+ " {'x': -122.3169787478772, 'y': 37.87385883871054},\n",
+ " {'x': -122.31695808826926, 'y': 37.87385578224377},\n",
+ " {'x': -122.31695464500127, 'y': 37.873816048164166},\n",
+ " {'x': -122.31692021232138, 'y': 37.873779370533214},\n",
+ " {'x': -122.31690988251741, 'y': 37.87373352346883},\n",
+ " {'x': -122.3168857796415, 'y': 37.873696845796786},\n",
+ " {'x': -122.3168547902296, 'y': 37.873684619902065},\n",
+ " {'x': -122.31682035754969, 'y': 37.873611264491025},\n",
+ " {'x': -122.31676526526188, 'y': 37.87355013492598},\n",
+ " {'x': -122.3167583787259, 'y': 37.87351651364362},\n",
+ " {'x': -122.31671017297403, 'y': 37.87348900531027},\n",
+ " {'x': -122.31671017297403, 'y': 37.873452327516496},\n",
+ " {'x': -122.31667918356217, 'y': 37.87344010158117},\n",
+ " {'x': -122.31663442107829, 'y': 37.87335451997715},\n",
+ " {'x': -122.31660343166638, 'y': 37.87334840700161},\n",
+ " {'x': -122.31659998839841, 'y': 37.873320898605485},\n",
+ " {'x': -122.31654489611057, 'y': 37.87329033370888},\n",
+ " {'x': -122.31652767977064, 'y': 37.87319863894286},\n",
+ " {'x': -122.31648980382273, 'y': 37.8731833564708},\n",
+ " {'x': -122.31648980382273, 'y': 37.873161961004534},\n",
+ " {'x': -122.31641749519497, 'y': 37.87309166157168},\n",
+ " {'x': -122.316410608659, 'y': 37.873054983580076},\n",
+ " {'x': -122.31639683558704, 'y': 37.873039701078184},\n",
+ " {'x': -122.31635551637117, 'y': 37.873039701078184},\n",
+ " {'x': -122.31635551637117, 'y': 37.87398109727749},\n",
+ " {'x': -122.31703039689702, 'y': 37.87397804081582}]}]"
+ ]
+ },
+ "metadata": {},
+ "execution_count": 24
+ }
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "source": [
+ "# If using NDJSON"
+ ],
+ "metadata": {
+ "id": "dXRQbo4co8Vh"
+ }
+ },
+ {
+ "cell_type": "code",
+ "source": [
+ "label_ndjson_method_2 = []\n",
+ "for prediction in [\n",
+ " radio_prediction_ndjson,\n",
+ " checklist_prediction_ndjson,\n",
+ " bbox_with_free_text_subclass_ndjson, \n",
+ " bbox_with_checklist_subclass_ndjson,\n",
+ " bbox_prediction_ndjson,\n",
+ " point_prediction_ndjson,\n",
+ " polyline_prediction_ndjson, \n",
+ " polygon_prediction_ndjson,\n",
+ " polygon_prediction_two_ndjson\n",
+ "]:\n",
+ " prediction.update({\n",
+ " 'uuid': str(uuid.uuid4()),\n",
+ " 'dataRow': {'id': data_row.uid},\n",
+ " })\n",
+ " label_ndjson_method_2.append(prediction)"
+ ],
+ "metadata": {
+ "id": "mwu3iXn-oofV"
+ },
+ "execution_count": 26,
+ "outputs": []
+ },
+ {
+ "cell_type": "markdown",
+ "source": [
+ "## Step 6. Upload the predictions payload to the Model Run "
+ ],
+ "metadata": {
+ "id": "viFHCnBeTD1Y"
+ }
+ },
+ {
+ "cell_type": "code",
+ "source": [
+ "# Upload the prediction label to the Model Run\n",
+ "upload_job_prediction = model_run.add_predictions(\n",
+ " name=\"prediction_upload_job\"+str(uuid.uuid4()),\n",
+ " predictions=label_ndjson)\n",
+ "\n",
+ "# Errors will appear for annotation uploads that failed.\n",
+ "print(\"Errors:\", upload_job_prediction.errors)"
+ ],
+ "metadata": {
+ "id": "uCI8pLTITQNG",
+ "colab": {
+ "base_uri": "https://localhost:8080/"
+ },
+ "outputId": "90720cd6-4fa0-4d3b-c36d-14f3b3e1c072"
+ },
+ "execution_count": 25,
+ "outputs": [
+ {
+ "output_type": "stream",
+ "name": "stdout",
+ "text": [
+ "Errors: []\n"
+ ]
+ }
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "source": [
+ "## Step 7: Send annotations to the Model Run \n",
+ "To send annotations to a Model Run, we must first import them into a project, create a label payload and then send them to the Model Run."
+ ],
+ "metadata": {
+ "id": "T-ZHWWI3JgmX"
+ }
+ },
+ {
+ "cell_type": "markdown",
+ "source": [
+ "##### 7.1. Create a labelbox project"
+ ],
+ "metadata": {
+ "id": "CYRiqHr2O_aL"
+ }
+ },
+ {
+ "cell_type": "code",
+ "source": [
+ "# Create a Labelbox project\n",
+ "project = client.create_project(name=\"geospatial_prediction_demo\", \n",
+ " queue_mode=lb_queue_mode.QueueMode.Batch,\n",
+ " # Quality Settings setup \n",
+ " auto_audit_percentage=1,\n",
+ " auto_audit_number_of_labels=1,\n",
+ " media_type=lb.MediaType.Geospatial_Tile)\n",
+ "project.setup_editor(ontology)"
+ ],
+ "metadata": {
+ "id": "jEtoDiDrPFvI"
+ },
+ "execution_count": 27,
+ "outputs": []
+ },
+ {
+ "cell_type": "markdown",
+ "source": [
+ "##### 7.2. Create a batch to send to the project "
+ ],
+ "metadata": {
+ "id": "7FEyC-nBPPuD"
+ }
+ },
+ {
+ "cell_type": "code",
+ "source": [
+ "project.create_batch(\n",
+ " \"batch_geospatial_prediction_demo\", # Each batch in a project must have a unique name\n",
+ " dataset.export_data_rows(), # A list of data rows or data row ids\n",
+ " 5 # priority between 1(Highest) - 5(lowest)\n",
+ ")"
+ ],
+ "metadata": {
+ "id": "WRr5tdVEPXXy",
+ "colab": {
+ "base_uri": "https://localhost:8080/"
+ },
+ "outputId": "fee3c579-b151-4b29-d016-244ac976a072"
+ },
+ "execution_count": 28,
+ "outputs": [
+ {
+ "output_type": "execute_result",
+ "data": {
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "execution_count": 28
+ }
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "source": [
+ "##### 7.3 Create the annotations payload"
+ ],
+ "metadata": {
+ "id": "FTGAI730UlZ3"
+ }
+ },
+ {
+ "cell_type": "code",
+ "source": [
+ "####### Point #######\n",
+ "\n",
+ "point_annotation_ndjson = {\n",
+ " \"name\": \"point_geo\",\n",
+ " \"point\": {\n",
+ " \"x\": -122.31741025134123,\n",
+ " \"y\": 37.87355669249922\n",
+ " }\n",
+ "}\n",
+ "\n",
+ "####### Polyline #######\n",
+ "# Coordinates\n",
+ "coords = [ \n",
+ " [\n",
+ " -122.31757789012927,\n",
+ " 37.87396317833991\n",
+ " ],\n",
+ " [\n",
+ " -122.31639782443663,\n",
+ " 37.87396741226917\n",
+ " ],\n",
+ " [\n",
+ " -122.31638977853417,\n",
+ " 37.87277872707839\n",
+ " ]\n",
+ " ]\n",
+ "\n",
+ "line_points_ndjson = []\n",
+ "\n",
+ "for sub in coords: \n",
+ " line_points_ndjson.append({\"x\":sub[0], \"y\":sub[1]})\n",
+ "\n",
+ "\n",
+ "polyline_annotation_ndjson = {\n",
+ " \"name\": \"polyline_geo\",\n",
+ " \"line\": line_points_ndjson\n",
+ "}\n",
+ "\n",
+ "####### Polygon #######\n",
+ "# Coordinates in the desired EPSG coordinate system\n",
+ "coords_polygon = [\n",
+ " [\n",
+ " -122.31691812612837,\n",
+ " 37.873289980495024\n",
+ " ],\n",
+ " [\n",
+ " -122.31710184090099,\n",
+ " 37.87304335144298\n",
+ " ],\n",
+ " [\n",
+ " -122.31680146054286,\n",
+ " 37.87303594197371\n",
+ " ],\n",
+ " [\n",
+ " -122.31691812612837,\n",
+ " 37.873289980495024\n",
+ " ]\n",
+ "]\n",
+ "\n",
+ "polygon_points_ndjson = []\n",
+ "\n",
+ "for sub in coords_polygon: \n",
+ " polygon_points_ndjson.append({\"x\":sub[0], \"y\":sub[1]})\n",
+ "\n",
+ "polygon_annotation_ndjson = {\n",
+ " \"name\": \"polygon_geo\",\n",
+ " \"polygon\": polygon_points_ndjson\n",
+ "}\n",
+ "\n",
+ "polygon_annotation_two_ndjson = {\n",
+ " \"name\": \"polygon_geo\",\n",
+ " \"polygon\": [\n",
+ " {'x': -122.31703039689702, 'y': 37.87397804081582},\n",
+ " {'x': -122.31702351036107, 'y': 37.87393525033866},\n",
+ " {'x': -122.31698907768116, 'y': 37.87389857276706},\n",
+ " {'x': -122.3169787478772, 'y': 37.87385883871054},\n",
+ " {'x': -122.31695808826926, 'y': 37.87385578224377},\n",
+ " {'x': -122.31695464500127, 'y': 37.873816048164166},\n",
+ " {'x': -122.31692021232138, 'y': 37.873779370533214},\n",
+ " {'x': -122.31690988251741, 'y': 37.87373352346883},\n",
+ " {'x': -122.3168857796415, 'y': 37.873696845796786},\n",
+ " {'x': -122.3168547902296, 'y': 37.873684619902065},\n",
+ " {'x': -122.31682035754969, 'y': 37.873611264491025},\n",
+ " {'x': -122.31676526526188, 'y': 37.87355013492598},\n",
+ " {'x': -122.3167583787259, 'y': 37.87351651364362},\n",
+ " {'x': -122.31671017297403, 'y': 37.87348900531027},\n",
+ " {'x': -122.31671017297403, 'y': 37.873452327516496},\n",
+ " {'x': -122.31667918356217, 'y': 37.87344010158117},\n",
+ " {'x': -122.31663442107829, 'y': 37.87335451997715},\n",
+ " {'x': -122.31660343166638, 'y': 37.87334840700161},\n",
+ " {'x': -122.31659998839841, 'y': 37.873320898605485},\n",
+ " {'x': -122.31654489611057, 'y': 37.87329033370888},\n",
+ " {'x': -122.31652767977064, 'y': 37.87319863894286},\n",
+ " {'x': -122.31648980382273, 'y': 37.8731833564708},\n",
+ " {'x': -122.31648980382273, 'y': 37.873161961004534},\n",
+ " {'x': -122.31641749519497, 'y': 37.87309166157168},\n",
+ " {'x': -122.316410608659, 'y': 37.873054983580076},\n",
+ " {'x': -122.31639683558704, 'y': 37.873039701078184},\n",
+ " {'x': -122.31635551637117, 'y': 37.873039701078184},\n",
+ " {'x': -122.31635551637117, 'y': 37.87398109727749},\n",
+ " {'x': -122.31703039689702, 'y': 37.87397804081582}\n",
+ " ]\n",
+ "}\n",
+ "\n",
+ "####### Bounding Box #######\n",
+ "coord_object = {\n",
+ " \"coordinates\": [\n",
+ " [\n",
+ " [\n",
+ " -122.31734455895823,\n",
+ " 37.873713376083884\n",
+ " ],\n",
+ " [\n",
+ " -122.31734455895823,\n",
+ " 37.87385944699745\n",
+ " ],\n",
+ " [\n",
+ " -122.31673038840458,\n",
+ " 37.87385944699745\n",
+ " ],\n",
+ " [\n",
+ " -122.31673038840458,\n",
+ " 37.873713376083884\n",
+ " ],\n",
+ " [\n",
+ " -122.31734455895823,\n",
+ " 37.873713376083884\n",
+ " ]\n",
+ " ]\n",
+ " ] \n",
+ " }\n",
+ "\n",
+ "\n",
+ "bbox_top_left = lb_types.Point(x=-122.31734455895823, y=37.873713376083884)\n",
+ "bbox_bottom_right = lb_types.Point(x=-122.31673038840458, y=37.87385944699745)\n",
+ "\n",
+ "bbox_annotation_ndjson = {\n",
+ " \"name\" : \"bbox_geo\",\n",
+ " \"bbox\" : {\n",
+ " 'top': coord_object[\"coordinates\"][0][1][1],\n",
+ " 'left': coord_object[\"coordinates\"][0][1][0],\n",
+ " 'height': coord_object[\"coordinates\"][0][3][1] - coord_object[\"coordinates\"][0][1][1], \n",
+ " 'width': coord_object[\"coordinates\"][0][3][0] - coord_object[\"coordinates\"][0][1][0]\n",
+ " }\n",
+ "}\n",
+ "\n",
+ "####### Classification - radio (single choice) #######\n",
+ "\n",
+ "radio_annotation_ndjson = {\n",
+ " \"name\": \"radio_question_geo\",\n",
+ " \"answer\": { \"name\": \"first_radio_answer\"}\n",
+ "}\n",
+ "\n",
+ "####### Classification - Checklist (multi-choice) #######\n",
+ "\n",
+ "coord_object_checklist = {\n",
+ " \"coordinates\": [\n",
+ " [\n",
+ " [\n",
+ " -122.31711256877092,\n",
+ " 37.87340218056304\n",
+ " ],\n",
+ " [\n",
+ " -122.31711256877092,\n",
+ " 37.87360752741479\n",
+ " ],\n",
+ " [\n",
+ " -122.31665529331502,\n",
+ " 37.87360752741479\n",
+ " ],\n",
+ " [\n",
+ " -122.31665529331502,\n",
+ " 37.87340218056304\n",
+ " ],\n",
+ " [\n",
+ " -122.31711256877092,\n",
+ " 37.87340218056304\n",
+ " ]\n",
+ " ]\n",
+ " ] \n",
+ "}\n",
+ "\n",
+ "bbox_with_checklist_subclass_annotation_ndjson = {\n",
+ " \"name\": \"bbox_checklist_geo\", \n",
+ " \"classifications\": [{\n",
+ " \"name\": \"checklist_class_name\",\n",
+ " \"answer\": [\n",
+ " { \"name\":\"first_checklist_answer\", \"confidence\": 0.5 }\n",
+ " ] \n",
+ " }],\n",
+ " \"bbox\": {\n",
+ " 'top': coord_object_checklist[\"coordinates\"][0][1][1],\n",
+ " 'left': coord_object_checklist[\"coordinates\"][0][1][0],\n",
+ " 'height': coord_object_checklist[\"coordinates\"][0][3][1] - coord_object_checklist[\"coordinates\"][0][1][1], \n",
+ " 'width': coord_object_checklist[\"coordinates\"][0][3][0] - coord_object_checklist[\"coordinates\"][0][1][0]\n",
+ " }\n",
+ "}\n",
+ "\n",
+ "####### Classification free form text with bbox #######\n",
+ "\n",
+ "coord_object_text ={\n",
+ " \"coordinates\": [\n",
+ " [\n",
+ " [\n",
+ " -122.31750814315438,\n",
+ " 37.87318201423049\n",
+ " ],\n",
+ " [\n",
+ " -122.31750814315438,\n",
+ " 37.87337992476082\n",
+ " ],\n",
+ " [\n",
+ " -122.31710049991725,\n",
+ " 37.87337992476082\n",
+ " ],\n",
+ " [\n",
+ " -122.31710049991725,\n",
+ " 37.87318201423049\n",
+ " ],\n",
+ " [\n",
+ " -122.31750814315438,\n",
+ " 37.87318201423049\n",
+ " ]\n",
+ " ]\n",
+ " ]\n",
+ "}\n",
+ "\n",
+ "bbox_with_free_text_subclass_annotation_ndjson = {\n",
+ " \"name\":\"bbox_text_geo\",\n",
+ " \"classifications\": [{\n",
+ " \"name\": \"free_text_geo\",\n",
+ " \"answer\": \"sample text\"\n",
+ " }],\n",
+ " \"bbox\": {\n",
+ " 'top': coord_object_text[\"coordinates\"][0][1][1],\n",
+ " 'left': coord_object_text[\"coordinates\"][0][1][0],\n",
+ " 'height': coord_object_text[\"coordinates\"][0][3][1] - coord_object_text[\"coordinates\"][0][1][1], \n",
+ " 'width': coord_object_text[\"coordinates\"][0][3][0] - coord_object_text[\"coordinates\"][0][1][0]\n",
+ " }\n",
+ "}\n",
+ "\n",
+ "####### Classification - Checklist (multi-choice) #######\n",
+ "\n",
+ "checklist_annotation_ndjson = {\n",
+ " 'name': 'checklist_question_geo',\n",
+ " 'answer': [\n",
+ " {'name': 'first_checklist_answer', \"confidence\": 0.5},\n",
+ " {'name': 'second_checklist_answer', \"confidence\": 0.5},\n",
+ " {'name': 'third_checklist_answer', \"confidence\": 0.5},\n",
+ " ]\n",
+ "}"
+ ],
+ "metadata": {
+ "id": "Xykw7ZACqlRe"
+ },
+ "execution_count": 30,
+ "outputs": []
+ },
+ {
+ "cell_type": "markdown",
+ "source": [
+ "##### 7.4. Create the label object"
+ ],
+ "metadata": {
+ "id": "8QwmguFvPltl"
+ }
+ },
+ {
+ "cell_type": "code",
+ "source": [
+ "# Create a Label object by identifying the applicable data row in Labelbox and providing a list of annotations\n",
+ "ndjson_annotation = []\n",
+ "for annot in [\n",
+ " radio_annotation_ndjson,\n",
+ " checklist_annotation_ndjson,\n",
+ " bbox_with_free_text_subclass_annotation_ndjson, \n",
+ " bbox_with_checklist_subclass_annotation_ndjson,\n",
+ " bbox_annotation_ndjson,\n",
+ " point_annotation_ndjson,\n",
+ " polyline_annotation_ndjson, \n",
+ " polygon_annotation_ndjson,\n",
+ " polygon_annotation_two_ndjson\n",
+ "]:\n",
+ " annot.update({\n",
+ " 'uuid': str(uuid.uuid4()),\n",
+ " 'dataRow': {'id': data_row.uid},\n",
+ " })\n",
+ " ndjson_annotation.append(annot) "
+ ],
+ "metadata": {
+ "id": "9gD_alThQA3G"
+ },
+ "execution_count": 31,
+ "outputs": []
+ },
+ {
+ "cell_type": "markdown",
+ "source": [
+ "##### 7.5. Upload annotations to the project using Label Import"
+ ],
+ "metadata": {
+ "id": "nGVNQlvPQ-kF"
+ }
+ },
+ {
+ "cell_type": "code",
+ "source": [
+ "upload_job_annotation = lb.LabelImport.create_from_objects(\n",
+ " client = client,\n",
+ " project_id = project.uid,\n",
+ " name=\"geospatial_annotations_import_\" + str(uuid.uuid4()),\n",
+ " labels=ndjson_annotation)\n",
+ "\n",
+ "upload_job_annotation.wait_until_done()\n",
+ "# Errors will appear for annotation uploads that failed.\n",
+ "print(\"Errors:\", upload_job_annotation.errors)\n"
+ ],
+ "metadata": {
+ "id": "HYh9AzrlRYX-",
+ "colab": {
+ "base_uri": "https://localhost:8080/"
+ },
+ "outputId": "6e7dfa65-4e39-4bba-fbe9-762f4e138397"
+ },
+ "execution_count": 32,
+ "outputs": [
+ {
+ "output_type": "stream",
+ "name": "stderr",
+ "text": [
+ "WARNING:labelbox.schema.annotation_import:\n",
+ " Confidence scores are not supported in Label Import.\n",
+ " Corresponding confidence score values will be ignored.\n",
+ " \n"
+ ]
+ },
+ {
+ "output_type": "stream",
+ "name": "stdout",
+ "text": [
+ "Errors: []\n"
+ ]
+ }
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "source": [
+ "##### 7.6. Send the annotations to the Model Run"
+ ],
+ "metadata": {
+ "id": "Y3rgM-5cRrxM"
+ }
+ },
+ {
+ "cell_type": "code",
+ "source": [
+ "# get the labels id from the project\n",
+ "label_ids = [x['ID'] for x in project.export_labels(download=True)]\n",
+ "model_run.upsert_labels(label_ids)"
+ ],
+ "metadata": {
+ "id": "i2BrS8CcSBzo",
+ "colab": {
+ "base_uri": "https://localhost:8080/"
+ },
+ "outputId": "dcff45fd-7af5-4b24-87f9-5fe71ddc4cc7"
+ },
+ "execution_count": 33,
+ "outputs": [
+ {
+ "output_type": "execute_result",
+ "data": {
+ "text/plain": [
+ "True"
+ ]
+ },
+ "metadata": {},
+ "execution_count": 33
+ }
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "source": [
+ "## Optional deletions for cleanup \n"
+ ],
+ "metadata": {
+ "id": "DMtOfWWDWFbJ"
+ }
+ },
+ {
+ "cell_type": "code",
+ "source": [
+ "#upload_job\n",
+ "# project.delete()\n",
+ "# dataset.delete()"
+ ],
+ "metadata": {
+ "id": "aAhkyvJlWK1p"
+ },
+ "execution_count": null,
+ "outputs": []
+ }
+ ]
+}