# Use Boundaries in your application

{% hint style="info" %}
The features and capabilities described in this guide are still experimental and they might be subject to change in the future.
{% endhint %}

## Introduction

A very common problem for map makers and developers is how to aggregate large amounts of data, such as millions of records; into known or custom boundaries, such as postal codes or census areas. Traditionally, it's hard to make these visualizations perform great, and even harder to build them with the ability to apply dynamic filtering and aggregations.

With CARTO this problem is solved thanks to a new method called **"Boundaries".**

This guide will teach you the fundamentals of Boundaries, and it will guide you through creating your first visualization using both predefined and custom boundaries.

## How Boundaries work

Boundaries in CARTO work by completely separating the data from the static geometries that we want to aggregate into, as seen in this image.

<div data-full-width="true"><figure><img src="https://3029946802-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FybPdpmLltPkzGFvz7m8A%2Fuploads%2Fgit-blob-1942dda0b9aaa67599dda5890780527cfbb4e350%2FScreenshot%202024-03-25%20at%2012.46.23.png?alt=media" alt=""><figcaption></figcaption></figure></div>

Because both the data and geometries share a matching column with an ID (eg: zip code), we are now able to perform the aggregation without using the geometry, only to incorporate the unchanged geometries later to visualize the result.

This approach provides an alternative to traditional methods of preparing, storing, and serving pre-calculated geometries for each filter combination, offering a more streamlined and efficient solution.

{% hint style="info" %}
**Components of Boundaries in CARTO**

To make this guide more readable, we'll be using specific terminology, such as:

