|
| 1 | +# Adding calculations in XLSForm |
| 2 | + |
| 3 | +Calculations can be used inside your form to derive new variables, build advanced form logic, and display results to respondents during collection. |
| 4 | + |
| 5 | +Calculations are processed within the form, helping save time during data analysis. The results are stored as new columns in the final dataset and can be used throughout the form to apply [skip logic](https://support.kobotoolbox.org/skip_logic_xls.html), set [constraints](https://support.kobotoolbox.org/constraints_xls.html), or display [dynamic content](https://support.kobotoolbox.org/form_logic_xls.html#question-referencing) in question labels and notes. |
| 6 | + |
| 7 | +This article explains how to add calculations in XLSForm, covering both basic arithmetic and more advanced expressions. |
| 8 | + |
| 9 | +<p class="note"> |
| 10 | +<strong>Note:</strong> This article focuses on adding calculations in <a href="https://support.kobotoolbox.org/getting_started_xlsform.html">XLSForm</a>. To learn about adding calculations in the KoboToolbox Formbuilder, see <a href="https://support.kobotoolbox.org/calculate_questions.html">Calculate question type</a>. |
| 11 | +<br><br> |
| 12 | +For hands-on practice with calculations in XLSForm, see KoboToolbox Academy’s <a href="https://academy.kobotoolbox.org/courses/xlsform-fundamentals">XLSForm Fundamentals Course</a>. |
| 13 | +</p> |
| 14 | + |
| 15 | +## Adding calculations in XLSForm |
| 16 | + |
| 17 | +Calculation expressions are constructed using a combination of [question references](https://support.kobotoolbox.org/form_logic_xls.html#question-referencing), [mathematical operators](https://support.kobotoolbox.org/form_logic_xls.html#mathematical-and-comparison-operators), [functions](https://support.kobotoolbox.org/functions_xls.html), and constants. |
| 18 | + |
| 19 | +To add a calculation in your XLSForm: |
| 20 | +1. In the `type` column of the `survey` worksheet, enter **calculate** to add a `calculate` question type. |
| 21 | +2. Enter a `name` for the `calculate` question. |
| 22 | + - Because the calculation is not displayed in the form, the `calculate` question does not require a **label**. |
| 23 | +3. Add a **calculation** column in the `survey` worksheet. |
| 24 | +4. In the `calculation` column, enter the **calculation expression.** |
| 25 | + - Calculations can range from [basic arithmetic calculations](https://support.kobotoolbox.org/calculations_xls.html#arithmetic-calculations) to [advanced calculations](https://support.kobotoolbox.org/calculations_xls.html#advanced-calculations) using functions and regular expressions. |
| 26 | + |
| 27 | +To refer to the calculation output in the rest of your form (e.g., inside a note question, question label, or form logic), use the [question referencing](https://support.kobotoolbox.org/form_logic_xls.html#question-referencing) format **${question_name}**, where `question_name` is the **name** of the `calculate` question. |
| 28 | + |
| 29 | +**survey worksheet** |
| 30 | + |
| 31 | +| type | name | label | calculation | |
| 32 | +|:----------|:--------------|:-------------------------------|:----------------------| |
| 33 | +| integer | bags | Total number of bags sold | | |
| 34 | +| decimal | price | Price per bag | | |
| 35 | +| calculate | total_amount | | ${bags} * ${price} | |
| 36 | +| note | display_total | The total is ${total_amount} | | |
| 37 | +| survey | |
| 38 | + |
| 39 | +## Arithmetic calculations |
| 40 | + |
| 41 | +Calculations in XLSForm can range from simple arithmetic calculations to advanced derivation of variables. |
| 42 | + |
| 43 | +Arithmetic **calculations** allow you to perform basic calculations using the following **operators**: |
| 44 | + |
| 45 | +| Operator | Description | |
| 46 | +|:----------|:-------------| |
| 47 | +| <strong>+</strong> | Addition | |
| 48 | +| <strong>-</strong> | Subtraction | |
| 49 | +| <strong>*</strong> | Multiplication | |
| 50 | +| <strong>div</strong> | Division | |
| 51 | +| <strong>mod</strong> | Modulo (calculates the remainder of a division) | |
| 52 | + |
| 53 | +Calculations in XLSForm follow the **BODMAS** rule for the order of mathematical operations: **B**rackets, **O**rder of powers, **D**ivision, **M**ultiplication, **A**ddition, and **S**ubtraction. This means that calculations within brackets are performed first, followed by powers, then divisions, multiplications, and so on. Using brackets (also known as parentheses) correctly ensures that your calculations function as expected. |
| 54 | + |
| 55 | +## Advanced calculations |
| 56 | + |
| 57 | +Advanced calculations in XLSForm often rely on **functions** and **regular expressions** to make calculations more efficient. [Functions](https://support.kobotoolbox.org/functions_xls.html) are predefined operations used to automatically perform complex tasks like rounding values, calculating powers, or extracting the current date. [Regular expressions](https://support.kobotoolbox.org/restrict_responses.html) (regex) are search patterns used to match specific characters within a string of text. |
| 58 | + |
| 59 | +<p class="note"> |
| 60 | + For a comprehensive list of functions available in XLSForm, see <a href="https://support.kobotoolbox.org/functions_xls.html">Using functions in XLSForm</a>. |
| 61 | +</p> |
| 62 | + |
| 63 | +Examples of more advanced calculations include: |
| 64 | + |
| 65 | +| Calculation | Description | |
| 66 | +|:-------------|:-------------| |
| 67 | +| `int((today()-${DOB}) div 365.25)` | Calculate age from date of birth. | |
| 68 | +| `int(today()-${date})` | Calculate days since a date. | |
| 69 | +| `format-date(${date}, '%b')` | Return just the month from a date. | |
| 70 | +| `concat(${first}, " ", ${middle}, " ", ${last})` | Create a single string with a respondent’s full name. | |
| 71 | +| `jr:choice-name(${question1}, '${question1}')` | Return a choice’s label, in the current language, from the choice list. | |
| 72 | +| `translate(${full_name}, "ABCDEFGHIJKLMNOPQRSTUVWXYZ ", "abcdefghijklmnopqrstuvwxyz_")` | Convert uppercase letters to lowercase and spaces to underscores. | |
| 73 | +| `substr(${question}, 1, 2)` | Keep only the 1st letter or number in a string. | |
| 74 | +| `int(random()*10)` | Generate a random number between 0 and 10. | |
| 75 | +| `selected-at(${gps}, 0)` | Isolate latitude from GPS coordinates. | |
| 76 | +| `selected-at(${gps}, 1)` | Isolate longitude from GPS coordinates. | |
| 77 | +| `if(regex(${id}, '^ML-'), 'yes', 'no')` | Create a binary variable that takes `yes` if the respondent ID starts with “ML-”. | |
| 78 | + |
| 79 | +### Setting dynamic default responses |
| 80 | + |
| 81 | +The `calculation` field can also be used to set **dynamic default responses.** Dynamic default responses allow you to display a default response inside a question based on a previous response. |
| 82 | + |
| 83 | +To set a dynamic default response: |
| 84 | +1. In the `calculation` column, enter the **reference to the question** that will dynamically populate the default response. |
| 85 | +2. In the `trigger` column, enter the question that will activate the calculation. |
| 86 | + - Typically, this would be the same question referenced in the `calculation` column, so that any change to the trigger question will also update the default response. |
| 87 | + |
| 88 | +**survey worksheet** |
| 89 | + |
| 90 | +| type | name | label | calculation | trigger | |
| 91 | +|:------|:-----------|:--------------------------|:-------------|:-------------| |
| 92 | +| text | hh_name | Name of the head of household | | | |
| 93 | +| text | phone | Household phone number | | | |
| 94 | +| text | phone_name | Name of the phone owner | ${hh_name} | ${hh_name} | |
| 95 | +| survey | |
| 96 | + |
| 97 | +<p class="note"> |
| 98 | +<strong>Note:</strong> If you want to prevent users from editing the field, set the <code>read_only</code> column to <code>TRUE</code>. |
| 99 | +</p> |
| 100 | + |
| 101 | +## Troubleshooting |
| 102 | + |
| 103 | +<details> |
| 104 | + <summary><strong>Troubleshooting recommendations</strong></summary> |
| 105 | + To facilitate troubleshooting, display calculation outputs in a note while developing your form. This helps determine if the calculation is evaluating correctly and makes identifying issues easier. You can also break down long expressions into smaller ones and display the output of each to pinpoint problems. |
| 106 | +</details> |
| 107 | + |
| 108 | +<br> |
| 109 | + |
| 110 | +<details> |
| 111 | + <summary><strong>Calculations not working properly</strong></summary> |
| 112 | + If your calculations are not working, check the following: |
| 113 | + <ul> |
| 114 | + <li><strong>Syntax:</strong> All opened parentheses are closed, straight quotes are used ('), and commas are included where needed.</li> |
| 115 | + <li><strong>References:</strong> Question references correctly match the question name, no spaces or typos, no circular references (i.e., the calculation does not depend on itself).</li> |
| 116 | + <li><strong>Data types:</strong> Numeric and string calculations are not combined within the same question, data types are used correctly.</li> |
| 117 | +</ul> |
| 118 | +</details> |
| 119 | + |
| 120 | +<br> |
| 121 | + |
| 122 | +<details> |
| 123 | + <summary><strong>Dealing with empty fields</strong></summary> |
| 124 | + Unanswered questions are treated as empty strings and will not automatically convert to zero. When an empty value is used in a calculation, it results in "Not a Number" (NaN). To convert empty values to zero for calculations, use the <code>coalesce()</code> or <code>if()</code> <a href="https://support.kobotoolbox.org/functions_xls.html">functions</a>. For example: |
| 125 | + <ul> |
| 126 | + <li><code>coalesce(${potentially_empty_value}, 0)</code></li> |
| 127 | + <li><code>if(${potentially_empty_value}="", 0, ${potentially_empty_value})</code></li> |
| 128 | +</ul> |
| 129 | + Another option is to set default values for each of the numeric variables to 0 in the <code>default</code> column. |
| 130 | +</details> |
| 131 | + |
| 132 | +<br> |
| 133 | + |
| 134 | +<details> |
| 135 | + <summary><strong>Calculations keep changing in the form</strong></summary> |
| 136 | + Expressions are re-evaluated as an enumerator progresses through a form. This is especially important for <a href="https://support.kobotoolbox.org/functions_xls.html">functions</a> not connected to fields in the form, such as <code>random()</code> or <code>now()</code>, as their values may change under these conditions. |
| 137 | +<br><br> |
| 138 | +Expressions are re-evaluated when: |
| 139 | + <ul> |
| 140 | + <li>A form is opened</li> |
| 141 | + <li>The value of any question in the calculation changes</li> |
| 142 | + <li>A repeat group is added or deleted</li> |
| 143 | + <li>A form is saved or finalized</li> |
| 144 | +</ul> |
| 145 | + To control when an expression is evaluated, set a <a href="https://support.kobotoolbox.org/question_options_xls.html#additional-question-options">trigger</a> to evaluate it only when a given question is answered, or the function `once()` to ensure the expression is only evaluated once (e.g., <code>once(random())</code> or <code>once(today())</code>). |
| 146 | +</details> |
| 147 | + |
| 148 | +<br> |
| 149 | + |
0 commit comments