The hardware and bandwidth for this mirror is donated by METANET, the Webhosting and Full Service-Cloud Provider.
If you wish to report a bug, or if you are interested in having us mirror your free-software or open-source project, please feel free to contact us at mirror[@]metanet.ch.

Supplying Passworded Models

Last updated: 2026-09-26

Update

From v0.4.0, users now have the option to Save and Load Sessions (located on the Main Simulation page, below the code editor), which may be more convenient. The original password-unlocked models functionality detailed below still remains supported, as it can handle multiple models.

Somewhat related but important to note that from v0.4.5, users now can use the Download Model button (located on the Main Simulation page, below the code editor) to export a standalone .zip file containing all necessary information to fully reproduce the simulations from MVP.

Motivation

To avoid re-entering in model code, dosing regimens, and other settings every time, users can provide an additional file to be sourced by MVP during launch. To use this functionality, it is assumed that users have a working knowledge of the Shiny framework.

How models are supplied to MVP

A list of models (stored as character objects) are included by default when MVPapp is installed. This is the list that the users sees in the drop-down list when they select models, and is stored as a vector of characters called model_examples_list. There are two functions related to model selection:

When both of these functions are re-defined by an external R script, additional password-protected models become available in MVP.

The external script is evaluated inside the app’s own environment, so the internal objects it refers to (e.g. model_examples_list, code_preamble, code_postamble and create_alert()) are available directly by name, even though they are not exported from MVPapp. Outside the app they can be inspected with the ::: operator, e.g. MVPapp:::model_examples_list.

An example external file is provided in /shiny/passworded_models_example.R. The user is recommended to copy this script locally and use it as a starting point to insert models, and supply the path for the pw_models_path argument to run_mvp(), i.e. run_mvp(pw_models_path = "path/to/your/private/models.R").

Re-defining model_switch_conditions()

The structure of model_switch_conditions() is relatively straightforward - each model is provided as a key-value pair, where the left-hand side (LHS) is the title of the model, and the right-hand side (RHS) is the code to be pasted when the associated title is selected.

In the example (passworded_models_example.R), you can see that the first one on the list is called “Test Passworded Model”. Note that this model is not visible when you launch MVP - this behavior is intended, as “Test Passworded Model” is hidden from selection by default from the drop-down list until a valid password has been supplied from the “More…” tab (in this case the password is “test”), in which case the model is “unlocked” and become available for selection. This is the basis of how passworded models work in MVP.

Therefore, the list in model_switch_conditions() must contain every model, both public and private.

Re-defining update_model_choices()

The structure of update_model_choices() looks a bit more complicated, however none of the arguments nor its return value is of importance for the user. The only relevant part is the following:

list_of_valid_passwords <- c("test")

### Example model
if (input_password == "test") {
  create_alert("FirstName LastName", "first.last@xxx.com")
  new_choices <- c('Test Passworded Model', model_examples_list)
  updateXXXInput(session, "YYY", value = ZZZ)
  .
  .
  .
  
} 
  

⚠️ If your external script was copied from a version of MVP before 1.0.0, please replace the block after # Update the selectInput with the new choices (at the end of update_model_choices()) with the one in the current passworded_models_example.R. Older copies reset both model selections (and any edited model code) while typing in the password box (#36).

As almost all Shiny Inputs can be updated this way and there are far too many to list, the most common Input id names are included below for reference:

Data Options

Description Shiny Input Type id
BLQ filter checkboxInput “BLQ_filter”
EVID filter checkboxInput “EVID_filter”
Coerce into numeric checkboxInput “turn_all_numeric”
Data Filtering Code Editor shinyAce::updateAceEditor “codes”

Dosing Options

