diff --git a/js/NatAtlas.js b/js/NatAtlas.js
index d02ad3738f5c7cddb79a34011fe8ce1699e30f73..521dde75df3c56b57395fde1d031e12097d917a7 100644
--- a/js/NatAtlas.js
+++ b/js/NatAtlas.js
@@ -6,19 +6,21 @@
  *
  * @author Barend Köbben - b.j.kobben@utwente.nl
  *
- * @version 0.6.0 [July 2015]
+ * @version 0.6.0 [August 2015]
  * - First attempt at new MapChooser
  * - repaired circles sizes to use Math.PI
- * - use object fro dataStats
+ * - use object for dataStats
  * - Changed metadata to one file with several languages
  * - moved common styles to natatlas.css
  * - cleaned up all: clear distinction globals/locals/attributes
  * - more error checking in metadata loading
+ * - added legends (based on d3.legend by Susie Lu: d3-legend.susielu.com)
  *
  */
 
-// metadata as bootstrap, all other data is in there:
-var METADATA_URL = "./data/metaData.json";
+// metadata as bootstrap, all other necessary data is in there:
+var METADATA_URL;
+METADATA_URL = "./data/metaData.json";
 var MD; //global MetaDataObject
 
 // global constants:
@@ -30,26 +32,18 @@ const errorMsg = 0, showMsg = 1, hideMsg = 2, debugMsg = 3;
 // TODO: Make rescalable (responsive?)
 const mapDivHeight = 650, mapDivWidth = 550;
 
-
 // global vars:
 var numClasses = 5;
 var minCircleSize = 0;
 var maxCircleSize = 20;
-
 var mapgroup = -1, mapsubject = -1,
     mapunit = -1, mapdate = -1;
-
 var DEBUG, DEBUG1;
 var curLang;
 var mainMap, mainMapBG, compareMap, compareMapBG;
-var mapMenu;
 var map_dims = {map_scale: 0.0, y_offset: 0.0, x_offset: 0.0};
-var numMapGroups, numMapSubjectsInGroup;
-var menuDiv, legendDiv, messageDiv;
+var legendDiv, messageDiv;
 var geo_path;
-
-
-//var waterColor = "#ccddf2";
 var tooltip;
 
 
