Select to view content in your preferred language

Calculating Percentages off of Multiple Yes/No Fields with Data Expressions

282
4
Jump to solution
2 weeks ago
andrewdfahey
Occasional Contributor

Good morning,

I have 3 different yes/no fields from a customer's dataset verifying if different cable providers exist along a particular roadway with another double field capturing length of the roadway in miles (Image 1 and Data Sample 1). They are curious what percentage of surveyed roadways has each provider. There are often multiple providers on the same segment, and plenty of roads have yet to be populated since surveying is still underway, so I'm trying to leverage this into a single bar chart rather than pie chart via an arcade data expression. However, I'm ignorant of how to leverage data in the dashboard profile since I'm unsure how to get around not being able to use profile variables like $feature or $datastore.

Here is my expression so far. It seems to accurately collect total length of the surveyed roads, but the amount per each provider comes out as zero across the board. I'm pretty confident my issue is where I'm calling feature['provider'] but I can't wrap my head around how to call a specific field without using profile variables.

Ultimately, I'm trying to show the customer that Comcast, Cox, and Verizon make up xy% of the roadways that have been surveyed. Appreciate any help on this.
 

// Get my layer

var fs = FeatureSetByPortalItem(

  Portal('{insertPortal}'),
  '{insertLayer}',
  0,
    ['Miles', 'Cox', 'Comcast', 'Verizon', 'Inspector'],
    false
);

 

// Placeholder variables for total length and provider-specific lengths

var totalMiles = 0;
var providerA_Length = 0;
var providerB_Length = 0;
var providerC_Length = 0;
// Iterate through features, only include features that have been surveyed
for (var feature in fs) {
    // Skip road segments where the "Inspector" field is null
    if (IsEmpty(feature['Inspector'])) {
        continue;
    }
    // Extract field values
    var miles = feature['Miles']; // Length field
    var isProviderA = feature['Comcast'];
    var isProviderB = feature['Cox'];
    var isProviderC = feature['Verizon'];
 
    // Total length calculation for percentages
    totalMiles += miles;
 
    // Provider-specific length calculations
    if (isProviderA == 'Yes') {providerA_Length += miles}
    if (isProviderB == 'Yes') {providerB_Length += miles}
    if (isProviderC == 'Yes') {providerC_Length += miles}
}
// Calculate percentages for each provider
var providerA_Percentage = (providerA_Length / totalMiles) * 100;
var providerB_Percentage = (providerB_Length / totalMiles) * 100;
var providerC_Percentage = (providerC_Length / totalMiles) * 100;
// Return results as an array
return [providerA_Percentage, providerB_Percentage, providerC_Percentage, totalMiles]
0 Kudos
1 Solution

Accepted Solutions
Neal_t_k
Frequent Contributor

Not sure why your code isn't working for you, using your sample data, your code worked correctly for me.  However I couldn't graph it in a table the way it was arranged.  How about something like this slightly modified from your code:

var portal = Portal('https://www.arcgis.com');
var fs = FeatureSetByPortalItem(
    portal,
    '<itemid>',
    <layerIndex>,
    ['Miles', 'Cox', 'Comcast', 'Verizon', 'Inspector'],
    false
);

// Initialize totals
var totalMiles = 0;
var comcastMiles = 0;
var coxMiles = 0;
var verizonMiles = 0;

// Loop through features
for (var feature in fs) {
    if (IsEmpty(feature['Inspector'])) {
        continue;
    }

    var miles = Number(feature['Miles']);
    if (IsEmpty(miles)) {
        continue;
    }

    if (feature['Comcast'] == 'Yes') {
        comcastMiles += miles;
    }
    if (feature['Cox'] == 'Yes') {
        coxMiles += miles;
    }
    if (feature['Verizon'] == 'Yes') {
        verizonMiles += miles;
    }

    totalMiles += miles;
}


if (totalMiles == 0) {
    return "No surveyed data available.";
}


var features = [];

Push(features, {
    attributes: {
        Provider: "Comcast",
        Miles: comcastMiles,
        PercentMiles: (comcastMiles / totalMiles) * 100
    }
});
Push(features, {
    attributes: {
        Provider: "Cox",
        Miles: coxMiles,
        PercentMiles: (coxMiles / totalMiles) * 100
    }
});
Push(features, {
    attributes: {
        Provider: "Verizon",
        Miles: verizonMiles,
        PercentMiles: (verizonMiles / totalMiles) * 100
    }
});

