Select to view content in your preferred language

How do you connect feature set dictionary to feature layer?

1891
8
Jump to solution
02-20-2023 09:51 AM
Labels (1)
ScoutStanley
Occasional Contributor

Hi! 

I am having a hard time figuring out arcade expression to work within my dashboard. I also don't fully know if it is even possible to do within dashboards. Anyway....

I have a dashboard that is connect to a Survey123. The survey contains a multiple select question, which I learned is saved as csv, so I found an expression to split out the answers from the multiple select question. The issue is I now need  to connect this new feature set dictionary to the existing feature layer within the webmap. So, I created a join expression, but I keep getting and can't figure out how to correct:

Expected "'", "(", "+", "-", "@", "CASE", "DATE", "EXTRACT", "FALSE", "INTERVAL", "N'", "NULL", "POSITION", "SUBSTRING", "TIMESTAMP", "TRIM", "TRUE", "`", [ \t\n\r], [0-9], or [A-Za-z_\x80-￿] but "$" found.

The end goal is that someone can search by specific rent amount and see what locations offer that rent amount. 

Dashboard below

https://dgco.maps.arcgis.com/apps/dashboards/2df513c195bb4560b61145f4064484dd

Expression below 

// Reference layer using the FeatureSetByPortalItem() function. 
var fs = FeatureSetByPortalItem(Portal('https://www.arcgis.com'), '288db7f54ea048c5b6241f156ef0f646' , 0, ['*'], true);

// Empty dictionary to capture each rental amount reported as separate rows. 
var choicesDict = {'fields': [{ 'name': 'split_choices', 'type': 'esriFieldTypeString'}], 
                    'geometryType': 'esriGeometryPoint', 'features': []}; 

var index = 0; 

// Split comma separated Rental Amountss and store in dictionary.  
for (var feature in fs) { 
    var split_array  =  Split(feature["rent_amount"], ',') 
    var count_arr = Count(split_array) 
    for(var i = 0; i < count_arr; i++ ){ 
        choicesDict.features[index++] = { 
            'attributes': { 'split_choices': Trim(split_array[i]),  
            }} 
}} 

// Convert dictionary to featureSet. 
var fs_dict = FeatureSet(Text(choicesDict)); 
GroupBy(fs_dict, ['split_choices'], 
       [{ name: 'split_count', expression: 'split_choices', statistic: 'COUNT' }]); 

var joinedDict = {
  fields: [
    { name: "split_choices", type: "esriFieldTypeString" },
    { name: "address", type: "esriFieldTypeString" },	
    { name: "landlord", type: "esriFieldTypeString" },
  ],
    geometryType: "esriGeometryPoint",
'features':[]};

var i = 0;
for (var t in fs_dict) {
    var fsid = t["split_choices"]
    for (var p in Filter(fs, "SplitChoices = "+fsID)){
        joinedDict.features[i] = {
            attributes: {
                SplitChoices: fsID,
                Address: p["address"],
				Landlord: t["landlord"],
            },
            geometry: Geometry(p)
        }
    }
i++
}
return FeatureSet(Text(joinedDict));

 

If there is better way for handling this issue, let me know! 

Thanks

Scout

0 Kudos
2 Solutions

Accepted Solutions
JohannesLindner
MVP Frequent Contributor

Your expression fails in line 37.

fsID is "$1000-$1100". The sql query you're constructing is "SplitChoices = $1000-$1100".

This is an invalid query, you need "SplitChoices = '$1000-$1100'", note the single quotes.

You could use the @ notation, that will handle the field type for you:

 

"SplitChoices = @fsID"

 

Or you could do it yourself with template literals: 

 

`SplitChoices = '${fsID}'`

 

But even then this line won't work, because you're either trying to filter the wrong featureset, or you use the wrong query. fs doesn't have a field SplitChoices, and if you want to query rent_amount, you should use LIKE:

 

