I'm trying to write a javascript web app that does a multi-stage raster calculation. At each stage, I'd like to display the output raster, then use it as input to the next stage. What is the best way to pass rasters from one GP tool to another?
I've tried setting the output parameter to raster dataset, which does generate a TIFF in the scratch workspace (for example http://xxxxxx:6080/arcgis/rest/directories/arcgisjobs/createrandomraster_gpserver/j20ddb907be1d44049...), but I can't work out how to use this url to create a layer that can be added to the map. A number of the layer constructors take a url, but none of them display the layer on my map.
ArcGISDynamicMapServiceLayer constructor
ArcGISImageServiceLayer constructor
I've also tried setting the tool output to raster layer, which displays on the web map ok, but doesn't work as an input to the second tool.
I've looked through the help docs and javascript api, but there isn't much detail on raster handling. I know I'm getting the input format wrong, but can't find any clues as to what I should be doing. The only response I get from the server is a Failed message, which isn't much use.
Any ideas? This discussion seems to cover the same area, but no-one has come up with the answer yet.
Solved! Go to Solution.
So, I'll answer my own question (again!):
Parameter data types need to be Raster Layer, and when you publish, make sure you check View Result with a Map Service on the Parameters tab.
Then when you get the result data, it's the value property that needs to be passed into the next tool. This is a JSON element containing type and url properties.
Here's a simplified example of the finished code:
gpSetup = { /** * @ Description: LFP setup basic GP tool. */ outZ: null, init: function () { require(["esri/layers/ImageParameters", "esri/tasks/Geoprocessor"], function (ImageParameters, Geoprocessor) { "use strict"; //Define the hosted geoprocessor task var gp = new Geoprocessor(urlSetup), //Pass in values that are found in the forms to the geoprocessor object params = { "Stage Age": "Aqui", "WATER Depth": "203.70" }; function setupCallback(jobInfo) { var imageParams; if (jobInfo.jobStatus !== "esriJobFailed") { setupJobId = jobInfo.jobId; //Put the resulting images in the following maps. imageParams = new ImageParameters(); imageParams.imageSpatialReference = map0.spatialReference; // keep output to pass on to next tool gp.getResultData(setupJobId, "InputZ", function (gpData) { gpSetup.outZ = gpData.value; gpNpp.init(); }); // display output as map layer gp.getResultImageLayer(setupJobId, "InputZ", imageParams, function (gpLayer) { map0.addLayer(gpLayer); leftMapTitle.innerHTML = "InputZ"; }); } } gp.submitJob(params, setupCallback, statusCallback, errorCallback); } ); } }; gpNpp = { /** * @ Description: Create NPP GP tool. */ init: function () { require(["esri/layers/ImageParameters", "esri/tasks/Geoprocessor"], function (ImageParameters, Geoprocessor) { "use strict"; var gp, params; //Define the hosted geoprocessor task gp = new Geoprocessor(urlNPP); //Pass in values that are found in the forms to the geoprocessor object params = { "Input_Z": gpSetup.outZ }; function nppCallback(jobInfo) { var imageParams; if (jobInfo.jobStatus !== "esriJobFailed") { nppJobId = jobInfo.jobId; //Put the resulting images in the following maps. imageParams = new ImageParameters(); imageParams.imageSpatialReference = map1.spatialReference; gp.getResultImageLayer(nppJobId, "NPP", imageParams, function (gpLayer) { map1.addLayer(gpLayer); rightMapTitle.innerHTML = "NPP"; }); } } gp.submitJob(params, nppCallback, statusCallback, errorCallback); } ); } };
So, I'll answer my own question (again!):
Parameter data types need to be Raster Layer, and when you publish, make sure you check View Result with a Map Service on the Parameters tab.
Then when you get the result data, it's the value property that needs to be passed into the next tool. This is a JSON element containing type and url properties.
Here's a simplified example of the finished code:
gpSetup = { /** * @ Description: LFP setup basic GP tool. */ outZ: null, init: function () { require(["esri/layers/ImageParameters", "esri/tasks/Geoprocessor"], function (ImageParameters, Geoprocessor) { "use strict"; //Define the hosted geoprocessor task var gp = new Geoprocessor(urlSetup), //Pass in values that are found in the forms to the geoprocessor object params = { "Stage Age": "Aqui", "WATER Depth": "203.70" }; function setupCallback(jobInfo) { var imageParams; if (jobInfo.jobStatus !== "esriJobFailed") { setupJobId = jobInfo.jobId; //Put the resulting images in the following maps. imageParams = new ImageParameters(); imageParams.imageSpatialReference = map0.spatialReference; // keep output to pass on to next tool gp.getResultData(setupJobId, "InputZ", function (gpData) { gpSetup.outZ = gpData.value; gpNpp.init(); }); // display output as map layer gp.getResultImageLayer(setupJobId, "InputZ", imageParams, function (gpLayer) { map0.addLayer(gpLayer); leftMapTitle.innerHTML = "InputZ"; }); } } gp.submitJob(params, setupCallback, statusCallback, errorCallback); } ); } }; gpNpp = { /** * @ Description: Create NPP GP tool. */ init: function () { require(["esri/layers/ImageParameters", "esri/tasks/Geoprocessor"], function (ImageParameters, Geoprocessor) { "use strict"; var gp, params; //Define the hosted geoprocessor task gp = new Geoprocessor(urlNPP); //Pass in values that are found in the forms to the geoprocessor object params = { "Input_Z": gpSetup.outZ }; function nppCallback(jobInfo) { var imageParams; if (jobInfo.jobStatus !== "esriJobFailed") { nppJobId = jobInfo.jobId; //Put the resulting images in the following maps. imageParams = new ImageParameters(); imageParams.imageSpatialReference = map1.spatialReference; gp.getResultImageLayer(nppJobId, "NPP", imageParams, function (gpLayer) { map1.addLayer(gpLayer); rightMapTitle.innerHTML = "NPP"; }); } } gp.submitJob(params, nppCallback, statusCallback, errorCallback); } ); } };
Wow, this code editor really is horrible. Apologies for bad layout above, but I don't have time to keep re-editing it to try and fix it.
Hi
I have a custom gp tool that does raster difference, the geoprocessing is working the esriJobSucceeded, however when I add the gpLayer to the map it trows an error saying ReferenceError: gp is not defined at completeCallback
I'm not sure what this mean, have you ever seen this error. Here is the code so you get some Idea
executeGP = function () {
if ($("#compareMethodDD").val() !== null) {
if ($("#compareMethodDD").val().length > 0) {
compareMethodVal = $("#compareMethodDD").val();
} else {
console.log("Compare method not selected.");
}
}
if ($("#compareLayer1DD").val() !== null) {
if ($("#compareLayer1DD").val().length > 0) {
compareLayer1Val = $("#compareLayer1DD").val();
} else {
console.log("Compare Layer 1 not selected.")
}
}
if ($("#compareLayer2DD").val() !== null) {
if ($("#compareLayer2DD").val().length > 0) {
compareLayer2Val = $("#compareLayer2DD").val();
} else {
console.log("Compare Layer 2 not selected.")
}
}
var gp = new Geoprocessor("gpURL);
gp.setOutputSpatialReference({
wkid: 4326
});
var params = {
Raster1: compareLayer1Val,
Raster2: compareLayer2Val
};
gp.submitJob(params, completeCallback, statusCallback);
}
function statusCallback(jobInfo) {
console.log(jobInfo.jobStatus);
}
function completeCallback(jobInfo) {
var imageParams = new ImageParameters();
imageParams.imageSpatialReference = map.spatialReference;
gp.getResultImageLayer(jobInfo.jobId, imageParams, "Output_Raster", function (gpLayer) {
gpLayer.setOpacity(0.5);
map.addLayer(gpLayer);
});
}
Hi Michelle,
Your statusCallback and completeCallback are outside the anonymous function. All you need to do is move the brace below gp.submitjob to the end of the snippet, then gp will be in scope for these functions too.
executeGP = function () { if ($("#compareMethodDD").val() !== null) { if ($("#compareMethodDD").val().length > 0) { compareMethodVal = $("#compareMethodDD").val(); } else { console.log("Compare method not selected."); } } if ($("#compareLayer1DD").val() !== null) { if ($("#compareLayer1DD").val().length > 0) { compareLayer1Val = $("#compareLayer1DD").val(); } else { console.log("Compare Layer 1 not selected.") } } if ($("#compareLayer2DD").val() !== null) { if ($("#compareLayer2DD").val().length > 0) { compareLayer2Val = $("#compareLayer2DD").val(); } else { console.log("Compare Layer 2 not selected.") } } var gp = new Geoprocessor("gpURL); gp.setOutputSpatialReference({ wkid: 4326 }); var params = { Raster1: compareLayer1Val, Raster2: compareLayer2Val }; function statusCallback(jobInfo) { console.log(jobInfo.jobStatus); } function completeCallback(jobInfo) { var imageParams = new ImageParameters(); imageParams.imageSpatialReference = map.spatialReference; gp.getResultImageLayer(jobInfo.jobId, imageParams, "Output_Raster", function (gpLayer) { gpLayer.setOpacity(0.5); map.addLayer(gpLayer); }); } gp.submitJob(params, completeCallback, statusCallback); }
Hi Jon
Thank you so much, I had been staring at this code for a long time, and it was something as simple as that, thanks again!!!!