j
j
jsGeoDa
Search
K

SCHC

Spatially constrained hierarchical clustering is a special form of constrained clustering, where the constraint is based on contiguity (common borders). The method builds up the clusters using agglomerative hierarchical clustering methods: single linkage, complete linkage, average linkage and Ward’s method (a special form of centroid linkage). Meanwhile, it also maintains the spatial contiguity when merging two clusters.

schc()

function schc(
WeightResult w,
Number k,
Array vals,
Number min_bound,
Array bound_vals,
String scale_method,
String distance_type)

Arguments

Name
Type
Description
weights
WeightsResult
The weights object WeightsResult
k
Number
The number of clusters
values
Array
The list of numeric vectors of selected variable
method
String
The method of agglomerative hierarchical clustering: {“single”, “complete”, “average”,”ward”}.
min_bound
Number
The minimum value that the sum value of bounding variable int each cluster should be greater than
bound_vals
Array
The numeric vector of selected bounding variable
scale_method
String
The scaling method: {'raw', 'standardize', 'demean', 'mad', 'range_standardize', 'range_adjust'}
distance_method
String
The distance method: {"euclidean", "manhattan"}

Return

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.read_geojson(data);
// create a queen contiguity weights
const w = geoda.queen_weights(nat);
// get values
const hr60 = geoda.get_col(nat, "HR60");
const ue60 = geoda.get_col(nat, "UE60");
// set minimum bound
const po60 = geoda.get_col(nat, "PO60");
// apply skater
const schc = geoda.schc(w, 10, [hr60, ue60], 'ward', 17845200, po60);
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 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"));
Try it yourself in the playground (jsgeoda + deck.gl):