Description Shiny Input Type id
Dose Amount, Regimen 1 (Model 1) updateNumericInput “amt1”
First Dose Time, Regimen 1 (Model 1) updateNumericInput “delay_time1”
Total Doses, Regimen 1 (Model 1) updateNumericInput “total1”
Dosing Interval, Regimen 1 (Model 1) updateNumericInput “ii1”
Infusion Duration, Regimen 1 (Model 1) updateNumericInput “tinf1”
Use MW (Model 1) updateCheckboxInput “mw_checkbox”
MW value (Model 1) updateNumericInput “mw”
MW multiplication factor (Model 1) updateNumericInput “multi_factor”
Use Weight-based dosing (Model 1) updateCheckboxInput “wt_based_dosing_checkbox”
Weight-based parameter name (Model 1) updateTextInput “wt_based_dosing_name”
Model Duration (Model 1) updateCheckboxInput “model_dur_checkbox”
Model Rate (Model 1) updateCheckboxInput “model_rate_checkbox”

Sampling Options

Description Shiny Input Type id
Max Sampling Time updateNumericInput “tgrid_max”
Sampling Frequency updateNumericInput “delta”
Custom Sampling Schedule updateTextInput “custom_sampling_time_text”
Add Sampling at Time 0 updateCheckboxInput “add_time_zero”
q1w_sampling <- c(2, 4, 8, 24, 72, 168)
q3w_sampling <- c(2, 4, 8, 24, 72, 168, 336, 504) + 168*6
q1w_repeated <- unlist(lapply(0:5, function(x) q1w_sampling + x * 168)) # end of Q1W sampling
q3w_repeated <- unlist(lapply(0:7, function(x) q3w_sampling + x * 504)) # end of Q3W sampling

updateTextInput(session, "custom_sampling_time_text", value = 'c(q1w_repeated, q3w_repeated)')

Plotting Options

Description Shiny Input Type id
Y-axis label updateTextInput “y_axis_label”
Log Y-axis (Simulation Page) updateCheckboxInput “log_y_axis”
Log Y-axis (PSA Page, Model 1) updateCheckboxInput “log_y_axis_model_1”
Log Y-axis (PSA Page, Model 2) updateCheckboxInput “log_y_axis_model_2”
Log Y-axis (Variability Page) updateCheckboxInput “log_y_axis_iiv”
Scale X-axis updateSelectizeInput “time_unit”
Show Sampling Points [sims] updateCheckboxInput “geom_point_sim_option”
updateSelectizeInput(session, "time_unit", selected = '168', options = list(create = TRUE))

Variability Options

Description Shiny Input Type id e.g.
Select Patient Database, Model 1 updateSelectizeInput “db_model_1” selected = “NHANES”
N Subjects, Model 1 updateNumericInput “n_subj_model_1”
Seed, Model 1 updateNumericInput “seed_number_model_1”
Age, Model 1 updateSliderInput “age_db_model_1” min = 0, max = 100, value = c(18, 65)
Weight, Model 1 updateSliderInput “wt_db_model_1” min = 0, max = 150, value = c(0, 150)
Males Percentage, Model 1 updateSliderInput “males_db_model_1” min = 0, max = 100, value = 100, step = 5
Custom Covariate 1, Model 1 updateTextInput “custom_cov_1_model_1” value = “CMINSS”
Custom Covariate 1 Distribution, Model 1 updateSelectInput “custom_cov_1_dist_model_1” selected = “Log-Normal”
Y-value Threshold updateNumericInput “y_value_threshold” value = 0

If the user wishes to update other Inputs that are not listed above, please refer to the source code for shiny/app.R.

Note: If the additional model(s) do not need to be password-gated, the entire update_model_choices() function can be removed from the external script (i.e. do not need to be re-defined), and only model_switch_conditions() needs to be changed to include the additional models.

Supplying Model Code

The last piece to tie it all together is to supply the actual model code itself. MVP accepts the character form of mrgsolve code, so objects have to be defined in the format of the following:

model_name <- paste0(code_preamble, '

"
  [mrgsolve model code]

"
', code_postamble)

Summary

The most ideal process would be to allow saving & opening projects based on a password all within the Shiny UI itself. However, since MVP was not originally developed with a database architecture in mind, the present solution still provides an an acceptable alternative to allow additional models to be supplied externally upon App launch. The main advantage of this approach is that if MVP is deployed and hosted elsewhere (e.g. via Posit Connect), as long as the hosted environment has access to the external models script, the App does not need to be re-deployed to access the updated models.

These binaries (installable software) and packages are in development.
They may not be fully stable and should be used with caution. We make no claims about them.