The previous post (creating a thematic map) described the use of an advanced style (color ranged-bucket style). The bucket style definition object has an attribute ('classification') which specifies the data classification scheme to use. It's values can be one of {'equal', 'quantile', 'logarithmic', 'custom'}. We use logarithmic in the previous example. Here we'll describe how to use a custom algorithm for classification. Specifically the Jenks Natural Breaks algorithm. We'll use the Javascript implementation in geostats.js
The sample code above needs a few changes which are listed below.
Include the geostats.js file after or before including oraclemapsv2.js
<script src="geostats.js"></script>
Modify the bucket style definition to use custom classification
Normal
0
false
false
false
EN-US
X-NONE
X-NONE
MicrosoftInternetExplorer4
/* Style Definitions */
table.MsoNormalTable
{mso-style-name:"Table Normal";
mso-tstyle-rowband-size:0;
mso-tstyle-colband-size:0;
mso-style-noshow:yes;
mso-style-priority:99;
mso-style-qformat:yes;
mso-style-parent:"";
mso-padding-alt:0in 5.4pt 0in 5.4pt;
mso-para-margin:0in;
mso-para-margin-bottom:.0001pt;
mso-pagination:widow-orphan;
font-size:11.0pt;
font-family:"Calibri","sans-serif";
mso-ascii-font-family:Calibri;
mso-ascii-theme-font:minor-latin;
mso-fareast-font-family:"Times New Roman";
mso-fareast-theme-font:minor-fareast;
mso-hansi-font-family:Calibri;
mso-hansi-theme-font:minor-latin;
mso-bidi-font-family:"Times New Roman";
mso-bidi-theme-font:minor-bidi;}
bucketStyleDef = {
numClasses : colorSeries[colorName].classes,
classification: 'custom', //'logarithmic', // use a logarithmic scale
algorithm: jenksFromGeostats,
styles: theStyles,
gradient: useGradient? 'linear' : 'off'
};
The function, which implements the custom classification scheme, is specified as the algorithm attribute value. It must accept two input parameters, an array of OM.feature and the name of the feature attribute (e.g. TOTPOP) to use in the classification, and must return an array of buckets (i.e. an array of or OM.style.Bucket or OM.style.RangedBucket in this case).
However the algorithm also needs to know the number of classes (i.e. the number of buckets to create). So we use a global to pass that info in. (Note: This bug/oversight will be fixed and the custom algorithm will be passed 3 parameters: the features array, attribute name, and number of classes).
So createBucketColorStyle() has the following changes
Normal
0
false
false
false
EN-US
X-NONE
X-NONE
MicrosoftInternetExplorer4
/* Style Definitions */
table.MsoNormalTable
{mso-style-name:"Table Normal";
mso-tstyle-rowband-size:0;
mso-tstyle-colband-size:0;
mso-style-noshow:yes;
mso-style-priority:99;
mso-style-qformat:yes;
mso-style-parent:"";
mso-padding-alt:0in 5.4pt 0in 5.4pt;
mso-para-margin:0in;
mso-para-margin-bottom:.0001pt;
mso-pagination:widow-orphan;
font-size:11.0pt;
font-family:"Calibri","sans-serif";
mso-ascii-font-family:Calibri;
mso-ascii-theme-font:minor-latin;
mso-fareast-font-family:"Times New Roman";
mso-fareast-theme-font:minor-fareast;
mso-hansi-font-family:Calibri;
mso-hansi-theme-font:minor-latin;
mso-bidi-font-family:"Times New Roman";
mso-bidi-theme-font:minor-bidi;}
var numClasses ;
function createBucketColorStyle(
colorName, colorSeries, rangeName, useGradient)
{
var theBucketStyle;
var bucketStyleDef;
var theStyles = [];
//var numClasses ; numClasses = colorSeries[colorName].classes; ...
and the function jenksFromGeostats is defined as
Normal
0
false
false
false
EN-US
X-NONE
X-NONE
MicrosoftInternetExplorer4
/* Style Definitions */
table.MsoNormalTable
{mso-style-name:"Table Normal";
mso-tstyle-rowband-size:0;
mso-tstyle-colband-size:0;
mso-style-noshow:yes;
mso-style-priority:99;
mso-style-qformat:yes;
mso-style-parent:"";
mso-padding-alt:0in 5.4pt 0in 5.4pt;
mso-para-margin:0in;
mso-para-margin-bottom:.0001pt;
mso-pagination:widow-orphan;
font-size:11.0pt;
font-family:"Calibri","sans-serif";
mso-ascii-font-family:Calibri;
mso-ascii-theme-font:minor-latin;
mso-fareast-font-family:"Times New Roman";
mso-fareast-theme-font:minor-fareast;
mso-hansi-font-family:Calibri;
mso-hansi-theme-font:minor-latin;
mso-bidi-font-family:"Times New Roman";
mso-bidi-theme-font:minor-bidi;}
function
jenksFromGeostats(featureArray, columnName)
{
var items = [] ; // array of attribute values to be classified
$.each(featureArray, function(i, feature) {
items.push(parseFloat(feature.getAttributeValue(columnName)));
});
// create the geostats object
var theSeries = new geostats(items); // call getJenks which returns an array of bounds
var theClasses = theSeries.getJenks(numClasses);
if(theClasses)
{
theClasses[theClasses.length-1]=parseFloat(theClasses[theClasses.length-1])+1;
}
else
{
alert(' empty result from getJenks');
}
var theBuckets = [], aBucket=null ;
for(var k=0; k<numClasses; k++)
{
aBucket =
new OM.style.RangedBucket(
{low:parseFloat(theClasses[k]),
high:parseFloat(theClasses[k+1])
});
theBuckets.push(aBucket);
}
return theBuckets;
}
A screenshot of the resulting map with 5 classes is shown below.
It is also possible to simply create the buckets and supply them when defining the Bucket style instead of specifying the function (algorithm). In that case the bucket style definition object would be
bucketStyleDef = { numClasses : colorSeries[colorName].classes, classification: 'custom', buckets: theBuckets, //since we are supplying all the buckets styles: theStyles, gradient: useGradient? 'linear' : 'off' };