|
POST
|
Yes, it turns out that it was related to a lock. The issue was caused by the fact I was trying to utilize Mutliprocessing and simultaneously output feature classes to the same .gdb. Apparently, when you try to write the first feature class to that .gdb , it gets a schema lock the prevents the other 'workers' in the pool from doing the same. My solution was to simply have a new `.gdb` created for each output by state. Its a pain in the but to access them later but it allowed the multiprocessing to work and improved the speed of the operation.
... View more
06-02-2020
06:07 AM
|
0
|
0
|
3316
|
|
POST
|
I am trying to use multiprocessing to process intersects between polygons and points for a list of states and territories (the data sets for the points are large, so my hope was that the multiprocessing would speed the process up). But there seems to be an issue. Suppose I was just doing DC and PR. The intersect first produce an empty table output for PR and then throws the following error for PR: Traceback(most recent call last):
File"C:\Projects\hh_intersects\just_hh_intersects.py", line 68,in<module>
pool.map(multi_proc, state_list)
....
arcgisscripting.ExecuteError: ERROR 000210:Cannot create output
T:\...\civis_hh_0520.gdb\PR_hh_intersects
Failed to execute (Intersect). I'm not sure what I am doing incorrectly here. Any ideas on how to fix this? import arcpy
import os
import time
import multiprocessing as mp
from multiprocessing import Pool, cpu_count
# Paths for hh_pts_gdb, input_polys_dir, and output_gdb s
tate_list = ['DC', 'PR']
start = time.time()
p_count = cpu_count()
# Functions
def multi_proc(state):
state_start = time.time()
arcpy.env.workspace = output_gdb
# Make output based on state
output = os.path.join(output_gdb, "{}_intersect".format(state))
# Pts
pt_name = "{}_hh_pts".format(state)
hh_pts = os.path.join(hh_pts_gdb, pt_name)
# Polys
st_poly = os.path.join(input_polys_dir, "{}/{}_UnionOutput.gdb/{}_Union".format(state, state, state))
# Intersect selected pts with polys
arcpy.Intersect_analysis([hh_pts, st_poly], output, "ALL")
print("Output row count for {}".format(state))
counter = arcpy.GetCount_management(output)
print(counter)
state_end = time.time()
print("{} Process duration: ".format(state))
print(state_end - state_start) if __name__ == '__main__':
pool = mp.Pool(p_count)
pool.map(multi_proc, state_list)
end = time.time()
print("Total Process duration: ")
print(end - start)
*Note- I have run the following by itself (outside of the multiprocessing) and it
worked with state = "DC" : arcpy.Intersect_analysis([hh_pts, st_poly], output, "ALL") .
... View more
05-21-2020
06:40 AM
|
0
|
2
|
3381
|
|
POST
|
Robert - Argghhh, I overlooked a really important detail. objs.lastupdated has to have an updated date to "update". It also had to be in epoch date format. I added the below with `objs.lastupdated = Date.now();` and it works fine now. Thanks for the assist: ... if (typeof proj_obj !== undefined) { for (var j = 0; j < proj_obj.length; j++) { if (s_proj == proj_type_obj .subproject) { var objs = proj_type_obj objs.lastupdated = Date.now(); p_obj = objs; } } } ....
... View more
04-20-2020
06:35 AM
|
0
|
0
|
1307
|
|
POST
|
Hey Robert - I think I almost have this working. Its not throwing an error but it's not updating in the REST Service table. Here's the function I made that gets triggered in the updateItem (item) function when I call thisWidget.updateSubprojObj(proj_type_obj, current_subproject); The parameter `proj_type_obj` is an literally an array object containing the ObjectID (oid), subprojectName, subptojectType, and lastUpdated values for all items in the SubprojectType Table. subproject is just a dijit.byId("subprojectSelect") value that corresponds to the current subproject that I want to update: updateSubprojObj: function (proj_obj, s_proj) { var p_obj = null; this.subprojectTypeTable = new FeatureLayer(subprojectTypeURL, { outFields: ["*"] }); if (typeof proj_obj !== undefined) { for (var j = 0; j < proj_obj.length; j++) { if (s_proj == proj_type_obj .subproject) { var objs = proj_type_obj p_obj = objs; } } } let updatedItem = Object.assign({}, p_obj); var updatedFeatureJson = updatedItem; var updatedFeature = new Graphic(null, null, updatedFeatureJson, null); this.subprojectTypeTable.applyEdits(null, [updatedFeature], null, function (editResult) { console.log(editResult); }, function (editError) { console.log(editError); throw "Issue updating record in database." }).then(function () { console.log('edit applied, updated item returned to grid') }); }, Note: I didn't end up using the currentDate function to convert the date because it ended up requiring the epoch data format. Do you see anything wrong with this? The graphic array, updatedFeature looks like this when its getting plugged in:
... View more
04-16-2020
07:30 PM
|
0
|
1
|
1307
|
|
POST
|
Suppose I have a WAB widget (version 1.2) called TaskManager. Everytime a user clicks a button (triggering a click event) I want to route it to a function that will update a specific field called 'lastupdated' in a REST Service (FEATURE Service) table called SuprojectTypeTable, which looks like this in my widget config,json: "subprojectTaskTrackingURL": "https://www.mywabapp.com/server/rest/services/.../FeatureServer", "subprojectTypeTable": { "index": "5", "oid": "objectid", "subprojectName": "subproject", "projectType": "projecttype", "lastUpdated": "lastupdated" }, This function will take one parameter, a subprojectName, so that it can update the specific row in the table that I want. It will also call a simple function that will get, format, and return the current date. This will be the value I want to plug into the 'lastupdated' field: currentDate: function(){
var d =newDate();
var month = d.getMonth()+1;
var day = d.getDate();
var currentD =((''+ month).length <2?'0':'')+ month +
'/'+((''+ day).length <2?'0':'')+ day +'/'+ d.getFullYear();
return currentD }, The REST Service can use apply edits and update features. updateSubprojObj: function (s_proj) { var new_date = thisWidget.currentDate(); var subproj = dijit.byId("subprojectSelect"); this.subprojectTypeTable.applyEdits(subproj, null, null, null, new_date, function (editResult) { console.log(editResult); }, function (editError) { console.log(editError); throw "Issue updating record in database." }).then(function () { console.log('edit applied, updated item returned to grid') }); }, The above does not work of course. What would be the best way to do this?
... View more
04-16-2020
01:37 PM
|
1
|
4
|
1375
|
|
POST
|
Hey Robert, Sorry for the delay in responding. Yes, the problem was totally caused by the variable `thisWidget`. Both widgets used `thisWidget` and they were both set to `thisWidget = this;` in `startup ()`, but ManageFolders widget also had it set to `thisWidget = this;` in the `onOpen()` function while TaskManager did not. After much trial and error, I finally was able to resolve this with one line of code by adding `thisWidget = this;` to the `onOpen` function in TaskManager.
... View more
04-15-2020
06:25 AM
|
0
|
0
|
1897
|
|
POST
|
I was able to resolve the css issue, but am still not able to get the main issue resolved. What seems to be happening is that the "thisWidget" variable is still assigned to "ManageFolders" so that when I call: dijit.byId('subprojectSelect').on('change', function (e) { thisWidget.loadData(e, proj_type_obj); }); in TaskManager, it is going to the "loadData" function in ManageFolders. How can I kill the ManageFolder "thisWidget" and make sure that it is assigned to TaskManager instead?
... View more
04-09-2020
08:00 AM
|
0
|
1
|
1897
|
|
POST
|
Hey Robert- So, I'm trying to figure out where to apply your suggestion. The Task Manager on change events fires and then it calls `thisWidget.loadData()` like this: dijit.byId('subprojectSelect').on('change', function (e) { thisWidget.loadData(e, proj_type_obj); }); At this point I expect it to to the Task Manager "loadData()" function but it instead goes to the Manage Folder "loadData" function. Here is the start of the Task Manager: loadDataTM: function (e, proj_typ) { var p_type = proj_typ; var proj = e; console.log('loadData Task Manager'); var dyfields = [{ type: "control", width: 40 }, { name: widgetConfig.taskTrackingTable.taskName, title: "Task Name", type: "text", width: 120, validate: "required" }, ... ]; var def = new Deferred(); this.getTempPortal(); ... } And here is the Manage Folders loadData function, which is also called with "thisWidget.loadData();": onOpen: function () { console.log('onOpen'); this.loadData(); }, loadData: function () { var def = new Deferred(); this.getTempPortal(); .... var projectNames = []; var strProjectNames = ""; .... } Note: Task Manager doesn't call "thisWidget.loadData();" in the onOpen() function while Manage Folders does. So how could I apply your suggestions here. Would I use something unique to Task Manager widget like this.dijit.byId("subprojectSelect") ? Would I use this unique identifier in the on change event or inside the loadData function?
... View more
04-08-2020
02:11 PM
|
0
|
0
|
1897
|
|
POST
|
I have 2 widgets: a Manage Folders widget and a Task Manager widget. They sit next to each other in the navbar of my Web AppBuilder version 1.2 app. There are several other widgets as well. If I launch Task Manager after any of the other widgets, there are no problems. However, if I launch the Manage Folders Widget, close it, and then open the Task Manager widget, I immediately notice that a dropdown is sized a little larger than normal. The dropdown controls what task items are displayed in a grid below it. Normally, if I select a new item from the dropdown, it triggers and on change event that loads the tasks for the new selection into the grid. Now however, when I select a new item from the dropdown, nothing happens; the items from the previous selection (or default) remain the same.In investigating this issue in Chrome DevTools, I noticed that when I make a change in the Task Managers dropdown, the on change event gets triggered but then it goes to the 'loadData' function in the widget.js file for the previously closed Manager Folders widget. Note: they both have a function called 'loadData'. How could this be?! Any suggestions (other than renaming one of the loadData functions? Why would this be happening? Could this be something set incorrectly in one of the .json files?
... View more
04-08-2020
10:37 AM
|
0
|
5
|
1984
|
|
POST
|
I have 2 dropdowns that are created onOpen using Dojo/Dijit Select in my custom Web AppBuilder widget. The first dropdown contains parent projects and the second dropdown contains a list of subprojects related to the currently selected parent project in the first dropdown. To populate each, a query is first made to a REST service , the results are parsed and then entered as a parameter into the function that actually creates the Dojo Select dropdown; Projects first and then subprojects. Here is an example of the Projects workflow, which contains an on('click') event to trigger the second subprojects query and dropdown creation: Parent Projects: function createProjectDropdown(items) {
// New dropdown for parent projects.
var projectNode = dom.byId("projectDropdown");
if (items.length >= 1) {
var projectsOptions = items.map(projectname => {
return { "label": projectname, "value": projectname }
});
}
else {
let current_user = parent.thisWidget.getCurrentUser();
var projectsOptions = [{ "label": `No projects available to user "${current_user}"`, "value": "Noprojects" }] } // Create project selector dropdown var projectSelector = new Select({ name: "projectSelect", id: "projectSelect", options: projectsOptions }).placeAt(projectNode).startup(); // This is the on change event that triggers the subprojects dropdown // change based on the user's input. e = user's selection. dijit.byId('projectSelect').on('change', function (e) { var subprojectQuery = new esriQuery(); let username = widgetConfig.userAuthorizationTable.usernameField; this.currentUser = IdentityManager.credentials[0].userId; let current_user = this.currentUser; subprojectQuery.where = `${username} = '${current_user}'`; var project_name = e var subprojectsField = widgetConfig.userAuthorizationTable.subprojectsField_1; subprojectQuery.outFields = [subprojectsField]; var subprojectAccessEndpoint = widgetConfig.subprojectTaskTrackingURL + "/" + widgetConfig.userAuthorizationTable.index;
var subprojectAccessQueryTask = new QueryTask(subprojectAccessEndpoint);
subprojectAccessQueryTask.execute(subprojectQuery,
function (results) {
let records = results.features;
if (records.length >= 1) {
let subprojects = records[0].attributes[subprojectsField];
let subprojects_list = subprojects.split(',');
let subprojects_trimmed = subprojects_list.map(item => item.trim());
subprojects_trimmed = subprojects_trimmed.sort();
// The subprojects dropdown function is called
createSubprojectDropdown(subprojects_trimmed);
console.log("query result: ", results);
thisWidget.loadData(e);
}
else {
let noSubprojectAccess = [];
createSubprojectDropdown(noSubprojectAccess);
}
},
function (error) {
console.log("query error: ", error);
});
});} Then the function is called: var projectAccessEndpoint = widgetConfig.subprojectTaskTrackingURL + "/" + widgetConfig.userAuthorizationTable.index;
var projectAccessQueryTask = new QueryTask(projectAccessEndpoint);
projectAccessQueryTask.execute(projectQuery,
function (results) {
let records = results.features;
if (records.length >= 1) {
let projects = records[0].attributes[projectsField];
let projects_list = projects.split(',');
let projects_trimmed = projects_list.map(item => item.trim())
createProjectDropdown(projects_trimmed);// The projects dropdown function is called
console.log("query result: ", results);
}
else {
let noProjectAccess = [];
createprojectDropdown(noProjectAccess);
}
},
function (error) {
console.log("query error: ", error);
}); //End of Query Project Task Now, my problem is that I have added a third part to this process. Right after the subprojects dropdown is created in onOpen , I want to look for a global variable created from another widget (this works - for brevity's sake, lets assume it works). This global variable is a subproject name. To use it, I first make another query (the 3rd) to a REST Service to get the parent project name that it is associated with. Once that is done I just want to 1) use the parent project name variable ( info_proj_name ) to select an item from the Projects dropdown- this triggers the on('change') event for the createProjectDropdown function): dijit.byId('projectSelect').set("value", info_proj_name); 2) Once the subprojects dropdown has been populated with the subprojects that correspond to the parent project name in #1, I want to select the subproject name (from the subproj_name global variable): dijit.byId('subprojectSelect').set("value", subproj_name); This must all happen in order. The project dropdown must first exist in the dom (dijit.byId() must be callable), the subprojects dropdown must then exist in the dom, then the parent project is selected (causing the corresponding subprojects in the dropdown to be populated) and finally, the subproject from the subprojects dropdown must be selected. How can I apply a callback or promise (including Dojo Deferred ) to make these events occur in the specified order?
... View more
04-02-2020
11:29 AM
|
0
|
0
|
889
|
|
POST
|
Hey Robert - The trick here was to make the variable coming from the 'calling' widget global, then assign the value as another variable in the 'recieving' widget and kill the original global variable (set it to null anyway). At the top of my InfoTemplate (the 'call' widget) script, just inside my declare for my BaseWidget, I added a global variable called 'taskManagerOriginalValue': var clazz = declare([BaseWidget, PoolControllerMixin], { name: 'CustomInfoTemplate', updateFeature: {}, updateFeatureOriginal: null, taskManagerOriginalValue: null, ....//rest of code I give it a value later in the script in my button's onClick event and the value persists when the second widget, Task Manager. editButton.on('click', lang.hitch(this, function () { editButton.setDisabled(true); //disable the edit button on first click var wm = WidgetManager.getInstance(); taskManagerOriginalValue = updateFeatureOriginal.attributes.projectname; ..... Then I initialize it's instance in my 'onOpen' function and assign it to another variable in the Task Manager widget and kill the original: onOpen: function () { console.log('onOpen'); this.taskManagerOriginalValue; .... if (typeof taskManagerOriginalValue !== 'undefined') { subproj_name = taskManagerOriginalValue; // Assign it to a new variable taskManagerOriginalValue = null; //Kill it So far, this seems to be working.
... View more
04-02-2020
07:54 AM
|
0
|
0
|
1045
|
|
POST
|
Aha! I just tried using `this.` That seemed to do the trick.
... View more
03-24-2020
09:27 AM
|
0
|
0
|
1422
|
|
POST
|
I want to use a value from one widget as a parameter to open another widget I currently have a widget, 'InfoTemplate' (a popup) that has a button that launches another widget, `TaskManager`, when clicked: var editButton = new Button({ label: "Edit Schedule" }); editButton.on('click', lang.hitch(this, function () { editButton.setDisabled(true); //disable the edit button on first click var wm = WidgetManager.getInstance(); var tm = wm.appConfig.widgetPool.widgets[8]; //TaskManager widget var hc = WidgetManager.getInstance().getWidgetsByName("HeaderController")[0]; hc.setOpenedIds([tm.id]); editButton.setDisabled(false); })); editButton.startup();
The task manager widget has two dropdowns, which onOpen, populate with a default list of items from a REST Service
(Project Name, and Subproject Name are the 2 dropdowns/attribute fields that get populated). In the `InfoTemplate` widget,
I am able to get the `Subproject Name` value of the feature being clicked on and create a variable that can be plugged into
my button's `.on('click' function):
var subproj = updateFeatureOriginal.attributes.projectname;
I have a function in my TaskManager widget that gets the list of subproject names, but more importantly, has an onChange event
handler that loads tasks in a table by subproject:
function createSubprojectDropdown(items) {
// Create subprojects dropdown
var subprojectNode = dom.byId("subprojectDropdown");
if (items.length >= 1) {
var subprojectsOptions = items.map(subproject => {
return { "label": subproject, "value": subproject }
});
}
else {
let current_user = parent.thisWidget.getCurrentUser();
var subprojectsOptions = [{ "label": `No subprojects available to user "${current_user}"`, "value": "NoSubprojects" }]
}
// Must check to see if subprojectSelect exists. If it does, destroy that node and create a new one (otherwise you get a registry error)
var p = registry.byId('subprojectSelect');
if (p) {
p.destroyRecursive();
}
var subprojectSelector = new Select({
name: "subprojectSelect",
id: "subprojectSelect",
options: subprojectsOptions
}).placeAt(subprojectNode).startup();
dijit.byId('subprojectSelect').on('change', function (e) {
thisWidget.loadData(e, proj_type_obj);
});
thisWidget.loadData();
}
To do this, I have it calls another function in my TaskManager widget that takes a parameter and populates the table with tasks accordingly (its too long to
paste here):
loadData: function (subproj_name, proj_typ) {....};
The proj_type is determined by the subproj_name and not of concern here. Basically, what I want to do is take the
subproj variable from InfoTemplate (which will be open) and use it to preselect the subproject name from the
dropdown in using my onChange event in the createSubprojectDropdown function. My initial idea is to simple add
something to check and see if there is a subproject value from InfoTemplate, and if so, send that to the loadData
function .
var subproj_name = updateFeatureOriginal.attributes.projectname;
if (subproj_name != undefined) {
thisWidget.loadData(subproj_name, proj_type_obj);
};
Is there an easier way to do this? Should I be using `FeatureAction` or some other methodology?
... View more
03-24-2020
08:37 AM
|
0
|
2
|
1113
|
|
POST
|
I eliminated the spaces, but I still got the "Uncaught ReferenceError: PanelManager is not defined" whenever I tried to create an instance of the PanelManager: var pm = PanelManager.getInstance();
... View more
03-24-2020
06:17 AM
|
0
|
1
|
1422
|
|
POST
|
It worked! Whoa, thanks for hanging in there with Robert! That was quite a thread. Adding the HeadController - hc did the trick!
... View more
03-20-2020
10:20 AM
|
0
|
1
|
1439
|
| Title | Kudos | Posted |
|---|---|---|
| 1 | 03-19-2021 01:41 PM | |
| 1 | 11-05-2019 07:44 AM | |
| 1 | 11-05-2019 09:58 AM | |
| 1 | 01-06-2021 05:41 AM | |
| 1 | 12-24-2020 06:48 AM |
| Online Status |
Offline
|
| Date Last Visited |
03-19-2022
10:13 PM
|