@UVRANGE
@UVRANGE is a REDCap action tag that checks a number against two ranges: a soft range that asks before saving an unusual value, and a hard range that holds an implausible one.
REDCap's number validation takes one minimum and one maximum, and only warns. A lab
value has two kinds of limit: the range most patients fall in, and the range outside
which the number is almost certainly a typing or unit error. @UVRANGE
checks both when the field is left and again when the form is saved. Outside the
soft range the value is unusual and the save asks first; outside the
hard range it is implausible and the save is held.
Syntax
JSON form only. At least one of soft and
hard.
@UVRANGE={"soft":[12,17.5],"hard":[3,25],"unit":"g/dL"}
@UVRANGE={"soft":[null,140],"softBlock":"off","hard":[40,250],"hardBlock":"confirm","unit":"mmHg"}
@UVRANGE={"soft":[12,15.5],"hard":[3,25],"unit":"g/dL","when":"[sex]='2'"}
@UVRANGE={"soft":[13.5,17.5],"hard":[3,25],"unit":"g/dL","when":"[sex]='1'"}
| Key | Meaning |
|---|---|
soft | [low, high], both ends included. Outside it the
value is unusual. null leaves an end open |
hard | [low, high], both ends included. Outside it the
value is implausible. The soft limits must lie inside the hard ones |
softBlock | confirm (default): the save asks first;
off: the note only |
hardBlock | hard (default): the save is held;
confirm: the save asks first |
unit | A short label shown in the note, such as
g/dL (up to 20 characters) |
message, when, caseSensitive |
As for the other tags |
Limits and values are compared as exact decimals, so 17.50 equals
17.5. A limit is kept exactly as written, quoted or not, so
0.12345678901234567890 keeps all twenty digits. blockSave is
refused: use softBlock and hardBlock.
Field types
Text fields with integer or number validation (any
number of decimals, comma decimals included) or with no validation, calc
fields and sliders. On a comma-decimal field 17,5 reads as
17.5 and the note writes the limits with a comma. A Text field without validation
accepts anything, so a value that is not a number is reported as implausible.
What is checked, and when
- A blank field checks nothing. Pair the field with
@UVREQUIREDwhen it must be filled. - The note appears when the field is left, not while a number is being typed. Clicking Save checks the value as it is, left or not.
- A value inside the soft range shows no note. The tag only speaks about numbers that need a second look.
- A calc field is noted but never holds the save, since nobody typed it. A read-only field is the same.
- Different limits per group: one tag per group, each with its own
when. When nowhenis true the field is not checked; add one tag withoutwhento cover everyone else. A selector on another form is read when the page opens, so that check is advisory and never blocks. - With event and instance references turned on in the project settings,
whenmay read another event or instance, such as[baseline_arm_1][sex]. Such a rule never blocks on the page; the audit and the scan check it. Thereferenceskey is refused. - The exponent form REDCap's number validation accepts is a number:
1.5E1is 15. Thousands separators (1,200) and a unit typed into the box are not numbers. - A field marked with one of the project's missing data codes
(
UNK,-99) holds the code, not a number. It is treated as blank, on the page, in the audit and in the scan.
Growth references
With reference, the limits apply to the value's z-score
for the child's sex and age, or length or height, computed the way WHO's own anthro
software computes it.
@UVRANGE={"reference":"who-wfa","sex":"[sex]","male":"1","female":"2",
"age":{"dob":"[dob]","at":"[visit_date]"},"soft":[-3,3],"hard":[-6,5]}
@UVRANGE={"reference":"who-wfh","sex":"[sex]","male":"1","female":"2",
"by":"[height_cm]","soft":[-3,3],"hard":[-5,5]}
| Key | Meaning |
|---|---|
reference | The reference: who-wfa,
who-lhfa, who-bfa, who-hcfa, who-acfa,
who-ssfa, who-tsfa, who-wfl, who-wfh
(WHO 2006, birth to 5 years) or who2007-wfa, who2007-hfa,
who2007-bfa (WHO 2007, 5 to 19 years) |
sex, male, female | The field holding the sex, and the codes it stores for male and for female |
age | {"dob":"[dob]","at":"[visit_date]"},
{"days":"[age_days]"} or {"months":"[age_months]"} |
by | For weight-for-length or weight-for-height: the field holding the length or height in cm |
soft, hard | z-score limits, from -20 to 20 |
plausible | [low, high] in the reference's unit,
judged when no z-score can be worked out (a blank date of birth, say) |
measureScale | Multiplies the typed value before the z-score:
0.001 for grams typed into a reference in kg |
WHO's software flags a z-score beyond these limits as implausible, and they make
good hard limits: weight-for-age -6 to 5; length/height-for-age -6 to 6;
weight-for-length, weight-for-height, BMI, head and arm circumference and the skinfolds
-5 to 5. For soft, -3 to 3 suits data checking; -2 to 2 asks "save anyway?"
for every moderately malnourished child unless "softBlock":"off".
- A value that is not a number, or a measurement of 0 or below, is implausible whatever the inputs say.
- A blank input, a sex code that is neither male nor female, and an age or length
outside the reference check nothing, unless
plausiblejudges the value. On a data entry form a grey note says why, and the audit logs the value as not evaluated. Sex codes match without regard to letter case unlesscaseSensitiveis true. - Tags that name different references on one field all apply (weight-for-age and weight-for-height on one weight, say). The worst result decides, and the note has one line per reference.
- A page carries at most four whole reference tables by default, a number an administrator can change. With the sex saved on another form, a table counts half. A rule past the limit is checked when the record is saved.
- Inputs on another form, or in another event, are read when the page opens and the z-score note does not block there. A survey, and a user without rights to that form, are not sent the values of another form: the page checks only that the value is a number above 0, and holds the save when it is not; the z-score is checked when the record is saved. A rule with an input in another event never blocks, on a survey either.
- A limit the reference can never pass is a configuration error. Some references give no z-score below (or above) a point at some ages: at 5 years, WHO triceps skinfold-for-age never goes below -6.97 for a girl, so a hard low limit of -7 would not hold back even 0.1 mm there.
- WHO's 0.7 cm correction for a length measured standing, or a height measured lying,
is not applied by the module. A calc field can apply it, and the guide of examples
shows how. For a child with oedema, skip weight rules with
when. - The WHO tables ship with the module under WHO's GPL-3 licence. A REDCap
administrator can add other references (CDC 2000, a national one) in a folder named
in the module's system settings, and check one z-score from the new table with
convert.php --check.
Writing values into fields
A growth rule can also write what it works out into Text fields on the same form, so
the z-score, the percentile or the usual range is saved with the record and appears in
exports. return maps each value to a field.
@UVRANGE={"reference":"who-wfa","sex":"[sex]","male":"1","female":"2",
"age":{"dob":"[dob]","at":"[visit_date]"},"soft":[-2,2],"hard":[-5,5],
"return":{"z":"[wfa_z]","lower":"[wfa_low]","upper":"[wfa_high]","range":"[wfa_range]"}}
@UVRANGE={"reference":"who-wfa","sex":"[sex]","male":"1","female":"2",
"age":{"dob":"[dob]","at":"[visit_date]"},
"return":{"percentile":"[wfa_pct]","valueAtZ:-2":"[wfa_sd_m2]",
"valueAtPercentile:50":"[wfa_p50]","valueAtPercentile:97":"[wfa_p97]"}}
For a boy of exactly one year weighing 9.6 kg the two rules write these values.
| Field | Written | What it is |
|---|---|---|
wfa_z | -0.04 | The z-score of the weight |
wfa_low | 7.8 | The lightest weight, to one
decimal, whose z-score passes -2, the low soft limit |
wfa_high | 11.9 | The heaviest weight, to one
decimal, whose z-score passes 2, the high soft limit |
wfa_range | 7.8 to 11.9 kg | The two as text, with the reference's unit |
wfa_pct | 48.3 | The percentile of the weight, to one decimal |
wfa_sd_m2 | 7.7 | The weight whose z-score is -2 (7.74 kg), to one decimal |
wfa_p50 | 9.6 | The median weight for his age and sex |
wfa_p97 | 11.8 | The weight at the 97th percentile |
The second rule has no soft or hard, since none of its four
values is made from a limit. With the weight still blank, wfa_z and
wfa_pct stay empty and the bounds and the three weights are still written, so
the form shows them before anything is measured. For a girl of the same age the range is
7.1 to 11.5 kg.
The values and the keys that shape them
| Value | What is written |
|---|---|
z | The z-score, with two decimals |
lower, upper | The smallest and the largest
measurement, written with decimals, whose two-decimal z-score passes the
low and the high limit. One unit of the last decimal beyond a bound is flagged |
range | The two bounds as text, such as
7.8 to 11.9 kg. With only a low limit it reads at least 7.8 kg,
with only a high one at most 11.9 kg |
percentile | 100 times the normal distribution function of the
unrounded z-score, written with percentileDecimals and rounded half away
from zero. Beside a z-score written -0.04 this boy's percentile reads
48.3, the percentile of -0.0437 |
valueAtZ:<z-score> | The measurement at that z-score, such
as valueAtZ:-2 or valueAtZ:2.5. The z-score lies from -6 to 6,
with at most two decimals |
valueAtPercentile:<percentile> | The measurement at that
percentile, such as valueAtPercentile:97 or
valueAtPercentile:2.5. The percentile lies from 0.1 to 99.9, with at most
two decimals. valueAtPercentile:50 is the median and equals
valueAtZ:0 |
| Key | Meaning |
|---|---|
return | An object from a value to a field of this form, such as
{"z":"[wfa_z]","valueAtPercentile:97":"[wfa_p97]"}. At most 16 values,
each key once and each to its own field |
returnLimits | soft (default) or hard,
the limits lower, upper and range are made
from |
decimals | 0 to 6, the decimals of lower,
upper, the bounds in range and the values at a z-score or
percentile. The default is the measured field's: N for number_Ndp (2 for
number_2dp, comma forms included), 0 for integer, otherwise
1 |
percentileDecimals | 0 to 3, the decimals of
percentile. The default is 1 |
- Limits only where they are used. A rule that returns only
z,percentileand values at a z-score or percentile needs nosoftorhard.lower,upperandrangeneed the limit they are made from, and the rule is refused without it. - Each key once.
valueAtZ:2andvalueAtZ:2.0are one key written two ways, as arevalueAtZ:0andvalueAtZ:-0, and a rule with both is refused. So are a z-score outside -6 to 6, a percentile outside 0.1 to 99.9, andvalueAtPercentilewith no percentile after the colon. - Keys that shape nothing are refused.
returnLimitsapplies tolower,upperandrange,decimalsto those and to the values at a z-score or percentile, andpercentileDecimalstopercentile. A rule that sets one of these keys and returns none of the values it applies to is refused, so"return":{"z":"[wfa_z]"},"decimals":3is a configuration error. - The ends of the percentile scale. The percentile stays one unit of its
last decimal inside 0 and 100. At one decimal
0.1stands for every percentile below 0.15 and99.9for every one from 99.85 up, so a boy of 6.6 kg (z-score -3.40, a percentile of 0.03) gets0.1. - Rounded values and accepted bounds. A value at a z-score or percentile
is rounded to the nearest unit of its last decimal, so 7.74 kg is written
7.7.lowerandupperare the last values the rule accepts, so the two can differ beside asoftlimit of -2. For this boyvalueAtZ:-2is7.7andloweris7.8, since 7.7 kg scores -2.05 and is flagged. - Beyond 3 SD. On the references WHO reads with its restricted method beyond 3 SD either side (weight, BMI, arm circumference and the skinfolds), the percentile and the values at a z-score or percentile use that method, as the z-score does. Length or height and head circumference use the LMS formula throughout.
- Grams against a table in kg. With
"measureScale":0.001the bounds are in grams. Add"unit":"g"andrangereads7737 to 11989 gfor the same boy. Withoutunitthe range has no unit, since the table's kg would be wrong. - Empty fields. A z-score that no measurement above 0 has, a limit the table cannot reach, and a value that rounds to 0 leave the field empty.
The fields
- Text fields on the same form as the measured field, so in the same event and instance. The measured field, an input of the rule and the record ID cannot take a value, and no field takes two. Two rules cannot return to one field, and both are refused, naming each other. Two references on one field each fill the fields of their own branches and cannot share one.
- A
rangefield takes no validation. The other values take none, number validation without a place count, or a place count equal to the decimals they are written with (two forz,percentileDecimalsforpercentile,decimalsfor the rest). REDCap'snumber_2dptakes exactly two places, so it refuses7.5as it refuses7.512. - A value written with no decimals (
decimals0, the default on an integer measured field, or"percentileDecimals":0) may go into an integer field;znever does. A field with comma-decimal validation gets a comma, and a field without validation takes the decimal mark of the measured field. - A field filled by
@CALCTEXT,@CALCDATEor@SETVALUE, or one that shows@RICHTEXTor a BioPortal ontology search, is refused. - No chains. A rule that returns values cannot read a returned field,
its own or another rule's, in its
when, an input or its measurement. The save works out every returned value from the record as it was saved, so a chain would always lag one save behind. The rule that reads is refused and names the rule that writes.
When the values are written
- On the page, as the page opens and again after the measurement or an input changes, whatever the verdict (a weight outside the limits still gets its z-score). The first fill does not mark the form as changed. After a change REDCap hears an input and a change event, so its calculations and branching logic that read the field run. When an input is on a form the page may not show, the page leaves the fields as they are and the save writes them.
- On save, for a form, a survey, an import and the API. The post-save
audit works out the same values from the saved record and writes those that differ.
The write appears in the record's log as an update by the user who saved, and is not
audited again. These values are written before any other rule is checked, so an
@UVREQUIREDon the z-score field checks the new value. An entry REDCap refuses to write, such as a locked form, is logged, and the others are still written. - A rule with an input in another event is checked in every visit it applies to, so saving the enrolment form after correcting the date of birth refills the fields of every visit.
- The rule owns its fields. When there is nothing to report (a blank
sex, an age or length outside the reference, a
whenthat is false) the fields are emptied. A field holding the same number spelled another way (7.80for7.8) is not rewritten. Mark the fields@READONLY, since a value typed there is overwritten at the next check. - The project setting "@UVRANGE returned values" (
range-return-no-save) keeps the page fill and writes nothing when a record is saved. The Validation scan never writes.
Growth chart and table on the form
show draws the reference's curves with this visit's point under the
field, and a table under them. They are on the page only. Nothing is saved, and the
check is the same without them. A rule that only shows needs no limits.
@UVRANGE={"reference":"who-wfa","sex":"[sex]","male":"1","female":"2",
"age":{"dob":"[dob]","at":"[visit_date]"},"soft":[-2,2],"hard":[-5,5],
"show":{"chart":{"lines":{"percentiles":[3,15,50,85,97]},"bands":true},
"table":true}}
- Up to 9 curves, at percentiles or z-scores (
{"z":[-2,0,2]}); withoutlines, 0 and each of the rule's limits.bandsshades thesoftrange. - The point sits at the child's age and the typed value, or as an arrow at the edge when it lies outside. On a table read by the nearest or the completed row, it sits at the row the check reads, so it falls on the side of a curve the verdict gives. The chart's description, for screen readers, gives the reference, the value, the z-score and the percentile. Only the point moves when the value changes.
- The chart fits the field's cell, 320 to 640 pixels wide. The x axis counts months
while the chart spans less than two years, years beyond, cm for weight-for-length,
or the
chartUnitof the reference (weeks for gestational age)."y":"z"draws z-scores instead of the measurement, andspanfixes the ages shown. "table":trueshows this visit's age, value, z-score and percentile;columnspicks any valuereturnwrites."rows":"curve"with asteplists the reference's own values instead, at most 100 rows.- Each label can be a text per Multi-Language Management language, and the x title
can hold
{unit}for the unit's word; the module's other words are English. The box is open on data entry and closed on surveys;openchanges that. - A page shows at most 4 sets of curves and tables of reference values
(
pageCharts); past that, staff see why, and the check is unchanged. Aspanthe reference does not cover, or a sex saved blank, also leaves the part off with a note to staff.
Audit
The post-save audit logs a value outside either range as type: range
with reason soft-low, soft-high, hard-low,
hard-high, not-a-number or, for a growth reference,
not-positive, plausible-low or plausible-high,
whatever softBlock says, and the Validation scan counts it. A growth
finding carries its reference, and its z-score only where values are kept raw (an audit
log set to raw values, a scan that stores raw values). The scan's report, when it returns, labels each one
an unusual value, an implausible value, not a number or (for a growth reference) not a
positive measurement, with the expected or allowed range.