Migrating from NCA v2
NCA v3, which ships with Pumas 2.9, is a rewrite of the package rather than an incremental release. Code written against NCA v2 (Pumas 2.8 and earlier, with plots from NCAUtilities) will not run unchanged. This page explains the changes and closes with a list of the individual renames and removals.
Migrating with a coding agent
The mechanical part of a migration is well suited to coding agents. For that purpose, you can point your agent at the skill file below, which covers the most common problems and their fixes.
Design changes
A v2 analysis and its v3 counterpart look like this:
# v2
using NCA, NCAUtilities
pop = read_nca(df; observations = :conc, amt = :amt, ii = :ii, ss = :ss, llq = 0.1)
# pop isa NCAPopulation
report = run_nca(pop; parameters = [:cmax, :aucinf_obs], sigdigits = 3)
# report isa NCAReport
results = report.reportdf
# results isa DataFrame
auc = NCA.auc(pop; interval = (0, 12))
observations_vs_time(pop)
# v3
using NCA
nca_data = read_nca(df; concentration = :conc, dose = :amt, tau = :tau)
# nca_data isa DataFrame
nca_data = transform_nca(nca_data; llq = 0.1)
results = run_nca(nca_data, [:cmax, :aucinf_obs, :auc_partial => (; interval = (0, 12)) => :auc_0_12])
# results isa DataFrame
observations_vs_time(nca_data)Profiles instead of subjects
NCA v2 was organised around NCASubject, an object holding all observations of one subject, with NCAPopulation as a vector of them. Single-dose and multi-dose subjects were represented with different data structures, which complicated the analysis as well as making tables, listings and figures.
NCA v3 replaces the different subject types with one concept, the profile: the observations belonging to a single dosing event. A subject that received three doses contributes three profiles. Multiple dosing is handled by one or more grouping columns that tell the profiles of a given subject apart. The user does not interact with a profile as a special type; a profile is simply the contiguous rows of the input DataFrame that belong to one dosing event.
Time in a profile is now always understood as time after dose, and absolute times are normalised automatically when the dose time is given. This makes the computations more robust and the inputs and outputs of NCA easier to understand.
DataFrames in, DataFrames out
Inputs and outputs of NCA are now plain DataFrames. read_nca returns one with a fixed layout (grouping columns, then id, then the profile index, then the observation and dose columns), and run_nca takes such a frame and returns one row per profile with one column per endpoint.
The NCAReport wrapper from v2 is gone. Reports are better served by Quarto notebooks with the native Julia engine, which combine the result tables and plots with far more flexibility.
Tidy input data by default
v2 read_nca accepted several layouts at once and guessed column names from a list of aliases and partial matches. NCA v3 has two readers with one layout each:
read_ncais the default and preferred reader. It reads tidy data, where every row is an observation and the dose information (dose,route,tau,duration,dose_time) is repeated on every row of a profile.read_nca_pumasis a convenience function for event-style tables, which appear mainly as the result of Pumas simulations, where only one row per profile carries the dose information. Use it only when the data already has this shape.
Column names are now matched exactly and case-insensitively against the v3 keyword names (concentration, dose, tau, ...), which reduces the potential for errors.
Steady state through tau and assumed_tau
v2 expressed steady state with the pair ii and ss, and the same ii value meant different things depending on the flag. NCA v3 has two columns with one meaning each. A non-missing tau marks a profile as measured at steady state and unlocks the observed interval endpoints (ctau, cavg, auctau_obs, auctau_pred, fluctuation, swing). A non-missing assumed_tau marks a single-dose profile with a hypothetical interval and unlocks the predicted steady-state endpoints (cmaxss, cminss, cavgss, accumulation_index). A profile may have only one of the two. Both are input columns of the read step, so they can vary per profile.
Endpoints are requested through run_nca
Individual endpoint functions such as NCA.auc(pop; interval = (0, 12)) are gone in favour of the central run_nca mechanism. Computing all requested endpoints in one pass lets shared intermediate results, such as the λz fit, be computed once and reused, which is more efficient. All endpoints are requested through the second positional argument of run_nca, as symbols, optionally with options and an output name:
run_nca(nca_data, [
:cmax,
:auclast => (; method = :linlog) => :auclast_log,
:auc_partial => (; interval = (0, 12)) => :auc_0_12,
:lambdaz => :kel,
])Endpoint names were made consistent: observed and predicted variants end in _obs and _pred, dose-normalised variants in _dn, percentages in _percent, and the λz regression statistics all start with lambdaz. The full mapping from v2 names is in the migration skill, and the current names are listed in the Endpoint Reference.
All endpoints were rewritten to agree with industry standards for performing NCA, so individual numerical results may differ from v2 where v2 deviated from those standards. The renames and removals at the end of this page therefore cover only API changes.
Failures are reported in the results
When an endpoint could not be computed for a profile, v2 logged a warning and moved on. Warnings are easily missed, especially in automated or agent-based workflows. NCA v3 therefore puts missing in any row where an endpoint could not be computed and adds an <endpoint>_err column with the reason for that row. These columns can then be analysed programmatically or by agents.
NCA v2 also warned when input data did not fully conform to the expected format. NCA v3 either succeeds or throws an error with a clear message.
Transformations keep every row
BLQ handling, LLQ truncation and sparse sampling moved from read_nca keywords into transform_nca, a separate step between reading and analysis. When it modifies concentrations, the original values stay in concentration_before_blq. Exclusions of individual observations work the same way: an exclusion column with reason strings is turned into a boolean exclusion_mask, and a lambdaz_mask column selects the points of the terminal regression. In all cases the rows remain in the frame, which keeps an audit trail and lets the plots show gaps in the data correctly.
Plots and tables live in NCA
NCAUtilities was merged into NCA, so observations_vs_time, subject_fits, parameters_vs_group, the dose linearity plots and geomean_cv_table come with using NCA. The observation plots take the read_nca output, the endpoint plots take the run_nca result.
Pumas interop via DataFrames
Pumas 2.9 no longer depends on NCA, so using Pumas does not bring NCA into scope and NCA has to be added to the project and loaded. The @nca block in models and the conversions of Subject and Population to NCASubject and NCAPopulation are removed. Instead, a simulation is turned into a table and read like any other event-style dataset:
using Pumas, NCA, DataFrames
df = DataFrame(simobs(model, population, params); include_events = true)
df.route .= "ivbolus"
nca_data = read_nca_pumas(df; concentration = :dv, dose = :amt, tau = :ii, group = [:dosenum])
results = run_nca(nca_data, [:cmax, :auclast, :half_life])route is no longer part of the Pumas dose representation. DosageRegimen(...; route = NCA.IVBolus) warns and ignores the keyword; carry the route as a covariate or add the string column to the table.
Renames and removals
read_nca and read_nca_pumas
- Keyword renames:
observationstoconcentration,amttodose,iitotauorassumed_tau,timeu,concu,amtuandvolumeutotime_unit,concentration_unit,dose_unitandvolume_unit. - Units are all or nothing: when one unit keyword is given, every dose-related column needs one, and numeric options such as
llqorintervalthen need units too. - Unitful support is an extension, so
Unitfulhas to be loaded explicitly andNCA.Unitfulno longer exists. DynamicQuantities is supported through a second extension. routeis required."ivbolus"and"ivinfusion"are the preferred spellings;"iv"and"inf"still work.NullRouteis deprecated in favour ofmissing.read_ncatakesdose_timefor absolute time columns; without it,timeis time after dose. Missing times are an error.blqmust be aBoolcolumn.llq,concblq,sparse,missingconc,missingvolumeandverboseare no longerread_ncakeywords.- Group column names that NCA uses itself (
dose,tau,route, ...) are reserved. - Both readers reject a non-positive
tauand a non-positive infusionduration.
run_nca and endpoints
- Endpoints are the second positional argument;
parameters,sigdigitsand the report metadata keywords are gone. - Renamed endpoints:
thalftohalf_life,lambdazrtolambdazcorr,auctautoauctau_obs,aumctautoaumctau_obs,aumctoaumcinf_obs,mrttomrtinf_obs,cltocl_obsorcl_f_obs,vztovz_obsorvz_f_obs,vsstovss_obs,accumulationindextoaccumulation_index,auc_extrap_percent,aumc_extrap_percent,auc_back_extrap_percentandaurc_extrap_percentto their_obsvariants,auc_stderrtoauclast_stderr, andaurctoaurclast. The old names still work with a deprecation warning. - Endpoints that take options (
auc_partial,cmax_interval,tmax_interval, themethod-aware AUC endpoints,lambdaz_fit,cpred) require an output name when options are given, and the name may not be another endpoint's name. dose,route,tauandassumed_tauare columns of the result, not endpoints.run_statusis removed; use the_errcolumns.concthresholdof the λz fit is removed; the BLQ system covers it.- New:
lambdaz_diagnosticswith per-point regression diagnostics, together withformat_diagnosticsandexclude_lambdaz(experimental).
summarize
- Takes the
run_ncaresult.skipmissingsis removed and missing values are always skipped.numsamplesandnonmissingare always included. Integer indices forparametersandstratify_byare no longer accepted, andparametersdefaults to every non-grouping column, including renamed and partial AUC endpoints.
Plots and tables
- Plot functions take the
read_ncaoutput or therun_ncaresult instead of a population or report.limitmay not be combined withrows/columns,facet = (; combinelabels = true)is removed, and axis linking is set with the AlgebraOfGraphics optionsfacet = (; linkxaxes, linkyaxes). geomean_cv_tableisNCA.geomean_cv_tableand takes therun_ncaresult.
Other
NCA.superpositiontakes theread_ncaframe and the keywordsassumed_tau,n_doses,maintenance_doseandloading_doseinstead ofii,ndosesandamt.steadystatetolis gone, andn_doses = Infis capped bymax_auto_doses.- Dose linearity models take the
run_ncaresult. - Removed:
NCASubject,NCAPopulation,NCADose,NCAReport,report,showunits,NCA.cleanblq,read_ncaon a file path, and the two-frameread_nca(df_obs, df_dose)form. - Joint plasma and urine datasets can no longer be analysed in one frame, since times may not be missing; analyse them separately.