Counting "unique" selections across repeats

6136
13
04-10-2019 04:33 PM
KarenTuerk2
New Contributor

OK, here's the deal. I am trying to create a field that will count the total number of plant species observed in a plant survey. The survey has 100 subplots (repeating form 1-100). Each subplot repeat and has a nested repeat that asks observers to choose all the plant species found in that subplot. I can use count(${plant_sp}) to get the total number of plant species selected throughout the survey, but I want to count only the number of unique species selected in the survey. This is to find the species richness of the site.

For example, if there is a daisy, coneflower, and hawkweed in every subplot, I need the count to be 3 and not 300. There are literally hundreds of possible choices for each subplot.

Is there a way to pull the number of unique codes from a concatenated list of all the species codes #from a
join(' ,' ${plant_sp}) perhaps?

Thoughts?

Thanks!

Karen

Tags (2)
0 Kudos
13 Replies
MaazaMekuria
Occasional Contributor

 Not clear if you want one for a subplot or one per overall survey? You may have to resort to Python or other programming tool after the data is stored if you would like to get one per sub-plot.  If per survey, you can  make a variable for each flower type and compute a variable if it was selected at least once its count would be greater than zero (set the default value to 0).  See below a use case for summing repeats from https://docs.opendatakit.org/form-repeats/#referencing-answers-in-repeats .  Also you can use the selected function for each item to find if present in the list of selected item. 

Some functions such as indexed-repeats are unfortunately not implemented in Survey123.  

KarenTuerk2
New Contributor

Thanks Maaza, 

I need to find unique selections across the survey. The number of selections (plants) will always match the number of species within the subplot. But the same species map be chosen more than once across the survey. 

Unfortunately, setting a variable for each species is not practical as there are thousands of plant species choices. 

Karen

0 Kudos
JamesTedrick
Esri Esteemed Contributor

Hi Karen,

This is something Survey123 may be able to support in the future - in the Early Adopter Community there is a feature 'custom JavaScript functions' that has been enhanced to be able to process repeat information.  The specific function would be dependent on the form's layout.

0 Kudos
DougBrowning
MVP Esteemed Contributor

You are on the right track.  Here is how I did it.  Not perfect.

Create a large txt (or note) field outside the repeat.  i did text so users can copy and paste it.

Add a calc joining the fields from the repeat join(", ", ${SpeciesList})

Set a constraint on this join field (not the field) - the trick here is to remove the last entry since it is the one you are trying to add currently. 

So like this not(contains(substr(${AllPlantsCheck}, 0, string-length(${AllPlantsCheck}) - 3), ${SpeciesList})) 

--If you do not do this it immediately adds to the list then complains it is already there.

--(note my plant codes are 4 chars. so if i remove the last 3 chars it will not find what I just added)

It can be funky if you go backwards and then change something but it still seems to work ok.

I even built on exceptions to the rule. If it contains a XXXXX generic code then the repeat is allowed.

Like contains(${SpeciesList}, "XXXX") or not(contains(substr(${AllPlantsCheck}, 0, string-length(${AllPlantsCheck}) - 3), ${SpeciesList}))

Now it sounds like you may want to compare across multiple repeats?  If so make a join() field for each repeat then make a master field that joins all of the joins together.  Then check against that.  (Confused yet )

Hope that helps.  Works slick for me.

RoryMcPherson
New Contributor III

Hi Doug,

I'm trying to understand how to make this work, and am a bit confused about some of your explanation above. I'm mostly confused about which fields in your form are ${SpeciesList}, ${AllPlansCheck}, possibly a third text/calculate field(?), and what's going on in each one.

Here is what I have:

- A select_one species_list question in a repeat with the database field name 'plant_species'.

- Outside and below the repeat I have a unique_species_list text question, which in the calculation field I'm using join(', ', ${plant_species}) to add all the selected plants from the repeats to.

- On the same unique_species_list text question, I've added to the the constraint field: not(contains(substr(${unique_species_list}, 0, string-length(${unique_species_list})), ${plant_species})).

This is joining everything together, where I just want a list of distinct values. Also, choice list has several thousand species that are updated now and then, so I don't have any specific string-length codes. I've left this off the constraint, as I don't think it's required?

Oh, and would you be able to share this part of your form? It would be much easier for me I could see the survey sheet, but no worries if you can't share it.

Thanks in advance!

DougBrowning
MVP Esteemed Contributor

You must take at least something off of the string to check otherwise it will find itself.  The add is instantaneous so the check would always fail.

Here are the lines.  Hope it helps.  You could remove the XXX check if you do not do Unknown codes.  So just this ->  not(contains(substr(${AllPlantsCheck}, 0, string-length(${AllPlantsCheck}) - 3), ${SpeciesList}))

typenamelabelhintconstraintconstraint_messagerequiredrequired_messageappearancedefaultreadonlyrelevantcalculationchoice_filterrepeat_countlabel::language1hint::language1media::audiomedia::imagebody::accuracyThresholdbind::esri:fieldTypebind::esri:fieldLengthbind::esri:fieldAliasbody::esri:inputMask

textAllPlantsCheckAll Species added so far${SpeciesList}='' or contains(${SpeciesList}, "XXXX") or contains(${SpeciesList}, "UNK") or not(contains(substr(${AllPlantsCheck}, 0, string-length(${AllPlantsCheck}) - 3), ${SpeciesList}))Species has already been added to the listyesjoin(", ", ${SpeciesList})null5000
RoryMcPherson
New Contributor III

Thanks for your quick response Doug. I gave this a go, but then found this post (Can I prevent a value from being submitted multiple times in a repeat question? ) and was able to use a JavaScript function to do this.

I appreciate the help though!

0 Kudos
DougBrowning
MVP Esteemed Contributor

Does it work offline?    I came up with my way a year ago before any javascript was available.

thanks

0 Kudos
RoryMcPherson
New Contributor III

Great question! I had to check but seems to work fine.

0 Kudos