* **Properties:** this is the data that you want to aggregate, such as transactions, features, events, etc.
* **Boundaries**: these are tilesets containing the geometries that will be the base of your aggregation, which can be:
  * **Known boundaries:** predefined boundaries made available by CARTO. You can find them in the [CARTO Boundaries Explorer](https://boundaries-explorer.carto.com/).
  * **Custom boundaries:** boundaries tilesets prepared by yourself, using your own geometries and the CARTO Analytics Toolbox. We'll cover this later in this guide.
* **geoid:** both the "Properties data" table and the "Boundaries" **must** have a column called **`geoid`** with the **same data type (eg: string)** that represents the common matching attribute, such as the zip code ID.
  {% endhint %}

{% hint style="success" %}
In our [example of Boundaries](https://github.com/CartoDB/deck.gl-examples/blob/master/boundaries/index.ts), the properties are financial transactions, the boundaries are zip codes in the US (known boundary from CARTO), and the geoid column contains the actual zip codes.
{% endhint %}

## Prepare your properties data

As we've covered above, we need to make sure that our properties (table or SQL query) contains a column called **`geoid`** that represents the common matching attribute, such as the zip code ID.

* For tables, you can use [CARTO Workflows](https://docs.carto.com/carto-user-manual/workflows) to rename or add columns.
* For SQL queries, you can simply do something such as:

```sql
SELECT 
    transaction_id,
    zipcode AS geoid
FROM ...
```

## Prepare your boundaries

Now that our properties are ready, let's find the corresponding boundaries:

### Find known boundaries

We have created a catalog that includes known boundaries for some countries. It currently covers different types of boundaries for the United States, Canada, Mexico, United Kingdom and Spain.

{% hint style="info" %}
We'll be progressively adding more boundaries to our known boundaries collection. Please contact us if you'd like CARTO to offer a specific boundary.
{% endhint %}

Explore the catalog from the [**CARTO Boundaries Explorer**](https://boundaries-explorer.carto.com/) application.

<figure><img src="https://3029946802-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FybPdpmLltPkzGFvz7m8A%2Fuploads%2Fgit-blob-ee8d7d8198b39f6c628d064c2e0f730d2a0f6621%2FScreenshot%202024-03-25%20at%2013.46.49.png?alt=media" alt=""><figcaption></figcaption></figure>

Select a country and the corresponding tileset to the boundary you're looking for. Then select the data warehouse between BigQuery and Snowflake, and click on "Use this boundary in your app" button.

This dialog shows all the necessary information to use a boundary in an application. Depending on the data warehouse selected in the explorer, you will find a different type of Boundary ID.

#### BigQuery

For BigQuery, you also need to select a region that matches the region where your data is hosted. The boundaries' tilesets are available in different public BigQuery datasets maintained by CARTO.

Copy the Boundary ID and use it directly in your application's code following the provided example.

#### Snowflake

For Snowflake, CARTO publishes the collection of boundaries in [**this public listing**](https://app.snowflake.com/marketplace/listing/GZT0Z4CM1E9L4).

Once you have the CARTO Boundaries database available in your Snowflake account, use the Boundary ID, making sure you use the appropriate database name.

<figure><img src="https://3029946802-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FybPdpmLltPkzGFvz7m8A%2Fuploads%2Fgit-blob-e677aca9a7ad59a2d9e25d393218c2edbdca515e%2FScreenshot%202024-03-25%20at%2014.09.34.png?alt=media" alt=""><figcaption></figcaption></figure>

### Create a custom boundary

While the collection of boundaries provided by CARTO will be expanding and covering more territories over time, you might need to use a custom set of geographies in your application. For example, when working with agricultural parcel data or disputed territory boundaries.

Generating a tileset that can be used as a boundary is easy using the CARTO Analytics Toolbox procedures in the tiler module. See the reference for [BigQuery](https://docs.carto.com/data-and-analysis/analytics-toolbox-for-bigquery/sql-reference/tiler#create_simple_tileset) and [Snowflake](https://docs.carto.com/data-and-analysis/analytics-toolbox-for-snowflake/sql-reference/tiler#create_simple_tileset).

The key for a tileset to be usable as a boundary is to include an additional `geoid` column. For this, make sure that you add the `"calculate_geoids": true` option to the tileset creation procedure.

These are examples for creating boundary tileset in BigQuery and Snowflake:

{% tabs %}
{% tab title="BigQuery" %}

```sql
CALL `carto-un`.carto.CREATE_SIMPLE_TILESET(
    '(SELECT geom, geoid, NAME_0 as name FROM `project.dataset.geography_admin_0_countries`)',
    '`carto-boundaries.us.tileset_glo_adm0_v1`',
    '''
    {
      "max_tile_size_kb": 1536, 
      "max_tile_size_strategy": "drop_fraction_as_needed", 
      "tile_feature_order": "ST_AREA(geom) DESC", 
      "geom_column": "geom", 
      "calculate_geoids": true, 
      "zoom_min": 0, 
      "zoom_max": 4, 
      "properties": {
        "geoid": "String", 
        "name": "String"
        }
    }
    '''
);
```

{% endtab %}

{% tab title="Snowflake" %}

<pre class="language-sql"><code class="lang-sql">CALL CARTO.CARTO.CREATE_SIMPLE_TILESET( 
<strong>  '(SELECT GEOM, GEOID, NAME FROM DATABASE.PUBLIC.GEOGRAPHY_ADMIN_0_COUNTRIES)', 
</strong>  'CARTO_BOUNDARIES.TILESETS.TILESET_GLO_ADM0_V1', 
  '{
    "max_tile_vertices": 200000, 
    "max_tile_size_strategy": "drop_fraction_as_needed", 
    "geom_column": "GEOM", 
    "calculate_geoids": true, 
    "single_query": true, 
    "zoom_min": 1, 
    "zoom_max": 4, 
    "properties": {
      "GEOID": "String", 
      "NAME": "String"
      }
    }' 
  );
</code></pre>

{% endtab %}
{% endtabs %}

## Create an API Access Token

As with any other interaction with the CARTO APIs, using Boundaries requires the user to provide a valid API Access Token with the appropriate grants.

{% hint style="info" %}
Make sure that your API Access Token has grants for both the boundary **`tilesetTableName`** and the **`propertiesSqlQuery`**
{% endhint %}

Check [this documentation](https://docs.carto.com/carto-user-manual/developers/managing-credentials/api-access-tokens#creating-an-api-access-token) to learn more about creating API Access Tokens.

Type or paste the Boundary ID, as well as the source for the data to be joined with.

<figure><img src="https://3029946802-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FybPdpmLltPkzGFvz7m8A%2Fuploads%2Fgit-blob-ae3814c06421d378d31dfb3774ba4c16db0d10cf%2FScreenshot%202024-06-24%20at%2017.31.56.png?alt=media" alt=""><figcaption></figcaption></figure>

## Build your app

Take a look at the live example for an application using Boundaries [here](https://github.com/CartoDB/deck.gl-examples/tree/master/boundaries).

See below the most relevant part of the example, where we select our properties as **`propertiesSqlQuery`** and our boundaries as **`tilesetTableName`** .

Please note that you could change your properties query dynamically to implement easy, performant and scalable filtering and aggregation methods.

```javascript
import {Deck} from '@deck.gl/core/typed';
import {vectorQuerySource, vectorTileLayer, …} from'@deck.gl/carto/typed';


// Optionally reuse authentication and connection parameters across sources

const apiBaseUrl = …
const accessToken = …
const connectionName = 'carto_dw';
const cartoConfig = {apiBaseUrl, accessToken, connectionName};

// Set up one or more CARTO boundary sources

const avgTicketByZipcode = boundaryQuerySource({
   ...cartoConfig,
   tilesetTableName: 'carto-boundaries.us.tileset_usa_zipcode_v1', // boundaries
   propertiesSqlQuery: `SELECT geoid, AVG(avg_ticket) as avg_ticket 
       FROM project.dataset.big_data_table
       GROUP BY geoid`, // data
    // Remember both the tileset and the properties need to have a column called "geoid"
 )};

// Whatever your app does, but you’ll need to somehow initialize deck.gl

deck = new Deck({
   …
   layers: [],
});


// Use your boundary sources as usual in your tile layers from the CARTO module

 const layers = [
   new VectorTileLayer({
     data: avgTicketByZipcode,
     getFillColor: … // style by avg_ticket!
   })
 ];

```

**Voilá!** 🎉

You should now be able to add Boundaries-based visualizations to your applications, and experience first-hand the improved performance, especially when changing dynamically the properties, filtering, or tweaking the aggregation method.

<figure><img src="https://3029946802-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FybPdpmLltPkzGFvz7m8A%2Fuploads%2Fgit-blob-3520f2bc259d4281af7b2ef7b3d6f72793fbd9aa%2Fboundaries.gif?alt=media" alt=""><figcaption></figcaption></figure>
