Skip to content

Basic Usage

This page gives some common basic usage examples. For more detailed information, see the documentation for the SDKs and the REST reference.

Setup

If you have an existing Python environment set up, you can add fathom-global-client-sdk to your existing requirements.txt file and install as normal.

To create a new virtualenv to use the Fathom Python module, proceed with the following steps.

# ensure you have the right requirements
python3 -m ensurepip

# Go to your project directory
cd /path/to/working/dir/
# Create a virtualenv in the 'venv' folder and activate it
python3 -m venv venv
source venv/bin/activate

# Install the package from pypi into the virtualenv
pip3 install fathom-global-client-sdk

The suggested way to interact with the Fathom API on the command line is using curl.

Authentication

Authentication tokens are required for API requests.

The SDK performs the obtaining of tokens for the user when creating a Client object. Just use the access credentials supplied by Fathom.

from fathom.sdk.v2 import Client

client = Client(
    "client_id",
    "client_secret",
)

# Future requests will be authenticated

To access data from the REST API endpoints you will need to authorize requests using a JWT token in the Authorization header. To be able to do this, you must obtain a token from our authorization server using your supplied client_id and client_secret.

curl --request POST \
  --url https://api.fathom.global/v2/auth/token \
  --header 'content-type: application/json' \
  --data '{"client_id":"CLIENT_ID","client_secret":"CLIENT_SECRET"}'

You should obtain a response like:

{
  "access_token": "access_token",
  "expire_secs": 86400
}

When you have the Auth0 JWT token you will need to pass it as a header with every request to any of the Fathom API endpoints using the pattern:

Authorization: Bearer ACCESS_TOKEN

Data queries

Key Values

There are some integer values that are used to represent special cases in the data. These are:

Value Title Examples
-32768 No Data A point in the ocean or an inland point on a coastal layer
-32767 Permanent Water A point just offshore or in a river

Project ID metadata

In some cases you may require Fathom API queries to be billed as part of an internal project. The SDK allows you to attach a project ID as part of a query. These project IDs are stored in Fathom's usage database and will be used to itemise usage for billing purposes.

Methods to fetch data take an optional project_id keyword argument that will pass the project ID along:

project_id = "large-engineering-project"
client.geo.get_points(([pt]), layer_ids, project_id)

Add the project id in a "metadata" dictionary in the request body:

curl --location --request POST 'https://api.fathom.global/v2/points:data' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer ACCESS_TOKEN' \
--data-raw '{
    "metadata": {"project_id": "large-engineering-project"},
    "points": [
        ...
    ],
    "layer_ids": {
        ...
    }
  }'

Point queries

To obtain values at specified points:

pts = [
    point(lat=51.448765, lng=-2.601340),
    point(lat=39.628574, lng=-105.1162333)
]

layer_ids = [
    "US-1_3ARCSEC-00_OFFSET-1in1000-FLUVIAL-DEFENDED-DEPTH-2020-PERCENTILE50-v2.0.0",
    "GLOBAL-1ARCSEC-NW_OFFSET-1in1000-FLUVIAL-UNDEFENDED-DEPTH-2020-PERCENTILE50-v3.0",
    "GLOBAL-1ARCSEC-NW_OFFSET-1in100-FLUVIAL-UNDEFENDED-DEPTH-2020-PERCENTILE50-v3.0"
]

data = client.geo.get_points(pts, layer_ids)

To obtain values at specified points:

Request:

curl --location --request POST 'https://api.fathom.global/v2/points:data' \
  --header 'Content-Type: application/json' \
  --header 'Authorization: Bearer ACCESS_TOKEN' \
  --data-raw '{
    "points": [
      {
        "longitude": -2.601340,
        "latitude": 51.448765
      },
      {
        "longitude": -105.1162333,
        "latitude": 39.628574
      }
    ],
    "layer_ids": [
      "US-1_3ARCSEC-00_OFFSET-1in1000-FLUVIAL-DEFENDED-DEPTH-2020-PERCENTILE50-v2.0.0",
      "GLOBAL-1ARCSEC-NW_OFFSET-1in1000-FLUVIAL-UNDEFENDED-DEPTH-2020-PERCENTILE50-v3.0",
      "GLOBAL-1ARCSEC-NW_OFFSET-1in100-FLUVIAL-UNDEFENDED-DEPTH-2020-PERCENTILE50-v3.0"
    ]
  }'

Expected response:

{
  "results": {
    "US-1_3ARCSEC-00_OFFSET-1in1000-FLUVIAL-DEFENDED-DEPTH-2020-PERCENTILE50-v2.0.0": {
      "values": [
        {
          "query_point": {
            "longitude": -2.60134,
            "latitude": 51.448765
          },
          "val": -32768
        },
        {
          "query_point": {
            "longitude": -105.1162333,
            "latitude": 39.628574
          },
          "val": 0
        }
      ]
    },
    "GLOBAL-1ARCSEC-NW_OFFSET-1in1000-FLUVIAL-UNDEFENDED-DEPTH-2020-PERCENTILE50-v3.0": {
      ...
    }
  }
}