`rent_amount LIKE '%${fsID}%'`

 

Also, GroupBy doesn't change the input featureset, but returns a new one, so you have to store the result in a variable (line 22).

 

I couldn't really make sense of your attempted join, but I think you are trying to achieve something like this:

 

// Reference layer using the FeatureSetByPortalItem() function. 
var fs = FeatureSetByPortalItem(Portal('https://www.arcgis.com'), '288db7f54ea048c5b6241f156ef0f646' , 0, ['*'], true);

var outputDict = {
    fields: [
        { name: "rent_amount", type: "esriFieldTypeString" },
        { name: "address", type: "esriFieldTypeString" },	
        { name: "landlord", type: "esriFieldTypeString" },
        ],
    geometryType: "esriGeometryPoint",
    features: []};

var i = 0;
// iterate over the input features
for (var f in fs) {
    // split the rent field
    var rentSplit = Split(f["rent_amount"], ",")
    // iterate over the rent amounts
    for(var r in rentSplit) {
        // append a new output feature with the input feature's attributes and the current rent amount
        outputDict.features[i++] = {
            attributes: {
                rent_amount: rentSplit[r],
                address: f["address"],
                landlord: f["landlord"]
            },
            geometry: Geometry(f)
        }
    }
}
return FeatureSet(Text(outputDict));

 

 

 

JohannesLindner_0-1676963204338.png

 


Have a great day!
Johannes

View solution in original post

0 Kudos
JohannesLindner
MVP Frequent Contributor

The problem is that the Dashboard can only filter by equality: rental_amount_layer = rental_amount_selector

But if you select "$500-$600", the dashboard can't find features to show, because the values in the layer are built like "$500-$600,$600-$800,$1000-$1100".

What you need is a LIKE filter, which doesn't seem to exist in Dashboard.

So, you've got (at least) two options:

 

If you have to use Dashboard, you need to reconfigure your layer to only show the separate rental amounts (many points at the same location). This way, you can even skip the data expression and build the category selector based on the layer.

 

If you don't have to use Dashboard, you can easily achieve this with an Experience. Add your map and a Filter widget, set the filter query to "Rent Amount - includes - predefined values", and define some categories.

JohannesLindner_0-1677657067015.pngJohannesLindner_1-1677657086811.png

 

And then you can select the amounts you want to filter:

JohannesLindner_2-1677657255864.pngJohannesLindner_3-1677657270640.pngJohannesLindner_4-1677657292102.pngJohannesLindner_5-1677657307507.pngJohannesLindner_6-1677657330622.png

 


Have a great day!
Johannes

View solution in original post

0 Kudos
8 Replies
JohannesLindner
MVP Frequent Contributor

Your expression fails in line 37.

fsID is "$1000-$1100". The sql query you're constructing is "SplitChoices = $1000-$1100".

This is an invalid query, you need "SplitChoices = '$1000-$1100'", note the single quotes.

You could use the @ notation, that will handle the field type for you:

 

"SplitChoices = @fsID"

 

Or you could do it yourself with template literals: 

 

`SplitChoices = '${fsID}'`

 

But even then this line won't work, because you're either trying to filter the wrong featureset, or you use the wrong query. fs doesn't have a field SplitChoices, and if you want to query rent_amount, you should use LIKE:

 

`rent_amount LIKE '%${fsID}%'`

 

Also, GroupBy doesn't change the input featureset, but returns a new one, so you have to store the result in a variable (line 22).

 

I couldn't really make sense of your attempted join, but I think you are trying to achieve something like this:

 

// Reference layer using the FeatureSetByPortalItem() function. 
var fs = FeatureSetByPortalItem(Portal('https://www.arcgis.com'), '288db7f54ea048c5b6241f156ef0f646' , 0, ['*'], true);