@@ -87,12 +81,11 @@ function init(language) {
                     theError = "HTTP " + error.status + "--" + error.statusText;
                 }
                 setMessage([
-                    "BOOTSTRAP MISLUKT: Laden MD mislukt\nURL= " + metadataURL + "\n" + theError,
-                    "BOOTSTRAP FAILED: Error loading MD\nURL= " + metadataURL + "\n" + theError
+                    "BOOTSTRAP MISLUKT: Laden MetaData mislukt\nURL= " + metadataURL + "\n" + theError,
+                    "BOOTSTRAP FAILED: Error loading MetaData\nURL= " + metadataURL + "\n" + theError
                 ], errorMsg);
             } else {
                 MD = json; //make global
-
                 // use RD projection limits to calculate scale and bounds needed for
                 // affine transformation of RD coordinates to screen coordinates
                 var map_minx = 13600;
@@ -118,6 +111,7 @@ function init(language) {
                 mainMap = mainMapSVG.append("g")
                     .attr("id", "mainMap")
                 ;
+                //note compareMap is created, hidden at start (-> CSS)
                 var compareMapSVG = d3.select("#compareMapDiv").append("svg")
                         .attr("id", "compareMapSVG")
                         .attr("width", mapDivWidth)
@@ -137,10 +131,7 @@ function init(language) {
                         map_dims.x_offset, map_dims.y_offset))
                 ;
 
-                // use metadata to create chooser menu
-                var mapMenu = createMenuTree(MD);
-
-                // load background map from basemap data and render it
+                // load background maps from basemap data and render it
                 // using the attrib baseMapClassAttr as a class name
                 createBackgroundMap(mainMapBG, MD.baseMapDataURL, MD.baseMapClassAttr);
                 createBackgroundMap(compareMapBG, MD.baseMapDataURL, MD.baseMapClassAttr);
@@ -151,9 +142,11 @@ function init(language) {
     tooltip = d3.select("body")
         .append("div")
         .attr("class", "tooltip")
-        .style("opacity", 0);
+        .style("opacity", 0)
+    ;
     tooltip.append("div")
-        .attr("class", "tooltip-text");
+        .attr("class", "tooltip-text")
+    ;
 
 
 }//init()
@@ -241,39 +234,75 @@ function setMessage(messageStrs, messageType) {
  */
 function createMenuTree(MD) {
 
-    numMapGroups = MD.mapgroups.length;
-    numMapSubjectsInGroup = [];
+    //document.getElementById("makeMapBtn").style.visibility = "hidden";
+
+    //fold open div:
+    d3.select("#chooserDiv")
+        .transition().duration(1000)
+        .style("width", "500px")
+        .style("height", "400px")
+    ;
+    //clean up open menus:
+    d3.select("#mGroup").selectAll("input").remove();
+    d3.select("#mSubject").selectAll("input").remove();
+    d3.select("#mUnit").selectAll("input").remove();
+    d3.select("#mDate").selectAll("input").remove();
 
-    for (i = 0; i < numMapGroups; i++) {
-        numMapSubjectsInGroup[i] = MD.mapgroups[i].mapsubjects.length;
+
+
+    var mapGroupsList = d3.select("#mGroup");
+    for (i = 0; i < MD.mapgroups.length; i++) {
+        mapGroupsList.append("input")
+            .attr("type", "button")
+            .attr("value", MD.mapgroups[i].groupname[curLang])
+            .attr("onclick", "showMapSubjects(" + i + ");")
+        ;
     }
-    for (i = 0; i < numMapGroups; i++) {
-        mapMenu = d3.select("#chooserDiv")
-            .append("h2")
-            .html(MD.mapgroups[i].groupname[curLang] + "<p>")
-            .append("select")
-            .attr("class", "menu")
-            .attr("id", "mapGroupSelect_" + i)
-            .attr("onchange", "mapsubject = " +
-            " document.getElementById('mapGroupSelect_' +" + i + ").value")
+}
+
+function showMapSubjects(mapGroup) {
+
+    //clean up open menus:
+    d3.select("#mSubject").selectAll("input").remove();
+    d3.select("#mUnit").selectAll("input").remove();
+    d3.select("#mDate").selectAll("input").remove();
+    var mapSubjectsList = d3.select("#mSubject");
+    for (i = 0; i < MD.mapgroups[mapGroup].mapsubjects.length; i++) {
+        mapSubjectsList.append("input")
+            .attr("type", "button")
+            .attr("value", MD.mapgroups[mapGroup].mapsubjects[i].name[curLang])
+            .attr("onclick", "showMapUnits(" + mapGroup + "," + i + ");")
         ;
-        mapMenu.append("option")
-            .html("Choose...")
-            .attr("value", "-1")
+    }
+}
+
+function showMapUnits(mapGroup, mapSubject) {
+
+    //clean up open menus:
+    d3.select("#mUnit").selectAll("input").remove();
+    d3.select("#mDate").selectAll("input").remove();
+    var mapUnitsList = d3.select("#mUnit");
+    for (i = 0; i < MD.mapgroups[mapGroup].mapsubjects[mapSubject].mapunits.length; i++) {
+        mapUnitsList.append("input")
+            .attr("type", "button")
+            .attr("value", MD.mapgroups[mapGroup].mapsubjects[mapSubject].mapunits[i].name[curLang])
+            .attr("onclick", "showMapDates(" + mapGroup + "," + mapSubject + "," + i + ");")
         ;
-        for (j = 0; j < numMapSubjectsInGroup[i]; j++) {
-            mapMenu.append("option")
-                .attr("value", j)
-                .html(MD.mapgroups[i].mapsubjects[j].name[curLang])
-            ;
-        }
     }
+}
 
-    var MakeMakeButton = d3.select("#chooserDiv")
-        .append("input").attr("type", "submit").attr("value", "Make Map")
-        .attr("onclick", "chooseMap(mapgroup, mapsubject, mapunit, mapdate);");
+function showMapDates(mapGroup, mapSubject, mapUnit) {
 
-    return mapMenu;
+    //clean up open menus:
+    d3.select("#mDate").selectAll("input").remove();
+    var mapDatesList = d3.select("#mDate");
+    for (i = 0; i < MD.mapgroups[mapGroup].mapsubjects[mapSubject].mapunits[mapUnit].mapdates.length; i++) {
+        mapDatesList.append("input")
+            .attr("type", "button")
+            .attr("value", MD.mapgroups[mapGroup].mapsubjects[mapSubject].mapunits[mapUnit].mapdates[i].date)
+            .attr("onclick", "chooseMap(" + mapGroup + "," + mapSubject + "," + mapUnit + "," + i + ");")
+        ;
+    }
 }
 
 /**
@@ -320,6 +349,15 @@ function createBackgroundMap(mapLayer, URL, theClassAttr) {
  * */
 function chooseMap(mapgroup, mapsubject, mapunit, mapdate) {
 
+    //fold down chooserDiv:
+    d3.select("#chooserDiv")
+        .transition().duration(250)
+        .style("width", "175px")
+        .style("height", "20px")
+    ;
+    document.getElementById("makeMapBtn").style.visibility = "visible";
+
+
     var geoData = undefined; // empty data layer
     var attribData = undefined; // empty attrib layer
 
@@ -344,8 +382,12 @@ function chooseMap(mapgroup, mapsubject, mapunit, mapdate) {
         var FK = MD.mapgroups[mapgroup].mapsubjects[mapsubject].mapunits[mapunit].mapdates[mapdate].FK;
 
         // geo_data loader:
-        var geoMD = MD.geo_sources[MD.mapgroups[mapgroup].mapsubjects[mapsubject].mapunits[mapunit].mapdates[mapdate].geo_data];
-        var geoURL = geoMD.serviceURL;
+        try {
+            var geoMD = MD.geo_sources[MD.mapgroups[mapgroup].mapsubjects[mapsubject].mapunits[mapunit].mapdates[mapdate].geo_data];
+            var geoURL = geoMD.serviceURL;
+        } catch (e) {
+            console.log(e);
+        }
         setMessage(["", "Loading geodata; URL=" + geoURL], debugMsg);
         d3.json(geoURL, function (error, json) {
             if (error != undefined) {
@@ -368,39 +410,83 @@ function chooseMap(mapgroup, mapsubject, mapunit, mapdate) {
                     "Invalid format [serviceOutputFormat = " + geoMD.serviceOutputFormat + "]"], errorMsg);
             }
 
-
             // attrib_data loader:
-            var attribMD = MD.attrib_sources[MD.mapgroups[mapgroup].mapsubjects[mapsubject].mapunits[mapunit].mapdates[mapdate].attrib_data];
-            var attribURL = attribMD.serviceURL;
+            try {
+                var attribMD = MD.attrib_sources[MD.mapgroups[mapgroup].mapsubjects[mapsubject].mapunits[mapunit].mapdates[mapdate].attrib_data];
+                var attribURL = attribMD.serviceURL;
+            } catch (e) {
+                console.log(e);
+            }
             setMessage(["", "Loading attribute data; URL=" + attribURL], debugMsg);
-            d3.csv(attribURL, function (error, csv) {
-                if (error != undefined) {
-                    if (error.status == undefined) { // it's not XMLHTTPrequest error}
-                        theError = error.name + ": " + error.message;
-                    } else {
-                        theError = "HTTP " + error.status + "--" + error.statusText;
+            if (attribMD.serviceOutputFormat == "geojson") {
+
+                d3.json(attribURL, function (error, json) {
+                    if (error != undefined) {
+                        if (error.status == undefined) { // it's not XMLHTTPrequest error}
+                            theError = error.name + ": " + error.message;
+                        } else {
+                            theError = "HTTP " + error.status + "--" + error.statusText;
+                        }
+                        setMessage(["LADEN ATTRIBUUTDATA MISLUKT!\nURL= " + attribURL + ";\nError: " + theError,
+                            "ERROR LOADING ATTRIBUTE DATA!\nURL= " + attribURL + ";\nError: " + theError], errorMsg);
+                        return;
                     }
-                    setMessage(["LADEN ATTRIBUUTDATA MISLUKT!\nURL= " + attribURL + ";\nError: " + theError,
-                        "ERROR LOADING ATTRIBUTE DATA!\nURL= " + attribURL + ";\nError: " + theError], errorMsg);
-                    return;
-                }
 
-                //create a map using FK as key:
-                attribData = d3.map(csv, function (d) {
-                    var FKval = eval("d." + FK);
-                    if (FKval == undefined) {
-                        setMessage(["Geen geldige FK. Check metadata!\nFK=" + FK + "; FKval=" + FKval,
-                            "No valid FK. Check metadata!\n(FK=" + FK + "; FKval=" + FKval], errorMsg);
+                    //create a map using FK as key:
+                    attribData = d3.map();
+                    json.features.forEach(function (d,i) {
+                        var FKval = eval("d.properties." + FK);
+                        var valuesObj = d.properties;
+                        if (FKval == undefined || valuesObj == undefined) {
+                            setMessage(["Geen geldige FK. Check metadata!\nFK=" + FK + "; FKval=" + FKval,
+                                "No valid FK. Check metadata!\n(FK=" + FK + "; FKval=" + FKval], errorMsg);
+                        }
+                        attribData.set(FKval,valuesObj);
+                    });
+
+                    setMessage(["Kaartdata geladen.", "Map data loaded."], hideMsg);
+                    createMap(geoData, mainMap);
+                    symboliseMap(geoData, attribData, FK, mainMap, mapgroup, mapsubject, mapunit, mapdate);
+                    setMessage(["Kaart gemaakt.", "Created map."], hideMsg);
+                }); // geojson attrib_data loader
+
+            } else if (attribMD.serviceOutputFormat == "csv") {
+
+                d3.csv(attribURL, function (error, csv) {
+                    if (error != undefined) {
+                        if (error.status == undefined) { // it's not XMLHTTPrequest error}
+                            theError = error.name + ": " + error.message;
+                        } else {
+                            theError = "HTTP " + error.status + "--" + error.statusText;
+                        }
+                        setMessage(["LADEN ATTRIBUUTDATA MISLUKT!\nURL= " + attribURL + ";\nError: " + theError,
+                            "ERROR LOADING ATTRIBUTE DATA!\nURL= " + attribURL + ";\nError: " + theError], errorMsg);
+                        return;
                     }
-                    return FKval;
-                });
 
-                setMessage(["Kaartdata geladen.", "Map data loaded."], hideMsg);
-                createMap(geoData, mainMap);
-                symboliseMap(geoData, attribData, FK, mainMap, mapgroup, mapsubject, mapunit, mapdate);
-                setMessage(["Kaart gemaakt.", "Created map."], hideMsg);
+                    //create a map using FK as key:
+                    attribData = d3.map(csv, function (d) {
+                        var FKval = eval("d." + FK);
+                        if (FKval == undefined) {
+                            setMessage(["Geen geldige FK. Check metadata!\nFK=" + FK + "; FKval=" + FKval,
+                                "No valid FK. Check metadata!\n(FK=" + FK + "; FKval=" + FKval], errorMsg);
+                        }
+                        return FKval;
+                    });
+
+                    setMessage(["Kaartdata geladen.", "Map data loaded."], hideMsg);
+                    createMap(geoData, mainMap);
+                    symboliseMap(geoData, attribData, FK, mainMap, mapgroup, mapsubject, mapunit, mapdate);
+                    setMessage(["Kaart gemaakt.", "Created map."], hideMsg);
+                }); // CSV attrib_data loader
+
+            } else {
+                setMessage(["Ongeldig formaat [serviceOutputFormat = " + attribMD.serviceOutputFormat + "]",
+                    "Invalid format [serviceOutputFormat = " + attribMD.serviceOutputFormat + "]"], errorMsg);
+            }
+
+
 
-            }); //attrib_data loader
         }); //geo_data loader
 
     } //if-else
@@ -439,7 +525,7 @@ function createMap(geoData, mapLayer) {
         .attr("cy", function (d) {
             return y = Math.round(geo_path.centroid(d)[1]);
         }) // transform the supplied json geo path centroid Y to svg "cy"
-        .attr("class", "defaultCircles")  // add defualt style (from css)
+        .attr("class", "defaultCircles")  // add default style (from css)
         .attr("r", 0)    // add radius , start with r = 0
         .on("mousemove", function () {
             toolTipMove(d3.event)
@@ -483,11 +569,12 @@ function symboliseMap(geoData, attribData, FK, mapLayer, mapgroup, mapsubject, m
     var mapFK = MD.mapgroups[mapgroup].mapsubjects[mapsubject].mapunits[mapunit].mapdates[mapdate].FK;
     var tooltipLabel = MD.mapgroups[mapgroup].mapsubjects[mapsubject].mapunits[mapunit].mapdates[mapdate].label;
     var mapUnit = MD.mapgroups[mapgroup].mapsubjects[mapsubject].data_unit[curLang];
+    var mapClassification = MD.mapgroups[mapgroup].mapsubjects[mapsubject].classification;
     var dataStats;
 
     // *** PROPORTIONAL POINT MAPS ****
     if (mapType == "point_size") {
-        dataStats = makeStats(attribData, mapAttrib, numClasses);
+        dataStats = makeStats(attribData, mapAttrib, mapType, mapClassification);
         // remove classified polygon fills
         mapLayer.selectAll("path")       // select path nodes
             .on("mouseenter", function (d) {
@@ -502,6 +589,7 @@ function symboliseMap(geoData, attribData, FK, mapLayer, mapgroup, mapsubject, m
         ;
         // change proportional circles sizes:
         mapLayer.selectAll("circle")   // select again all the current circle nodes
+            .style("fill", mapClassification.colours)
             .on("mouseenter", function (d) {
                 toolTipShow(infoTextFromData(d, attribData, tooltipLabel, mapAttrib, mapFK, mapUnit));
             })
@@ -516,7 +604,7 @@ function symboliseMap(geoData, attribData, FK, mapLayer, mapgroup, mapsubject, m
 
 // *** CHOROPLETH MAPS ****
     } else if (mapType == "area_value") { // choropleth map:
-        dataStats = makeStats(attribData, mapAttrib, numClasses);
+        dataStats = makeStats(attribData, mapAttrib, mapType, mapClassification);
         // shrink circles :
         mapLayer.selectAll("circle")   // select again all the current circle nodes
             .transition().duration(1000)
@@ -566,7 +654,7 @@ function symboliseMap(geoData, attribData, FK, mapLayer, mapgroup, mapsubject, m
 
         // *** CHOROCHROMATIC MAPS ****
     } else if (mapType == "area_colour") { // simple label map:
-        dataStats = makeStats(attribData, mapAttrib, -1);
+        dataStats = makeStats(attribData, mapAttrib, mapType, mapClassification);
         // shrink circles :
         mapLayer.selectAll("circle")   // select again all the current circle nodes
             .transition().duration(1000)
@@ -593,17 +681,18 @@ function symboliseMap(geoData, attribData, FK, mapLayer, mapgroup, mapsubject, m
     }
 
     setMessage(["", "Created map symbolisation."], debugMsg);
-    makeLegend(mapgroup, mapsubject, mapunit, mapdate, mapType, dataStats);
+    makeLegend(mapgroup, mapsubject, mapunit, mapdate, mapType, mapClassification, dataStats);
 }
 
 function getAttribValue(d, attribData, mapAttrib, mapFK) {
     var FKval = undefined;
     var attribValue = undefined;
-    FKval = eval("d.properties." + mapFK);
-    attribValue = eval("attribData.get(FKval)." + mapAttrib);
-    if (FKval == undefined || attribValue == undefined) {
-        setMessage(["Ongeldige waarde(n)! \nFK=" + FKval + "; attribuut=" + mapAttrib + "; waarde=" + attribValue,
-            "Invalid value(s)! \n(FK=" + FKval + "; attribute=" + mapAttrib + "; value=" + attribValue], errorMsg);
+    try {
+        FKval = eval("d.properties." + mapFK);
+        attribValue = eval("attribData.get(FKval)." + mapAttrib);
+    } catch (e) {
+        setMessage(["Fout in data!\nFK=" + FKval + "; attribuut=" + mapAttrib + "; waarde=" + attribValue,
+        "Error retrieving data!\n(FK=" + FKval + "; attribute=" + mapAttrib + "; value=" + attribValue], errorMsg);
     }
     return attribValue;
 }
@@ -612,7 +701,7 @@ function getAttribValue(d, attribData, mapAttrib, mapFK) {
  * update legendDiv according to mapgroup/map chosen in menu
  *
  */
-function makeLegend(mapgroup, mapsubject, mapunit, mapdate, mapType, dataStats) {
+function makeLegend(mapgroup, mapsubject, mapunit, mapdate, mapType, mapClassification, dataStats) {
 
     var geoSourceStr = ["Geodata", "Geodata"];
     var dataSourceStr = ["Attribuut data", "Attribute data"];
@@ -620,16 +709,17 @@ function makeLegend(mapgroup, mapsubject, mapunit, mapdate, mapType, dataStats)
     var mapObj = MD.mapgroups[mapgroup].mapsubjects[mapsubject].mapunits[mapunit].mapdates[mapdate];
 
     var legendHeader = "<h3>" + MD.mapgroups[mapgroup].groupname[curLang] + "</h3>";
-    legendHeader += "<h1>" + MD.mapgroups[mapgroup].mapsubjects[mapsubject].name[curLang] + "</h1>";
-    legendHeader += "<h4>" + MD.mapgroups[mapgroup].mapsubjects[mapsubject].data_unit[curLang];
-    legendHeader += " per " + MD.mapgroups[mapgroup].mapsubjects[mapsubject].mapunits[mapunit].name[curLang];
-    legendHeader += " (" + mapObj.date + ")</h4>";
+    legendHeader += "<h1>" + MD.mapgroups[mapgroup].mapsubjects[mapsubject].name[curLang] + "</h1><h4>";
+    if (MD.mapgroups[mapgroup].mapsubjects[mapsubject].mapunits[mapunit].name[curLang] != "") {
+        legendHeader += "per " + MD.mapgroups[mapgroup].mapsubjects[mapsubject].mapunits[mapunit].name[curLang] + " ";
+    }
+    legendHeader += "(" + mapObj.date + ")</h4>";
+    if (MD.mapgroups[mapgroup].mapsubjects[mapsubject].data_unit[curLang] != "") {
+        legendHeader += MD.mapgroups[mapgroup].mapsubjects[mapsubject].data_unit[curLang] + ":";
+    }
 
     legendDiv.html(legendHeader);
 
-
-    DEBUG = dataStats;
-
     var legendSVG = legendDiv.append("svg")
             .attr("id", "legendSVG")
             .attr("width", "100%")
@@ -644,12 +734,12 @@ function makeLegend(mapgroup, mapsubject, mapunit, mapdate, mapType, dataStats)
             .attr("class", "mySizeLegend")
             .attr("transform", "translate(20,20)")
         ;
-        var linearSize = d3.scale.linear().domain([0,dataStats.dMax]).range([0, maxCircleSize]);
+        var linearSize = d3.scale.linear().domain([0, dataStats.dMax]).range([0, maxCircleSize]);
         //var linearSize = d3.scale.linear().domain([0,100]).range([10, 20]);
 
         var mySizeLegend = d3.legend.size()
                 .scale(linearSize)
-                .labelFormat(d3.format(".0f"))
+                .labelFormat(d3.format(mapClassification.format))
                 .shape('circle')
                 .shapePadding(2)
                 .labelOffset(1)
@@ -659,6 +749,8 @@ function makeLegend(mapgroup, mapsubject, mapunit, mapdate, mapType, dataStats)
         legendSVG.select(".mySizeLegend")
             .call(mySizeLegend)
         ;
+        legendSVG.selectAll("circle").style("fill", mapClassification.colours);
+
         legendSVG.style("height", mySizeLegend.legendHeight());
 
         // *** CHOROPLETH MAPS ****
@@ -670,7 +762,7 @@ function makeLegend(mapgroup, mapsubject, mapunit, mapdate, mapType, dataStats)
             .attr("transform", "translate(0,0)")
         ;
         var myColorLegend = d3.legend.color()
-                .labelFormat(d3.format(".0f"))
+                .labelFormat(d3.format(mapClassification.format))
                 .labelDelimiter("–")
                 .shapeWidth(20)
                 .useClass(false)
@@ -748,44 +840,135 @@ function infoTextFromData(d, attribData, labelAttrib, mapAttrib, mapFK, mapUnit)
 }
 
 
-function makeStats(attribData, attrib, numClasses) {
+function makeStats(attribData, attrib, mapType, mapClassification) {
 
     var myStats = {
         dValues: undefined, dMin: undefined, dMax: undefined, dCircleRatio: undefined,
-        dJenksClasses: undefined, dClass2Value: undefined, dClass2Colour: undefined
+        dClasses: undefined, dClass2Value: undefined, dClass2Colour: undefined
     };
 
     var numFeatures = attribData.size();
     myStats.dValues = new Array(numFeatures);
     var i = 0;
+    var errorStr = "";
     attribData.forEach(function (k, v) {
-        myStats.dValues[i] = +eval("v." + attrib); //+ to force numerical
+        if (mapType == "point_size" || mapType == "area_value") {
+            myStats.dValues[i] = +eval("v." + attrib); //+ to force numerical
+            if (myStats.dValues[i] == undefined || isNaN(myStats.dValues[i])) {
+                errorStr = "Maptype=" + mapType + "; data=" + myStats.dValues[i];
+            }
+        } else { //area_label or area_colour
+            myStats.dValues[i] = eval("v." + attrib);
+            if (myStats.dValues[i] == undefined) {
+                errorStr = "Maptype=" + mapType + "; data=" + myStats.dValues[i];
+            }
+        }
         i++;
     });
+    if (errorStr != "") {
+        setMessage(["ONGELDIGE DATA VOOR DIT MAPTYPE!\n" + errorStr,
+            "INVALID DATA FOR THIS MAPTYPE!\n" + errorStr], errorMsg);
+        console.log(myStats.dValues);
+    }
 
-    if (numClasses == -1) { //non numerical data
-        // an ordinal scale for (chorochromatic) nominal maps
-        myStats.dClass2Colour = d3.scale.ordinal() // make a classes array using d3 ordinal
-            .range(colorbrewer.Spectral[11])   // assign to 11 classes Spectral CB range
-    } else {
+    var clStr = "type=" + mapClassification.type + "; numclasses=" + mapClassification.numclasses + "; classes="
+        + mapClassification.classes + "; colours=" + mapClassification.colours + "; format=" + mapClassification.format;
+    console.log(clStr);
+
+    // *** PROPORTIONAL POINT MAPS ****
+    if (mapType == "point_size") {
         myStats.dMin = d3.min(myStats.dValues);
         //TODO: less crappy solution for NoData vals:
         if (myStats.dMin <= -99999997) { // is NoData
             myStats.dMin = 0
-        }//
+        }
         myStats.dMax = d3.max(myStats.dValues);
-        //now determine key measures:
         // a ratio between values and circles radius for (proportional) ratio maps:
         myStats.dCircleRatio = maxCircleSize / (Math.sqrt(myStats.dMax) / Math.PI );
-        //use Jenks.js to calculate Jenks Natural breaks for x classes
-        myStats.dJenksClasses = jenks(myStats.dValues, numClasses);
+
+        // *** CHOROPLETH MAPS ****
+    } else if (mapType == "area_value") { // choropleth map:
+        myStats.dMin = d3.min(myStats.dValues);
+        //TODO: less crappy solution for NoData vals:
+        if (myStats.dMin <= -99999997) { // is NoData
+            myStats.dMin = 0
+        }
+        myStats.dMax = d3.max(myStats.dValues);
+        if (mapClassification.numclasses == undefined) {
+            mapClassification.numclasses = 5;
+        }
+        if (mapClassification.numclasses < 3 || mapClassification.numclasses > 11) {
+            InvalidClassMessage(clStr + "\nInvalid numclasses (<3 or >11).");
+        }
+        if (mapClassification.type == "jenks") { //use jenks.js to calculate Jenks Natural breaks
+            myStats.dClasses = jenks(myStats.dValues, mapClassification.numclasses);
+        } else if (mapClassification.type == "manual") { // use manual
+            if (mapClassification.classes == undefined) {
+                InvalidClassMessage(clStr + "\nClasses array needed for manual classification.");
+            }
+            if (mapClassification.classes[0] == "dMin") {
+                mapClassification.classes[0] = myStats.dMin;
+            }
+            if (mapClassification.classes[mapClassification.classes.length - 1] == "dMax") {
+                mapClassification.classes[mapClassification.classes.length - 1] = myStats.dMax;
+            }
+            //check manual classes
+            if (mapClassification.classes[0] > myStats.dMin) {
+                InvalidClassMessage(clStr + "\nData min < lowest class.");
+            } else if (mapClassification.classes[mapClassification.classes.length - 1] < myStats.dMax) {
+                InvalidClassMessage(clStr + "\nData max > highest class.");
+            } else if (mapClassification.classes.length - 1 != mapClassification.numclasses) {
+                InvalidClassMessage(clStr + "\nClasses array length does not match number of classes.");
+            } else { // all correct
+                myStats.dClasses = mapClassification.classes;
+            }
+
+        } else {
+            InvalidClassMessage(clStr + "\nInvalid type.");
+        }
         // a classed scale for (choropleth) ordered or relative ratio maps:
+        try {
+            var CBrange = eval("colorbrewer." + mapClassification.colours + "[" + mapClassification.numclasses + "]");
+        } catch (e) {
+            InvalidClassMessage(clStr + "\n'" + mapClassification.colours + "' is not a valid ColorBrewer name.");
+        }
         myStats.dClass2Value = d3.scale.quantile()
-            .domain(myStats.dJenksClasses) // use Jenks classes (see above)
-            .range(colorbrewer.Greens[numClasses])   // assign to numClasses classes in Green CB range
+            .domain(myStats.dClasses) // use jenks or manual classes (see above)
+            .range(CBrange)
         ;
+
+        // *** LABEL MAPS ****
+    } else if (mapType == "area_label") { // simple label map:
+
+        // *** CHOROCHROMATIC MAPS ****
+    } else if (mapType == "area_colour") { // simple label map:
+
+        // an ordinal scale for (chorochromatic) nominal maps
+        if (mapClassification.numclasses == undefined) {
+            mapClassification.numclasses = 25; //25 is max for scale MaxColours
+        }
+        if (mapClassification.numclasses < 3 || mapClassification.numclasses > 25) {
+            InvalidClassMessage(clStr + "\nInvalid numclasses (<3 or >24).");
+        }
+        try {
+            var CBrange = eval("colorbrewer." + mapClassification.colours + "[" + mapClassification.numclasses + "]");
+        } catch (e) {
+            InvalidClassMessage(clStr + "\n'" + mapClassification.colours + "' not valid ColorBrewer name, or no. of classes not available.");
+        }
+        myStats.dClass2Colour = d3.scale.ordinal() // make a classes array using d3 ordinal
+            .range(CBrange)
+
+    } else {
+        setMessage(
+            ["Onbekend Map Type [" + mapType + "]", "Unknown Map Type [" + mapType + "]"], errorMsg);
     }
+
     setMessage(["", "Calculated map statistics."], debugMsg);
     //if (debugOn) console.log(myStats);
     return myStats;
+}
+
+function InvalidClassMessage(Str) {
+    setMessage(["ONGELDIGE CLASSIFICATIE!\n" + Str,
+        "INVALID CLASSIFICATION!\n" + Str], errorMsg);
 }
\ No newline at end of file