Polygon queries

  • Polygons may not contain holes.
  • Polygons can either be simple_polygon objects or shapefiles.
  • The polygon's points must be specified in counterclockwise order.
  • The first and last points must be the same.
  • Consecutive duplicate points are not supported.
  • Polygons that cross the antimeridian are not supported. To retrieve data for this area, create separate polygons on either side of the antimeridian

To obtain data within an area defined by a polygon object:

layer_ids = [
    "GLOBAL-1ARCSEC-NW_OFFSET-1in1000-FLUVIAL-UNDEFENDED-DEPTH-2020-PERCENTILE50-v3.0",
    "US-1_3ARCSEC-00_OFFSET-1in1000-FLUVIAL-DEFENDED-DEPTH-2020-PERCENTILE50-v2.0.0"
]

poly = polygon(
    [
        point(51.45, 0),
        point(51.55, 0),
        point(51.55, -0.1),
        point(51.45, -0.1),
        point(51.45, 0),
    ]
)

results = client.geo.get_polygon(poly, layer_ids).results

# we return one tif per layer, this example saves the tif for each layer using the layer ID as the filename
for layer_id, data in results.items():
    f = open(layer_id+".tif", "wb")
    f.write(data.geo_tiff)
    f.close()

Request:

curl --location --request POST 'https://api.fathom.global/v2/polygon:data' \
  --header 'Content-Type: application/json' \
  --header 'Authorization: Bearer ACCESS_TOKEN' \
  --data-raw '{
    "layer_ids": [
      "GLOBAL-1ARCSEC-NW_OFFSET-1in1000-PLUVIAL-DEFENDED-DEPTH-2020-PERCENTILE50-v3.0"
    ],
    "polygon": {
      "points": [
        {
          "latitude": 51.45,
          "longitude": 0
        },
        {
          "latitude": 51.55,
          "longitude": 0
        },
        {
          "latitude": 51.55,
          "longitude": -0.1
        },
        {
          "latitude": 51.45,
          "longitude": -0.1
        },
        {
          "latitude": 51.45,
          "longitude": 0
        }
      ]
    }
  }'

Response:

{
  "results": {
    "GLOBAL-1ARCSEC-NW_OFFSET-1in100-PLUVIAL-DEFENDED-DEPTH-2020-PERCENTILE50-v3.0": {
      "geo_tiff": "SUkqAAgAAAASAA..."
    }
  }
}

The geo_tiff element is a raw GeoTIFF file encoded as a base64-URL-encoded string. To write this to a file, first decode the base64 string then save the result to a file with a .tiff or .tif extension. An example for doing this in python is as follows:

encoded_string = response['results']['GLOBAL-1ARCSEC-NW_OFFSET-1in100-PLUVIAL-DEFENDED-DEPTH-2020-PERCENTILE50-v3.0']['geo_tiff']
encoded_bytes = encoded_string.encode('ascii')

decoded = base64.decodebytes(encoded_bytes)

with open(output_file_path, 'wb') as output_file:
    output_file.write(decoded)

Polygon stats queries

Allows fetching statistical data about a polygonal area. We currently return:

  • Mean
  • Max
  • Min
  • Standard Deviation

Polygons submitted to the polygon stats endpoint must follow the same rules as polygon queries.

poly = polygon(
    [
        point(52.41, -1.52),
        point(52.4, -1.52),
        point(52.4, -1.5),
        point(52.41, -1.5),
        point(52.41, -1.52),
    ]
)

layer_ids = [
    "US-1_3ARCSEC-00_OFFSET-1in1000-FLUVIAL-DEFENDED-DEPTH-2020-PERCENTILE50-v2.0.0",
    "GLOBAL-1ARCSEC-NW_OFFSET-1in1000-FLUVIAL-UNDEFENDED-DEPTH-2020-PERCENTILE50-v3.0",
    "GLOBAL-1ARCSEC-NW_OFFSET-1in100-FLUVIAL-UNDEFENDED-DEPTH-2020-PERCENTILE50-v3.0"
]

data = client.geo.get_polygon_stats(poly, layer_ids)

Request:

curl --location --request POST 'https://api.fathom.global/v2/polygon:stats' \
  --header 'Content-Type: application/json' \
  --header 'Authorization: Bearer ACCESS_TOKEN' \
  --data-raw '{
    "polygon": {
      "points": [
        {
          "latitude": 51.45,
          "longitude": 0
        },
        {
          "latitude": 51.55,
          "longitude": 0
        },
        {
          "latitude": 51.55,
          "longitude": -0.1
        },
        {
          "latitude": 51.45,
          "longitude": -0.1
        },
        {
          "latitude": 51.45,
          "longitude": 0
        }
      ]
    },
    "layer_ids": [
      "US-1_3ARCSEC-00_OFFSET-1in1000-FLUVIAL-DEFENDED-DEPTH-2020-PERCENTILE50-v2.0.0",
      "GLOBAL-1ARCSEC-NW_OFFSET-1in1000-FLUVIAL-UNDEFENDED-DEPTH-2020-PERCENTILE50-v3.0",
      "GLOBAL-1ARCSEC-NW_OFFSET-1in100-FLUVIAL-UNDEFENDED-DEPTH-2020-PERCENTILE50-v3.0"
    ]
  }'

Expected response:

{
  "results": {
    "US-1_3ARCSEC-00_OFFSET-1in1000-FLUVIAL-DEFENDED-DEPTH-2020-PERCENTILE50-v2.0.0": {
      "mean": 5,
      "max": 10,
      "min": 1,
      "stdDev": 2
    },
    "GLOBAL-1ARCSEC-NW_OFFSET-1in1000-FLUVIAL-UNDEFENDED-DEPTH-2020-PERCENTILE50-v3.0": {
      ...
    }
  }
}

GeoJSON queries

The GeoJSON endpoints as documented in the REST reference and the Python SDK reference only accepts a subset of GeoJSON. In short:

  • Only 'Point', 'MultiPoint', and 'Polygon' are accepted
  • 'LineString', 'MultiPolygon', and 'MultiLineString' are not accepted
  • Inputs may be contained in a 'FeatureCollection' or 'Feature', but not 'GeometryCollection'
  • 'Polygon' geometries must follow the same rules as the rules for other endpoints

A non-exhaustive set of examples of valid inputs:

{
  "type": "Point",
  "coordinates": [-1.1081944, 50.8162643]
}
{
  "type": "MultiPoint",
  "coordinates": [
    [-1.1081944, 50.8162643],
    [-1.1071944, 50.8163643]
  ]
}
{
  "type": "Feature",
  "geometry": {
    "type": "Point",
    "coordinates": [-1.1081944, 50.8162643]
  },
  "properties": {
    "name": "Dinagat Islands"
  }
}
{
  "type": "Feature",
  "geometry": {
    "type": "Polygon",
    "coordinates": [
      [
        [100.0, 0.0],
        [101.0, 0.0],
        [101.0, 1.0],
        [100.0, 1.0],
        [100.0, 0.0]
      ]
    ]
  }
}
{
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "geometry": {
        "type": "Point",
        "coordinates": [-1.1081944, 50.8162643]
      },
      "properties": {
        "name": "Point 1"
      }
    },
    {
      "type": "Feature",
      "geometry": {
        "type": "Point",
        "coordinates": [-1.1071944, 50.8163643]
      },
      "properties": {
        "name": "Point 2"
      }
    }
  ]
}

Note

If a FeatureCollection of Point or MultiPoint (or a combination) is given, the results from the API will be flattened into one response object. For the above 'FeatureCollection of Point' example, this will result in:

{
  "results": {
    "FLOOD_MAP-...": {
      "values": [
        {
          "query_point": {
            "longitude": -1.1081944,
            "latitude": 50.8162643
          },
          "val": 12
        },
        {
          "query_point": {
            "longitude": -1.1071944,
            "latitude": 50.8163643
          },
          "val": 56
        }
      ]
    }
  }
}

Some examples of invalid inputs:

Failure

LineString geometries are not allowed.

{
  "type": "Feature",
  "geometry": {
    "type": "LineString",
    "coordinates": [
      [102.0, 0.0],
      [103.0, 1.0],
      [104.0, 0.0],
      [105.0, 1.0]
    ]
  }
}

Failure

Polygons with multiple rings are not allowed.

{
  "type": "Feature",
  "geometry": {
    "type": "Polygon",
    "coordinates": [
      [
        [100.0, 0.0],
        [101.0, 0.0],
        [101.0, 1.0],
        [100.0, 1.0],
        [100.0, 0.0]
      ],
      [
        [100.0, 0.0],
        [101.0, 0.0],
        [101.0, 1.0],
        [100.0, 1.0],
        [100.0, 0.0]
      ]
    ]
  }
}

Failure

Only one polygon per request is allowed.

{
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "geometry": {
        "type": "Polygon",
        "coordinates": [
          [
            [100.0, 0.0],
            [101.0, 0.0],
            [101.0, 1.0],
            [100.0, 1.0],
            [100.0, 0.0]
          ]
        ]
      }
    },
    {
      "type": "Feature",
      "geometry": {
        "type": "Polygon",
        "coordinates": [
          [
            [100.0, 0.0],
            [101.0, 0.0],
            [101.0, 1.0],
            [100.0, 1.0],
            [100.0, 0.0]
          ]
        ]
      }
    }
  ]
}

Vector file queries

The Python SDK supports reading polygons from a variety of vector files (see the SDK documentation for more information.)