Push(features, {
    attributes: {
        Provider: "Total",
        Miles: totalMiles,
        PercentMiles: (totalMiles / totalMiles) * 100
    }
});

// Return as FeatureSet
return FeatureSet(Text({
    fields: [
        { name: "Provider", type: "esriFieldTypeString" },
        { name: "Miles", type: "esriFieldTypeDouble" },
        { name: "PercentMiles", type: "esriFieldTypeDouble" }
    ],
    geometryType: "",
    features: features
}));

 

That returns this:

Neal_t_k_2-1763048852394.png

 

Neal_t_k_3-1763048888116.png

 

 

View solution in original post

4 Replies
Neal_t_k
Frequent Contributor

Not sure why your code isn't working for you, using your sample data, your code worked correctly for me.  However I couldn't graph it in a table the way it was arranged.  How about something like this slightly modified from your code:

var portal = Portal('https://www.arcgis.com');
var fs = FeatureSetByPortalItem(
    portal,
    '<itemid>',
    <layerIndex>,
    ['Miles', 'Cox', 'Comcast', 'Verizon', 'Inspector'],
    false
);

// Initialize totals
var totalMiles = 0;
var comcastMiles = 0;
var coxMiles = 0;
var verizonMiles = 0;

// Loop through features
for (var feature in fs) {
    if (IsEmpty(feature['Inspector'])) {
        continue;
    }

    var miles = Number(feature['Miles']);
    if (IsEmpty(miles)) {
        continue;
    }

    if (feature['Comcast'] == 'Yes') {
        comcastMiles += miles;
    }
    if (feature['Cox'] == 'Yes') {
        coxMiles += miles;
    }
    if (feature['Verizon'] == 'Yes') {
        verizonMiles += miles;
    }

    totalMiles += miles;
}


if (totalMiles == 0) {
    return "No surveyed data available.";
}


var features = [];

Push(features, {
    attributes: {
        Provider: "Comcast",
        Miles: comcastMiles,
        PercentMiles: (comcastMiles / totalMiles) * 100
    }
});
Push(features, {
    attributes: {
        Provider: "Cox",
        Miles: coxMiles,
        PercentMiles: (coxMiles / totalMiles) * 100
    }
});
Push(features, {
    attributes: {
        Provider: "Verizon",
        Miles: verizonMiles,
        PercentMiles: (verizonMiles / totalMiles) * 100
    }
});

Push(features, {
    attributes: {
        Provider: "Total",
        Miles: totalMiles,
        PercentMiles: (totalMiles / totalMiles) * 100
    }
});

// Return as FeatureSet
return FeatureSet(Text({
    fields: [
        { name: "Provider", type: "esriFieldTypeString" },
        { name: "Miles", type: "esriFieldTypeDouble" },
        { name: "PercentMiles", type: "esriFieldTypeDouble" }
    ],
    geometryType: "",
    features: features
}));

 

That returns this:

Neal_t_k_2-1763048852394.png

 

Neal_t_k_3-1763048888116.png

 

 

andrewdfahey
Occasional Contributor

Hey @Neal_t_k this is a much better approach, thanks! Weirdly enough though, it works on the sample data too but does not on the original dataset, so I guess I've been looking at the wrong element this whole time.

I'm more than happy to accept this as a solution, but I might as well ask if you know what could cause this returning zero hiccup in data.

0 Kudos
Neal_t_k
Frequent Contributor

Given it works with the sample data, but not your data set, My guess would be something with the matches here: 

Neal_t_k_0-1763068432942.png

 

you could try something like this to normalize what the feature is returning, by trimming and empty space and ensure it is all the same case.  This would be for the code I provided, but you could do something similar in yours.

    if (Lower(Trim(feature['Comcast'])) == 'yes') {
        comcastMiles += miles;

 

andrewdfahey
Occasional Contributor

You're insanely fast and have helped tremendously, thanks so much. Turns out I somehow overlooked that the Yes/No was a domain that was coded as "Y" and "N", so it was always returning false in the bottom section of your second post there.

0 Kudos