Upload
Download a template file

Carried onto every table, plot and export. Record your inclusion criteria here.
What the app read
Estimated reference interval
Ferritin is roughly log-normal, so most of the sample is squeezed into the left of a linear axis. The log view is where the fit through the bulk of the data can actually be judged.
Thresholds
Not peer reviewed. The dynamic threshold method was presented as an abstract at the Nordic Congress in Clinical Biochemistry 2026 and is planned for a future manuscript. As of September 2026 it has not been peer reviewed, and results from it should be described that way wherever they are reported or cited.

Presented as: Hallén G, Becker C, Rosmark O, Olsson AO, Sandstedt J, Beshara S. Proposed age-, gender- and platform-specific ferritin reference intervals in Sweden using indirect and dynamic approaches [abstract]. Nordic Congress in Clinical Biochemistry, 2026.

Main outcomes
Every margin the settings define, including the analytical-imprecision floor and two within-subject CVs.
The same fit read against alternative anchor intervals — point estimates only. If these move a lot, the anchor choice is doing more work than the data.
What this subset produced
Export

The workbook carries every setting, count and version behind these numbers, plus the interpretation notes.

Download result workbook (.xlsx)
Runs this session
Each completed run is kept here so several subsets can be compared. Cleared when you close the tab.

A standalone way to run two published methods on your own data, so their results can be reproduced and examined independently. It is not the analysis pipeline of any particular study, it holds no study's data, and it is not covered by any study's ethical approval — every parameter here is an editable default, not a fixed choice inherited from one. What you analyse, and on what basis, is entirely your own.

The two analyses answer different questions, and are meant to be read side by side rather than reconciled. One describes where the tested population's ferritin sits; the other describes where hemoglobin starts to fall. A gap between them is a finding, not an error.

The file needs one row per person and these columns:

Column Required Unit Notes
Ferritin yes µg/L, ng/mL or pmol/L One value per row. Set which one above the file input.
Hemoglobin for dynamic thresholds only g/L or g/dL From the same sample as the ferritin on that row.

Units are declared, not detected — the app applies exactly what you set above the file input. See Units below.

Column names are detected automatically for ordinary spellings (ferritin, S-Ferritin, hb, hemoglobin, Hgb, …) and can be corrected by hand after upload. .csv, .tsv, .xlsx and .parquet are accepted, with either . or , as the decimal mark.

One file is one subset. Select the population you want thresholds for, filter your own data down to it, and upload just those rows. This app applies no age, sex or clinical filtering of its own, so whatever is in the file is the population being described. Record the criteria you used in the subset label — it is carried onto every table, plot and export.

Repeat measurements. Both methods assume independent observations. If a patient appears more than once, reduce them to one row before uploading — the app cannot do this, because it never sees a patient identifier.

How much data. refineR needs a substantial sample: a few hundred values at absolute minimum, thousands in practice. There is nothing to set: a sample too small for refineR to say anything at all is refused, and any run under n = 1000 is carried out and flagged as fragile, because the subpopulation separation an indirect method depends on becomes unstable. The dynamic thresholds need paired ferritin and hemoglobin, and enough observations inside the fitted ferritin range to define a curve.

Set the units above the file input, before uploading. Tables, plots and the export are all reported back in them, and the export records the choice.

Internally the app works in µg/L and g/L, converting on the way in and out — so the unit changes how a number reads, not what was computed.

Analyte Choices Conversion
Ferritin µg/L, ng/mL, pmol/L 1 ng/mL = 1 µg/L. 1 µg/L = 2.247 pmol/L.
Hemoglobin g/L, g/dL 1 g/dL = 10 g/L.

An indirect method: it takes a mixed sample of routine laboratory results, estimates the distribution of the non-pathological subpopulation inside it, and reports that distribution's 2.5th and 97.5th percentiles. The algorithm is described in Ammer et al. (2021) and is run here as the authors' published R package — it is not reimplemented in this app, so the numbers are the method's own. Full citations are under References below.

The figure shows refineR's own fitted curve over your histogram, redrawn from the model parameters the package returned. Where the curve sits below the bars is the pathological remainder refineR excluded — the thing an indirect method is actually doing, made visible.

The confidence interval is opt-in. Bootstrapping is refineR's only source of intervals and each replicate costs about as much as the fit itself, so replicates default to 0 and a run finishes in seconds. At 0 the two limits are point estimates and nothing on screen implies otherwise. Set replicates in the sidebar to get refineR's interval, at a proportional wait.

One quirk worth knowing: the point estimate is fitted to all the data while the interval is a quantile of the replicates, so the two are estimated separately and a narrow interval can fail to contain its own point estimate. That means too few replicates, not a fault.

An indirect interval is not a health-based one. It describes the population that was tested, not a recruited healthy cohort.

Not peer reviewed. The dynamic threshold method was presented as an abstract at the Nordic Congress in Clinical Biochemistry 2026 and is planned for a future manuscript. As of September 2026 it has not been peer reviewed, and results from it should be described that way wherever they are reported or cited.

Presented as: Hallén G, Becker C, Rosmark O, Olsson AO, Sandstedt J, Beshara S. Proposed age-, gender- and platform-specific ferritin reference intervals in Sweden using indirect and dynamic approaches [abstract]. Nordic Congress in Clinical Biochemistry, 2026.

