# AZP

The automatic zoning procedure (AZP) was initially outlined in Openshaw (1977) as a way to address some of the consequences of the modifiable areal unit problem (MAUP). In essence, it consists of a heuristic to find the best set of combinations of contiguous spatial units into p regions, minimizing the within sum of squares as a criterion of homogeneity. The number of regions needs to be specified beforehand.

## azpGreedy()

A simulated annealing algorithm to solve the AZP problem

```sql
function azpGreedy(
    WeightResult w,
    Number k, 
    Array vals,
    Number inits,
    Array init_region,
    Array min_bound_values, 
    Array min_bounds,
    Array max_bound_values, 
    Array max_bounds,
    String scale_method,
    String distance_type,
    Number seed)

```

### Arguments

| Name                | Type          | Description                                                                                                                                     |
| ------------------- | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
| `weights`           | WeightsResult | The weights object `WeightsResult`                                                                                                              |
| `k`                 | Number        | The number of spatially constrained clusters                                                                                                    |
| `vals`              | Array         | The list of numeric vectors of the selected variable.                                                                                           |
| `inits`             | Number        | The number of construction re-runs, which is for ARiSeL "automatic regionalization with initial seed location"                                  |
| `init_region`       | Array         | The initial regions that the local search starts with. Default is empty. means the local search starts with a random process to "grow" clusters |
| `min_bounds_values` | Array         | The list of numeric array of selected minimum bounding variables.                                                                               |
| `min_bounds`        | Array         | The list of minimum values that the sum value of bounding variables in each cluster should be greater than.                                     |
| `max_bounds_values` | Array         | The list of numeric arrays of selected maximum bounding variables.                                                                              |
| `max_bounds`        | Array         | The list of minimum value that the sum value of bounding variables in each cluster should be less than.                                         |
| `scale_method`      | String        | The scaling methods {'raw', 'standardize', 'demean', 'mad', 'range\_standardize', 'range\_adjust'}. Defaults to 'standardize'.                  |
| `distance_method`   | String        | The distance methods {"euclidean", "manhattan"}. Defaults to 'euclidean'.                                                                       |
| `seed`              | Number        | The seed for random number generator.                                                                                                           |

### Return

| Type             | Description                                                                            |
| ---------------- | -------------------------------------------------------------------------------------- |
| ClusteringResult | The Clustering object: {'total\_ss', 'within\_ss', 'between\_ss', 'ratio', 'clusters'} |

**Examples**

{% tabs %}
{% tab title="Node.js" %}

```javascript
const jsgeoda = require('jsgeoda');
const fs = require('fs');

// load data
const data = fs.readFileSync('./data/natregimes.geojson').buffer;

// create jsgeoda instance
const geoda = await jsgeoda.New();

// load geojson in jsgeoda
const nat = geoda.readGeoJSON(data);

// create a queen contiguity weights
const w = geoda.getQueenWeights(nat);

// get values
const hr60 = geoda.getColumn(nat, "HR60");
const ue60 = geoda.getColumn(nat, "UE60");

// set minimum bound
const po60 = geoda.getColumn(nat, "PO60");

// apply azp_greedy
const inits = 1;
const init_region = [];
const min_bound_vals = [po60];
const min_bounds = [17845200];
const azp = geoda.azpGreedy(w, 20, [hr60, ue60], inits, init_region, min_bound_vals,min_bounds);

```

{% endtab %}

{% tab title="React" %}

```javascript
import React, { Component } from "react";
import ReactDOM from "react-dom";
import DeckGL from "@deck.gl/react";
import { GeoJsonLayer } from "@deck.gl/layers";
import { StaticMap } from "react-map-gl";
import colorbrewer from "colorbrewer";
import jsgeoda from "jsgeoda";

// Set your mapbox access token here
const MAPBOX_TOKEN =
  "pk.eyJ1IjoibGl4dW45MTAiLCJhIjoiY2locXMxcWFqMDAwenQ0bTFhaTZmbnRwaiJ9.VRNeNnyb96Eo-CorkJmIqg";

// The geojson data
const DATA_URL = `https://webgeoda.github.io/data/natregimes.geojson`;