var outputDict = {
    fields: [
        { name: "rent_amount", type: "esriFieldTypeString" },
        { name: "address", type: "esriFieldTypeString" },	
        { name: "landlord", type: "esriFieldTypeString" },
        ],
    geometryType: "esriGeometryPoint",
    features: []};

var i = 0;
// iterate over the input features
for (var f in fs) {
    // split the rent field
    var rentSplit = Split(f["rent_amount"], ",")
    // iterate over the rent amounts
    for(var r in rentSplit) {
        // append a new output feature with the input feature's attributes and the current rent amount
        outputDict.features[i++] = {
            attributes: {
                rent_amount: rentSplit[r],
                address: f["address"],
                landlord: f["landlord"]
            },
            geometry: Geometry(f)
        }
    }
}
return FeatureSet(Text(outputDict));

 

 

 

JohannesLindner_0-1676963204338.png

 


Have a great day!
Johannes
0 Kudos
ScoutStanley
Occasional Contributor

Yes! That is exactly what I was trying to go for! Much appreciation 😁  and thank you for helping me understand the expression! 

0 Kudos
ScoutStanley
Occasional Contributor

Hey Johannes! 

Another question...  I am using category select widget within my dashboard using this expression. The issue is I want to have only one option instead of multiple options with same answer. Such as, currently there are three options for $500-$600. Instead, I want there to be one option $500-$600 and then the other widgets filter out those rentals containing option $500-$600 within dashboard. Do you know if this is possible to do? 

0 Kudos
JohannesLindner
MVP Frequent Contributor

Inside the category filter, don't use the "Features" option. You need the "Grouped Values" option and group by rent_amount, which should give you distinct values.

JohannesLindner_0-1677569775458.png

 


Have a great day!
Johannes
0 Kudos
ScoutStanley
Occasional Contributor

I tried doing it by "Grouped Values". However, when I do that it doesn't work with the geometry within the map or the other widgets. And it doesn't save my actions for filters. The image below is what it looks like after I reopen the widget to see if it saved my active targets. So how do I get it to filter the map and other widgets? or is this a bug? 

 

Capture11.png

 

0 Kudos
JohannesLindner
MVP Frequent Contributor

The problem is that the Dashboard can only filter by equality: rental_amount_layer = rental_amount_selector

But if you select "$500-$600", the dashboard can't find features to show, because the values in the layer are built like "$500-$600,$600-$800,$1000-$1100".

What you need is a LIKE filter, which doesn't seem to exist in Dashboard.

So, you've got (at least) two options:

 

If you have to use Dashboard, you need to reconfigure your layer to only show the separate rental amounts (many points at the same location). This way, you can even skip the data expression and build the category selector based on the layer.

 

If you don't have to use Dashboard, you can easily achieve this with an Experience. Add your map and a Filter widget, set the filter query to "Rent Amount - includes - predefined values", and define some categories.

JohannesLindner_0-1677657067015.pngJohannesLindner_1-1677657086811.png

 

And then you can select the amounts you want to filter:

JohannesLindner_2-1677657255864.pngJohannesLindner_3-1677657270640.pngJohannesLindner_4-1677657292102.pngJohannesLindner_5-1677657307507.pngJohannesLindner_6-1677657330622.png

 


Have a great day!
Johannes
0 Kudos
Tiff
by
Frequent Contributor

Hello @JohannesLindner! This is a delayed response, but I wanted to reach out as you know a lot about dashboards and advanced calculations. I have something similar where I have a lot of output fields in the dictionary because I need to use them for filtering these calculated attributes. However, upkeep of that can be difficult and I was wondering if there was a simpler way that you know of to output all fields automatically in a dictionary to then be used as the output feature set. Usually what I am doing is calculating one field that is used as the indicator element, and all other output fields are there for the common key when filter actions are applied.

0 Kudos
ScoutStanley
Occasional Contributor

Ah okay, thanks for sharing! I think I will try to go the experience builder route. I really appreciate the help with this! 

0 Kudos