Smart M.App discussions

Looking for answers in regards to M.Apps, M.App Exchange or M.App Studio? Smart M.App Tech Discussion board is where you can search, ask your questions and assist others by sharing your knowledge. Join the conversation, connect, contribute and share.
Showing results for 
Search instead for 
Do you mean 
Reply
Highlighted
Contributor
Posts: 34
Registered: ‎10-21-2016
Accepted Solution

Choropleth registered but NOT displayed

I have been trying to get a shapefile into a map, by using the BI panel to visualize the vector data as a choropleth map (see the topic: http://community.hexagongeospatial.com/t5/Smart-M-App-Tech-Discussions/Output-from-recipe-shapefile-... ).

 

Right now I am as far as having a registered choropleth. However, I do not see it in the map yet. I have defined the stage model and the choropleth, which is registered (I don't use any widgets) but I am missing a way to 'display' or render the registered choropleth in the map.

 

I'm wondering if I'm forgetting something - everything is successful and the code is completely ran through (so the choropleth must be there) but the choropleth doesn't show up. My code at the current moment (which leads to 'success' in the console):

 

var stageModel = {
    "id": "3dVolume",
    "features": [{
        "id": "feature_geom",
        "key": "PrimaryKey",
        "name": "features"
    }],
	values: [
	{
		id: 'Volume',
		value: 'Volume',
		name: 'Volume'
	}
	],
    "colors": {
        "paletteYellow": {
            "range": ["#FE228B", "#FEE022", "#D73027", "#A50026", "#1A9850", "#F46D43", "#D9EF8B", "#22E08B", "#FEE08B", "#FDAE61", "#662263", "#A6D96A", "#66BD63"]
        },
        "paletteMap": {
            "range": ["#A50026", "#D73027", "#F46D43", "#FDAE61", "#FEE08B", "#D9EF8B", "#A6D96A", "#66BD63", "#1A9850", "#662263", "#22E08B", "#FE228B", "#FEE022"]
        }
    },
};
 
$GP.bi.config.overwriteConfiguration(function (configuration){
    var ret = configuration || {};
    ret.mapConfig = {
        "tooltipAttributes": ["Volume"],
        "mapLegendPlacement": "map",
        "mapLegendEnabled": true,
        "mapTitleEnabled": true
    };
    return ret;
});

var stage = $GP.bi.stage;
            
function updateStage(gjson) {
	var choroplethModel1 = {
		chart: "choropleth",
		name: "3d Volume",
		target: "map",
		layer: "feature_geom",
		key: "PrimaryKey",
		values: ["Volume"],
		colors: "paletteMap",
		id: "volumeChoropleth"
	};
	
    stage.registerStageModel({
        stageModel: stageModel
    }, function registerStageModelSuccess () {
        stage.registerDataTable({
            tableSource: gjson
        }
        , 
        function registerDataTableSuccess(){
            stage.registerChoropleth({
                model: choroplethModel1,
                mapTitleEnabled: true,
                mapLegendEnabled: true,
                mapLegendPlacement: "map",
                tooltipAttributes: ["Volume"]
            }, 
            function registerChoroplethSuccess() { console.log('success')},
            function registerChoroplethError ( e ) {
				onError('registerChoropleth ' + e );
			}
			);
        }, 
        function registerDataTableError(e) {
			onError('registerDataTable ' + e );
		});
    }, function registerStageModelError(e) {
		onError('registerStageModel ' + e );
	});   
}	

function onError(e) {
    console.log("Something went wrong: ", e);
}
 
gsp.m_app.messages.subscribe("geoJSONloaded", function (messageParams) {
	var url = messageParams.url;

	// load that object back from M.App Chest
	$GP.m_app.utils.connection(url).then(function(result) { 
		newGeoJson = JSON.parse(result.entity);

		// after extracting the data, refresh the charts
		updateStage(newGeoJson);
	});
});

Does anybody know how to do this? Any help would be appreciated!

Vincent

Highlighted
Technical Evangelist
Posts: 1,351
Registered: ‎09-11-2015

Re: Choropleth registered but NOT displayed

[ Edited ]

Hi Vincent,

 

You must add the choropleth also to the legend. This function extracted from the sample here summarizes the process:

 

function display (config) {
    //config definition
    var stageModel = config.stageModel,
        tableSource = config.tableSource,
        chartDescriptors = config.chartDescriptors,
        choroplethModel = config.choroplethModel,
        legendModel = config.legendModel;

    // store widget ids to remove them later by id
    currentWidgetIds = chartDescriptors.map(function(obj){
        return obj.chartM.id;
    });
    s.registerStageModel({
        stageModel: stageModel
    }, function() {
        s.registerDataTable({
            tableSource: tableSource
        }, function() {
            s.addWidgets({
                descriptors: chartDescriptors
            }, function() {
                s.registerChoropleth({
                    model: choroplethModel,
                    mapTitleEnabled: true,
                    mapLegendEnabled: true,
                    mapLegendPlacement: "map"
                }, function(layerName) {
                    // begin workaround
                    // legend.add adds properties to the 
                    // legendModel and it would not be usable later
                    var legendModelClone = JSON.parse(JSON.stringify(legendModel));
                    // end workaround
                    gsp.legend.add(legendModelClone, function() {
                        console.log("Registered layer");
                        currentModel = choroplethModel;
                        currentLayer = legendModel;
                    }, onError);
                }, onError);
            });
        }, onError);
        currentId = stageModel.id;
    }, onError);
}

 

And usual legend model:

    var layer1 = {
        definitionName: "MAppPlatformGeoJson",
        url: geometryUrl,
        name: "<same as choropleth name>",
        id: "<same as choropleth name>",
        bbox: [0, 0, 0, 0],
        bboxCrs: "EPSG:4326",
        supportedCrses: ["EPSG:4326", "EPSG:3857"],
        style: {
            display: "thematicLayer"
        }
    };

 

Hope this helps.

 

Jan

Jan Neumann
Post Sales Engineer Web Applications
Hexagon Geospatial

Highlighted
Contributor
Posts: 34
Registered: ‎10-21-2016

Re: Choropleth registered but NOT displayed

[ Edited ]

Thanks for the quick response!

 

I was on the right track. But my problem was - and still is - when I try to add a legend, i get the error: geometryURL is not defined. I'll try to construct it.

 

Highlighted
Technical Evangelist
Posts: 1,351
Registered: ‎09-11-2015

Re: Choropleth registered but NOT displayed

Your geometryUrl could be a link to the geojson attachment + obtained APIKey to be able to directly download it.

 

Jan

Jan Neumann
Post Sales Engineer Web Applications
Hexagon Geospatial

Highlighted
Contributor
Posts: 34
Registered: ‎10-21-2016

Re: Choropleth registered but NOT displayed

[ Edited ]

Jan,

 

Again, big thanks for your help. I passed the url from the first part of the code ('publish catalog item and send to map') and used it as geometryURL. At this moment I am getting the error "InvalidArgument: ids array shouldn't be empty", and it seems to be coming from the registerChoropleth function.

 

I was wondering if there is any further documentation about how a chart is made, what the needed components are, and how they work in more detail. I've been trying to implement and manipulate code from examples and the API for a few days now, but I still feel out of control over the components of the code. E.g. I added a function to add Widgets (because with only a legend the code still didn't work) and have tried with different values for the keys/values for content of 'chartM' inside 'chartDescriptors'. But I don't know what is neccessary or right; actually I don't even want Widgets. Anyway, I tried to 'fill in' the chartDescriptors/-model with the values I have from the choropleth. Since I don't have any other values to use and the choropleth is also a 'chart' this was the only thing I could think of, but it feels like I am duplicating stuff I shouldn't duplicate, or doing things which don't make sense. 

 

This is the code which leads to the errors. Note: in my geoJSON there are unique ID's. I don't know exactly what the id's array should be (again, a more detailed documentation of the minimum requirements could be helpful) and why the id's array is empty, and what's the reason for that.

 

//# sourceURL=BIMap.js

var stageModel = {
    "id": "3dVolume",
    "features": [{
        "id": "feature_geom",
        "key": "PrimaryKey",
        "name": "features"
    }],
    "fields": [],
    "totals": [],
	"values": [
	{
		"id": 'Volume',
		"value": 'Volume',
		"name": 'Volume'
	}
	],
    "colors": {
        "paletteYellow": {
            "range": ["#FE228B", "#FEE022", "#D73027", "#A50026", "#1A9850", "#F46D43", "#D9EF8B", "#22E08B", "#FEE08B", "#FDAE61", "#662263", "#A6D96A", "#66BD63"]
        },
        "paletteMap": {
            "range": ["#A50026", "#D73027", "#F46D43", "#FDAE61", "#FEE08B", "#D9EF8B", "#A6D96A", "#66BD63", "#1A9850", "#662263", "#22E08B", "#FE228B", "#FEE022"]
        }
    },
};
 
$GP.bi.config.overwriteConfiguration(function (configuration){
    var ret = configuration || {};
    ret.mapConfig = {
        "tooltipAttributes": ["Volume"],
        "mapLegendPlacement": "map",
        "mapLegendEnabled": true,
        "mapTitleEnabled": true
    };
    return ret;
});

var stage = $GP.bi.stage;
stageId = stageModel.id;
            
function updateStage(gjson, geometryUrl) {
	var choroplethModel1 = {
		chart: "choropleth",
		name: "3d Volume",
		target: "map",
		layer: "feature_geom",
		key: "PrimaryKey",
		values: ["Volume"],
		colors: ['#ffbf00', '#a50026', '#d73027', '#f46d43', '#fdae61'],
		id: "3d Volume"
	};
	
	var chartDescriptors = {
        chartM: {
            id: "3d Volume",
            name: "3d Volume",
            title: "3d Volume",
            key: "PrimaryKey",
            values: ["Volume"],
            tooltips: "{Volume}",
            colors: ['#ffbf00', '#a50026', '#d73027', '#f46d43', '#fdae61'],
            chart: "choropleth"
        }
    };
	
	var legendModel = {
		definitionName: "MAppPlatformGeoJson",
		url: geometryUrl,
		name: "3d Volume",
		id: "3d Volume",
		bbox: [0, 0, 0, 0],
		bboxCrs: "EPSG:32631",
		supportedCrses: ["EPSG:32631"],
		style: {
			display: "thematicLayer"
		}
	};

    stage.registerStageModel({
        stageModel: stageModel
    }, function registerStageModelSuccess () {
        stage.registerDataTable({
            tableSource: gjson
        }, 
        function registerDataTableSuccess(){
			stage.addWidgets({
                descriptors: chartDescriptors
            }, function addWidgetsSuccess() {	
				stage.registerChoropleth({
					model: choroplethModel1,
					mapTitleEnabled: true,
					mapLegendEnabled: true,
					mapLegendPlacement: "map",
					tooltipAttributes: ["Volume"]
				}, 
				function(legendModel) {
					// begin workaround
					// legend.add adds properties to the legendModel and it would not be usable later
					var legendModelClone = JSON.parse(JSON.stringify(legendModel));
					// end workaround
					gsp.legend.add(legendModelClone, function() {
						console.log("Registered layer");
						currentModel = choroplethModel1;
						currentLayer = legendModel;
					}, function registerChoroplethError(e) {
						onError('registerChoropleth ', e);
					}, function registerDataTableError(e) {
    					onError('registerDataTable ', e);
    				});
				}, function registerStageModelError(e) {
					onError('registerStageModel ', e);
				});  
			}, function addWidgetsError(e) {
				onError('addWidgetsError ', e);
			}); 
        }, function registerDataTableError(e) {
			onError('registerDataTableError ', e);
        });
    }, function registerStageModelError(e) {
		onError('registerStageModelError ', e);
    });	
}

function onError(message, e) {
    console.log(message, e);
}
 
gsp.m_app.messages.subscribe("geoJSONloaded", function (messageParams) {
	var url = messageParams.url;

	// load that object back from M.App Chest
	$GP.m_app.utils.connection(url).then(function(result) { 
		newGeoJson = JSON.parse(result.entity);

		// after extracting the data, refresh the charts
		updateStage(newGeoJson, url);
	});
});
Highlighted
Contributor
Posts: 34
Registered: ‎10-21-2016

Re: Choropleth registered but NOT displayed

Hi Jan,

 

I've reduced everything to the code below. All the success functions are executed, but if I examine the stage in the debugger I get this:

 

(in debugger) 
stage = stage.__biManager.__stageManager.__stages[0]
stage.render() DataStage: no table data to process

I'm also wondering: at what point does the stage get rendered? Is stage.registerChoropleth() enough? This is unclear from the documentation.

 

//# sourceURL=BIMap.js

var stageModel = {
    "id": "3dVolume",
    "features": [{
        "id": "feature_geom",
        "key": "PrimaryKey",
        "name": "features",
        "convertToTable": true // DOES THIS WORK??
    }],
    "fields": [],
    "totals": [],
	"values": [
	{
		"id": 'Volume',
		"value": 'Volume',
		"name": 'Volume'
	}
	],
    "colors": {
        "paletteMap": {
            "range": ["#A50026", "#D73027", "#F46D43", "#FDAE61", "#FEE08B", "#D9EF8B", "#A6D96A", "#66BD63", "#1A9850", "#662263", "#22E08B", "#FE228B", "#FEE022"]
        }
    },
};
 
var stage = $GP.bi.stage;

function updateStage(gjson, geometryUrl) {
	var choroplethModel1 = {
		chart: "choropleth",
		name: "3d Volume",
		target: "map",
		layer: "feature_geom",
		key: "PrimaryKey",
		values: ["Volume"],
		colors: "paletteMap",
		id: "3d Volume"
	};
	
    stage.registerStageModel({
            stageModel: stageModel
        },
        
        function registerStageModelSuccess () {
			stage.registerChoropleth(
			    {
    				model: choroplethModel1,
    				mapTitleEnabled: false,
    				mapLegendEnabled: false,
    				mapLegendPlacement: "map",
    			}, 
    			function registerChoroplethSuccess() {
    				console.log("Registered layer");
    				console.log(stage);
// -> debugcode above is executed here <-
}, function registerChoroplethError(e) { onError('registerChoropleth ', e); } ); }, function registerStageModelError(e) { onError('registerStageModel ', e); } ); } function onError(message, e) { console.log(message, e); }
Highlighted
Technical Evangelist
Posts: 1,351
Registered: ‎09-11-2015

Re: Choropleth registered but NOT displayed

Hi Vincent,

 

The stage is rendered when any of the widgets (incl. choropleth) are added. To display the vector data you must:

  • registerChoropleth
  • add legend entry

The legend entry Url must point to the GeoJSON attachment file together with proper APIKey. Can you check if you have correct link generated for the data?

 

Jan

Jan Neumann
Post Sales Engineer Web Applications
Hexagon Geospatial

Highlighted
Contributor
Posts: 34
Registered: ‎10-21-2016

Re: Choropleth registered but NOT displayed

Hi Jan, 

 

I still get the error "ids array shouldn't be empty" inside the registerChoropleth-function. Do you know what might be the cause for this, and what the ids array actually is, or where it should be, in what form? I cannot find any reference.

 

I also don't know where I should get the APIKey from. Is there an easy way to obtain it?

 

Thanks again for your help here, I really appreciate it.

 

Vincent

Highlighted
Technical Evangelist
Posts: 1,351
Registered: ‎09-11-2015

Re: Choropleth registered but NOT displayed

Try to change the choropleth model to:

 

	var choroplethModel1 = {
		chart: "choropleth",
		name: "3d Volume",
		target: "map",
		layer: "feature_geom",
		key: "PrimaryKey",
		values: "Volume",
		colors: "paletteMap",
		id: "3d_Volume"
	};

Changed ID to remove blank spaces:

	var legendModel = {
		definitionName: "MAppPlatformGeoJson",
		url: geometryUrl,
		name: "3d Volume",
		id: "3d_Volume",
		bbox: [0, 0, 0, 0],
		bboxCrs: "EPSG:32631",
		supportedCrses: ["EPSG:32631"],
		style: {
			display: "thematicLayer"
		}
	};

 

Regarding the APIKey please see my sample here:

http://community.hexagongeospatial.com/t5/Smart-M-App-Tech-Discussions/Creating-data-download-button...

 

The APIKey is required whenever you want to get a direct URL for downloading data on your M.App Chest.

 

Jan

Jan Neumann
Post Sales Engineer Web Applications
Hexagon Geospatial

Highlighted
Contributor
Posts: 34
Registered: ‎10-21-2016

Re: Choropleth registered but NOT displayed

[ Edited ]

I have tried the program and it leads to 'SUCCESS', and I see several errors. However, in some of these errors I can see this:

 

(...) https://mapp.hexagongeospatial.com/api/v1/downloads/download-3de481cf-d6e9-4316-8907-08f2ec2eb96c/zip?apiKey=c3120c7dccc6a976

The last part of it is:

 

apiKey=caaaac7dccc6a976

Does this mean that my apiKey is 

caaaac7dccc6a976

(?)

 

If so, I am still wondering how to construct the url needed for the legendModel/legend entry/geometryUrl. You told it should be a combination of an url which points to the GeoJSON attachment and a proper APIKey. But I am not sure what it should be.

 

The link to my GeoJSON attachment is this:

api/v1/items/f8027fa7-66bf-4ce9-a9c3-6294c1c03c56_2c918082579a7fab01580664c4cf59a4/attachments/Output.geojson.attachment

When I combine my results with a '?' in between I get the following url:

api/v1/items/f8027fa7-66bf-4ce9-a9c3-6294c1c03c56_2c918082579a7fab01580664c4cf59a4/attachments/Output.geojson.attachment?apiKey=caaaac7dccc6a976

I'll give it a try, but I'm not sure if this is the right way to do it. 

 

Thanks a lot Jan, you're really helping me/us out. 

 

Vincent