# Max-p

The max-p-region problem is a special case of constrained clustering where a finite number of geographical areas are aggregated into the maximum number of regions (max-p-regions), such that each region is geographically connected and the clusters could maximize internal homogeneity.

## maxpGreedy()

A simulated annealing algorithm to solve the max-p-region problem

```sql
function maxpGreedy(
    WeightResult w,
    Array vals,
    Number iterations,
    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`                                                                                             |
| `vals`              | Array         | The list of numeric vectors of selected variable.                                                                              |
| `iterations`        | Number        | The number of iterations of greedy algorithm. Defaults to 1.                                                                   |
| `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'} |

**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 min_bound_vals = [po60];
const min_bounds = [17845200];
const azp = geoda.maxp_greedy(w, [hr60, ue60], 49, 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.readGeoJSON(data);
        const w = geoda.getQueenWeights(nat);
        const hr60 = geoda.getColumn(nat, "HR60");
        const ue60 = geoda.getColumn(nat, "UE60");
        const po60 = geoda.getColumn(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.azpGreedy(w, 20, [hr60, ue60], 1, [], [po60],[17845200]);
        //const redcap = geoda.azpTabu(w, 20, [hr60, ue60], 10, 10, 1, [], [po60],[17845200]);
        //const redcap = geoda.azpSA(w, 20, [hr60, ue60], 0.85, 1, 1, [], [po60],[17845200]);
        //const redcap = geoda.maxpGreedy(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>" %}

## maxpSA()

A simulated annealing algorithm to solve the max-p-region problem

```sql
function maxpSA(
    WeightResult w,
    Array vals,
    Number cooling_rate,
    Number sa_maxit,
    Number iteration,
    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`                                                                                             |
| `values`            | Array         | The list of numeric vectors of selected variable.                                                                              |
| `cooling_rate`      | Number        | The cooling rate of a simulated annealing algorithm. Defaults to 0.85                                                          |
| `sa_maxit`          | Number        | The number of iterations of simulated annealing. Defaults to 1                                                                 |
| `iterations`        | Number        | The number of iterations of greedy algorithm. Defaults to 1.                                                                   |
| `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'} |

## maxpTabu()

A simulated annealing algorithm to solve the max-p-region problem

```sql
function maxpTabu (
    WeightResult w,
    Array vals,
    Number tabu_length,
    Number conv_tabu,
    Number iterations,
    Array min_bound_values, 
    Array min_bounds,
    Array max_bound_values, 
    Array max_bounds,
    String scale_method,
    String distance_type,
    Number seed)

```

### Arguments

| `weights`           | WeightsResult | The weights object `WeightsResult`                                                                                             |
| ------------------- | ------------- | ------------------------------------------------------------------------------------------------------------------------------ |
| `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.                                                                             |
| `iterations`        | Number        | The number of iterations of greedy algorithm. Defaults to 1.                                                                   |
| `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'} |