class App extends Component {
  constructor() {
    super();
    this.state = {
      mapId: "",
      layer: null,
      viewPort: {
        longitude: -100.4,
        latitude: 38.74,
        zoom: 2.5,
        maxZoom: 20
      }
    };
  }

  // load spatial data when mount this component
  loadSpatialData(geoda) {
    fetch(DATA_URL)
      .then((res) => res.arrayBuffer())
      .then((data) => {
        // load geojson in jsgeoda, an unique id (string) will be returned for further usage
        const nat = geoda.read_geojson(data);
        const w = geoda.queen_weights(nat);
        const hr60 = geoda.get_col(nat, "HR60");
        const ue60 = geoda.get_col(nat, "UE60");
        const po60 = geoda.get_col(nat, "PO60");
        const redcap = geoda.skater(w, 10, [hr60, ue60], 17845200, po60);
        //const redcap = geoda.schc(w, 10, [hr60, ue60], 'ward', 17845200, po60);
        //const redcap = geoda.redcap(w, 10, [hr60, ue60], "fullorder-wardlinkage", 17845200, po60);
        //const azp = geoda.azp_greedy(w, 20, [hr60, ue60], 1, [], [po60],[17845200]);
        //const redcap = geoda.azp_tabu(w, 20, [hr60, ue60], 10, 10, 1, [], [po60],[17845200]);
        //const redcap = geoda.azp_sa(w, 20, [hr60, ue60], 0.85, 1, 1, [], [po60],[17845200]);
        //const redcap = geoda.maxp_greedy(w, [hr60, ue60],  1, [po60],[17845200]);
        const colors = colorbrewer["Paired"][10].map((c) =>
          c
            .toLowerCase()
            .match(/[0-9a-f]{2}/g)
            .map((x) => parseInt(x, 16))
        );

        // Viewport settings
        const view_port = geoda.get_viewport(
          nat,
          window.innerHeight,
          window.innerWidth
        );

        // Create GeoJsonLayer
        const layer = new GeoJsonLayer({
          id: "GeoJsonLayer",
          data: DATA_URL,
          filled: true,
          getFillColor: (f) => this.getFillColor(f, redcap.clusters, colors),
          stroked: true,
          pickable: true
        });

        // Trigger to draw map
        this.setState({
          mapId: nat,
          layer: layer,
          viewPort: view_port
        });
      });
  }

  componentDidMount() {
    // jsgeoda.New() function will create an instance from WASM
    jsgeoda.New().then((geoda) => {
      this.loadSpatialData(geoda);
    });
  }

  // Determine which color for which geometry
  getFillColor(f, clusters, colors) {
    const i = f.properties.POLY_ID - 1;
    const c = clusters[i] - 1;
    return colors[c];
  }

  render() {
    return (
      <div>
        <DeckGL
          initialViewState={this.state.viewPort}
          layers={[this.state.layer]}
          controller={true}
          getTooltip={({ object }) =>
            object && `${object.properties.NAME}: ${object.properties.HR60}`
          }
        >
          <StaticMap mapboxApiAccessToken={MAPBOX_TOKEN} />
        </DeckGL>
      </div>
    );
  }
}

ReactDOM.render(<App />, document.getElementById("root"));

```

{% endtab %}
{% endtabs %}

**Try it yourself in the playground (jsgeoda + deck.gl):**

{% embed url="<https://codesandbox.io/s/7spatialclustering-uvz12>" %}

## azpSA()

A simulated annealing algorithm to solve the AZP problem

```sql
function azpSA(
    WeightResult w,
    Number k, 
    Array vals,
    Number cooling_rate,
    Number sa_maxit,
    Number inits,
    Array init_region,
    Array min_bound_values, 
    Array min_bounds,
    Array max_bound_values, 
    Array max_bounds,
    String scale_method,
    String distance_type,
    Number seed)

