Commit 98f1d353 authored by Anne Blankert's avatar Anne Blankert

support quantile classification

parent fb6dab19
...@@ -13,6 +13,8 @@ ...@@ -13,6 +13,8 @@
flex-wrap: wrap; flex-wrap: wrap;
} }
#map {display: inline-block; width: 500px; height: 500px; border: 1 px solid lightblue;} #map {display: inline-block; width: 500px; height: 500px; border: 1 px solid lightblue;}
#legendcontainer {display: flex;}
#legend {min-width: 250px;}
#featurecontainer { #featurecontainer {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
...@@ -48,8 +50,8 @@ ...@@ -48,8 +50,8 @@
const attrType = urlParams.get("columntype"); const attrType = urlParams.get("columntype");
const geomType = urlParams.get('geomtype'); const geomType = urlParams.get('geomtype');
const geomColumn = urlParams.get('geom_column'); const geomColumn = urlParams.get('geom_column');
document.querySelector('#tablename').innerHTML = `${fullTableName} ${geomColumn}`; document.querySelector('#tablename').innerHTML = `Layer: ${fullTableName}<br>Geometry: ${geomColumn}`;
document.querySelector('#columnname').innerHTML = `${attrName} (${attrType})`; document.querySelector('#columnname').innerHTML = `Attribute: ${attrName} (${attrType})`;
document.querySelector('#back').innerHTML = `<a href="tableinfo.html?table=${fullTableName}&geom_column=${geomColumn}">Back to layer info</a>`; document.querySelector('#back').innerHTML = `<a href="tableinfo.html?table=${fullTableName}&geom_column=${geomColumn}">Back to layer info</a>`;
initMap(); initMap();
...@@ -354,38 +356,93 @@ ...@@ -354,38 +356,93 @@
function classButton(classType) { function classButton(classType) {
if (prepareLegend()) { if (prepareLegend()) {
const classCount = document.querySelector('#classcount').value; const classCount = Number(document.querySelector('#classcount').value);
if (classCount === 1) { if (classCount === 1) {
// special case, single classification // special case, single classification
} else { } else {
// classCount > 1 // classCount > 1
const layerType = map.getLayer('attrlayer').type; const layerType = map.getLayer('attrlayer').type;
const rowCount = globalStats.percentiles.reduce((result, percentile)=>result + percentile.count, 0); const rowCount = globalStats.percentiles.reduce((result, percentile)=>result + percentile.count, 0);
let classValues = globalStats.values.filter(value=>value.value !== null); let mapboxPaint;
if (classValues.length > classCount) { switch(classType) {
classValues = classValues.slice(0, classCount - 1); case 'qualitative':
const classValuesRowCount = classValues.reduce((result, value)=>result+value.count,0); let classValues = globalStats.values.filter(value=>value.value !== null);
classValues.push({ const needsSlice = classValues.length > classCount;
value:"other", if (needsSlice) {
count: rowCount - classValuesRowCount classValues = classValues.slice(0, classCount - 1);
}) const classValuesRowCount = classValues.reduce((result, value)=>result+value.count,0);
const schemes = getColorSchemes(classCount, 'qual'); classValues.push({
const mapboxPaint = [ value:"other",
"match", count: rowCount - classValuesRowCount
["get",`${globalStats.column}`] })
]; }
classValues.forEach((value, index) => { const schemes = getColorSchemes(classCount, 'qual');
addLegendLine(schemes[0].colors[index], value.value, layerType); mapboxPaint = [
if (value.value !== 'other') { "match",
mapboxPaint.push(value.value); ["get",`${globalStats.column}`]
mapboxPaint.push(schemes[0].colors[index]); ];
classValues.forEach((value, index) => {
addLegendLine(schemes[0].colors[index], value.value, layerType);
if (index < classValues.length - 1 || !needsSlice) {
mapboxPaint.push(value.value);
mapboxPaint.push(schemes[0].colors[index]);
}
});
mapboxPaint.push(schemes[0].colors[classValues.length -1]);
break;
case 'quantile':
let percentileBreaks = globalStats.percentiles.reduce((result, percentile)=>{
percentile.pcount = 1;
if (result.length === 0) {
result.push(percentile);
return result;
}
if (result[result.length - 1].to === percentile.from) {
result[result.length - 1].to = percentile.to;
result[result.length - 1].count += percentile.count;
result[result.length - 1].pcount++;
return result;
}
result.push(percentile);
return result;
},[]);
const seqSchemes = getColorSchemes(classCount, 'qual');
if (classCount > percentileBreaks.length) {
classCount = percentileBreaks.length
} else {
let totalPCount = percentileBreaks.reduce((result, percentile)=>result+percentile.pcount, 0);
const pCountPerClass = totalPCount / classCount;
let sumPCount = 0;
let sumClassCount = 0
percentileBreaks = percentileBreaks.reduce((result, percentile)=>{
sumPCount += percentile.pcount;
if (sumPCount > sumClassCount * pCountPerClass) {
// new class
result.push(percentile);
sumClassCount++;
} else {
result[result.length - 1].to = percentile.to;
result[result.length - 1].count += percentile.count;
result[result.length - 1].pcount += percentile.pcount;
}
return result;
},[])
} }
}); mapboxPaint = [
mapboxPaint.push(schemes[0].colors[classValues.length -1]); "case"
const colorprop = `${layerType}-color`; ]
map.setPaintProperty('attrlayer', colorprop, mapboxPaint);
updateLayerJsonDisplay(); percentileBreaks.forEach((brk, index, arr)=>{
addLegendLine(seqSchemes[0].colors[index], `${brk.from} - ${brk.to}`, layerType);
mapboxPaint.push(["<",["get", globalStats.column],brk.to],seqSchemes[0].colors[index])
})
mapboxPaint.push(seqSchemes[0].colors[classCount - 1])
break;
} }
const colorprop = `${layerType}-color`;
map.setPaintProperty('attrlayer', colorprop, mapboxPaint);
updateLayerJsonDisplay();
} }
const nullValues = globalStats.values.filter(value=>value.value === null).reduce((result, value)=>result+value.count,0); const nullValues = globalStats.values.filter(value=>value.value === null).reduce((result, value)=>result+value.count,0);
...@@ -417,25 +474,27 @@ ...@@ -417,25 +474,27 @@
<div id="map"></div> <div id="map"></div>
<div id="featurecontainer"> <div id="featurecontainer">
<div id="legendcontainer"> <div id="legendcontainer">
<select id="classcount" name="classcount">
<option value="1" selected>1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
<option value="5">5</option>
<option value="6">6</option>
<option value="7">7</option>
<option value="8">8</option>
<option value="9">9</option>
<option value="10">10</option>
<option value="11">11</option>
<option value="12">12</option>
</select><label for="numclasses">number of classes</label><br>
<button onclick="classButton('interval')">equal interval</button>
<button onclick="classButton('quantile')">quantile</button>
<button onclick="classButton('qualitative')">qualitative</button><br>
<input type="checkbox" id="hidenulls" name="hidenulls" checked><label for="hidenulls">Hide no-data</label>
<div id="legend"></div> <div id="legend"></div>
<div id="legendformcontainer">
<select id="classcount" name="classcount">
<option value="1" selected>1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
<option value="5">5</option>
<option value="6">6</option>
<option value="7">7</option>
<option value="8">8</option>
<option value="9">9</option>
<option value="10">10</option>
<option value="11">11</option>
<option value="12">12</option>
</select><label for="numclasses">number of classes</label><br>
<button onclick="classButton('interval')">equal interval</button>
<button onclick="classButton('quantile')">quantile</button>
<button onclick="classButton('qualitative')">qualitative</button><br>
<input type="checkbox" id="hidenulls" name="hidenulls" checked><label for="hidenulls">Hide no-data</label>
</div>
</div> </div>
<div id="featureinfo"></div> <div id="featureinfo"></div>
</div> </div>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment