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.
A simulated annealing algorithm to solve the max-p-region problem
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)
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 |
Type | Description |
ClusteringResult | The Clustering object: {'total_ss', 'within_ss', 'between_ss', 'ratio', 'clusters'} |
Examples
Node.js
React
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);
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"));
Try it yourself in the playground (jsgeoda + deck.gl):
A simulated annealing algorithm to solve the max-p-region problem
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)
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. |
Type | Description |
ClusteringResult | The Clustering object: {'total_ss', 'within_ss', 'between_ss', 'ratio', 'clusters'} |
A simulated annealing algorithm to solve the max-p-region problem
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)
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. |
Type | Description |
ClusteringResult | The Clustering object: {'total_ss', 'within_ss', 'between_ss', 'ratio', 'clusters'} |
Last modified 2yr ago