```

### Arguments

| Name                | Type          | Description                                                                                                                                     |
| ------------------- | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
| `weights`           | WeightsResult | The weights object `WeightsResult`                                                                                                              |
| `k`                 | Number        | The number of spatially constrained clusters                                                                                                    |
| `vals`              | Array         | The list of numeric vectors of selected variable.                                                                                               |
| `cooling_rate`      | Number        | The number of iterations of simulated annealing. Defaults to 1                                                                                  |
| `sa_maxit`          | Number        | The number of iterations of simulated annealing. Defaults to 1                                                                                  |
| `inits`             | Number        | The number of construction re-runs, which is for ARiSeL "automatic regionalization with initial seed location"                                  |
| `init_region`       | Array         | The initial regions that the local search starts with. Default is empty. means the local search starts with a random process to "grow" clusters |
| `min_bounds_values` | Array         | The list of numeric array of selected minimum bounding variables.                                                                               |
| `min_bounds`        | Array         | The list of minimum value that the sum value of bounding variables in each cluster should be greater than.                                      |
| `max_bounds_values` | Array         | The list of numeric array of selected maximum bounding variables.                                                                               |
| `max_bounds`        | Array         | The list of minimum value that the sum value of bounding variables in each cluster should be less than.                                         |
| `scale_method`      | String        | The scaling methods {'raw', 'standardize', 'demean', 'mad', 'range\_standardize', 'range\_adjust'}. Defaults to 'standardize'.                  |
| `distance_method`   | String        | The distance methods {"euclidean", "manhattan"}. Defaults to 'euclidean'.                                                                       |
| `seed`              | Number        | The seed for random number generator.                                                                                                           |

### Return

| Type             | Description                                                                            |
| ---------------- | -------------------------------------------------------------------------------------- |
| ClusteringResult | The Clustering object: {'total\_ss', 'within\_ss', 'between\_ss', 'ratio', 'clusters'} |

## azpTabu()

A tabu algorithm to solve the AZP problem

```sql
function azpTabu(
    WeightResult w,
    Number k, 
    Array vals,
    Number tabu_length,
    Number conv_tabu,
    Number inits,
    Array init_region,
    Array min_bound_values, 
    Array min_bounds,
    Array max_bound_values, 
    Array max_bounds,
    String scale_method,
    String distance_type,
    Number seed)

```

### Arguments

| Name                | Type          | Description                                                                                                                                     |
| ------------------- | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
| `weights`           | WeightsResult | The weights object `WeightsResult`                                                                                                              |
| `k`                 | Number        | The number of spatially constrained clusters                                                                                                    |
| `values`            | Array         | The list of numeric vectors of selected variable.                                                                                               |
| `tabu_length`       | Number        | The length of a tabu search heuristic of tabu algorithm. Defaults to 10.                                                                        |
| `conv_tabu`         | Number        | The number of non-improving moves. Defaults to 10.                                                                                              |
| `inits`             | Number        | The number of construction re-runs, which is for ARiSeL "automatic regionalization with initial seed location"                                  |
| `init_region`       | Array         | The initial regions that the local search starts with. Default is empty. means the local search starts with a random process to "grow" clusters |
| `min_bounds_values` | Array         | The list of numeric array of selected minimum bounding variables.                                                                               |
| `min_bounds`        | Array         | The list of minimum value that the sum value of bounding variables in each cluster should be greater than.                                      |
| `max_bounds_values` | Array         | The list of numeric array of selected maximum bounding variables.                                                                               |
| `max_bounds`        | Array         | The list of minimum value that the sum value of bounding variables in each cluster should be less than.                                         |
| `scale_method`      | String        | The scaling methods {'raw', 'standardize', 'demean', 'mad', 'range\_standardize', 'range\_adjust'}. Defaults to 'standardize'.                  |
| `distance_method`   | String        | The distance methods {"euclidean", "manhattan"}. Defaults to 'euclidean'.                                                                       |
| `seed`              | Number        | The seed for random number generator.                                                                                                           |

### Return

| Type             | Description                                                                            |
| ---------------- | -------------------------------------------------------------------------------------- |
| ClusteringResult | The Clustering object: {'total\_ss', 'within\_ss', 'between\_ss', 'ratio', 'clusters'} |


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://xunli.gitbook.io/jsgeoda/spatial-clustering/azp.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