A functional method. Hemoglobin is modelled against ferritin as a Michaelis–Menten curve

Hb(f)=y0+(by0)·fk + f
f
ferritin, in the unit you selected — µg/L, ng/mL or pmol/L
y0
modelled hemoglobin as ferritin approaches zero
b
the plateau — modelled hemoglobin at full repletion
k
the ferritin at which hemoglobin has risen halfway from y₀ to the plateau

fitted to individual observations by least absolute deviations, which keeps the fit from being dragged by outlying haemoglobins. The curve rises to a plateau; the iron-replete anchor is the median of the fitted curve across a ferritin interval taken to represent repletion. Each threshold is then the ferritin at which the modelled hemoglobin has fallen below that anchor by a margin derived from biological variation:

Margin Meaning
Analytical imprecision A fall larger than analytical imprecision alone can explain.
1 × within-subject CV A fall of one within-subject biological CV — signs of iron deficiency.
2 × within-subject CV A fall of two within-subject biological CVs.
Reference change value (p = 0.10) The fall a repeat result must show, against analytical and biological variation together, to be a real change at one-sided p = 0.10.
Reference change value (p = 0.05) The same at one-sided p = 0.05 — the usual primary cutoff.

The margins are computed from hemoglobin's analytical CV (CVa) and within-subject CV (CVi), both editable in the sidebar; the percentages update live as you change them.

The results tab leads with the main outcomes — the two reference change values and the one-CV early-decline marker, which is what a functional threshold is usually quoted as. The analytical-imprecision floor and the two-CV margin bracket those and are a check rather than an answer, so they are under All margins below, together with the anchor sensitivity table.

Confidence intervals here do not propagate uncertainty in CVa and CVi, which are treated as fixed — so they understate total uncertainty, and changing CVa moves the margins by more than the interval width.

How it is computed

Implemented in Python with NumPy and SciPy; refineR is called out to R and shares none of this code path.

Loss

Least absolute deviations (L1) on individual observations, not on binned or aggregated means. L1 is used so that outlying haemoglobins — which routine data has plenty of — move the fit far less than they would under squared error.

Fitting

Iteratively reweighted least squares around scipy.optimize.curve_fit: 15 reweightings, each with weights sᵢ = √max(|residualᵢ|, 10⁻³), which approaches the L1 solution. Because the parameters are bounded, curve_fit uses the trust-region-reflective solver; iteration stops early once the largest parameter change falls below 10⁻⁶.

Anchor

The median of the fitted curve across the anchor interval, evaluated on a 500-point grid — not the median of the observations there, which is carried only as a diagnostic (computed as a Harrell–Davis quantile, scipy.stats.mstats.hdquantiles).

Thresholds

Solved in closed form from the fitted parameters, f = k(target − y₀) / (b − target). A crossing outside the fitted ferritin range is reported as absent rather than extrapolated.

Confidence intervals

Nonparametric bootstrap: observations are resampled with replacement and the whole curve — anchor included — is refitted, 200 replicates by default. Replicate i is seeded from (seed, i) together, so a given replicate is unchanged by the total number requested and a rerun reproduces exactly.

  • A crossing outside the fitted ferritin range is not reported. The curve is not extrapolated past the data it was fitted to, so a blank threshold means the modelled hemoglobin never fell that far inside the range — not that the calculation failed.
  • Ferritin is not comparable across analytical platforms. Assays differ in calibration and are traceable to different international standards. A threshold derived on one platform should not be applied to another without a comparison study.
  • The anchor is a choice. The sensitivity table shows the same fit read against alternative anchor intervals, so you can see how much the choice moved the answer.
  • The exported workbook is the record. It carries every setting, count and version behind the numbers, plus these notes. A threshold without its settings is not a result.

Uploads are not stored. A file lives in your session and is gone when you close the tab. The temporary copy refineR reads is deleted as soon as the run ends, whether it succeeded or not. The app keeps no accounts, no logs of what has been uploaded, and no record that a run happened.

Nothing you upload is sent anywhere except to the server running this app. If that is still more than you want, the app runs perfectly well on your own machine with no network involved — see the project README.

Neither analysis uses a patient identifier, a date, or any demographic field, so none of them should be in the file to begin with.

The reference-interval algorithm. If you publish an interval obtained here, cite refineR — the method is the authors', not this app's.

Ammer T, Schützenmeister A, Prokosch H-U, Rauh M, Rank CM, Zierk J. refineR: A Novel Algorithm for Reference Interval Estimation from Real-World Data. Scientific Reports 11, 16023 (2021). https://doi.org/10.1038/s41598-021-95301-2

The software actually executed, which is the R package rather than the paper, and is what a methods section should record alongside its version:

Ammer T, Rank CM, Schuetzenmeister A. refineR: Reference Interval Estimation using Real-World Data. R package. https://cran.r-project.org/package=refineR

Biological variation of hemoglobin. The default CVa (0.7%) and CVi (2.7%) behind every dynamic margin are representative values; the within-subject figure follows the EFLM Biological Variation Database. They are editable, and whichever values you use are recorded in the export — so cite the source you actually adopted.

EFLM Biological Variation Database. https://biologicalvariation.eu/