diff --git a/.Rbuildignore b/.Rbuildignore index 3c87de3a..5e168052 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -1,3 +1,5 @@ +^CONTRIBUTING\.md$ +^path$ ^renv$ ^renv\.lock$ ^.*\.Rproj$ @@ -6,3 +8,5 @@ ^docs$ ^pkgdown$ ^\.github$ +^data-raw$ +^path/to/venv/ \ No newline at end of file diff --git a/.gitignore b/.gitignore index 81483352..028307fb 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,5 @@ # Mac .DS_Store inst/doc + +*.code-workspace diff --git a/DESCRIPTION b/DESCRIPTION index 57ab3f59..26a7b4c2 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,15 +1,16 @@ Package: recodeflow Type: Package Title: Contains functions to interface with variable details sheets, including recoding variables and converting them to PMML -Version: 0.1.0 +Version: 0.1.1 Authors@R: c( - person(given = "Yulric", family = "Sequeira", role = c("aut"), email = "ysequeira@ohri.ca"), - person(given = "Luke",family = "Bailey", email = "lbailey@toh.ca", role = c("aut")), - person(given = "Rostyslav", family = "Vyuha", role = c("aut","cre"), email = "rvyuha@toh.ca")) -Maintainer: Rostyslav Vyuha + person("Yulric", "Sequeira", email = "ysequeira@ohri.ca", role = c("aut", "cre")), + person("Luke", "Bailey", role = c("aut")), + person("Rostyslav", role = c("aut")) + ) +Maintainer: Yulric Sequeria Description: Recode and harmonize data using variable and details sheets. Depends: - R (>= 3.1.0) + R (>= 3.5) Imports: sjlabelled, stringr, @@ -17,19 +18,19 @@ Imports: haven, dplyr, magrittr, - glue, - survival License: MIT + file LICENSE URL: https://github.com/Big-Life-Lab/recodeflow BugReports: https://github.com/Big-Life-Lab/recodeflow/issues Encoding: UTF-8 LazyData: true -RoxygenNote: 7.2.3 +RoxygenNote: 7.3.2 Suggests: DT, kableExtra, knitr, rmarkdown, - testthat (>= 3.0.0) + readr, + testthat (>= 3.0.0), + survival Config/testthat/edition: 3 VignetteBuilder: knitr diff --git a/NAMESPACE b/NAMESPACE index 343bfc9b..6ef3df29 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -1,6 +1,5 @@ # Generated by roxygen2: do not edit by hand -export(example_der_fun) export(get_table_name) export(is_equal) export(is_table_feeder_var) diff --git a/R/data.R b/R/data.R new file mode 100644 index 00000000..a8c36b88 --- /dev/null +++ b/R/data.R @@ -0,0 +1,129 @@ +#' The pbc dataset +#' +#' @format A data frame with 418 observations and 20 variables. +#' \describe{ +#' \item{id}{case number} +#' \item{time}{number of days between registration and the earlier of death, transplantation, or study analysis time} +#' \item{status}{status at endpoint, 0/1/2 for censored, transplant, dead} +#' \item{trt}{1/2/NA for D-penicillamine, placebo, or not randomized} +#' \item{age}{age in years} +#' \item{sex}{m/f} +#' \item{ascites}{presence of ascites} +#' \item{hepato}{presence of hepatomegaly or enlarged liver} +#' \item{spiders}{blood vessel malformations in the skin} +#' \item{edema}{0 no edema, 0.5 untreated or successfully treated, 1 edema despite diuretic therapy} +#' \item{bili}{serum bilirubin (mg/dl)} +#' \item{chol}{serum cholesterol (mg/dl)} +#' \item{albumin}{serum albumin (g/dl)} +#' \item{copper}{urine copper (ug/day)} +#' \item{alk.phos}{alkaline phosphotase (U/liter)} +#' \item{ast}{aspartate aminotransferase (U/ml)} +#' \item{trig}{triglycerides (mg/dl)} +#' \item{platelet}{platelet count} +#' \item{protime}{standardised blood clotting time} +#' \item{stage}{histologic stage of disease (1, 2, 3, or 4)} +#' } +#' @source {https://cran.r-project.org/web/packages/survival/survival.pdf} +"pbc" + +#' Metadata for the pbc dataset using the DCIM standard +#' +#' @format A list containing DCMI metadata: +#' \describe{ +#' \item{title}{title} +#' \item{creator}{creator} +#' \item{subject}{subject} +#' \item{description}{description} +#' \item{publisher}{publisher} +#' \item{date}{date} +#' \item{type}{type} +#' \item{format}{format} +#' \item{identifier}{identifier} +#' \item{source}{source} +#' \item{language}{language} +#' \item{rights}{rights} +#' \item{references}{references} +#' } +"pbc_metadata" + +#' Variables sheet for the pbc dataset +#' +#' @format A data frame with 24 rows and 11 columns: +#' \describe{ +#' \item{variable}{variable name} +#' \item{label}{variable label} +#' \item{labelLong}{variable label long} +#' \item{subject}{subject} +#' \item{section}{section} +#' \item{variableType}{variable type} +#' \item{databaseStart}{database start} +#' \item{units}{units} +#' \item{variableStart}{variable start} +#' \item{notes}{logical indicating presence of notes} +#' \item{description}{logical indicating presence of description} +#' } +"pbc_variables" + +#' Variable details sheet for the pbc dataset +#' +#' @format A data frame with 69 rows and 16 columns: +#' \describe{ +#' \item{variable}{variable name} +#' \item{dummyVariable}{dummy variable name} +#' \item{typeEnd}{end type} +#' \item{databaseStart}{database start} +#' \item{variableStart}{variable start} +#' \item{typeStart}{start type} +#' \item{recEnd}{record end} +#' \item{recStart}{record start} +#' \item{catLabel}{category label} +#' \item{catLabelLong}{category long label} +#' \item{numValidCat}{number of valid categories (numeric)} +#' \item{units}{logical indicating presence of units} +#' \item{notes}{logical indicating presence of notes} +#' \item{catStartLabel}{category start label} +#' \item{variableStartShortLabel}{variable start short label} +#' \item{variableStartLabel}{variable start label} +#' } +"pbc_variable_details" + +#' Example variables sheet for vignettes +#' +#' @format A data frame with 24 rows and 11 columns: +#' \describe{ +#' \item{variable}{variable name} +#' \item{label}{variable label} +#' \item{labelLong}{variable label long} +#' \item{subject}{subject} +#' \item{section}{section} +#' \item{variableType}{variable type} +#' \item{databaseStart}{database start} +#' \item{units}{units} +#' \item{variableStart}{variable start} +#' \item{notes}{logical indicating presence of notes} +#' \item{description}{logical indicating presence of description} +#' } +"tester_variables" + +#' Example variable details sheet for vignettes +#' +#' @format A data frame with 69 rows and 16 columns: +#' \describe{ +#' \item{variable}{variable name} +#' \item{dummyVariable}{dummy variable name} +#' \item{typeEnd}{end type} +#' \item{databaseStart}{database start} +#' \item{variableStart}{variable start} +#' \item{typeStart}{start type} +#' \item{recEnd}{record end} +#' \item{recStart}{record start} +#' \item{catLabel}{category label} +#' \item{catLabelLong}{category long label} +#' \item{numValidCat}{number of valid categories (numeric)} +#' \item{units}{logical indicating presence of units} +#' \item{notes}{logical indicating presence of notes} +#' \item{catStartLabel}{category start label} +#' \item{variableStartShortLabel}{variable start short label} +#' \item{variableStartLabel}{variable start label} +#' } +"tester_variable_details" diff --git a/R/example_der_function.R b/R/example_der_function.R index c8e97639..2fad9125 100644 --- a/R/example_der_function.R +++ b/R/example_der_function.R @@ -1,7 +1,7 @@ #' example_der_fun caluclates chol*bili #' @param chol the row value for chol #' @param bili the row value for bili -#' @export +#' @keywords internal example_der_fun <- function(chol, bili){ # as numeric is used to coerce in case categorical numeric variables are used. # Warning either chol or bili being NA will result in NA return diff --git a/R/recode-with-table.R b/R/recode-with-table.R index 64f35a7f..dd0ccd6e 100644 --- a/R/recode-with-table.R +++ b/R/recode-with-table.R @@ -44,7 +44,7 @@ is_equal <- function(v1, v2) { #' Creates new variables by recoding variables in a dataset using the rules #' specified in a variables details sheet #' -#' The \href{https://github.com/Big-Life-Lab/recodeflow/blob/master/inst/extdata/PBC-variableDetails.csv}{variable_details} +#' The \href{https://github.com/Big-Life-Lab/recodeflow/blob/master/inst/extdata/pbc_variable_details.csv}{variable_details} #' dataframe needs the following columns: #' \describe{ #' \item{variable}{Name of the new variable created. The name of the new @@ -523,6 +523,7 @@ recode_call <- #' @param variable_being_checked the name of the recoded variable #' #' @return the data equivalent of variable_being_checked +#' @keywords internal get_data_variable_name <- function(data_name, data, @@ -586,6 +587,7 @@ get_data_variable_name <- #' @param tables A list of reference tables #' #' @return Returns recoded and labeled data +#' @keywords internal recode_columns <- function(data, variables_details_rows_to_process, @@ -979,7 +981,7 @@ recode_non_derived_variables <- function( ) if (length(else_value) > 0) { extra_row <- nrow(log_table) + 1 - log_table[extra_row , "value_to"] <- else_value + log_table[extra_row , "value_to"] <- as.character(else_value) log_table[extra_row , "From"] <- "else" log_table[extra_row , "rows_recoded"] <- @@ -1009,6 +1011,7 @@ recode_non_derived_variables <- function( #' #' @return a boolean vector containing true for rows where the #' comparison is true +#' @keywords internal compare_value_based_on_interval <- function(left_boundary, right_boundary, @@ -1101,6 +1104,7 @@ update_variable_details_based_on_variable_sheet <- #' @param var_type the toType of a variable #' #' @return an appropriately coded tagged NA +#' @keywords internal format_recoded_value <- function(cell_value, var_type) { recode_value <- NULL if (grepl("NA", cell_value)) { @@ -1370,6 +1374,7 @@ calculate_custom_function_row_value <- #' @param variable_details_row A data frame with a single row which will be #' checked #' @return A boolean +#' @keywords internal is_derived_var <- function(variable_details_row) { derived_var_regex <- "DerivedVar::\\[(.+?)\\]|DerivedVar::\\[\\]" return(length(grep( diff --git a/R/test_data_generator.R b/R/test_data_generator.R deleted file mode 100644 index b69f6480..00000000 --- a/R/test_data_generator.R +++ /dev/null @@ -1,95 +0,0 @@ -variable_details <- data.frame( - "variable" = c(rep("time",times = 2) , rep("status", times = 4), rep("trt", times = 5), rep("age", times = 2), rep("sex", times = 3), rep("ascites", times = 4), rep("hepato", times = 4), rep("spiders", times = 4), rep("edema", times = 4), - rep("bili", times = 2), rep("chol", times =3), rep("albumin", times =2), rep("copper", times = 3), rep("alk.phos", times=3), rep("ast", times = 3), rep("trig", times=3), rep("platelet", times = 3), rep("protime", times = 3), rep("stage", times = 6), - "example_der", rep("agegrp5", times = 12), rep("agegrp10", times = 7), rep("age_cont", times = 19), rep("agegrp10", times = 12)), - - "typeEnd" = c(rep("cont", times = 2), rep("cat", times = 4), rep("cat", times = 5), rep("cont", times = 2), rep("cat", times = 3), rep("cat", times = 4), rep("cat", times = 4), rep("cat", times = 4), rep("cat", times = 4), - rep("cont", times = 2), rep("cont", times = 3), rep("cont", times = 2), rep("cont", times = 3), rep("cont", times = 3), rep("cont", times = 3), rep("cont", times = 3), rep("cont", times = 3), rep("cont", times = 3), rep("cat", times = 6), - "cont", rep("cat", times = 12), rep("cat", times = 7), rep("cont", times = 19), rep("cat", times = 12)), - - "typeStart" = c(rep("cont", times = 2), rep("cat", times = 4), rep("cat", times = 5), rep("cont", times = 2), rep("cat", times = 3), rep("cat", times = 4), rep("cat", times = 4), rep("cat", times = 4), rep("cat", times = 4), - rep("cont", times = 2), rep("cont", times = 3), rep("cont", times = 2), rep("cont", times = 3), rep("cont", times = 3), rep("cont", times = 3), rep("cont", times = 3), rep("cont", times = 3), rep("cont", times = 3), rep("cat", times = 6), - "cont", rep("cat", times =12), rep("cat", times = 7), rep("cat", times = 19), rep("cat", times = 12)), - - "databaseStart" = c(rep("tester1, tester2", times = 64), - rep("tester1", times = 12), rep("tester2", times = 7), rep("tester1", times = 12), rep("tester2", times = 7), rep("tester1", times =12)), - - "variableStart" = c(rep("[time]", times = 2), rep("[status]", times = 4), rep("[trt]", times = 5), rep("[age]",times = 2), rep("[sex]", times = 3), rep("[ascites]", times = 4), rep("[hepato]", times = 4), rep("[spiders]", times = 4), rep("[edema]", times = 4), - rep("[bili]", times = 2), rep("[chol]", times =3), rep("[albumin]", times =2), rep("[copper]", times =3), rep("[alk.phos]", times = 3), rep("[ast]", times = 3), rep("[trig]", times = 3), rep("[platelet]", times =3), rep("[protime]", times = 3), rep("[stage]", times = 6), - "DerivedVar::[chol, bili]", rep("tester1::agegrp", times = 12), rep("tester2::agegrp", times = 7), rep("tester1::agegrp", times = 12), rep("tester2::agegrp", times = 7), rep("tester1::agegrp", times = 12)), - - "variableStartLabel" = c(rep("time", times = 2), rep("status", times = 4), rep("treatment", times = 5), rep("age", times = 2), rep("sex", times = 3), rep("ascites", times = 4), rep("hepato", times = 4), rep("spiders", times = 4), rep("edema", times = 4), - rep("bili", times =2), rep("chol", times = 3), rep("albumin", times = 2), rep("copper", times =3), rep("alk.phos", times = 3), rep("ast", times = 3), rep("trig", times = 3), rep("platelet", times = 3), rep("protime", times = 3), rep("stage", times = 6), - "example_der", rep("agegrp", times =12), rep("agegrp", times = 7), rep("agegrp", times = 19), rep("agegrp", times = 12)), - - "numValidCat" = c(rep("N/A", times = 2), rep("3", times = 4), rep("3", times = 5), rep("N/A", times =2), rep("2", times = 3), rep("2", times = 4), rep("2", times = 4), rep("2", times = 4), rep("3", times = 4), - rep("N/A", times = 2), rep("N/A", times = 3), rep("N/A", times =2), rep("N/A", times = 3), rep("N/A", times = 3), rep("N/A", times = 3), rep("N/A", times = 3), rep("N/A", times = 3), rep("N/A", times = 3), rep("4", times = 6), - "N/A", rep("11", times = 12), rep("6", times = 7), rep("N/A", times = 19), rep("6", times = 12)), - - "recEnd" = c(c("copy", "NA::b"), c("0", "1","2", "NA::b"), c("1","2","3","NA::a", "NA::b"), c("copy","NA::b"), c("0","1", "NA::b"), c("0", "1","NA::a", "NA::b"), c("0", "1","NA::a", "NA::b"),c("0", "1","NA::a", "NA::b"), c("0.0","0.5","1.0", "Na::b"), - c("copy", "Na::b"), c("copy", "Na::a", "Na::b"), c("copy", "Na::b"), c("copy", "Na::a", "Na::b"), c("copy", "Na::a", "Na::b"), c("copy", "Na::a", "Na::b"), c("copy", "Na::a", "Na::b"), c("copy", "Na::a", "Na::b"), c("copy", "Na::a", "Na::b"), c("1", "2","3","4", "Na::a", "NA::b"), - "Func::example_der_fun", c("1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "Na::b"), c("1", "2", "3", "4", "5", "6", "Na::b"), c("27", "32", "37", "42", "47", "52", "57", "62", "67", "72", "77", "Na::b"), c("25", "35", "45", "55", "65", "75", "Na::b"), c("1", "2", "2", "3", "3", "4", "4", "5", "5", "6", "6", "Na::b")), - - "catLabel" = c(c("N/A", "missing"), c("censored", "transplant","dead", "missing"), c("D-penicillmain","Placebo", "none", "N/A", "missing"), rep("N/A", times = 2), c("Male","Female", "missing"), c("No ascites", "Yes ascites", "NA", "missing"), c("No hepatomegaly","yes hepatomegaly", "NA", "missing"), c("no spiders","yes spiders", "NA", "missing"), c("edema 0","edema 0.5","edema 1", "missing"), - c("bili", "missing"), c("chol", "N/A", "missing"), c("albumin", "missing"), c("cooper", "N/A", "missing"), c("alk.phos", "N/A", "missing"), c("ast", "N/A", "missing"), c("trig", "N/A", "missing"), c("platelet", "N/A", "missing"), c("protime", "N/A", "missing"), c("stage 1", "stage 2","stage 3","stage 4", "NA", "missing"), - "N/A", c("25-29", "30-34", "35-39", "40-44", "45-49", "50-54", "55-59", "60-64", "65-69", "70-74", "75-79", "missing"), c("20-29", "30-39", "40-49", "50-59", "60-69", "70-79", "missing"), c("27", "32", "37", "42", "47", "52", "57", "62", "67", "72", "77", "missing"), c("25", "35", "45", "55", "65", "75", "missing"), c("20-29", "30-39", "30-39", "40-49", "40-49", "50-59", "50-59", "60-69", "60-69", "70-79", "70-79", "missing")), - - "catLabelLong" = c(c("N/A", "missing"), c("censored", "transplant","dead", "missing"), c("D-penicillmain","Placebo", "no treatment", "N/A", "missing"), rep("N/A", times = 2), c("Male","Female", "missing"), c("No ascites", "Yes ascites", "NA", "missing"), c("No hepatomegaly","yes hepatomegaly", "NA", "missing"), c("no spiders","yes spiders", "NA", "missing"), c("edema 0","edema 0.5","edema 1", "missing"), - c("N/A", "missing"), c("N/A", "N/A", "missing"), c("N/A", "missing"), c("N/A", "N/A", "missing"), c("N/A", "N/A", "missing"), c("N/A", "N/A", "missing"), c("N/A", "N/A", "missing"), c("N/A", "N/A", "missing"), c("N/A", "N/A", "missing"), c("stage 1", "stage 2","stage 3","stage 4", "NA", "missing"), - "N/A", c("25-29", "30-34", "35-39", "40-44", "45-49", "50-54", "55-59", "60-64", "65-69", "70-74", "75-79", "missing"), c("20-29", "30-39", "40-49", "50-59", "60-69", "70-79", "missing"), c("27", "32", "37", "42", "47", "52", "57", "62", "67", "72", "77", "missing"), c("25", "35", "45", "55", "65", "75", "missing"), c("20-29", "30-39", "30-39", "40-49", "40-49", "50-59", "50-59", "60-69", "60-69", "70-79", "70-79", "missing")), - - "units" = c(rep("days", times = 2), rep("N/A", times = 4), rep("N/A", times = 5), rep("years", time = 2), rep("N/A", times = 3), rep("N/A", times = 4), rep("N/A", times = 4), rep("N/A", times = 4), rep("N/A", times = 4), - rep("mg/dl", times = 2), rep("mg/dl", times = 3), rep("g/dl", times = 2), rep("ug/dl", times = 3), rep("U/L", times = 3), rep("U/L", times = 3), rep("mg/dl", times = 3), rep("N/A", times = 3), rep("N/A", times = 3), rep("N/A", times = 6), - "mg/dl", rep("years", times = 12), rep("years", times = 7), rep("years", times = 19), rep("years", times = 12)), - - "recStart" = c(c("[0,4556]","else"), c("0", "1","2", "else"), c("1","2","3", "NA", "else"), c("[25,79]", "else"), c("m","f", "else"), c("0", "1", "NA", "else"), c("0", "1","NA", "else"), c("0", "1","NA", "else"), c("0.0","0.5","1.0", "else"), - c("[0,28]", "else"), c("[120, 1775]", "NA", "else"), c("[1.960, 4.64]", "else"), c("[4,588]", "NA", "else"), c("[289, 13863]", "NA", "else"), c("[26, 458]", "NA", "else"), c("[33, 598]", "NA", "else"), c("[62, 721]", "NA", "else"), c("[9,18]", "NA", "else"), c("1", "2","3","4","Na","else"), - "else", c("1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "Na::b"), c("1", "2", "3", "4", "5", "6", "else"), c("1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "Na::b"), c("1", "2", "3", "4", "5", "6", "Na::b"), c("1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "Na::b")), - - "catStartLabel" = c(c("time", "N/A"), c("censored", "transplant","dead", "else"), c("D-penicillmain","Placebo", "none", "N/A", "else"), c("age", "else"), c("Male","Female", "else"), c("No ascites", "Yes ascites", "NA", "else"), c("No hepatomegaly","yes hepatomegaly", "NA", "else"), c("no spiders","yes spiders", "NA", "else"), c("edema 0","edema 0.5","edema 1", "else"), - c("bili", "N/A"), c("chol", "N/A", "else"), c("albumin", "else"), c("copper", "N/A", "else"), c("alk.phos", "N/A", "else"), c("ast", "N/A", "else"), c("trig", "N/A", "else"), c("platelet", "N/A", "else"), c("protime", "N/A", "else"), c("stage 1", "stage 2","stage 3","stage 4", "N/A", "missing"), - "N/A", c("25-29", "30-34", "35-39", "40-44", "45-49", "50-54", "55-59", "60-64", "65-69", "70-74", "75-79", "else"), c("20-29", "30-39", "40-49", "50-59", "60-69", "70-79", "else"), - c("25-29", "30-34", "35-39", "40-44", "45-49", "50-54", "55-59", "60-64", "65-69", "70-74", "75-79","else"), c("20-29", "30-39", "40-49", "50-59", "60-69", "70-79", "else"), c("25-29", "30-34", "35-39", "40-44", "45-49", "50-54", "55-59", "60-64", "65-69", "70-74", "75-79","else")), - - "notes" = c(rep("This is sample survival pbc data", times = 64), rep("adapted from sample survival pbc data", times = 50)) -) - -variables <- - data.frame( - "variable" = c("time","status","trt", "age","sex","ascites","hepato", "spiders", "edema", "bili", "chol", "albumin", "copper", "alk.phos", "ast", "trig", "platelet", "protime", "stage", - "example_der", "agegrp5", "agegrp10", "age_cont"), - "label" = c("time","status","treatment", "age","sex","ascites","hepato", "spiders", "edema", "bili", "chol", "albumin", "copper", "alk.phos", "ast", "trig", "platelet", "protime", "stage", - "example_der", "agegrp5", "agegrp10", "age_cont"), - "labelLong" = c("number of days between registration and the earlier of death, treatment or end of study", "status at end of study", "treatment", "age", "sex", "prescence of ascites", "prescence of hepatomegaly or enlarged liver", - "prescence of spiders", "edema", "bilirunbin concentration (blood)", "cholestral concentration (blood)", "albumin concentration (blood)", "copper concentration (urine)", "alkaline phosphotase concentration (blood)", - " aspartate aminotransferase concentration (blood)", "triglycerides concentration (blood)", "platelet count", "standarized blood clotting time", "histologic stage of disease", - "example of dervived function: concentration of cholestral * concentration of bilirunbin", "five year age groups", "ten year age groups", "continous age created from age groups"), - "subject" = c(rep("study",times = 3), rep("demographic",times = 2), rep("physical symptom",times = 4), rep("lab test",times = 10), - "derived", rep("demographics", times =3)), - "section" = c("time","status","trt", "age","sex","ascites","hepato", "spiders", "edema", "bili", "chol", "albumin", "copper", "alk.phos", "ast", "trig", "platelet", "protime", "stage", - "example", "age", "age", "age"), - "variableType" = c("cont", "cat", "cat", "cont","cat", "cat", "cat","cat", "cat", rep("cont", times = 9), "cat", - "cont", rep("cat", times = 2), "cont"), - "databaseStart" = c(rep("tester1, tester2", times = 20), "tester1", rep("tester1, tester2", times =2)), - "units" = c("days", rep("N/A", times = 2), "years", rep("N/A", times = 5), rep("mg/dl", times = 2), "g/dl", "ug/dl", rep("U/L", times = 2), "mg/dl", rep("N/A", times = 3), - "mg/dl", rep("years", times = 3)), - "variableStart" = c("[time]","[status]", "[trt]", "[age]", "[sex]", "[ascites]","[hepato]","[spiders]","[edema]", "[bili]", "[chol]", "[albumin]", "[copper]", "[alk.phos]", "[ast]", "[trig]", "[platelet]", "[protime]","[stage]", - "[example_der]", "tester1::agegrp", "[agegrp]", "[agegrp]") - ) - -test1 <- survival::pbc[1:209,] -test2 <- survival::pbc[210:418,] - -#Adapting the data for How To examples. Breaking cont age variable into categories - 5 and 10 year age groups. -range(test1$age) -agegrp <- cut(test1$age, breaks = c(25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80), right = FALSE) -agegrp <- as.numeric(agegrp) -tester1 <- cbind(test1, agegrp) - - -range(test2$age) -agegrp <- cut(test2$age, breaks = c(20, 30, 40, 50, 60, 70, 80), right = FALSE) -agegrp <- as.numeric(agegrp) -tester2 <- cbind(test2, agegrp) - - diff --git a/R/utils.R b/R/utils.R index 857cb929..8900a962 100644 --- a/R/utils.R +++ b/R/utils.R @@ -1,3 +1,10 @@ +#' Utility functions for the recodeflow package +#' +#' @name utils +#' @description A collection of utility functions for the recodeflow package +#' @keywords internal +NULL + #' ID role creation #' #' Creates ID row for rec_with_table @@ -8,6 +15,7 @@ #' @param variables variables sheet containing variable information #' #' @return data with the ID row attached +#' @keywords internal create_id_row <- function(data, id_role_name, database_name, variables){ # Flag to check for presence of data_name before execusion keep_data_name <- FALSE @@ -46,6 +54,7 @@ create_id_row <- function(data, id_role_name, database_name, variables){ #' @param variable_rows all variable details rows containing 1 variable information #' #' @return a list containing labels for the passed variable +#' @keywords internal create_label_list_element <- function(variable_rows) { ret_list <- list( # Variable type diff --git a/R/variable-start.R b/R/variable-start.R index b43502e1..a2dee6a3 100644 --- a/R/variable-start.R +++ b/R/variable-start.R @@ -1,26 +1,38 @@ -# This file has helper functions for the variableStart column and its values - +#' Variable start helper functions +#' +#' These functions help in processing and validating variable start values, +#' particularly for handling table-based variables. +#' +#' @name variable-start +#' @keywords internal +NULL +# This file has helper functions for the variableStart column and its values #' Checks whether a variable start is a table #' #' @param feeder_var string The variable start to check -#' -#' @return bool +#' @return logical TRUE if the variable is a table feeder, FALSE otherwise #' @export -#' #' @examples +#' # Check if a variable is a table feeder +#' is_table_feeder_var("$table:my_lookup") # Returns TRUE +#' is_table_feeder_var("[regular_var]") # Returns FALSE +#' is_table_feeder_var("$table:values") # Returns TRUE +#' @keywords internal is_table_feeder_var <- function(feeder_var) { - return(grepl(pkg.env$recode.key.tables, feeder_var)) + return(grepl(pkg.env$recode.key.tables, feeder_var)) } #' Returns the name of the table for a table start variable #' #' @param table_feeder_var string The table variable start -#' -#' @return string +#' @return string The extracted table name #' @export -#' #' @examples +#' # Extract table names from table feeder variables +#' get_table_name("$table:lookup_codes") # Returns "lookup_codes" +#' get_table_name("$table:reference") # Returns "reference" +#' get_table_name("$table:values") # Returns "values" get_table_name <- function(table_feeder_var) { - return(trimws(gsub(pkg.env$recode.key.tables, "", table_feeder_var))) + return(trimws(gsub(pkg.env$recode.key.tables, "", table_feeder_var))) } diff --git a/README.md b/README.md index 5a0956aa..1a63022d 100644 --- a/README.md +++ b/README.md @@ -6,12 +6,6 @@ -```{=html} - -``` # Introduction ## What is `recodeflow`? diff --git a/_pkgdown.yml b/_pkgdown.yml index 79694abb..c6a9af26 100644 --- a/_pkgdown.yml +++ b/_pkgdown.yml @@ -48,4 +48,19 @@ reference: desc: Other useful functions contents: - set_data_labels - + - select_vars_by_role + - get_table_name + - label_data + - is_equal + - title: "Example worksheets" + desc: Examples of worksheets for databases + contents: + - pbc_variables + - pbc_variable_details + - tester_variables + - tester_variable_details + - title: "Example data" + desc: Data for examples + contents: + - pbc + - pbc_metadata diff --git a/data-raw/prep_pbc_data.R b/data-raw/prep_pbc_data.R new file mode 100644 index 00000000..203180a1 --- /dev/null +++ b/data-raw/prep_pbc_data.R @@ -0,0 +1,106 @@ +## code to prepare dataset goes here +library(yaml) +library(readr) +library(usethis) +library(survival) + +variables_sheet_cols <- cols( + variable = col_character(), + label = col_character(), + labelLong = col_character(), + subject = col_character(), + section = col_character(), + variableType = col_character(), + databaseStart = col_character(), + units = col_character(), # changed from logical + variableStart = col_character(), + notes = col_logical(), + description = col_logical() +) + +variable_details_sheet_cols <- cols( + variable = col_character(), + dummyVariable = col_character(), + typeEnd = col_character(), + typeStart = col_character(), + databaseStart = col_character(), + variableStart = col_character(), + variableStartLabel = col_character(), + numValidCat = col_double(), + recEnd = col_character(), + catLabel = col_character(), + catLabelLong = col_character(), + units = col_character(), + recStart = col_character(), + catLabelLong = col_character(), + variableStartShortLabel = col_character(), + notes = col_character(), + .default = col_character() # for any remaining columns +) + +# ------ pbc.rda data ------ +# Get PBC data from survival package +data(pbc, package = "survival") + +# Save both the original pbc data +usethis::use_data(pbc, overwrite = TRUE) + +# ------ import the pbc_metadata.yaml file ------ +pbc_metadata <- read_yaml("inst/extdata/pbc_metadata.yaml") +usethis::use_data(pbc_metadata, overwrite = TRUE) + +# ------ import the pbc_variables.csv file -------- +pbc_variables <- read_csv("inst/extdata/pbc_variables.csv", + show_col_types = FALSE, + col_types = variables_sheet_cols +) + +# Check for any parsing problems +if(nrow(problems(pbc_variables)) != 0) { + print("Problems with pbc_variables:") + print(problems(pbc_variables)) +} + +usethis::use_data(pbc_variables, overwrite = TRUE) + +# ------- import the pbc_variable_details.csv file ------ +pbc_variable_details <- read_csv("inst/extdata/pbc_variable_details.csv", + show_col_types = FALSE, + col_types = variable_details_sheet_cols +) + +# Check for any parsing problems +if(nrow(problems(pbc_variable_details)) != 0) { + print("Problems with pbc_variable_details:") + print(problems(pbc_variable_details)) +} + +usethis::use_data(pbc_variable_details, overwrite = TRUE) + +# ------ import the tester_variables.csv file -------- +tester_variables <- read_csv("inst/extdata/tester_variables.csv", + show_col_types = FALSE, + col_types = variables_sheet_cols +) + +# Check for any parsing problems +if(nrow(problems(tester_variables)) != 0) { + print("Problems with tester_variables:") + print(problems(tester_variables)) +} + +usethis::use_data(tester_variables, overwrite = TRUE) + +# ------- import the tester_variable_details.csv file ------ +tester_variable_details <- read_csv("inst/extdata/tester_variable_details.csv", + show_col_types = FALSE, + col_types = variable_details_sheet_cols +) + +# Check for any parsing problems +if(nrow(problems(tester_variable_details)) != 0) { + print("Problems with tester_variable_details:") + print(problems(tester_variable_details)) +} + +usethis::use_data(tester_variable_details, overwrite = TRUE) diff --git a/data/pbc.rda b/data/pbc.rda new file mode 100644 index 00000000..c9af70b7 Binary files /dev/null and b/data/pbc.rda differ diff --git a/data/pbc_metadata.rda b/data/pbc_metadata.rda new file mode 100644 index 00000000..63c10d04 Binary files /dev/null and b/data/pbc_metadata.rda differ diff --git a/data/pbc_variable_details.rda b/data/pbc_variable_details.rda new file mode 100644 index 00000000..a0369a8a Binary files /dev/null and b/data/pbc_variable_details.rda differ diff --git a/data/pbc_variables.rda b/data/pbc_variables.rda new file mode 100644 index 00000000..354cb185 Binary files /dev/null and b/data/pbc_variables.rda differ diff --git a/data/tester_variable_details.rda b/data/tester_variable_details.rda new file mode 100644 index 00000000..25e0da5a Binary files /dev/null and b/data/tester_variable_details.rda differ diff --git a/data/tester_variables.rda b/data/tester_variables.rda new file mode 100644 index 00000000..868e600d Binary files /dev/null and b/data/tester_variables.rda differ diff --git a/docs/404.html b/docs/404.html index 4fd2cc90..65da0b5f 100644 --- a/docs/404.html +++ b/docs/404.html @@ -1,73 +1,34 @@ - - - - + + + + - Page not found (404) • recodeflow - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + - - - -
-
- + +
+ + + - - -
+
+
-
- +
+ - - - + + diff --git a/docs/CONTRIBUTING.html b/docs/CONTRIBUTING.html index 7d466bfd..8770372a 100644 --- a/docs/CONTRIBUTING.html +++ b/docs/CONTRIBUTING.html @@ -1,73 +1,12 @@ - - - - - - - -Contributing to recodeflow • recodeflow - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Contributing to recodeflow • recodeflow + - - - -
-
- - -
-
+
-
- +
+ + - - - + diff --git a/docs/LICENSE-text.html b/docs/LICENSE-text.html index a5cc1344..91b0d188 100644 --- a/docs/LICENSE-text.html +++ b/docs/LICENSE-text.html @@ -1,73 +1,12 @@ - - - - - - - -License • recodeflow - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -License • recodeflow + - - - -
-
- - -
-
+
+
-
- +
+ + - - - + diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 00000000..43d49638 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,10 @@ +# Building the documentation + +To build the documentation run the following commands in the R console from +the repo root: + +1. `source('data-raw/prep_pbc_data.R')`. This will fill the data directory + with all the files needed by the documentation. +2. `devtools::document()`. This will update the `man` folder. +3. `pkgdown::build_site()`. This will build the documentation website and put + it in the docs folder. diff --git a/docs/articles/custom-variables.html b/docs/articles/custom-variables.html new file mode 100644 index 00000000..6c9df38f --- /dev/null +++ b/docs/articles/custom-variables.html @@ -0,0 +1,275 @@ + + + + + + + +Template Variables • recodeflow + + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + + +
+
+ + + + +

The role of a template variable is to avoid the duplication of work +that can happen when recoding two variables with the same specification +but that represent different information. For example, imagine a +database with two columns called PL and SL +that encodes the primary and secondary language that an individual +speaks. Both columns are categorical with the same set of categories, +English, French, +Mandarin, Hindi and +N/A. The last category represents a “not applicable” +value, for example if an individual does not speak a second language. An +example dataset is shown below,

+
+example_dataset <- read.csv(system.file("example-dataset.csv", package="recodeflow"), fileEncoding = "UTF-8-BOM")
+
+DT::datatable(example_dataset)
+
+

If we want to use these language variables in a study, we should +probably assign a unique number to each category, effectively converting +both variables to a numeric categorical variable. We want to +recode the above example dataset to the one below,

+
+example_dataset <- read.csv(system.file("recoded-dataset.csv", package="recodeflow"), fileEncoding = "UTF-8-BOM")
+
+DT::datatable(example_dataset)
+
+

The recoding will create two new categorical variables, +primary_lang and secondary_lang from the +PL and SL respectively with the recoding rules +shown below,

+
+recoding_rules <- data.frame(
+  language = c("English", "French", "Mandarin", "Hindi", "N/A"),
+  recoded_value = c(1,2,3,4,"NA(a)")
+)
+
+DT::datatable(recoding_rules)
+
+

The variable details sheet which encodes the recoding rules above is +shown below,

+
+variable_details <- read.csv(system.file("no-template-variable-variable-details.csv", package="recodeflow"), fileEncoding = "UTF-8-BOM")
+
+DT::datatable(variable_details)
+
+

Both variables have the same specification (the same categories) but +represent different concepts (different variable names and labels). With +a few variables and categories, it’s easy enough to repeat the rules in +the respective sheet (variable_details). But imagine this situation +scaled to 8 variables and 132 categories - a real use case that prompted +this feature! With so many variables and categories, it would be tiring +to create the specifications as well as maintain them. A +template variable can save you the headache!

+

The templateVariable column allows you to specify a +“virtual variable”, a variable that does not exist in the database, but +whose specification can be used by other variables in the database. For +example, we can rewrite the above variables details sheet using a +template variable called language.

+
+variable_details <- read.csv(system.file("template-variable-variable-details.csv", package="recodeflow"), fileEncoding = "UTF-8-BOM")
+
+DT::datatable(variable_details)
+
+

In the above sheet we have defined a new template variable called +language (rows 1 to 6) which provides the reusable +specifications for other languages in the database. The template +variable can now be reused in other concrete variables in the database +like the primary_language and +secondary_language variables as defined in rows 7 and 8. To +use a template variable, simply set the templateVariable +column to the name of the template variable.

+

As we can see, by creating a template variable we can reduce the +number of rows in our variable details sheet but more importantly reduce +the duplication of rows, which in turn increases maintainability of our +sheet.

+
+

Working with template variables +

+

The templateVariable column can have one of the +following values:

+
    +
  1. +Yes: Value to set when the row is defining a +template variable
  2. +
  3. +No: Value to set when the row is defining a normal +variable that does not extend a template variable
  4. +
  5. +: The name of a template +variable that this row is extending
  6. +
+

When creating a template variable,

+
    +
  1. The variable column should be the name of the template +variable
  2. +
  3. The templateVariable column should be Yes
  4. +
  5. The variableStart and variableStartLabel +column should be N/A. Variables that extend the template +variable will set them.
  6. +
  7. All the other columns should be completed as normal
  8. +
+

When extending a template variable,

+
    +
  1. The template variable column should be set to the name of the +template variable being extended
  2. +
  3. The typeEnd, typeStart, +databaseStart columns should be equal to value set in the +template variable. The numValidCat, catLabel, +catLabeLong, units, recStart, and +catStartLabel should be set to N/A. These will come from +the template variable.
  4. +
  5. If the variable is a derived variable then the recStart +column can be set to a function, otherwise it should be +N/A.
  6. +
+
+
+ + + +
+ + + +
+ +
+

+

Site built with pkgdown 2.1.1.

+
+ +
+
+ + + + + + + + diff --git a/docs/articles/custom-variables_files/crosstalk-1.2.1/css/crosstalk.min.css b/docs/articles/custom-variables_files/crosstalk-1.2.1/css/crosstalk.min.css new file mode 100644 index 00000000..6b453828 --- /dev/null +++ b/docs/articles/custom-variables_files/crosstalk-1.2.1/css/crosstalk.min.css @@ -0,0 +1 @@ +.container-fluid.crosstalk-bscols{margin-left:-30px;margin-right:-30px;white-space:normal}body>.container-fluid.crosstalk-bscols{margin-left:auto;margin-right:auto}.crosstalk-input-checkboxgroup .crosstalk-options-group .crosstalk-options-column{display:inline-block;padding-right:12px;vertical-align:top}@media only screen and (max-width: 480px){.crosstalk-input-checkboxgroup .crosstalk-options-group .crosstalk-options-column{display:block;padding-right:inherit}}.crosstalk-input{margin-bottom:15px}.crosstalk-input .control-label{margin-bottom:0;vertical-align:middle}.crosstalk-input input[type="checkbox"]{margin:4px 0 0;margin-top:1px;line-height:normal}.crosstalk-input .checkbox{position:relative;display:block;margin-top:10px;margin-bottom:10px}.crosstalk-input .checkbox>label{padding-left:20px;margin-bottom:0;font-weight:400;cursor:pointer}.crosstalk-input .checkbox input[type="checkbox"],.crosstalk-input .checkbox-inline input[type="checkbox"]{position:absolute;margin-top:2px;margin-left:-20px}.crosstalk-input .checkbox+.checkbox{margin-top:-5px}.crosstalk-input .checkbox-inline{position:relative;display:inline-block;padding-left:20px;margin-bottom:0;font-weight:400;vertical-align:middle;cursor:pointer}.crosstalk-input .checkbox-inline+.checkbox-inline{margin-top:0;margin-left:10px} diff --git a/docs/articles/custom-variables_files/crosstalk-1.2.1/js/crosstalk.js b/docs/articles/custom-variables_files/crosstalk-1.2.1/js/crosstalk.js new file mode 100644 index 00000000..fd9eb53d --- /dev/null +++ b/docs/articles/custom-variables_files/crosstalk-1.2.1/js/crosstalk.js @@ -0,0 +1,1474 @@ +(function(){function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o b) { + return 1; + } +} + +/** + * @private + */ + +var FilterSet = function () { + function FilterSet() { + _classCallCheck(this, FilterSet); + + this.reset(); + } + + _createClass(FilterSet, [{ + key: "reset", + value: function reset() { + // Key: handle ID, Value: array of selected keys, or null + this._handles = {}; + // Key: key string, Value: count of handles that include it + this._keys = {}; + this._value = null; + this._activeHandles = 0; + } + }, { + key: "update", + value: function update(handleId, keys) { + if (keys !== null) { + keys = keys.slice(0); // clone before sorting + keys.sort(naturalComparator); + } + + var _diffSortedLists = (0, _util.diffSortedLists)(this._handles[handleId], keys), + added = _diffSortedLists.added, + removed = _diffSortedLists.removed; + + this._handles[handleId] = keys; + + for (var i = 0; i < added.length; i++) { + this._keys[added[i]] = (this._keys[added[i]] || 0) + 1; + } + for (var _i = 0; _i < removed.length; _i++) { + this._keys[removed[_i]]--; + } + + this._updateValue(keys); + } + + /** + * @param {string[]} keys Sorted array of strings that indicate + * a superset of possible keys. + * @private + */ + + }, { + key: "_updateValue", + value: function _updateValue() { + var keys = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this._allKeys; + + var handleCount = Object.keys(this._handles).length; + if (handleCount === 0) { + this._value = null; + } else { + this._value = []; + for (var i = 0; i < keys.length; i++) { + var count = this._keys[keys[i]]; + if (count === handleCount) { + this._value.push(keys[i]); + } + } + } + } + }, { + key: "clear", + value: function clear(handleId) { + if (typeof this._handles[handleId] === "undefined") { + return; + } + + var keys = this._handles[handleId]; + if (!keys) { + keys = []; + } + + for (var i = 0; i < keys.length; i++) { + this._keys[keys[i]]--; + } + delete this._handles[handleId]; + + this._updateValue(); + } + }, { + key: "value", + get: function get() { + return this._value; + } + }, { + key: "_allKeys", + get: function get() { + var allKeys = Object.keys(this._keys); + allKeys.sort(naturalComparator); + return allKeys; + } + }]); + + return FilterSet; +}(); + +exports.default = FilterSet; + +},{"./util":11}],4:[function(require,module,exports){ +(function (global){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; + +exports.default = group; + +var _var2 = require("./var"); + +var _var3 = _interopRequireDefault(_var2); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +// Use a global so that multiple copies of crosstalk.js can be loaded and still +// have groups behave as singletons across all copies. +global.__crosstalk_groups = global.__crosstalk_groups || {}; +var groups = global.__crosstalk_groups; + +function group(groupName) { + if (groupName && typeof groupName === "string") { + if (!groups.hasOwnProperty(groupName)) { + groups[groupName] = new Group(groupName); + } + return groups[groupName]; + } else if ((typeof groupName === "undefined" ? "undefined" : _typeof(groupName)) === "object" && groupName._vars && groupName.var) { + // Appears to already be a group object + return groupName; + } else if (Array.isArray(groupName) && groupName.length == 1 && typeof groupName[0] === "string") { + return group(groupName[0]); + } else { + throw new Error("Invalid groupName argument"); + } +} + +var Group = function () { + function Group(name) { + _classCallCheck(this, Group); + + this.name = name; + this._vars = {}; + } + + _createClass(Group, [{ + key: "var", + value: function _var(name) { + if (!name || typeof name !== "string") { + throw new Error("Invalid var name"); + } + + if (!this._vars.hasOwnProperty(name)) this._vars[name] = new _var3.default(this, name); + return this._vars[name]; + } + }, { + key: "has", + value: function has(name) { + if (!name || typeof name !== "string") { + throw new Error("Invalid var name"); + } + + return this._vars.hasOwnProperty(name); + } + }]); + + return Group; +}(); + +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) + +},{"./var":12}],5:[function(require,module,exports){ +(function (global){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _group = require("./group"); + +var _group2 = _interopRequireDefault(_group); + +var _selection = require("./selection"); + +var _filter = require("./filter"); + +var _input = require("./input"); + +require("./input_selectize"); + +require("./input_checkboxgroup"); + +require("./input_slider"); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +var defaultGroup = (0, _group2.default)("default"); + +function var_(name) { + return defaultGroup.var(name); +} + +function has(name) { + return defaultGroup.has(name); +} + +if (global.Shiny) { + global.Shiny.addCustomMessageHandler("update-client-value", function (message) { + if (typeof message.group === "string") { + (0, _group2.default)(message.group).var(message.name).set(message.value); + } else { + var_(message.name).set(message.value); + } + }); +} + +var crosstalk = { + group: _group2.default, + var: var_, + has: has, + SelectionHandle: _selection.SelectionHandle, + FilterHandle: _filter.FilterHandle, + bind: _input.bind +}; + +/** + * @namespace crosstalk + */ +exports.default = crosstalk; + +global.crosstalk = crosstalk; + +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) + +},{"./filter":2,"./group":4,"./input":6,"./input_checkboxgroup":7,"./input_selectize":8,"./input_slider":9,"./selection":10}],6:[function(require,module,exports){ +(function (global){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.register = register; +exports.bind = bind; +var $ = global.jQuery; + +var bindings = {}; + +function register(reg) { + bindings[reg.className] = reg; + if (global.document && global.document.readyState !== "complete") { + $(function () { + bind(); + }); + } else if (global.document) { + setTimeout(bind, 100); + } +} + +function bind() { + Object.keys(bindings).forEach(function (className) { + var binding = bindings[className]; + $("." + binding.className).not(".crosstalk-input-bound").each(function (i, el) { + bindInstance(binding, el); + }); + }); +} + +// Escape jQuery identifier +function $escape(val) { + return val.replace(/([!"#$%&'()*+,./:;<=>?@[\\\]^`{|}~])/g, "\\$1"); +} + +function bindEl(el) { + var $el = $(el); + Object.keys(bindings).forEach(function (className) { + if ($el.hasClass(className) && !$el.hasClass("crosstalk-input-bound")) { + var binding = bindings[className]; + bindInstance(binding, el); + } + }); +} + +function bindInstance(binding, el) { + var jsonEl = $(el).find("script[type='application/json'][data-for='" + $escape(el.id) + "']"); + var data = JSON.parse(jsonEl[0].innerText); + + var instance = binding.factory(el, data); + $(el).data("crosstalk-instance", instance); + $(el).addClass("crosstalk-input-bound"); +} + +if (global.Shiny) { + var inputBinding = new global.Shiny.InputBinding(); + var _$ = global.jQuery; + _$.extend(inputBinding, { + find: function find(scope) { + return _$(scope).find(".crosstalk-input"); + }, + initialize: function initialize(el) { + if (!_$(el).hasClass("crosstalk-input-bound")) { + bindEl(el); + } + }, + getId: function getId(el) { + return el.id; + }, + getValue: function getValue(el) {}, + setValue: function setValue(el, value) {}, + receiveMessage: function receiveMessage(el, data) {}, + subscribe: function subscribe(el, callback) { + _$(el).data("crosstalk-instance").resume(); + }, + unsubscribe: function unsubscribe(el) { + _$(el).data("crosstalk-instance").suspend(); + } + }); + global.Shiny.inputBindings.register(inputBinding, "crosstalk.inputBinding"); +} + +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) + +},{}],7:[function(require,module,exports){ +(function (global){ +"use strict"; + +var _input = require("./input"); + +var input = _interopRequireWildcard(_input); + +var _filter = require("./filter"); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +var $ = global.jQuery; + +input.register({ + className: "crosstalk-input-checkboxgroup", + + factory: function factory(el, data) { + /* + * map: {"groupA": ["keyA", "keyB", ...], ...} + * group: "ct-groupname" + */ + var ctHandle = new _filter.FilterHandle(data.group); + + var lastKnownKeys = void 0; + var $el = $(el); + $el.on("change", "input[type='checkbox']", function () { + var checked = $el.find("input[type='checkbox']:checked"); + if (checked.length === 0) { + lastKnownKeys = null; + ctHandle.clear(); + } else { + var keys = {}; + checked.each(function () { + data.map[this.value].forEach(function (key) { + keys[key] = true; + }); + }); + var keyArray = Object.keys(keys); + keyArray.sort(); + lastKnownKeys = keyArray; + ctHandle.set(keyArray); + } + }); + + return { + suspend: function suspend() { + ctHandle.clear(); + }, + resume: function resume() { + if (lastKnownKeys) ctHandle.set(lastKnownKeys); + } + }; + } +}); + +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) + +},{"./filter":2,"./input":6}],8:[function(require,module,exports){ +(function (global){ +"use strict"; + +var _input = require("./input"); + +var input = _interopRequireWildcard(_input); + +var _util = require("./util"); + +var util = _interopRequireWildcard(_util); + +var _filter = require("./filter"); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +var $ = global.jQuery; + +input.register({ + className: "crosstalk-input-select", + + factory: function factory(el, data) { + /* + * items: {value: [...], label: [...]} + * map: {"groupA": ["keyA", "keyB", ...], ...} + * group: "ct-groupname" + */ + + var first = [{ value: "", label: "(All)" }]; + var items = util.dataframeToD3(data.items); + var opts = { + options: first.concat(items), + valueField: "value", + labelField: "label", + searchField: "label" + }; + + var select = $(el).find("select")[0]; + + var selectize = $(select).selectize(opts)[0].selectize; + + var ctHandle = new _filter.FilterHandle(data.group); + + var lastKnownKeys = void 0; + selectize.on("change", function () { + if (selectize.items.length === 0) { + lastKnownKeys = null; + ctHandle.clear(); + } else { + var keys = {}; + selectize.items.forEach(function (group) { + data.map[group].forEach(function (key) { + keys[key] = true; + }); + }); + var keyArray = Object.keys(keys); + keyArray.sort(); + lastKnownKeys = keyArray; + ctHandle.set(keyArray); + } + }); + + return { + suspend: function suspend() { + ctHandle.clear(); + }, + resume: function resume() { + if (lastKnownKeys) ctHandle.set(lastKnownKeys); + } + }; + } +}); + +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) + +},{"./filter":2,"./input":6,"./util":11}],9:[function(require,module,exports){ +(function (global){ +"use strict"; + +var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }(); + +var _input = require("./input"); + +var input = _interopRequireWildcard(_input); + +var _filter = require("./filter"); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +var $ = global.jQuery; +var strftime = global.strftime; + +input.register({ + className: "crosstalk-input-slider", + + factory: function factory(el, data) { + /* + * map: {"groupA": ["keyA", "keyB", ...], ...} + * group: "ct-groupname" + */ + var ctHandle = new _filter.FilterHandle(data.group); + + var opts = {}; + var $el = $(el).find("input"); + var dataType = $el.data("data-type"); + var timeFormat = $el.data("time-format"); + var round = $el.data("round"); + var timeFormatter = void 0; + + // Set up formatting functions + if (dataType === "date") { + timeFormatter = strftime.utc(); + opts.prettify = function (num) { + return timeFormatter(timeFormat, new Date(num)); + }; + } else if (dataType === "datetime") { + var timezone = $el.data("timezone"); + if (timezone) timeFormatter = strftime.timezone(timezone);else timeFormatter = strftime; + + opts.prettify = function (num) { + return timeFormatter(timeFormat, new Date(num)); + }; + } else if (dataType === "number") { + if (typeof round !== "undefined") opts.prettify = function (num) { + var factor = Math.pow(10, round); + return Math.round(num * factor) / factor; + }; + } + + $el.ionRangeSlider(opts); + + function getValue() { + var result = $el.data("ionRangeSlider").result; + + // Function for converting numeric value from slider to appropriate type. + var convert = void 0; + var dataType = $el.data("data-type"); + if (dataType === "date") { + convert = function convert(val) { + return formatDateUTC(new Date(+val)); + }; + } else if (dataType === "datetime") { + convert = function convert(val) { + // Convert ms to s + return +val / 1000; + }; + } else { + convert = function convert(val) { + return +val; + }; + } + + if ($el.data("ionRangeSlider").options.type === "double") { + return [convert(result.from), convert(result.to)]; + } else { + return convert(result.from); + } + } + + var lastKnownKeys = null; + + $el.on("change.crosstalkSliderInput", function (event) { + if (!$el.data("updating") && !$el.data("animating")) { + var _getValue = getValue(), + _getValue2 = _slicedToArray(_getValue, 2), + from = _getValue2[0], + to = _getValue2[1]; + + var keys = []; + for (var i = 0; i < data.values.length; i++) { + var val = data.values[i]; + if (val >= from && val <= to) { + keys.push(data.keys[i]); + } + } + keys.sort(); + ctHandle.set(keys); + lastKnownKeys = keys; + } + }); + + // let $el = $(el); + // $el.on("change", "input[type="checkbox"]", function() { + // let checked = $el.find("input[type="checkbox"]:checked"); + // if (checked.length === 0) { + // ctHandle.clear(); + // } else { + // let keys = {}; + // checked.each(function() { + // data.map[this.value].forEach(function(key) { + // keys[key] = true; + // }); + // }); + // let keyArray = Object.keys(keys); + // keyArray.sort(); + // ctHandle.set(keyArray); + // } + // }); + + return { + suspend: function suspend() { + ctHandle.clear(); + }, + resume: function resume() { + if (lastKnownKeys) ctHandle.set(lastKnownKeys); + } + }; + } +}); + +// Convert a number to a string with leading zeros +function padZeros(n, digits) { + var str = n.toString(); + while (str.length < digits) { + str = "0" + str; + }return str; +} + +// Given a Date object, return a string in yyyy-mm-dd format, using the +// UTC date. This may be a day off from the date in the local time zone. +function formatDateUTC(date) { + if (date instanceof Date) { + return date.getUTCFullYear() + "-" + padZeros(date.getUTCMonth() + 1, 2) + "-" + padZeros(date.getUTCDate(), 2); + } else { + return null; + } +} + +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) + +},{"./filter":2,"./input":6}],10:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.SelectionHandle = undefined; + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _events = require("./events"); + +var _events2 = _interopRequireDefault(_events); + +var _group = require("./group"); + +var _group2 = _interopRequireDefault(_group); + +var _util = require("./util"); + +var util = _interopRequireWildcard(_util); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +/** + * Use this class to read and write (and listen for changes to) the selection + * for a Crosstalk group. This is intended to be used for linked brushing. + * + * If two (or more) `SelectionHandle` instances in the same webpage share the + * same group name, they will share the same state. Setting the selection using + * one `SelectionHandle` instance will result in the `value` property instantly + * changing across the others, and `"change"` event listeners on all instances + * (including the one that initiated the sending) will fire. + * + * @param {string} [group] - The name of the Crosstalk group, or if none, + * null or undefined (or any other falsy value). This can be changed later + * via the [SelectionHandle#setGroup](#setGroup) method. + * @param {Object} [extraInfo] - An object whose properties will be copied to + * the event object whenever an event is emitted. + */ +var SelectionHandle = exports.SelectionHandle = function () { + function SelectionHandle() { + var group = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null; + var extraInfo = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; + + _classCallCheck(this, SelectionHandle); + + this._eventRelay = new _events2.default(); + this._emitter = new util.SubscriptionTracker(this._eventRelay); + + // Name of the group we're currently tracking, if any. Can change over time. + this._group = null; + // The Var we're currently tracking, if any. Can change over time. + this._var = null; + // The event handler subscription we currently have on var.on("change"). + this._varOnChangeSub = null; + + this._extraInfo = util.extend({ sender: this }, extraInfo); + + this.setGroup(group); + } + + /** + * Changes the Crosstalk group membership of this SelectionHandle. The group + * being switched away from (if any) will not have its selection value + * modified as a result of calling `setGroup`, even if this handle was the + * most recent handle to set the selection of the group. + * + * The group being switched to (if any) will also not have its selection value + * modified as a result of calling `setGroup`. If you want to set the + * selection value of the new group, call `set` explicitly. + * + * @param {string} group - The name of the Crosstalk group, or null (or + * undefined) to clear the group. + */ + + + _createClass(SelectionHandle, [{ + key: "setGroup", + value: function setGroup(group) { + var _this = this; + + // If group is unchanged, do nothing + if (this._group === group) return; + // Treat null, undefined, and other falsy values the same + if (!this._group && !group) return; + + if (this._var) { + this._var.off("change", this._varOnChangeSub); + this._var = null; + this._varOnChangeSub = null; + } + + this._group = group; + + if (group) { + this._var = (0, _group2.default)(group).var("selection"); + var sub = this._var.on("change", function (e) { + _this._eventRelay.trigger("change", e, _this); + }); + this._varOnChangeSub = sub; + } + } + + /** + * Retrieves the current selection for the group represented by this + * `SelectionHandle`. + * + * - If no selection is active, then this value will be falsy. + * - If a selection is active, but no data points are selected, then this + * value will be an empty array. + * - If a selection is active, and data points are selected, then the keys + * of the selected data points will be present in the array. + */ + + }, { + key: "_mergeExtraInfo", + + + /** + * Combines the given `extraInfo` (if any) with the handle's default + * `_extraInfo` (if any). + * @private + */ + value: function _mergeExtraInfo(extraInfo) { + // Important incidental effect: shallow clone is returned + return util.extend({}, this._extraInfo ? this._extraInfo : null, extraInfo ? extraInfo : null); + } + + /** + * Overwrites the current selection for the group, and raises the `"change"` + * event among all of the group's '`SelectionHandle` instances (including + * this one). + * + * @fires SelectionHandle#change + * @param {string[]} selectedKeys - Falsy, empty array, or array of keys (see + * {@link SelectionHandle#value}). + * @param {Object} [extraInfo] - Extra properties to be included on the event + * object that's passed to listeners (in addition to any options that were + * passed into the `SelectionHandle` constructor). + */ + + }, { + key: "set", + value: function set(selectedKeys, extraInfo) { + if (this._var) this._var.set(selectedKeys, this._mergeExtraInfo(extraInfo)); + } + + /** + * Overwrites the current selection for the group, and raises the `"change"` + * event among all of the group's '`SelectionHandle` instances (including + * this one). + * + * @fires SelectionHandle#change + * @param {Object} [extraInfo] - Extra properties to be included on the event + * object that's passed to listeners (in addition to any that were passed + * into the `SelectionHandle` constructor). + */ + + }, { + key: "clear", + value: function clear(extraInfo) { + if (this._var) this.set(void 0, this._mergeExtraInfo(extraInfo)); + } + + /** + * Subscribes to events on this `SelectionHandle`. + * + * @param {string} eventType - Indicates the type of events to listen to. + * Currently, only `"change"` is supported. + * @param {SelectionHandle~listener} listener - The callback function that + * will be invoked when the event occurs. + * @return {string} - A token to pass to {@link SelectionHandle#off} to cancel + * this subscription. + */ + + }, { + key: "on", + value: function on(eventType, listener) { + return this._emitter.on(eventType, listener); + } + + /** + * Cancels event subscriptions created by {@link SelectionHandle#on}. + * + * @param {string} eventType - The type of event to unsubscribe. + * @param {string|SelectionHandle~listener} listener - Either the callback + * function previously passed into {@link SelectionHandle#on}, or the + * string that was returned from {@link SelectionHandle#on}. + */ + + }, { + key: "off", + value: function off(eventType, listener) { + return this._emitter.off(eventType, listener); + } + + /** + * Shuts down the `SelectionHandle` object. + * + * Removes all event listeners that were added through this handle. + */ + + }, { + key: "close", + value: function close() { + this._emitter.removeAllListeners(); + this.setGroup(null); + } + }, { + key: "value", + get: function get() { + return this._var ? this._var.get() : null; + } + }]); + + return SelectionHandle; +}(); + +/** + * @callback SelectionHandle~listener + * @param {Object} event - An object containing details of the event. For + * `"change"` events, this includes the properties `value` (the new + * value of the selection, or `undefined` if no selection is active), + * `oldValue` (the previous value of the selection), and `sender` (the + * `SelectionHandle` instance that made the change). + */ + +/** + * @event SelectionHandle#change + * @type {object} + * @property {object} value - The new value of the selection, or `undefined` + * if no selection is active. + * @property {object} oldValue - The previous value of the selection. + * @property {SelectionHandle} sender - The `SelectionHandle` instance that + * changed the value. + */ + +},{"./events":1,"./group":4,"./util":11}],11:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; + +exports.extend = extend; +exports.checkSorted = checkSorted; +exports.diffSortedLists = diffSortedLists; +exports.dataframeToD3 = dataframeToD3; + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function extend(target) { + for (var _len = arguments.length, sources = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { + sources[_key - 1] = arguments[_key]; + } + + for (var i = 0; i < sources.length; i++) { + var src = sources[i]; + if (typeof src === "undefined" || src === null) continue; + + for (var key in src) { + if (src.hasOwnProperty(key)) { + target[key] = src[key]; + } + } + } + return target; +} + +function checkSorted(list) { + for (var i = 1; i < list.length; i++) { + if (list[i] <= list[i - 1]) { + throw new Error("List is not sorted or contains duplicate"); + } + } +} + +function diffSortedLists(a, b) { + var i_a = 0; + var i_b = 0; + + if (!a) a = []; + if (!b) b = []; + + var a_only = []; + var b_only = []; + + checkSorted(a); + checkSorted(b); + + while (i_a < a.length && i_b < b.length) { + if (a[i_a] === b[i_b]) { + i_a++; + i_b++; + } else if (a[i_a] < b[i_b]) { + a_only.push(a[i_a++]); + } else { + b_only.push(b[i_b++]); + } + } + + if (i_a < a.length) a_only = a_only.concat(a.slice(i_a)); + if (i_b < b.length) b_only = b_only.concat(b.slice(i_b)); + return { + removed: a_only, + added: b_only + }; +} + +// Convert from wide: { colA: [1,2,3], colB: [4,5,6], ... } +// to long: [ {colA: 1, colB: 4}, {colA: 2, colB: 5}, ... ] +function dataframeToD3(df) { + var names = []; + var length = void 0; + for (var name in df) { + if (df.hasOwnProperty(name)) names.push(name); + if (_typeof(df[name]) !== "object" || typeof df[name].length === "undefined") { + throw new Error("All fields must be arrays"); + } else if (typeof length !== "undefined" && length !== df[name].length) { + throw new Error("All fields must be arrays of the same length"); + } + length = df[name].length; + } + var results = []; + var item = void 0; + for (var row = 0; row < length; row++) { + item = {}; + for (var col = 0; col < names.length; col++) { + item[names[col]] = df[names[col]][row]; + } + results.push(item); + } + return results; +} + +/** + * Keeps track of all event listener additions/removals and lets all active + * listeners be removed with a single operation. + * + * @private + */ + +var SubscriptionTracker = exports.SubscriptionTracker = function () { + function SubscriptionTracker(emitter) { + _classCallCheck(this, SubscriptionTracker); + + this._emitter = emitter; + this._subs = {}; + } + + _createClass(SubscriptionTracker, [{ + key: "on", + value: function on(eventType, listener) { + var sub = this._emitter.on(eventType, listener); + this._subs[sub] = eventType; + return sub; + } + }, { + key: "off", + value: function off(eventType, listener) { + var sub = this._emitter.off(eventType, listener); + if (sub) { + delete this._subs[sub]; + } + return sub; + } + }, { + key: "removeAllListeners", + value: function removeAllListeners() { + var _this = this; + + var current_subs = this._subs; + this._subs = {}; + Object.keys(current_subs).forEach(function (sub) { + _this._emitter.off(current_subs[sub], sub); + }); + } + }]); + + return SubscriptionTracker; +}(); + +},{}],12:[function(require,module,exports){ +(function (global){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _events = require("./events"); + +var _events2 = _interopRequireDefault(_events); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +var Var = function () { + function Var(group, name, /*optional*/value) { + _classCallCheck(this, Var); + + this._group = group; + this._name = name; + this._value = value; + this._events = new _events2.default(); + } + + _createClass(Var, [{ + key: "get", + value: function get() { + return this._value; + } + }, { + key: "set", + value: function set(value, /*optional*/event) { + if (this._value === value) { + // Do nothing; the value hasn't changed + return; + } + var oldValue = this._value; + this._value = value; + // Alert JavaScript listeners that the value has changed + var evt = {}; + if (event && (typeof event === "undefined" ? "undefined" : _typeof(event)) === "object") { + for (var k in event) { + if (event.hasOwnProperty(k)) evt[k] = event[k]; + } + } + evt.oldValue = oldValue; + evt.value = value; + this._events.trigger("change", evt, this); + + // TODO: Make this extensible, to let arbitrary back-ends know that + // something has changed + if (global.Shiny && global.Shiny.onInputChange) { + global.Shiny.onInputChange(".clientValue-" + (this._group.name !== null ? this._group.name + "-" : "") + this._name, typeof value === "undefined" ? null : value); + } + } + }, { + key: "on", + value: function on(eventType, listener) { + return this._events.on(eventType, listener); + } + }, { + key: "off", + value: function off(eventType, listener) { + return this._events.off(eventType, listener); + } + }]); + + return Var; +}(); + +exports.default = Var; + +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) + +},{"./events":1}]},{},[5]) +//# sourceMappingURL=crosstalk.js.map diff --git a/docs/articles/custom-variables_files/crosstalk-1.2.1/js/crosstalk.js.map b/docs/articles/custom-variables_files/crosstalk-1.2.1/js/crosstalk.js.map new file mode 100644 index 00000000..cff94f08 --- /dev/null +++ b/docs/articles/custom-variables_files/crosstalk-1.2.1/js/crosstalk.js.map @@ -0,0 +1,37 @@ +{ + "version": 3, + "sources": [ + "node_modules/browser-pack/_prelude.js", + "javascript/src/events.js", + "javascript/src/filter.js", + "javascript/src/filterset.js", + "javascript/src/group.js", + "javascript/src/index.js", + "javascript/src/input.js", + "javascript/src/input_checkboxgroup.js", + "javascript/src/input_selectize.js", + "javascript/src/input_slider.js", + "javascript/src/selection.js", + "javascript/src/util.js", + "javascript/src/var.js" + ], + "names": [], + "mappings": "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", + "file": "generated.js", + "sourceRoot": "", + "sourcesContent": [ + "(function(){function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require==\"function\"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error(\"Cannot find module '\"+o+\"'\");throw f.code=\"MODULE_NOT_FOUND\",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require==\"function\"&&require;for(var o=0;o {\n this._eventRelay.trigger(\"change\", e, this);\n });\n this._varOnChangeSub = sub;\n }\n }\n\n /**\n * Combine the given `extraInfo` (if any) with the handle's default\n * `_extraInfo` (if any).\n * @private\n */\n _mergeExtraInfo(extraInfo) {\n return util.extend({},\n this._extraInfo ? this._extraInfo : null,\n extraInfo ? extraInfo : null);\n }\n\n /**\n * Close the handle. This clears this handle's contribution to the filter set,\n * and unsubscribes all event listeners.\n */\n close() {\n this._emitter.removeAllListeners();\n this.clear();\n this.setGroup(null);\n }\n\n /**\n * Clear this handle's contribution to the filter set.\n *\n * @param {Object} [extraInfo] - Extra properties to be included on the event\n * object that's passed to listeners (in addition to any options that were\n * passed into the `FilterHandle` constructor).\n * \n * @fires FilterHandle#change\n */\n clear(extraInfo) {\n if (!this._filterSet)\n return;\n this._filterSet.clear(this._id);\n this._onChange(extraInfo);\n }\n\n /**\n * Set this handle's contribution to the filter set. This array should consist\n * of the keys of the rows that _should_ be displayed; any keys that are not\n * present in the array will be considered _filtered out_. Note that multiple\n * `FilterHandle` instances in the group may each contribute an array of keys,\n * and only those keys that appear in _all_ of the arrays make it through the\n * filter.\n *\n * @param {string[]} keys - Empty array, or array of keys. To clear the\n * filter, don't pass an empty array; instead, use the\n * {@link FilterHandle#clear} method.\n * @param {Object} [extraInfo] - Extra properties to be included on the event\n * object that's passed to listeners (in addition to any options that were\n * passed into the `FilterHandle` constructor).\n * \n * @fires FilterHandle#change\n */\n set(keys, extraInfo) {\n if (!this._filterSet)\n return;\n this._filterSet.update(this._id, keys);\n this._onChange(extraInfo);\n }\n\n /**\n * @return {string[]|null} - Either: 1) an array of keys that made it through\n * all of the `FilterHandle` instances, or, 2) `null`, which means no filter\n * is being applied (all data should be displayed).\n */\n get filteredKeys() {\n return this._filterSet ? this._filterSet.value : null;\n }\n\n /**\n * Subscribe to events on this `FilterHandle`.\n *\n * @param {string} eventType - Indicates the type of events to listen to.\n * Currently, only `\"change\"` is supported.\n * @param {FilterHandle~listener} listener - The callback function that\n * will be invoked when the event occurs.\n * @return {string} - A token to pass to {@link FilterHandle#off} to cancel\n * this subscription.\n */\n on(eventType, listener) {\n return this._emitter.on(eventType, listener);\n }\n\n /**\n * Cancel event subscriptions created by {@link FilterHandle#on}.\n *\n * @param {string} eventType - The type of event to unsubscribe.\n * @param {string|FilterHandle~listener} listener - Either the callback\n * function previously passed into {@link FilterHandle#on}, or the\n * string that was returned from {@link FilterHandle#on}.\n */\n off(eventType, listener) {\n return this._emitter.off(eventType, listener);\n }\n\n _onChange(extraInfo) {\n if (!this._filterSet)\n return;\n this._filterVar.set(this._filterSet.value, this._mergeExtraInfo(extraInfo));\n }\n\n /**\n * @callback FilterHandle~listener\n * @param {Object} event - An object containing details of the event. For\n * `\"change\"` events, this includes the properties `value` (the new\n * value of the filter set, or `null` if no filter set is active),\n * `oldValue` (the previous value of the filter set), and `sender` (the\n * `FilterHandle` instance that made the change).\n */\n\n}\n\n/**\n * @event FilterHandle#change\n * @type {object}\n * @property {object} value - The new value of the filter set, or `null`\n * if no filter set is active.\n * @property {object} oldValue - The previous value of the filter set.\n * @property {FilterHandle} sender - The `FilterHandle` instance that\n * changed the value.\n */\n", + "import { diffSortedLists } from \"./util\";\n\nfunction naturalComparator(a, b) {\n if (a === b) {\n return 0;\n } else if (a < b) {\n return -1;\n } else if (a > b) {\n return 1;\n }\n}\n\n/**\n * @private\n */\nexport default class FilterSet {\n constructor() {\n this.reset();\n }\n\n reset() {\n // Key: handle ID, Value: array of selected keys, or null\n this._handles = {};\n // Key: key string, Value: count of handles that include it\n this._keys = {};\n this._value = null;\n this._activeHandles = 0;\n }\n\n get value() {\n return this._value;\n }\n\n update(handleId, keys) {\n if (keys !== null) {\n keys = keys.slice(0); // clone before sorting\n keys.sort(naturalComparator);\n }\n\n let {added, removed} = diffSortedLists(this._handles[handleId], keys);\n this._handles[handleId] = keys;\n\n for (let i = 0; i < added.length; i++) {\n this._keys[added[i]] = (this._keys[added[i]] || 0) + 1;\n }\n for (let i = 0; i < removed.length; i++) {\n this._keys[removed[i]]--;\n }\n\n this._updateValue(keys);\n }\n\n /**\n * @param {string[]} keys Sorted array of strings that indicate\n * a superset of possible keys.\n * @private\n */\n _updateValue(keys = this._allKeys) {\n let handleCount = Object.keys(this._handles).length;\n if (handleCount === 0) {\n this._value = null;\n } else {\n this._value = [];\n for (let i = 0; i < keys.length; i++) {\n let count = this._keys[keys[i]];\n if (count === handleCount) {\n this._value.push(keys[i]);\n }\n }\n }\n }\n\n clear(handleId) {\n if (typeof(this._handles[handleId]) === \"undefined\") {\n return;\n }\n\n let keys = this._handles[handleId];\n if (!keys) {\n keys = [];\n }\n\n for (let i = 0; i < keys.length; i++) {\n this._keys[keys[i]]--;\n }\n delete this._handles[handleId];\n\n this._updateValue();\n }\n\n get _allKeys() {\n let allKeys = Object.keys(this._keys);\n allKeys.sort(naturalComparator);\n return allKeys;\n }\n}\n", + "import Var from \"./var\";\n\n// Use a global so that multiple copies of crosstalk.js can be loaded and still\n// have groups behave as singletons across all copies.\nglobal.__crosstalk_groups = global.__crosstalk_groups || {};\nlet groups = global.__crosstalk_groups;\n\nexport default function group(groupName) {\n if (groupName && typeof(groupName) === \"string\") {\n if (!groups.hasOwnProperty(groupName)) {\n groups[groupName] = new Group(groupName);\n }\n return groups[groupName];\n } else if (typeof(groupName) === \"object\" && groupName._vars && groupName.var) {\n // Appears to already be a group object\n return groupName;\n } else if (Array.isArray(groupName) &&\n groupName.length == 1 &&\n typeof(groupName[0]) === \"string\") {\n return group(groupName[0]);\n } else {\n throw new Error(\"Invalid groupName argument\");\n }\n}\n\nclass Group {\n constructor(name) {\n this.name = name;\n this._vars = {};\n }\n\n var(name) {\n if (!name || typeof(name) !== \"string\") {\n throw new Error(\"Invalid var name\");\n }\n\n if (!this._vars.hasOwnProperty(name))\n this._vars[name] = new Var(this, name);\n return this._vars[name];\n }\n\n has(name) {\n if (!name || typeof(name) !== \"string\") {\n throw new Error(\"Invalid var name\");\n }\n\n return this._vars.hasOwnProperty(name);\n }\n}\n", + "import group from \"./group\";\nimport { SelectionHandle } from \"./selection\";\nimport { FilterHandle } from \"./filter\";\nimport { bind } from \"./input\";\nimport \"./input_selectize\";\nimport \"./input_checkboxgroup\";\nimport \"./input_slider\";\n\nconst defaultGroup = group(\"default\");\n\nfunction var_(name) {\n return defaultGroup.var(name);\n}\n\nfunction has(name) {\n return defaultGroup.has(name);\n}\n\nif (global.Shiny) {\n global.Shiny.addCustomMessageHandler(\"update-client-value\", function(message) {\n if (typeof(message.group) === \"string\") {\n group(message.group).var(message.name).set(message.value);\n } else {\n var_(message.name).set(message.value);\n }\n });\n}\n\nconst crosstalk = {\n group: group,\n var: var_,\n has: has,\n SelectionHandle: SelectionHandle,\n FilterHandle: FilterHandle,\n bind: bind\n};\n\n/**\n * @namespace crosstalk\n */\nexport default crosstalk;\nglobal.crosstalk = crosstalk;\n", + "let $ = global.jQuery;\n\nlet bindings = {};\n\nexport function register(reg) {\n bindings[reg.className] = reg;\n if (global.document && global.document.readyState !== \"complete\") {\n $(() => {\n bind();\n });\n } else if (global.document) {\n setTimeout(bind, 100);\n }\n}\n\nexport function bind() {\n Object.keys(bindings).forEach(function(className) {\n let binding = bindings[className];\n $(\".\" + binding.className).not(\".crosstalk-input-bound\").each(function(i, el) {\n bindInstance(binding, el);\n });\n });\n}\n\n// Escape jQuery identifier\nfunction $escape(val) {\n return val.replace(/([!\"#$%&'()*+,./:;<=>?@[\\\\\\]^`{|}~])/g, \"\\\\$1\");\n}\n\nfunction bindEl(el) {\n let $el = $(el);\n Object.keys(bindings).forEach(function(className) {\n if ($el.hasClass(className) && !$el.hasClass(\"crosstalk-input-bound\")) {\n let binding = bindings[className];\n bindInstance(binding, el);\n }\n });\n}\n\nfunction bindInstance(binding, el) {\n let jsonEl = $(el).find(\"script[type='application/json'][data-for='\" + $escape(el.id) + \"']\");\n let data = JSON.parse(jsonEl[0].innerText);\n\n let instance = binding.factory(el, data);\n $(el).data(\"crosstalk-instance\", instance);\n $(el).addClass(\"crosstalk-input-bound\");\n}\n\nif (global.Shiny) {\n let inputBinding = new global.Shiny.InputBinding();\n let $ = global.jQuery;\n $.extend(inputBinding, {\n find: function(scope) {\n return $(scope).find(\".crosstalk-input\");\n },\n initialize: function(el) {\n if (!$(el).hasClass(\"crosstalk-input-bound\")) {\n bindEl(el);\n }\n },\n getId: function(el) {\n return el.id;\n },\n getValue: function(el) {\n\n },\n setValue: function(el, value) {\n\n },\n receiveMessage: function(el, data) {\n\n },\n subscribe: function(el, callback) {\n $(el).data(\"crosstalk-instance\").resume();\n },\n unsubscribe: function(el) {\n $(el).data(\"crosstalk-instance\").suspend();\n }\n });\n global.Shiny.inputBindings.register(inputBinding, \"crosstalk.inputBinding\");\n}\n", + "import * as input from \"./input\";\nimport { FilterHandle } from \"./filter\";\n\nlet $ = global.jQuery;\n\ninput.register({\n className: \"crosstalk-input-checkboxgroup\",\n\n factory: function(el, data) {\n /*\n * map: {\"groupA\": [\"keyA\", \"keyB\", ...], ...}\n * group: \"ct-groupname\"\n */\n let ctHandle = new FilterHandle(data.group);\n\n let lastKnownKeys;\n let $el = $(el);\n $el.on(\"change\", \"input[type='checkbox']\", function() {\n let checked = $el.find(\"input[type='checkbox']:checked\");\n if (checked.length === 0) {\n lastKnownKeys = null;\n ctHandle.clear();\n } else {\n let keys = {};\n checked.each(function() {\n data.map[this.value].forEach(function(key) {\n keys[key] = true;\n });\n });\n let keyArray = Object.keys(keys);\n keyArray.sort();\n lastKnownKeys = keyArray;\n ctHandle.set(keyArray);\n }\n });\n\n return {\n suspend: function() {\n ctHandle.clear();\n },\n resume: function() {\n if (lastKnownKeys)\n ctHandle.set(lastKnownKeys);\n }\n };\n }\n});\n", + "import * as input from \"./input\";\nimport * as util from \"./util\";\nimport { FilterHandle } from \"./filter\";\n\nlet $ = global.jQuery;\n\ninput.register({\n className: \"crosstalk-input-select\",\n\n factory: function(el, data) {\n /*\n * items: {value: [...], label: [...]}\n * map: {\"groupA\": [\"keyA\", \"keyB\", ...], ...}\n * group: \"ct-groupname\"\n */\n\n let first = [{value: \"\", label: \"(All)\"}];\n let items = util.dataframeToD3(data.items);\n let opts = {\n options: first.concat(items),\n valueField: \"value\",\n labelField: \"label\",\n searchField: \"label\"\n };\n\n let select = $(el).find(\"select\")[0];\n\n let selectize = $(select).selectize(opts)[0].selectize;\n\n let ctHandle = new FilterHandle(data.group);\n\n let lastKnownKeys;\n selectize.on(\"change\", function() {\n if (selectize.items.length === 0) {\n lastKnownKeys = null;\n ctHandle.clear();\n } else {\n let keys = {};\n selectize.items.forEach(function(group) {\n data.map[group].forEach(function(key) {\n keys[key] = true;\n });\n });\n let keyArray = Object.keys(keys);\n keyArray.sort();\n lastKnownKeys = keyArray;\n ctHandle.set(keyArray);\n }\n });\n\n return {\n suspend: function() {\n ctHandle.clear();\n },\n resume: function() {\n if (lastKnownKeys)\n ctHandle.set(lastKnownKeys);\n }\n };\n }\n});\n", + "import * as input from \"./input\";\nimport { FilterHandle } from \"./filter\";\n\nlet $ = global.jQuery;\nlet strftime = global.strftime;\n\ninput.register({\n className: \"crosstalk-input-slider\",\n\n factory: function(el, data) {\n /*\n * map: {\"groupA\": [\"keyA\", \"keyB\", ...], ...}\n * group: \"ct-groupname\"\n */\n let ctHandle = new FilterHandle(data.group);\n\n let opts = {};\n let $el = $(el).find(\"input\");\n let dataType = $el.data(\"data-type\");\n let timeFormat = $el.data(\"time-format\");\n let round = $el.data(\"round\");\n let timeFormatter;\n\n // Set up formatting functions\n if (dataType === \"date\") {\n timeFormatter = strftime.utc();\n opts.prettify = function(num) {\n return timeFormatter(timeFormat, new Date(num));\n };\n\n } else if (dataType === \"datetime\") {\n let timezone = $el.data(\"timezone\");\n if (timezone)\n timeFormatter = strftime.timezone(timezone);\n else\n timeFormatter = strftime;\n\n opts.prettify = function(num) {\n return timeFormatter(timeFormat, new Date(num));\n };\n } else if (dataType === \"number\") {\n if (typeof round !== \"undefined\")\n opts.prettify = function(num) {\n let factor = Math.pow(10, round);\n return Math.round(num * factor) / factor;\n };\n }\n\n $el.ionRangeSlider(opts);\n\n function getValue() {\n let result = $el.data(\"ionRangeSlider\").result;\n\n // Function for converting numeric value from slider to appropriate type.\n let convert;\n let dataType = $el.data(\"data-type\");\n if (dataType === \"date\") {\n convert = function(val) {\n return formatDateUTC(new Date(+val));\n };\n } else if (dataType === \"datetime\") {\n convert = function(val) {\n // Convert ms to s\n return +val / 1000;\n };\n } else {\n convert = function(val) { return +val; };\n }\n\n if ($el.data(\"ionRangeSlider\").options.type === \"double\") {\n return [convert(result.from), convert(result.to)];\n } else {\n return convert(result.from);\n }\n }\n\n let lastKnownKeys = null;\n\n $el.on(\"change.crosstalkSliderInput\", function(event) {\n if (!$el.data(\"updating\") && !$el.data(\"animating\")) {\n let [from, to] = getValue();\n let keys = [];\n for (let i = 0; i < data.values.length; i++) {\n let val = data.values[i];\n if (val >= from && val <= to) {\n keys.push(data.keys[i]);\n }\n }\n keys.sort();\n ctHandle.set(keys);\n lastKnownKeys = keys;\n }\n });\n\n\n // let $el = $(el);\n // $el.on(\"change\", \"input[type=\"checkbox\"]\", function() {\n // let checked = $el.find(\"input[type=\"checkbox\"]:checked\");\n // if (checked.length === 0) {\n // ctHandle.clear();\n // } else {\n // let keys = {};\n // checked.each(function() {\n // data.map[this.value].forEach(function(key) {\n // keys[key] = true;\n // });\n // });\n // let keyArray = Object.keys(keys);\n // keyArray.sort();\n // ctHandle.set(keyArray);\n // }\n // });\n\n return {\n suspend: function() {\n ctHandle.clear();\n },\n resume: function() {\n if (lastKnownKeys)\n ctHandle.set(lastKnownKeys);\n }\n };\n }\n});\n\n\n// Convert a number to a string with leading zeros\nfunction padZeros(n, digits) {\n let str = n.toString();\n while (str.length < digits)\n str = \"0\" + str;\n return str;\n}\n\n// Given a Date object, return a string in yyyy-mm-dd format, using the\n// UTC date. This may be a day off from the date in the local time zone.\nfunction formatDateUTC(date) {\n if (date instanceof Date) {\n return date.getUTCFullYear() + \"-\" +\n padZeros(date.getUTCMonth()+1, 2) + \"-\" +\n padZeros(date.getUTCDate(), 2);\n\n } else {\n return null;\n }\n}\n", + "import Events from \"./events\";\nimport grp from \"./group\";\nimport * as util from \"./util\";\n\n/**\n * Use this class to read and write (and listen for changes to) the selection\n * for a Crosstalk group. This is intended to be used for linked brushing.\n *\n * If two (or more) `SelectionHandle` instances in the same webpage share the\n * same group name, they will share the same state. Setting the selection using\n * one `SelectionHandle` instance will result in the `value` property instantly\n * changing across the others, and `\"change\"` event listeners on all instances\n * (including the one that initiated the sending) will fire.\n *\n * @param {string} [group] - The name of the Crosstalk group, or if none,\n * null or undefined (or any other falsy value). This can be changed later\n * via the [SelectionHandle#setGroup](#setGroup) method.\n * @param {Object} [extraInfo] - An object whose properties will be copied to\n * the event object whenever an event is emitted.\n */\nexport class SelectionHandle {\n\n constructor(group = null, extraInfo = null) {\n this._eventRelay = new Events();\n this._emitter = new util.SubscriptionTracker(this._eventRelay);\n\n // Name of the group we're currently tracking, if any. Can change over time.\n this._group = null;\n // The Var we're currently tracking, if any. Can change over time.\n this._var = null;\n // The event handler subscription we currently have on var.on(\"change\").\n this._varOnChangeSub = null;\n\n this._extraInfo = util.extend({ sender: this }, extraInfo);\n\n this.setGroup(group);\n }\n\n /**\n * Changes the Crosstalk group membership of this SelectionHandle. The group\n * being switched away from (if any) will not have its selection value\n * modified as a result of calling `setGroup`, even if this handle was the\n * most recent handle to set the selection of the group.\n *\n * The group being switched to (if any) will also not have its selection value\n * modified as a result of calling `setGroup`. If you want to set the\n * selection value of the new group, call `set` explicitly.\n *\n * @param {string} group - The name of the Crosstalk group, or null (or\n * undefined) to clear the group.\n */\n setGroup(group) {\n // If group is unchanged, do nothing\n if (this._group === group)\n return;\n // Treat null, undefined, and other falsy values the same\n if (!this._group && !group)\n return;\n\n if (this._var) {\n this._var.off(\"change\", this._varOnChangeSub);\n this._var = null;\n this._varOnChangeSub = null;\n }\n\n this._group = group;\n\n if (group) {\n this._var = grp(group).var(\"selection\");\n let sub = this._var.on(\"change\", (e) => {\n this._eventRelay.trigger(\"change\", e, this);\n });\n this._varOnChangeSub = sub;\n }\n }\n\n /**\n * Retrieves the current selection for the group represented by this\n * `SelectionHandle`.\n *\n * - If no selection is active, then this value will be falsy.\n * - If a selection is active, but no data points are selected, then this\n * value will be an empty array.\n * - If a selection is active, and data points are selected, then the keys\n * of the selected data points will be present in the array.\n */\n get value() {\n return this._var ? this._var.get() : null;\n }\n\n /**\n * Combines the given `extraInfo` (if any) with the handle's default\n * `_extraInfo` (if any).\n * @private\n */\n _mergeExtraInfo(extraInfo) {\n // Important incidental effect: shallow clone is returned\n return util.extend({},\n this._extraInfo ? this._extraInfo : null,\n extraInfo ? extraInfo : null);\n }\n\n /**\n * Overwrites the current selection for the group, and raises the `\"change\"`\n * event among all of the group's '`SelectionHandle` instances (including\n * this one).\n *\n * @fires SelectionHandle#change\n * @param {string[]} selectedKeys - Falsy, empty array, or array of keys (see\n * {@link SelectionHandle#value}).\n * @param {Object} [extraInfo] - Extra properties to be included on the event\n * object that's passed to listeners (in addition to any options that were\n * passed into the `SelectionHandle` constructor).\n */\n set(selectedKeys, extraInfo) {\n if (this._var)\n this._var.set(selectedKeys, this._mergeExtraInfo(extraInfo));\n }\n\n /**\n * Overwrites the current selection for the group, and raises the `\"change\"`\n * event among all of the group's '`SelectionHandle` instances (including\n * this one).\n *\n * @fires SelectionHandle#change\n * @param {Object} [extraInfo] - Extra properties to be included on the event\n * object that's passed to listeners (in addition to any that were passed\n * into the `SelectionHandle` constructor).\n */\n clear(extraInfo) {\n if (this._var)\n this.set(void 0, this._mergeExtraInfo(extraInfo));\n }\n\n /**\n * Subscribes to events on this `SelectionHandle`.\n *\n * @param {string} eventType - Indicates the type of events to listen to.\n * Currently, only `\"change\"` is supported.\n * @param {SelectionHandle~listener} listener - The callback function that\n * will be invoked when the event occurs.\n * @return {string} - A token to pass to {@link SelectionHandle#off} to cancel\n * this subscription.\n */\n on(eventType, listener) {\n return this._emitter.on(eventType, listener);\n }\n\n /**\n * Cancels event subscriptions created by {@link SelectionHandle#on}.\n *\n * @param {string} eventType - The type of event to unsubscribe.\n * @param {string|SelectionHandle~listener} listener - Either the callback\n * function previously passed into {@link SelectionHandle#on}, or the\n * string that was returned from {@link SelectionHandle#on}.\n */\n off(eventType, listener) {\n return this._emitter.off(eventType, listener);\n }\n\n /**\n * Shuts down the `SelectionHandle` object.\n *\n * Removes all event listeners that were added through this handle.\n */\n close() {\n this._emitter.removeAllListeners();\n this.setGroup(null);\n }\n}\n\n/**\n * @callback SelectionHandle~listener\n * @param {Object} event - An object containing details of the event. For\n * `\"change\"` events, this includes the properties `value` (the new\n * value of the selection, or `undefined` if no selection is active),\n * `oldValue` (the previous value of the selection), and `sender` (the\n * `SelectionHandle` instance that made the change).\n */\n\n/**\n * @event SelectionHandle#change\n * @type {object}\n * @property {object} value - The new value of the selection, or `undefined`\n * if no selection is active.\n * @property {object} oldValue - The previous value of the selection.\n * @property {SelectionHandle} sender - The `SelectionHandle` instance that\n * changed the value.\n */\n", + "export function extend(target, ...sources) {\n for (let i = 0; i < sources.length; i++) {\n let src = sources[i];\n if (typeof(src) === \"undefined\" || src === null)\n continue;\n\n for (let key in src) {\n if (src.hasOwnProperty(key)) {\n target[key] = src[key];\n }\n }\n }\n return target;\n}\n\nexport function checkSorted(list) {\n for (let i = 1; i < list.length; i++) {\n if (list[i] <= list[i-1]) {\n throw new Error(\"List is not sorted or contains duplicate\");\n }\n }\n}\n\nexport function diffSortedLists(a, b) {\n let i_a = 0;\n let i_b = 0;\n\n if (!a) a = [];\n if (!b) b = [];\n\n let a_only = [];\n let b_only = [];\n\n checkSorted(a);\n checkSorted(b);\n\n while (i_a < a.length && i_b < b.length) {\n if (a[i_a] === b[i_b]) {\n i_a++;\n i_b++;\n } else if (a[i_a] < b[i_b]) {\n a_only.push(a[i_a++]);\n } else {\n b_only.push(b[i_b++]);\n }\n }\n\n if (i_a < a.length)\n a_only = a_only.concat(a.slice(i_a));\n if (i_b < b.length)\n b_only = b_only.concat(b.slice(i_b));\n return {\n removed: a_only,\n added: b_only\n };\n}\n\n// Convert from wide: { colA: [1,2,3], colB: [4,5,6], ... }\n// to long: [ {colA: 1, colB: 4}, {colA: 2, colB: 5}, ... ]\nexport function dataframeToD3(df) {\n let names = [];\n let length;\n for (let name in df) {\n if (df.hasOwnProperty(name))\n names.push(name);\n if (typeof(df[name]) !== \"object\" || typeof(df[name].length) === \"undefined\") {\n throw new Error(\"All fields must be arrays\");\n } else if (typeof(length) !== \"undefined\" && length !== df[name].length) {\n throw new Error(\"All fields must be arrays of the same length\");\n }\n length = df[name].length;\n }\n let results = [];\n let item;\n for (let row = 0; row < length; row++) {\n item = {};\n for (let col = 0; col < names.length; col++) {\n item[names[col]] = df[names[col]][row];\n }\n results.push(item);\n }\n return results;\n}\n\n/**\n * Keeps track of all event listener additions/removals and lets all active\n * listeners be removed with a single operation.\n *\n * @private\n */\nexport class SubscriptionTracker {\n constructor(emitter) {\n this._emitter = emitter;\n this._subs = {};\n }\n\n on(eventType, listener) {\n let sub = this._emitter.on(eventType, listener);\n this._subs[sub] = eventType;\n return sub;\n }\n\n off(eventType, listener) {\n let sub = this._emitter.off(eventType, listener);\n if (sub) {\n delete this._subs[sub];\n }\n return sub;\n }\n\n removeAllListeners() {\n let current_subs = this._subs;\n this._subs = {};\n Object.keys(current_subs).forEach((sub) => {\n this._emitter.off(current_subs[sub], sub);\n });\n }\n}\n", + "import Events from \"./events\";\n\nexport default class Var {\n constructor(group, name, /*optional*/ value) {\n this._group = group;\n this._name = name;\n this._value = value;\n this._events = new Events();\n }\n\n get() {\n return this._value;\n }\n\n set(value, /*optional*/ event) {\n if (this._value === value) {\n // Do nothing; the value hasn't changed\n return;\n }\n let oldValue = this._value;\n this._value = value;\n // Alert JavaScript listeners that the value has changed\n let evt = {};\n if (event && typeof(event) === \"object\") {\n for (let k in event) {\n if (event.hasOwnProperty(k))\n evt[k] = event[k];\n }\n }\n evt.oldValue = oldValue;\n evt.value = value;\n this._events.trigger(\"change\", evt, this);\n\n // TODO: Make this extensible, to let arbitrary back-ends know that\n // something has changed\n if (global.Shiny && global.Shiny.onInputChange) {\n global.Shiny.onInputChange(\n \".clientValue-\" +\n (this._group.name !== null ? this._group.name + \"-\" : \"\") +\n this._name,\n typeof(value) === \"undefined\" ? null : value\n );\n }\n }\n\n on(eventType, listener) {\n return this._events.on(eventType, listener);\n }\n\n off(eventType, listener) {\n return this._events.off(eventType, listener);\n }\n}\n" + ] +} \ No newline at end of file diff --git a/docs/articles/custom-variables_files/crosstalk-1.2.1/js/crosstalk.min.js b/docs/articles/custom-variables_files/crosstalk-1.2.1/js/crosstalk.min.js new file mode 100644 index 00000000..b7ec0ac9 --- /dev/null +++ b/docs/articles/custom-variables_files/crosstalk-1.2.1/js/crosstalk.min.js @@ -0,0 +1,2 @@ +!function o(u,a,l){function s(n,e){if(!a[n]){if(!u[n]){var t="function"==typeof require&&require;if(!e&&t)return t(n,!0);if(f)return f(n,!0);var r=new Error("Cannot find module '"+n+"'");throw r.code="MODULE_NOT_FOUND",r}var i=a[n]={exports:{}};u[n][0].call(i.exports,function(e){var t=u[n][1][e];return s(t||e)},i,i.exports,o,u,a,l)}return a[n].exports}for(var f="function"==typeof require&&require,e=0;e?@[\\\]^`{|}~])/g,"\\$1")+"']"),r=JSON.parse(n[0].innerText),i=e.factory(t,r);o(t).data("crosstalk-instance",i),o(t).addClass("crosstalk-input-bound")}if(t.Shiny){var e=new t.Shiny.InputBinding,u=t.jQuery;u.extend(e,{find:function(e){return u(e).find(".crosstalk-input")},initialize:function(e){var t,n;u(e).hasClass("crosstalk-input-bound")||(n=o(t=e),Object.keys(r).forEach(function(e){n.hasClass(e)&&!n.hasClass("crosstalk-input-bound")&&i(r[e],t)}))},getId:function(e){return e.id},getValue:function(e){},setValue:function(e,t){},receiveMessage:function(e,t){},subscribe:function(e,t){u(e).data("crosstalk-instance").resume()},unsubscribe:function(e){u(e).data("crosstalk-instance").suspend()}}),t.Shiny.inputBindings.register(e,"crosstalk.inputBinding")}}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{}],7:[function(r,e,t){(function(e){"use strict";var t=function(e){{if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[n]=e[n]);return t.default=e,t}}(r("./input")),n=r("./filter");var a=e.jQuery;t.register({className:"crosstalk-input-checkboxgroup",factory:function(e,r){var i=new n.FilterHandle(r.group),o=void 0,u=a(e);return u.on("change","input[type='checkbox']",function(){var e=u.find("input[type='checkbox']:checked");if(0===e.length)o=null,i.clear();else{var t={};e.each(function(){r.map[this.value].forEach(function(e){t[e]=!0})});var n=Object.keys(t);n.sort(),o=n,i.set(n)}}),{suspend:function(){i.clear()},resume:function(){o&&i.set(o)}}}})}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{"./filter":2,"./input":6}],8:[function(r,e,t){(function(e){"use strict";var t=n(r("./input")),l=n(r("./util")),s=r("./filter");function n(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[n]=e[n]);return t.default=e,t}var f=e.jQuery;t.register({className:"crosstalk-input-select",factory:function(e,n){var t=l.dataframeToD3(n.items),r={options:[{value:"",label:"(All)"}].concat(t),valueField:"value",labelField:"label",searchField:"label"},i=f(e).find("select")[0],o=f(i).selectize(r)[0].selectize,u=new s.FilterHandle(n.group),a=void 0;return o.on("change",function(){if(0===o.items.length)a=null,u.clear();else{var t={};o.items.forEach(function(e){n.map[e].forEach(function(e){t[e]=!0})});var e=Object.keys(t);e.sort(),a=e,u.set(e)}}),{suspend:function(){u.clear()},resume:function(){a&&u.set(a)}}}})}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{"./filter":2,"./input":6,"./util":11}],9:[function(n,e,t){(function(e){"use strict";var d=function(e,t){if(Array.isArray(e))return e;if(Symbol.iterator in Object(e))return function(e,t){var n=[],r=!0,i=!1,o=void 0;try{for(var u,a=e[Symbol.iterator]();!(r=(u=a.next()).done)&&(n.push(u.value),!t||n.length!==t);r=!0);}catch(e){i=!0,o=e}finally{try{!r&&a.return&&a.return()}finally{if(i)throw o}}return n}(e,t);throw new TypeError("Invalid attempt to destructure non-iterable instance")},t=function(e){{if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[n]=e[n]);return t.default=e,t}}(n("./input")),a=n("./filter");var v=e.jQuery,p=e.strftime;function y(e,t){for(var n=e.toString();n.length {\n this._eventRelay.trigger(\"change\", e, this);\n });\n this._varOnChangeSub = sub;\n }\n }\n\n /**\n * Combine the given `extraInfo` (if any) with the handle's default\n * `_extraInfo` (if any).\n * @private\n */\n _mergeExtraInfo(extraInfo) {\n return util.extend({},\n this._extraInfo ? this._extraInfo : null,\n extraInfo ? extraInfo : null);\n }\n\n /**\n * Close the handle. This clears this handle's contribution to the filter set,\n * and unsubscribes all event listeners.\n */\n close() {\n this._emitter.removeAllListeners();\n this.clear();\n this.setGroup(null);\n }\n\n /**\n * Clear this handle's contribution to the filter set.\n *\n * @param {Object} [extraInfo] - Extra properties to be included on the event\n * object that's passed to listeners (in addition to any options that were\n * passed into the `FilterHandle` constructor).\n * \n * @fires FilterHandle#change\n */\n clear(extraInfo) {\n if (!this._filterSet)\n return;\n this._filterSet.clear(this._id);\n this._onChange(extraInfo);\n }\n\n /**\n * Set this handle's contribution to the filter set. This array should consist\n * of the keys of the rows that _should_ be displayed; any keys that are not\n * present in the array will be considered _filtered out_. Note that multiple\n * `FilterHandle` instances in the group may each contribute an array of keys,\n * and only those keys that appear in _all_ of the arrays make it through the\n * filter.\n *\n * @param {string[]} keys - Empty array, or array of keys. To clear the\n * filter, don't pass an empty array; instead, use the\n * {@link FilterHandle#clear} method.\n * @param {Object} [extraInfo] - Extra properties to be included on the event\n * object that's passed to listeners (in addition to any options that were\n * passed into the `FilterHandle` constructor).\n * \n * @fires FilterHandle#change\n */\n set(keys, extraInfo) {\n if (!this._filterSet)\n return;\n this._filterSet.update(this._id, keys);\n this._onChange(extraInfo);\n }\n\n /**\n * @return {string[]|null} - Either: 1) an array of keys that made it through\n * all of the `FilterHandle` instances, or, 2) `null`, which means no filter\n * is being applied (all data should be displayed).\n */\n get filteredKeys() {\n return this._filterSet ? this._filterSet.value : null;\n }\n\n /**\n * Subscribe to events on this `FilterHandle`.\n *\n * @param {string} eventType - Indicates the type of events to listen to.\n * Currently, only `\"change\"` is supported.\n * @param {FilterHandle~listener} listener - The callback function that\n * will be invoked when the event occurs.\n * @return {string} - A token to pass to {@link FilterHandle#off} to cancel\n * this subscription.\n */\n on(eventType, listener) {\n return this._emitter.on(eventType, listener);\n }\n\n /**\n * Cancel event subscriptions created by {@link FilterHandle#on}.\n *\n * @param {string} eventType - The type of event to unsubscribe.\n * @param {string|FilterHandle~listener} listener - Either the callback\n * function previously passed into {@link FilterHandle#on}, or the\n * string that was returned from {@link FilterHandle#on}.\n */\n off(eventType, listener) {\n return this._emitter.off(eventType, listener);\n }\n\n _onChange(extraInfo) {\n if (!this._filterSet)\n return;\n this._filterVar.set(this._filterSet.value, this._mergeExtraInfo(extraInfo));\n }\n\n /**\n * @callback FilterHandle~listener\n * @param {Object} event - An object containing details of the event. For\n * `\"change\"` events, this includes the properties `value` (the new\n * value of the filter set, or `null` if no filter set is active),\n * `oldValue` (the previous value of the filter set), and `sender` (the\n * `FilterHandle` instance that made the change).\n */\n\n}\n\n/**\n * @event FilterHandle#change\n * @type {object}\n * @property {object} value - The new value of the filter set, or `null`\n * if no filter set is active.\n * @property {object} oldValue - The previous value of the filter set.\n * @property {FilterHandle} sender - The `FilterHandle` instance that\n * changed the value.\n */\n","import { diffSortedLists } from \"./util\";\n\nfunction naturalComparator(a, b) {\n if (a === b) {\n return 0;\n } else if (a < b) {\n return -1;\n } else if (a > b) {\n return 1;\n }\n}\n\n/**\n * @private\n */\nexport default class FilterSet {\n constructor() {\n this.reset();\n }\n\n reset() {\n // Key: handle ID, Value: array of selected keys, or null\n this._handles = {};\n // Key: key string, Value: count of handles that include it\n this._keys = {};\n this._value = null;\n this._activeHandles = 0;\n }\n\n get value() {\n return this._value;\n }\n\n update(handleId, keys) {\n if (keys !== null) {\n keys = keys.slice(0); // clone before sorting\n keys.sort(naturalComparator);\n }\n\n let {added, removed} = diffSortedLists(this._handles[handleId], keys);\n this._handles[handleId] = keys;\n\n for (let i = 0; i < added.length; i++) {\n this._keys[added[i]] = (this._keys[added[i]] || 0) + 1;\n }\n for (let i = 0; i < removed.length; i++) {\n this._keys[removed[i]]--;\n }\n\n this._updateValue(keys);\n }\n\n /**\n * @param {string[]} keys Sorted array of strings that indicate\n * a superset of possible keys.\n * @private\n */\n _updateValue(keys = this._allKeys) {\n let handleCount = Object.keys(this._handles).length;\n if (handleCount === 0) {\n this._value = null;\n } else {\n this._value = [];\n for (let i = 0; i < keys.length; i++) {\n let count = this._keys[keys[i]];\n if (count === handleCount) {\n this._value.push(keys[i]);\n }\n }\n }\n }\n\n clear(handleId) {\n if (typeof(this._handles[handleId]) === \"undefined\") {\n return;\n }\n\n let keys = this._handles[handleId];\n if (!keys) {\n keys = [];\n }\n\n for (let i = 0; i < keys.length; i++) {\n this._keys[keys[i]]--;\n }\n delete this._handles[handleId];\n\n this._updateValue();\n }\n\n get _allKeys() {\n let allKeys = Object.keys(this._keys);\n allKeys.sort(naturalComparator);\n return allKeys;\n }\n}\n","import Var from \"./var\";\n\n// Use a global so that multiple copies of crosstalk.js can be loaded and still\n// have groups behave as singletons across all copies.\nglobal.__crosstalk_groups = global.__crosstalk_groups || {};\nlet groups = global.__crosstalk_groups;\n\nexport default function group(groupName) {\n if (groupName && typeof(groupName) === \"string\") {\n if (!groups.hasOwnProperty(groupName)) {\n groups[groupName] = new Group(groupName);\n }\n return groups[groupName];\n } else if (typeof(groupName) === \"object\" && groupName._vars && groupName.var) {\n // Appears to already be a group object\n return groupName;\n } else if (Array.isArray(groupName) &&\n groupName.length == 1 &&\n typeof(groupName[0]) === \"string\") {\n return group(groupName[0]);\n } else {\n throw new Error(\"Invalid groupName argument\");\n }\n}\n\nclass Group {\n constructor(name) {\n this.name = name;\n this._vars = {};\n }\n\n var(name) {\n if (!name || typeof(name) !== \"string\") {\n throw new Error(\"Invalid var name\");\n }\n\n if (!this._vars.hasOwnProperty(name))\n this._vars[name] = new Var(this, name);\n return this._vars[name];\n }\n\n has(name) {\n if (!name || typeof(name) !== \"string\") {\n throw new Error(\"Invalid var name\");\n }\n\n return this._vars.hasOwnProperty(name);\n }\n}\n","import group from \"./group\";\nimport { SelectionHandle } from \"./selection\";\nimport { FilterHandle } from \"./filter\";\nimport { bind } from \"./input\";\nimport \"./input_selectize\";\nimport \"./input_checkboxgroup\";\nimport \"./input_slider\";\n\nconst defaultGroup = group(\"default\");\n\nfunction var_(name) {\n return defaultGroup.var(name);\n}\n\nfunction has(name) {\n return defaultGroup.has(name);\n}\n\nif (global.Shiny) {\n global.Shiny.addCustomMessageHandler(\"update-client-value\", function(message) {\n if (typeof(message.group) === \"string\") {\n group(message.group).var(message.name).set(message.value);\n } else {\n var_(message.name).set(message.value);\n }\n });\n}\n\nconst crosstalk = {\n group: group,\n var: var_,\n has: has,\n SelectionHandle: SelectionHandle,\n FilterHandle: FilterHandle,\n bind: bind\n};\n\n/**\n * @namespace crosstalk\n */\nexport default crosstalk;\nglobal.crosstalk = crosstalk;\n","let $ = global.jQuery;\n\nlet bindings = {};\n\nexport function register(reg) {\n bindings[reg.className] = reg;\n if (global.document && global.document.readyState !== \"complete\") {\n $(() => {\n bind();\n });\n } else if (global.document) {\n setTimeout(bind, 100);\n }\n}\n\nexport function bind() {\n Object.keys(bindings).forEach(function(className) {\n let binding = bindings[className];\n $(\".\" + binding.className).not(\".crosstalk-input-bound\").each(function(i, el) {\n bindInstance(binding, el);\n });\n });\n}\n\n// Escape jQuery identifier\nfunction $escape(val) {\n return val.replace(/([!\"#$%&'()*+,./:;<=>?@[\\\\\\]^`{|}~])/g, \"\\\\$1\");\n}\n\nfunction bindEl(el) {\n let $el = $(el);\n Object.keys(bindings).forEach(function(className) {\n if ($el.hasClass(className) && !$el.hasClass(\"crosstalk-input-bound\")) {\n let binding = bindings[className];\n bindInstance(binding, el);\n }\n });\n}\n\nfunction bindInstance(binding, el) {\n let jsonEl = $(el).find(\"script[type='application/json'][data-for='\" + $escape(el.id) + \"']\");\n let data = JSON.parse(jsonEl[0].innerText);\n\n let instance = binding.factory(el, data);\n $(el).data(\"crosstalk-instance\", instance);\n $(el).addClass(\"crosstalk-input-bound\");\n}\n\nif (global.Shiny) {\n let inputBinding = new global.Shiny.InputBinding();\n let $ = global.jQuery;\n $.extend(inputBinding, {\n find: function(scope) {\n return $(scope).find(\".crosstalk-input\");\n },\n initialize: function(el) {\n if (!$(el).hasClass(\"crosstalk-input-bound\")) {\n bindEl(el);\n }\n },\n getId: function(el) {\n return el.id;\n },\n getValue: function(el) {\n\n },\n setValue: function(el, value) {\n\n },\n receiveMessage: function(el, data) {\n\n },\n subscribe: function(el, callback) {\n $(el).data(\"crosstalk-instance\").resume();\n },\n unsubscribe: function(el) {\n $(el).data(\"crosstalk-instance\").suspend();\n }\n });\n global.Shiny.inputBindings.register(inputBinding, \"crosstalk.inputBinding\");\n}\n","import * as input from \"./input\";\nimport { FilterHandle } from \"./filter\";\n\nlet $ = global.jQuery;\n\ninput.register({\n className: \"crosstalk-input-checkboxgroup\",\n\n factory: function(el, data) {\n /*\n * map: {\"groupA\": [\"keyA\", \"keyB\", ...], ...}\n * group: \"ct-groupname\"\n */\n let ctHandle = new FilterHandle(data.group);\n\n let lastKnownKeys;\n let $el = $(el);\n $el.on(\"change\", \"input[type='checkbox']\", function() {\n let checked = $el.find(\"input[type='checkbox']:checked\");\n if (checked.length === 0) {\n lastKnownKeys = null;\n ctHandle.clear();\n } else {\n let keys = {};\n checked.each(function() {\n data.map[this.value].forEach(function(key) {\n keys[key] = true;\n });\n });\n let keyArray = Object.keys(keys);\n keyArray.sort();\n lastKnownKeys = keyArray;\n ctHandle.set(keyArray);\n }\n });\n\n return {\n suspend: function() {\n ctHandle.clear();\n },\n resume: function() {\n if (lastKnownKeys)\n ctHandle.set(lastKnownKeys);\n }\n };\n }\n});\n","import * as input from \"./input\";\nimport * as util from \"./util\";\nimport { FilterHandle } from \"./filter\";\n\nlet $ = global.jQuery;\n\ninput.register({\n className: \"crosstalk-input-select\",\n\n factory: function(el, data) {\n /*\n * items: {value: [...], label: [...]}\n * map: {\"groupA\": [\"keyA\", \"keyB\", ...], ...}\n * group: \"ct-groupname\"\n */\n\n let first = [{value: \"\", label: \"(All)\"}];\n let items = util.dataframeToD3(data.items);\n let opts = {\n options: first.concat(items),\n valueField: \"value\",\n labelField: \"label\",\n searchField: \"label\"\n };\n\n let select = $(el).find(\"select\")[0];\n\n let selectize = $(select).selectize(opts)[0].selectize;\n\n let ctHandle = new FilterHandle(data.group);\n\n let lastKnownKeys;\n selectize.on(\"change\", function() {\n if (selectize.items.length === 0) {\n lastKnownKeys = null;\n ctHandle.clear();\n } else {\n let keys = {};\n selectize.items.forEach(function(group) {\n data.map[group].forEach(function(key) {\n keys[key] = true;\n });\n });\n let keyArray = Object.keys(keys);\n keyArray.sort();\n lastKnownKeys = keyArray;\n ctHandle.set(keyArray);\n }\n });\n\n return {\n suspend: function() {\n ctHandle.clear();\n },\n resume: function() {\n if (lastKnownKeys)\n ctHandle.set(lastKnownKeys);\n }\n };\n }\n});\n","import * as input from \"./input\";\nimport { FilterHandle } from \"./filter\";\n\nlet $ = global.jQuery;\nlet strftime = global.strftime;\n\ninput.register({\n className: \"crosstalk-input-slider\",\n\n factory: function(el, data) {\n /*\n * map: {\"groupA\": [\"keyA\", \"keyB\", ...], ...}\n * group: \"ct-groupname\"\n */\n let ctHandle = new FilterHandle(data.group);\n\n let opts = {};\n let $el = $(el).find(\"input\");\n let dataType = $el.data(\"data-type\");\n let timeFormat = $el.data(\"time-format\");\n let round = $el.data(\"round\");\n let timeFormatter;\n\n // Set up formatting functions\n if (dataType === \"date\") {\n timeFormatter = strftime.utc();\n opts.prettify = function(num) {\n return timeFormatter(timeFormat, new Date(num));\n };\n\n } else if (dataType === \"datetime\") {\n let timezone = $el.data(\"timezone\");\n if (timezone)\n timeFormatter = strftime.timezone(timezone);\n else\n timeFormatter = strftime;\n\n opts.prettify = function(num) {\n return timeFormatter(timeFormat, new Date(num));\n };\n } else if (dataType === \"number\") {\n if (typeof round !== \"undefined\")\n opts.prettify = function(num) {\n let factor = Math.pow(10, round);\n return Math.round(num * factor) / factor;\n };\n }\n\n $el.ionRangeSlider(opts);\n\n function getValue() {\n let result = $el.data(\"ionRangeSlider\").result;\n\n // Function for converting numeric value from slider to appropriate type.\n let convert;\n let dataType = $el.data(\"data-type\");\n if (dataType === \"date\") {\n convert = function(val) {\n return formatDateUTC(new Date(+val));\n };\n } else if (dataType === \"datetime\") {\n convert = function(val) {\n // Convert ms to s\n return +val / 1000;\n };\n } else {\n convert = function(val) { return +val; };\n }\n\n if ($el.data(\"ionRangeSlider\").options.type === \"double\") {\n return [convert(result.from), convert(result.to)];\n } else {\n return convert(result.from);\n }\n }\n\n let lastKnownKeys = null;\n\n $el.on(\"change.crosstalkSliderInput\", function(event) {\n if (!$el.data(\"updating\") && !$el.data(\"animating\")) {\n let [from, to] = getValue();\n let keys = [];\n for (let i = 0; i < data.values.length; i++) {\n let val = data.values[i];\n if (val >= from && val <= to) {\n keys.push(data.keys[i]);\n }\n }\n keys.sort();\n ctHandle.set(keys);\n lastKnownKeys = keys;\n }\n });\n\n\n // let $el = $(el);\n // $el.on(\"change\", \"input[type=\"checkbox\"]\", function() {\n // let checked = $el.find(\"input[type=\"checkbox\"]:checked\");\n // if (checked.length === 0) {\n // ctHandle.clear();\n // } else {\n // let keys = {};\n // checked.each(function() {\n // data.map[this.value].forEach(function(key) {\n // keys[key] = true;\n // });\n // });\n // let keyArray = Object.keys(keys);\n // keyArray.sort();\n // ctHandle.set(keyArray);\n // }\n // });\n\n return {\n suspend: function() {\n ctHandle.clear();\n },\n resume: function() {\n if (lastKnownKeys)\n ctHandle.set(lastKnownKeys);\n }\n };\n }\n});\n\n\n// Convert a number to a string with leading zeros\nfunction padZeros(n, digits) {\n let str = n.toString();\n while (str.length < digits)\n str = \"0\" + str;\n return str;\n}\n\n// Given a Date object, return a string in yyyy-mm-dd format, using the\n// UTC date. This may be a day off from the date in the local time zone.\nfunction formatDateUTC(date) {\n if (date instanceof Date) {\n return date.getUTCFullYear() + \"-\" +\n padZeros(date.getUTCMonth()+1, 2) + \"-\" +\n padZeros(date.getUTCDate(), 2);\n\n } else {\n return null;\n }\n}\n","import Events from \"./events\";\nimport grp from \"./group\";\nimport * as util from \"./util\";\n\n/**\n * Use this class to read and write (and listen for changes to) the selection\n * for a Crosstalk group. This is intended to be used for linked brushing.\n *\n * If two (or more) `SelectionHandle` instances in the same webpage share the\n * same group name, they will share the same state. Setting the selection using\n * one `SelectionHandle` instance will result in the `value` property instantly\n * changing across the others, and `\"change\"` event listeners on all instances\n * (including the one that initiated the sending) will fire.\n *\n * @param {string} [group] - The name of the Crosstalk group, or if none,\n * null or undefined (or any other falsy value). This can be changed later\n * via the [SelectionHandle#setGroup](#setGroup) method.\n * @param {Object} [extraInfo] - An object whose properties will be copied to\n * the event object whenever an event is emitted.\n */\nexport class SelectionHandle {\n\n constructor(group = null, extraInfo = null) {\n this._eventRelay = new Events();\n this._emitter = new util.SubscriptionTracker(this._eventRelay);\n\n // Name of the group we're currently tracking, if any. Can change over time.\n this._group = null;\n // The Var we're currently tracking, if any. Can change over time.\n this._var = null;\n // The event handler subscription we currently have on var.on(\"change\").\n this._varOnChangeSub = null;\n\n this._extraInfo = util.extend({ sender: this }, extraInfo);\n\n this.setGroup(group);\n }\n\n /**\n * Changes the Crosstalk group membership of this SelectionHandle. The group\n * being switched away from (if any) will not have its selection value\n * modified as a result of calling `setGroup`, even if this handle was the\n * most recent handle to set the selection of the group.\n *\n * The group being switched to (if any) will also not have its selection value\n * modified as a result of calling `setGroup`. If you want to set the\n * selection value of the new group, call `set` explicitly.\n *\n * @param {string} group - The name of the Crosstalk group, or null (or\n * undefined) to clear the group.\n */\n setGroup(group) {\n // If group is unchanged, do nothing\n if (this._group === group)\n return;\n // Treat null, undefined, and other falsy values the same\n if (!this._group && !group)\n return;\n\n if (this._var) {\n this._var.off(\"change\", this._varOnChangeSub);\n this._var = null;\n this._varOnChangeSub = null;\n }\n\n this._group = group;\n\n if (group) {\n this._var = grp(group).var(\"selection\");\n let sub = this._var.on(\"change\", (e) => {\n this._eventRelay.trigger(\"change\", e, this);\n });\n this._varOnChangeSub = sub;\n }\n }\n\n /**\n * Retrieves the current selection for the group represented by this\n * `SelectionHandle`.\n *\n * - If no selection is active, then this value will be falsy.\n * - If a selection is active, but no data points are selected, then this\n * value will be an empty array.\n * - If a selection is active, and data points are selected, then the keys\n * of the selected data points will be present in the array.\n */\n get value() {\n return this._var ? this._var.get() : null;\n }\n\n /**\n * Combines the given `extraInfo` (if any) with the handle's default\n * `_extraInfo` (if any).\n * @private\n */\n _mergeExtraInfo(extraInfo) {\n // Important incidental effect: shallow clone is returned\n return util.extend({},\n this._extraInfo ? this._extraInfo : null,\n extraInfo ? extraInfo : null);\n }\n\n /**\n * Overwrites the current selection for the group, and raises the `\"change\"`\n * event among all of the group's '`SelectionHandle` instances (including\n * this one).\n *\n * @fires SelectionHandle#change\n * @param {string[]} selectedKeys - Falsy, empty array, or array of keys (see\n * {@link SelectionHandle#value}).\n * @param {Object} [extraInfo] - Extra properties to be included on the event\n * object that's passed to listeners (in addition to any options that were\n * passed into the `SelectionHandle` constructor).\n */\n set(selectedKeys, extraInfo) {\n if (this._var)\n this._var.set(selectedKeys, this._mergeExtraInfo(extraInfo));\n }\n\n /**\n * Overwrites the current selection for the group, and raises the `\"change\"`\n * event among all of the group's '`SelectionHandle` instances (including\n * this one).\n *\n * @fires SelectionHandle#change\n * @param {Object} [extraInfo] - Extra properties to be included on the event\n * object that's passed to listeners (in addition to any that were passed\n * into the `SelectionHandle` constructor).\n */\n clear(extraInfo) {\n if (this._var)\n this.set(void 0, this._mergeExtraInfo(extraInfo));\n }\n\n /**\n * Subscribes to events on this `SelectionHandle`.\n *\n * @param {string} eventType - Indicates the type of events to listen to.\n * Currently, only `\"change\"` is supported.\n * @param {SelectionHandle~listener} listener - The callback function that\n * will be invoked when the event occurs.\n * @return {string} - A token to pass to {@link SelectionHandle#off} to cancel\n * this subscription.\n */\n on(eventType, listener) {\n return this._emitter.on(eventType, listener);\n }\n\n /**\n * Cancels event subscriptions created by {@link SelectionHandle#on}.\n *\n * @param {string} eventType - The type of event to unsubscribe.\n * @param {string|SelectionHandle~listener} listener - Either the callback\n * function previously passed into {@link SelectionHandle#on}, or the\n * string that was returned from {@link SelectionHandle#on}.\n */\n off(eventType, listener) {\n return this._emitter.off(eventType, listener);\n }\n\n /**\n * Shuts down the `SelectionHandle` object.\n *\n * Removes all event listeners that were added through this handle.\n */\n close() {\n this._emitter.removeAllListeners();\n this.setGroup(null);\n }\n}\n\n/**\n * @callback SelectionHandle~listener\n * @param {Object} event - An object containing details of the event. For\n * `\"change\"` events, this includes the properties `value` (the new\n * value of the selection, or `undefined` if no selection is active),\n * `oldValue` (the previous value of the selection), and `sender` (the\n * `SelectionHandle` instance that made the change).\n */\n\n/**\n * @event SelectionHandle#change\n * @type {object}\n * @property {object} value - The new value of the selection, or `undefined`\n * if no selection is active.\n * @property {object} oldValue - The previous value of the selection.\n * @property {SelectionHandle} sender - The `SelectionHandle` instance that\n * changed the value.\n */\n","export function extend(target, ...sources) {\n for (let i = 0; i < sources.length; i++) {\n let src = sources[i];\n if (typeof(src) === \"undefined\" || src === null)\n continue;\n\n for (let key in src) {\n if (src.hasOwnProperty(key)) {\n target[key] = src[key];\n }\n }\n }\n return target;\n}\n\nexport function checkSorted(list) {\n for (let i = 1; i < list.length; i++) {\n if (list[i] <= list[i-1]) {\n throw new Error(\"List is not sorted or contains duplicate\");\n }\n }\n}\n\nexport function diffSortedLists(a, b) {\n let i_a = 0;\n let i_b = 0;\n\n if (!a) a = [];\n if (!b) b = [];\n\n let a_only = [];\n let b_only = [];\n\n checkSorted(a);\n checkSorted(b);\n\n while (i_a < a.length && i_b < b.length) {\n if (a[i_a] === b[i_b]) {\n i_a++;\n i_b++;\n } else if (a[i_a] < b[i_b]) {\n a_only.push(a[i_a++]);\n } else {\n b_only.push(b[i_b++]);\n }\n }\n\n if (i_a < a.length)\n a_only = a_only.concat(a.slice(i_a));\n if (i_b < b.length)\n b_only = b_only.concat(b.slice(i_b));\n return {\n removed: a_only,\n added: b_only\n };\n}\n\n// Convert from wide: { colA: [1,2,3], colB: [4,5,6], ... }\n// to long: [ {colA: 1, colB: 4}, {colA: 2, colB: 5}, ... ]\nexport function dataframeToD3(df) {\n let names = [];\n let length;\n for (let name in df) {\n if (df.hasOwnProperty(name))\n names.push(name);\n if (typeof(df[name]) !== \"object\" || typeof(df[name].length) === \"undefined\") {\n throw new Error(\"All fields must be arrays\");\n } else if (typeof(length) !== \"undefined\" && length !== df[name].length) {\n throw new Error(\"All fields must be arrays of the same length\");\n }\n length = df[name].length;\n }\n let results = [];\n let item;\n for (let row = 0; row < length; row++) {\n item = {};\n for (let col = 0; col < names.length; col++) {\n item[names[col]] = df[names[col]][row];\n }\n results.push(item);\n }\n return results;\n}\n\n/**\n * Keeps track of all event listener additions/removals and lets all active\n * listeners be removed with a single operation.\n *\n * @private\n */\nexport class SubscriptionTracker {\n constructor(emitter) {\n this._emitter = emitter;\n this._subs = {};\n }\n\n on(eventType, listener) {\n let sub = this._emitter.on(eventType, listener);\n this._subs[sub] = eventType;\n return sub;\n }\n\n off(eventType, listener) {\n let sub = this._emitter.off(eventType, listener);\n if (sub) {\n delete this._subs[sub];\n }\n return sub;\n }\n\n removeAllListeners() {\n let current_subs = this._subs;\n this._subs = {};\n Object.keys(current_subs).forEach((sub) => {\n this._emitter.off(current_subs[sub], sub);\n });\n }\n}\n","import Events from \"./events\";\n\nexport default class Var {\n constructor(group, name, /*optional*/ value) {\n this._group = group;\n this._name = name;\n this._value = value;\n this._events = new Events();\n }\n\n get() {\n return this._value;\n }\n\n set(value, /*optional*/ event) {\n if (this._value === value) {\n // Do nothing; the value hasn't changed\n return;\n }\n let oldValue = this._value;\n this._value = value;\n // Alert JavaScript listeners that the value has changed\n let evt = {};\n if (event && typeof(event) === \"object\") {\n for (let k in event) {\n if (event.hasOwnProperty(k))\n evt[k] = event[k];\n }\n }\n evt.oldValue = oldValue;\n evt.value = value;\n this._events.trigger(\"change\", evt, this);\n\n // TODO: Make this extensible, to let arbitrary back-ends know that\n // something has changed\n if (global.Shiny && global.Shiny.onInputChange) {\n global.Shiny.onInputChange(\n \".clientValue-\" +\n (this._group.name !== null ? this._group.name + \"-\" : \"\") +\n this._name,\n typeof(value) === \"undefined\" ? null : value\n );\n }\n }\n\n on(eventType, listener) {\n return this._events.on(eventType, listener);\n }\n\n off(eventType, listener) {\n return this._events.off(eventType, listener);\n }\n}\n"]} \ No newline at end of file diff --git a/docs/articles/custom-variables_files/crosstalk-1.2.1/scss/crosstalk.scss b/docs/articles/custom-variables_files/crosstalk-1.2.1/scss/crosstalk.scss new file mode 100644 index 00000000..35665616 --- /dev/null +++ b/docs/articles/custom-variables_files/crosstalk-1.2.1/scss/crosstalk.scss @@ -0,0 +1,75 @@ +/* Adjust margins outwards, so column contents line up with the edges of the + parent of container-fluid. */ +.container-fluid.crosstalk-bscols { + margin-left: -30px; + margin-right: -30px; + white-space: normal; +} + +/* But don't adjust the margins outwards if we're directly under the body, + i.e. we were the top-level of something at the console. */ +body > .container-fluid.crosstalk-bscols { + margin-left: auto; + margin-right: auto; +} + +.crosstalk-input-checkboxgroup .crosstalk-options-group .crosstalk-options-column { + display: inline-block; + padding-right: 12px; + vertical-align: top; +} + +@media only screen and (max-width:480px) { + .crosstalk-input-checkboxgroup .crosstalk-options-group .crosstalk-options-column { + display: block; + padding-right: inherit; + } +} + +/* Relevant BS3 styles to make filter_checkbox() look reasonable without Bootstrap */ +.crosstalk-input { + margin-bottom: 15px; /* a la .form-group */ + .control-label { + margin-bottom: 0; + vertical-align: middle; + } + input[type="checkbox"] { + margin: 4px 0 0; + margin-top: 1px; + line-height: normal; + } + .checkbox { + position: relative; + display: block; + margin-top: 10px; + margin-bottom: 10px; + } + .checkbox > label{ + padding-left: 20px; + margin-bottom: 0; + font-weight: 400; + cursor: pointer; + } + .checkbox input[type="checkbox"], + .checkbox-inline input[type="checkbox"] { + position: absolute; + margin-top: 2px; + margin-left: -20px; + } + .checkbox + .checkbox { + margin-top: -5px; + } + .checkbox-inline { + position: relative; + display: inline-block; + padding-left: 20px; + margin-bottom: 0; + font-weight: 400; + vertical-align: middle; + cursor: pointer; + } + .checkbox-inline + .checkbox-inline { + margin-top: 0; + margin-left: 10px; + } +} diff --git a/docs/articles/custom-variables_files/datatables-binding-0.33/datatables.js b/docs/articles/custom-variables_files/datatables-binding-0.33/datatables.js new file mode 100644 index 00000000..765b53cb --- /dev/null +++ b/docs/articles/custom-variables_files/datatables-binding-0.33/datatables.js @@ -0,0 +1,1539 @@ +(function() { + +// some helper functions: using a global object DTWidget so that it can be used +// in JS() code, e.g. datatable(options = list(foo = JS('code'))); unlike R's +// dynamic scoping, when 'code' is eval'ed, JavaScript does not know objects +// from the "parent frame", e.g. JS('DTWidget') will not work unless it was made +// a global object +var DTWidget = {}; + +// 123456666.7890 -> 123,456,666.7890 +var markInterval = function(d, digits, interval, mark, decMark, precision) { + x = precision ? d.toPrecision(digits) : d.toFixed(digits); + if (!/^-?[\d.]+$/.test(x)) return x; + var xv = x.split('.'); + if (xv.length > 2) return x; // should have at most one decimal point + xv[0] = xv[0].replace(new RegExp('\\B(?=(\\d{' + interval + '})+(?!\\d))', 'g'), mark); + return xv.join(decMark); +}; + +DTWidget.formatCurrency = function(data, currency, digits, interval, mark, decMark, before, zeroPrint) { + var d = parseFloat(data); + if (isNaN(d)) return ''; + if (zeroPrint !== null && d === 0.0) return zeroPrint; + var res = markInterval(d, digits, interval, mark, decMark); + res = before ? (/^-/.test(res) ? '-' + currency + res.replace(/^-/, '') : currency + res) : + res + currency; + return res; +}; + +DTWidget.formatString = function(data, prefix, suffix) { + var d = data; + if (d === null) return ''; + return prefix + d + suffix; +}; + +DTWidget.formatPercentage = function(data, digits, interval, mark, decMark, zeroPrint) { + var d = parseFloat(data); + if (isNaN(d)) return ''; + if (zeroPrint !== null && d === 0.0) return zeroPrint; + return markInterval(d * 100, digits, interval, mark, decMark) + '%'; +}; + +DTWidget.formatRound = function(data, digits, interval, mark, decMark, zeroPrint) { + var d = parseFloat(data); + if (isNaN(d)) return ''; + if (zeroPrint !== null && d === 0.0) return zeroPrint; + return markInterval(d, digits, interval, mark, decMark); +}; + +DTWidget.formatSignif = function(data, digits, interval, mark, decMark, zeroPrint) { + var d = parseFloat(data); + if (isNaN(d)) return ''; + if (zeroPrint !== null && d === 0.0) return zeroPrint; + return markInterval(d, digits, interval, mark, decMark, true); +}; + +DTWidget.formatDate = function(data, method, params) { + var d = data; + if (d === null) return ''; + // (new Date('2015-10-28')).toDateString() may return 2015-10-27 because the + // actual time created could be like 'Tue Oct 27 2015 19:00:00 GMT-0500 (CDT)', + // i.e. the date-only string is treated as UTC time instead of local time + if ((method === 'toDateString' || method === 'toLocaleDateString') && /^\d{4,}\D\d{2}\D\d{2}$/.test(d)) { + d = d.split(/\D/); + d = new Date(d[0], d[1] - 1, d[2]); + } else { + d = new Date(d); + } + return d[method].apply(d, params); +}; + +window.DTWidget = DTWidget; + +// A helper function to update the properties of existing filters +var setFilterProps = function(td, props) { + // Update enabled/disabled state + var $input = $(td).find('input').first(); + var searchable = $input.data('searchable'); + $input.prop('disabled', !searchable || props.disabled); + + // Based on the filter type, set its new values + var type = td.getAttribute('data-type'); + if (['factor', 'logical'].includes(type)) { + // Reformat the new dropdown options for use with selectize + var new_vals = props.params.options.map(function(item) { + return { text: item, value: item }; + }); + + // Find the selectize object + var dropdown = $(td).find('.selectized').eq(0)[0].selectize; + + // Note the current values + var old_vals = dropdown.getValue(); + + // Remove the existing values + dropdown.clearOptions(); + + // Add the new options + dropdown.addOption(new_vals); + + // Preserve the existing values + dropdown.setValue(old_vals); + + } else if (['number', 'integer', 'date', 'time'].includes(type)) { + // Apply internal scaling to new limits. Updating scale not yet implemented. + var slider = $(td).find('.noUi-target').eq(0); + var scale = Math.pow(10, Math.max(0, +slider.data('scale') || 0)); + var new_vals = [props.params.min * scale, props.params.max * scale]; + + // Note what the new limits will be just for this filter + var new_lims = new_vals.slice(); + + // Determine the current values and limits + var old_vals = slider.val().map(Number); + var old_lims = slider.noUiSlider('options').range; + old_lims = [old_lims.min, old_lims.max]; + + // Preserve the current values if filters have been applied; otherwise, apply no filtering + if (old_vals[0] != old_lims[0]) { + new_vals[0] = Math.max(old_vals[0], new_vals[0]); + } + + if (old_vals[1] != old_lims[1]) { + new_vals[1] = Math.min(old_vals[1], new_vals[1]); + } + + // Update the endpoints of the slider + slider.noUiSlider({ + start: new_vals, + range: {'min': new_lims[0], 'max': new_lims[1]} + }, true); + } +}; + +var transposeArray2D = function(a) { + return a.length === 0 ? a : HTMLWidgets.transposeArray2D(a); +}; + +var crosstalkPluginsInstalled = false; + +function maybeInstallCrosstalkPlugins() { + if (crosstalkPluginsInstalled) + return; + crosstalkPluginsInstalled = true; + + $.fn.dataTable.ext.afnFiltering.push( + function(oSettings, aData, iDataIndex) { + var ctfilter = oSettings.nTable.ctfilter; + if (ctfilter && !ctfilter[iDataIndex]) + return false; + + var ctselect = oSettings.nTable.ctselect; + if (ctselect && !ctselect[iDataIndex]) + return false; + + return true; + } + ); +} + +HTMLWidgets.widget({ + name: "datatables", + type: "output", + renderOnNullValue: true, + initialize: function(el, width, height) { + // in order that the type=number inputs return a number + $.valHooks.number = { + get: function(el) { + var value = parseFloat(el.value); + return isNaN(value) ? "" : value; + } + }; + $(el).html(' '); + return { + data: null, + ctfilterHandle: new crosstalk.FilterHandle(), + ctfilterSubscription: null, + ctselectHandle: new crosstalk.SelectionHandle(), + ctselectSubscription: null + }; + }, + renderValue: function(el, data, instance) { + if (el.offsetWidth === 0 || el.offsetHeight === 0) { + instance.data = data; + return; + } + instance.data = null; + var $el = $(el); + $el.empty(); + + if (data === null) { + $el.append(' '); + // clear previous Shiny inputs (if any) + for (var i in instance.clearInputs) instance.clearInputs[i](); + instance.clearInputs = {}; + return; + } + + var crosstalkOptions = data.crosstalkOptions; + if (!crosstalkOptions) crosstalkOptions = { + 'key': null, 'group': null + }; + if (crosstalkOptions.group) { + maybeInstallCrosstalkPlugins(); + instance.ctfilterHandle.setGroup(crosstalkOptions.group); + instance.ctselectHandle.setGroup(crosstalkOptions.group); + } + + // if we are in the viewer then we always want to fillContainer and + // and autoHideNavigation (unless the user has explicitly set these) + if (window.HTMLWidgets.viewerMode) { + if (!data.hasOwnProperty("fillContainer")) + data.fillContainer = true; + if (!data.hasOwnProperty("autoHideNavigation")) + data.autoHideNavigation = true; + } + + // propagate fillContainer to instance (so we have it in resize) + instance.fillContainer = data.fillContainer; + + var cells = data.data; + + if (cells instanceof Array) cells = transposeArray2D(cells); + + $el.append(data.container); + var $table = $el.find('table'); + if (data.class) $table.addClass(data.class); + if (data.caption) $table.prepend(data.caption); + + if (!data.selection) data.selection = { + mode: 'none', selected: null, target: 'row', selectable: null + }; + if (HTMLWidgets.shinyMode && data.selection.mode !== 'none' && + data.selection.target === 'row+column') { + if ($table.children('tfoot').length === 0) { + $table.append($('')); + $table.find('thead tr').clone().appendTo($table.find('tfoot')); + } + } + + // column filters + var filterRow; + switch (data.filter) { + case 'top': + $table.children('thead').append(data.filterHTML); + filterRow = $table.find('thead tr:last td'); + break; + case 'bottom': + if ($table.children('tfoot').length === 0) { + $table.append($('')); + } + $table.children('tfoot').prepend(data.filterHTML); + filterRow = $table.find('tfoot tr:first td'); + break; + } + + var options = { searchDelay: 1000 }; + if (cells !== null) $.extend(options, { + data: cells + }); + + // options for fillContainer + var bootstrapActive = typeof($.fn.popover) != 'undefined'; + if (instance.fillContainer) { + + // force scrollX/scrollY and turn off autoWidth + options.scrollX = true; + options.scrollY = "100px"; // can be any value, we'll adjust below + + // if we aren't paginating then move around the info/filter controls + // to save space at the bottom and rephrase the info callback + if (data.options.paging === false) { + + // we know how to do this cleanly for bootstrap, not so much + // for other themes/layouts + if (bootstrapActive) { + options.dom = "<'row'<'col-sm-4'i><'col-sm-8'f>>" + + "<'row'<'col-sm-12'tr>>"; + } + + options.fnInfoCallback = function(oSettings, iStart, iEnd, + iMax, iTotal, sPre) { + return Number(iTotal).toLocaleString() + " records"; + }; + } + } + + // auto hide navigation if requested + // Note, this only works on client-side processing mode as on server-side, + // cells (data.data) is null; In addition, we require the pageLength option + // being provided explicitly to enable this. Despite we may be able to deduce + // the default value of pageLength, it may complicate things so we'd rather + // put this responsiblity to users and warn them on the R side. + if (data.autoHideNavigation === true && data.options.paging !== false) { + // strip all nav if length >= cells + if ((cells instanceof Array) && data.options.pageLength >= cells.length) + options.dom = bootstrapActive ? "<'row'<'col-sm-12'tr>>" : "t"; + // alternatively lean things out for flexdashboard mobile portrait + else if (bootstrapActive && window.FlexDashboard && window.FlexDashboard.isMobilePhone()) + options.dom = "<'row'<'col-sm-12'f>>" + + "<'row'<'col-sm-12'tr>>" + + "<'row'<'col-sm-12'p>>"; + } + + $.extend(true, options, data.options || {}); + + var searchCols = options.searchCols; + if (searchCols) { + searchCols = searchCols.map(function(x) { + return x === null ? '' : x.search; + }); + // FIXME: this means I don't respect the escapeRegex setting + delete options.searchCols; + } + + // server-side processing? + var server = options.serverSide === true; + + // use the dataSrc function to pre-process JSON data returned from R + var DT_rows_all = [], DT_rows_current = []; + if (server && HTMLWidgets.shinyMode && typeof options.ajax === 'object' && + /^session\/[\da-z]+\/dataobj/.test(options.ajax.url) && !options.ajax.dataSrc) { + options.ajax.dataSrc = function(json) { + DT_rows_all = $.makeArray(json.DT_rows_all); + DT_rows_current = $.makeArray(json.DT_rows_current); + var data = json.data; + if (!colReorderEnabled()) return data; + var table = $table.DataTable(), order = table.colReorder.order(), flag = true, i, j, row; + for (i = 0; i < order.length; ++i) if (order[i] !== i) flag = false; + if (flag) return data; + for (i = 0; i < data.length; ++i) { + row = data[i].slice(); + for (j = 0; j < order.length; ++j) data[i][j] = row[order[j]]; + } + return data; + }; + } + + var thiz = this; + if (instance.fillContainer) $table.on('init.dt', function(e) { + thiz.fillAvailableHeight(el, $(el).innerHeight()); + }); + // If the page contains serveral datatables and one of which enables colReorder, + // the table.colReorder.order() function will exist but throws error when called. + // So it seems like the only way to know if colReorder is enabled or not is to + // check the options. + var colReorderEnabled = function() { return "colReorder" in options; }; + var table = $table.DataTable(options); + $el.data('datatable', table); + + if ('rowGroup' in options) { + // Maintain RowGroup dataSrc when columns are reordered (#1109) + table.on('column-reorder', function(e, settings, details) { + var oldDataSrc = table.rowGroup().dataSrc(); + var newDataSrc = details.mapping[oldDataSrc]; + table.rowGroup().dataSrc(newDataSrc); + }); + } + + // Unregister previous Crosstalk event subscriptions, if they exist + if (instance.ctfilterSubscription) { + instance.ctfilterHandle.off("change", instance.ctfilterSubscription); + instance.ctfilterSubscription = null; + } + if (instance.ctselectSubscription) { + instance.ctselectHandle.off("change", instance.ctselectSubscription); + instance.ctselectSubscription = null; + } + + if (!crosstalkOptions.group) { + $table[0].ctfilter = null; + $table[0].ctselect = null; + } else { + var key = crosstalkOptions.key; + function keysToMatches(keys) { + if (!keys) { + return null; + } else { + var selectedKeys = {}; + for (var i = 0; i < keys.length; i++) { + selectedKeys[keys[i]] = true; + } + var matches = {}; + for (var j = 0; j < key.length; j++) { + if (selectedKeys[key[j]]) + matches[j] = true; + } + return matches; + } + } + + function applyCrosstalkFilter(e) { + $table[0].ctfilter = keysToMatches(e.value); + table.draw(); + } + instance.ctfilterSubscription = instance.ctfilterHandle.on("change", applyCrosstalkFilter); + applyCrosstalkFilter({value: instance.ctfilterHandle.filteredKeys}); + + function applyCrosstalkSelection(e) { + if (e.sender !== instance.ctselectHandle) { + table + .rows('.' + selClass, {search: 'applied'}) + .nodes() + .to$() + .removeClass(selClass); + if (selectedRows) + changeInput('rows_selected', selectedRows(), void 0, true); + } + + if (e.sender !== instance.ctselectHandle && e.value && e.value.length) { + var matches = keysToMatches(e.value); + + // persistent selection with plotly (& leaflet) + var ctOpts = crosstalk.var("plotlyCrosstalkOpts").get() || {}; + if (ctOpts.persistent === true) { + var matches = $.extend(matches, $table[0].ctselect); + } + + $table[0].ctselect = matches; + table.draw(); + } else { + if ($table[0].ctselect) { + $table[0].ctselect = null; + table.draw(); + } + } + } + instance.ctselectSubscription = instance.ctselectHandle.on("change", applyCrosstalkSelection); + // TODO: This next line doesn't seem to work when renderDataTable is used + applyCrosstalkSelection({value: instance.ctselectHandle.value}); + } + + var inArray = function(val, array) { + return $.inArray(val, $.makeArray(array)) > -1; + }; + + // search the i-th column + var searchColumn = function(i, value) { + var regex = false, ci = true; + if (options.search) { + regex = options.search.regex, + ci = options.search.caseInsensitive !== false; + } + // need to transpose the column index when colReorder is enabled + if (table.colReorder) i = table.colReorder.transpose(i); + return table.column(i).search(value, regex, !regex, ci); + }; + + if (data.filter !== 'none') { + if (!data.hasOwnProperty('filterSettings')) data.filterSettings = {}; + + filterRow.each(function(i, td) { + + var $td = $(td), type = $td.data('type'), filter; + var $input = $td.children('div').first().children('input'); + var disabled = $input.prop('disabled'); + var searchable = table.settings()[0].aoColumns[i].bSearchable; + $input.prop('disabled', !searchable || disabled); + $input.data('searchable', searchable); // for updating later + $input.on('input blur', function() { + $input.next('span').toggle(Boolean($input.val())); + }); + // Bootstrap sets pointer-events to none and we won't be able to click + // the clear button + $input.next('span').css('pointer-events', 'auto').hide().click(function() { + $(this).hide().prev('input').val('').trigger('input').focus(); + }); + var searchCol; // search string for this column + if (searchCols && searchCols[i]) { + searchCol = searchCols[i]; + $input.val(searchCol).trigger('input'); + } + var $x = $td.children('div').last(); + + // remove the overflow: hidden attribute of the scrollHead + // (otherwise the scrolling table body obscures the filters) + // The workaround and the discussion from + // https://github.com/rstudio/DT/issues/554#issuecomment-518007347 + // Otherwise the filter selection will not be anchored to the values + // when the columns number is many and scrollX is enabled. + var scrollHead = $(el).find('.dataTables_scrollHead,.dataTables_scrollFoot'); + var cssOverflowHead = scrollHead.css('overflow'); + var scrollBody = $(el).find('.dataTables_scrollBody'); + var cssOverflowBody = scrollBody.css('overflow'); + var scrollTable = $(el).find('.dataTables_scroll'); + var cssOverflowTable = scrollTable.css('overflow'); + if (cssOverflowHead === 'hidden') { + $x.on('show hide', function(e) { + if (e.type === 'show') { + scrollHead.css('overflow', 'visible'); + scrollBody.css('overflow', 'visible'); + scrollTable.css('overflow-x', 'scroll'); + } else { + scrollHead.css('overflow', cssOverflowHead); + scrollBody.css('overflow', cssOverflowBody); + scrollTable.css('overflow-x', cssOverflowTable); + } + }); + $x.css('z-index', 25); + } + + if (inArray(type, ['factor', 'logical'])) { + $input.on({ + click: function() { + $input.parent().hide(); $x.show().trigger('show'); filter[0].selectize.focus(); + }, + input: function() { + var v1 = JSON.stringify(filter[0].selectize.getValue()), v2 = $input.val(); + if (v1 === '[]') v1 = ''; + if (v1 !== v2) filter[0].selectize.setValue(v2 === '' ? [] : JSON.parse(v2)); + } + }); + var $input2 = $x.children('select'); + filter = $input2.selectize($.extend({ + options: $input2.data('options').map(function(v, i) { + return ({text: v, value: v}); + }), + plugins: ['remove_button'], + hideSelected: true, + onChange: function(value) { + if (value === null) value = []; // compatibility with jQuery 3.0 + $input.val(value.length ? JSON.stringify(value) : ''); + if (value.length) $input.trigger('input'); + $input.attr('title', $input.val()); + if (server) { + searchColumn(i, value.length ? JSON.stringify(value) : '').draw(); + return; + } + // turn off filter if nothing selected + $td.data('filter', value.length > 0); + table.draw(); // redraw table, and filters will be applied + } + }, data.filterSettings.select)); + filter[0].selectize.on('blur', function() { + $x.hide().trigger('hide'); $input.parent().show(); $input.trigger('blur'); + }); + filter.next('div').css('margin-bottom', 'auto'); + } else if (type === 'character') { + var fun = function() { + searchColumn(i, $input.val()).draw(); + }; + // throttle searching for server-side processing + var throttledFun = $.fn.dataTable.util.throttle(fun, options.searchDelay); + $input.on('input', function(e, immediate) { + // always bypass throttling when immediate = true (via the updateSearch method) + (immediate || !server) ? fun() : throttledFun(); + }); + } else if (inArray(type, ['number', 'integer', 'date', 'time'])) { + var $x0 = $x; + $x = $x0.children('div').first(); + $x0.css({ + 'background-color': '#fff', + 'border': '1px #ddd solid', + 'border-radius': '4px', + 'padding': data.vertical ? '35px 20px': '20px 20px 10px 20px' + }); + var $spans = $x0.children('span').css({ + 'margin-top': data.vertical ? '0' : '10px', + 'white-space': 'nowrap' + }); + var $span1 = $spans.first(), $span2 = $spans.last(); + var r1 = +$x.data('min'), r2 = +$x.data('max'); + // when the numbers are too small or have many decimal places, the + // slider may have numeric precision problems (#150) + var scale = Math.pow(10, Math.max(0, +$x.data('scale') || 0)); + r1 = Math.round(r1 * scale); r2 = Math.round(r2 * scale); + var scaleBack = function(x, scale) { + if (scale === 1) return x; + var d = Math.round(Math.log(scale) / Math.log(10)); + // to avoid problems like 3.423/100 -> 0.034230000000000003 + return (x / scale).toFixed(d); + }; + var slider_min = function() { + return filter.noUiSlider('options').range.min; + }; + var slider_max = function() { + return filter.noUiSlider('options').range.max; + }; + $input.on({ + focus: function() { + $x0.show().trigger('show'); + // first, make sure the slider div leaves at least 20px between + // the two (slider value) span's + $x0.width(Math.max(160, $span1.outerWidth() + $span2.outerWidth() + 20)); + // then, if the input is really wide or slider is vertical, + // make the slider the same width as the input + if ($x0.outerWidth() < $input.outerWidth() || data.vertical) { + $x0.outerWidth($input.outerWidth()); + } + // make sure the slider div does not reach beyond the right margin + if ($(window).width() < $x0.offset().left + $x0.width()) { + $x0.offset({ + 'left': $input.offset().left + $input.outerWidth() - $x0.outerWidth() + }); + } + }, + blur: function() { + $x0.hide().trigger('hide'); + }, + input: function() { + if ($input.val() === '') filter.val([slider_min(), slider_max()]); + }, + change: function() { + var v = $input.val().replace(/\s/g, ''); + if (v === '') return; + v = v.split('...'); + if (v.length !== 2) { + $input.parent().addClass('has-error'); + return; + } + if (v[0] === '') v[0] = slider_min(); + if (v[1] === '') v[1] = slider_max(); + $input.parent().removeClass('has-error'); + // treat date as UTC time at midnight + var strTime = function(x) { + var s = type === 'date' ? 'T00:00:00Z' : ''; + var t = new Date(x + s).getTime(); + // add 10 minutes to date since it does not hurt the date, and + // it helps avoid the tricky floating point arithmetic problems, + // e.g. sometimes the date may be a few milliseconds earlier + // than the midnight due to precision problems in noUiSlider + return type === 'date' ? t + 3600000 : t; + }; + if (inArray(type, ['date', 'time'])) { + v[0] = strTime(v[0]); + v[1] = strTime(v[1]); + } + if (v[0] != slider_min()) v[0] *= scale; + if (v[1] != slider_max()) v[1] *= scale; + filter.val(v); + } + }); + var formatDate = function(d) { + d = scaleBack(d, scale); + if (type === 'number') return d; + if (type === 'integer') return parseInt(d); + var x = new Date(+d); + if (type === 'date') { + var pad0 = function(x) { + return ('0' + x).substr(-2, 2); + }; + return x.getUTCFullYear() + '-' + pad0(1 + x.getUTCMonth()) + + '-' + pad0(x.getUTCDate()); + } else { + return x.toISOString(); + } + }; + var opts = type === 'date' ? { step: 60 * 60 * 1000 } : + type === 'integer' ? { step: 1 } : {}; + + opts.orientation = data.vertical ? 'vertical': 'horizontal'; + opts.direction = data.vertical ? 'rtl': 'ltr'; + + filter = $x.noUiSlider($.extend({ + start: [r1, r2], + range: {min: r1, max: r2}, + connect: true + }, opts, data.filterSettings.slider)); + if (scale > 1) (function() { + var t1 = r1, t2 = r2; + var val = filter.val(); + while (val[0] > r1 || val[1] < r2) { + if (val[0] > r1) { + t1 -= val[0] - r1; + } + if (val[1] < r2) { + t2 += r2 - val[1]; + } + filter = $x.noUiSlider($.extend({ + start: [t1, t2], + range: {min: t1, max: t2}, + connect: true + }, opts, data.filterSettings.slider), true); + val = filter.val(); + } + r1 = t1; r2 = t2; + })(); + // format with active column renderer, if defined + var colDef = data.options.columnDefs.find(function(def) { + return (def.targets === i || inArray(i, def.targets)) && 'render' in def; + }); + var updateSliderText = function(v1, v2) { + // we only know how to use function renderers + if (colDef && typeof colDef.render === 'function') { + var restore = function(v) { + v = scaleBack(v, scale); + return inArray(type, ['date', 'time']) ? new Date(+v) : v; + } + $span1.text(colDef.render(restore(v1), 'display')); + $span2.text(colDef.render(restore(v2), 'display')); + } else { + $span1.text(formatDate(v1)); + $span2.text(formatDate(v2)); + } + }; + updateSliderText(r1, r2); + var updateSlider = function(e) { + var val = filter.val(); + // turn off filter if in full range + $td.data('filter', val[0] > slider_min() || val[1] < slider_max()); + var v1 = formatDate(val[0]), v2 = formatDate(val[1]), ival; + if ($td.data('filter')) { + ival = v1 + ' ... ' + v2; + $input.attr('title', ival).val(ival).trigger('input'); + } else { + $input.attr('title', '').val(''); + } + updateSliderText(val[0], val[1]); + if (e.type === 'slide') return; // no searching when sliding only + if (server) { + searchColumn(i, $td.data('filter') ? ival : '').draw(); + return; + } + table.draw(); + }; + filter.on({ + set: updateSlider, + slide: updateSlider + }); + } + + // server-side processing will be handled by R (or whatever server + // language you use); the following code is only needed for client-side + // processing + if (server) { + // if a search string has been pre-set, search now + if (searchCol) $input.trigger('input').trigger('change'); + return; + } + + var customFilter = function(settings, data, dataIndex) { + // there is no way to attach a search function to a specific table, + // and we need to make sure a global search function is not applied to + // all tables (i.e. a range filter in a previous table should not be + // applied to the current table); we use the settings object to + // determine if we want to perform searching on the current table, + // since settings.sTableId will be different to different tables + if (table.settings()[0] !== settings) return true; + // no filter on this column or no need to filter this column + if (typeof filter === 'undefined' || !$td.data('filter')) return true; + + var r = filter.val(), v, r0, r1; + var i_data = function(i) { + if (!colReorderEnabled()) return i; + var order = table.colReorder.order(), k; + for (k = 0; k < order.length; ++k) if (order[k] === i) return k; + return i; // in theory it will never be here... + } + v = data[i_data(i)]; + if (type === 'number' || type === 'integer') { + v = parseFloat(v); + // how to handle NaN? currently exclude these rows + if (isNaN(v)) return(false); + r0 = parseFloat(scaleBack(r[0], scale)) + r1 = parseFloat(scaleBack(r[1], scale)); + if (v >= r0 && v <= r1) return true; + } else if (type === 'date' || type === 'time') { + v = new Date(v); + r0 = new Date(r[0] / scale); r1 = new Date(r[1] / scale); + if (v >= r0 && v <= r1) return true; + } else if (type === 'factor') { + if (r.length === 0 || inArray(v, r)) return true; + } else if (type === 'logical') { + if (r.length === 0) return true; + if (inArray(v === '' ? 'na' : v, r)) return true; + } + return false; + }; + + $.fn.dataTable.ext.search.push(customFilter); + + // search for the preset search strings if it is non-empty + if (searchCol) $input.trigger('input').trigger('change'); + + }); + + } + + // highlight search keywords + var highlight = function() { + var body = $(table.table().body()); + // removing the old highlighting first + body.unhighlight(); + + // don't highlight the "not found" row, so we get the rows using the api + if (table.rows({ filter: 'applied' }).data().length === 0) return; + // highlight global search keywords + body.highlight($.trim(table.search()).split(/\s+/)); + // then highlight keywords from individual column filters + if (filterRow) filterRow.each(function(i, td) { + var $td = $(td), type = $td.data('type'); + if (type !== 'character') return; + var $input = $td.children('div').first().children('input'); + var column = table.column(i).nodes().to$(), + val = $.trim($input.val()); + if (type !== 'character' || val === '') return; + column.highlight(val.split(/\s+/)); + }); + }; + + if (options.searchHighlight) { + table + .on('draw.dt.dth column-visibility.dt.dth column-reorder.dt.dth', highlight) + .on('destroy', function() { + // remove event handler + table.off('draw.dt.dth column-visibility.dt.dth column-reorder.dt.dth'); + }); + + // Set the option for escaping regex characters in our search string. This will be used + // for all future matching. + jQuery.fn.highlight.options.escapeRegex = (!options.search || !options.search.regex); + + // initial highlight for state saved conditions and initial states + highlight(); + } + + // run the callback function on the table instance + if (typeof data.callback === 'function') data.callback(table); + + // double click to edit the cell, row, column, or all cells + if (data.editable) table.on('dblclick.dt', 'tbody td', function(e) { + // only bring up the editor when the cell itself is dbclicked, and ignore + // other dbclick events bubbled up (e.g. from the ) + if (e.target !== this) return; + var target = [], immediate = false; + switch (data.editable.target) { + case 'cell': + target = [this]; + immediate = true; // edit will take effect immediately + break; + case 'row': + target = table.cells(table.cell(this).index().row, '*').nodes(); + break; + case 'column': + target = table.cells('*', table.cell(this).index().column).nodes(); + break; + case 'all': + target = table.cells().nodes(); + break; + default: + throw 'The editable parameter must be "cell", "row", "column", or "all"'; + } + var disableCols = data.editable.disable ? data.editable.disable.columns : null; + var numericCols = data.editable.numeric; + var areaCols = data.editable.area; + var dateCols = data.editable.date; + for (var i = 0; i < target.length; i++) { + (function(cell, current) { + var $cell = $(cell), html = $cell.html(); + var _cell = table.cell(cell), value = _cell.data(), index = _cell.index().column; + var $input; + if (inArray(index, numericCols)) { + $input = $(''); + } else if (inArray(index, areaCols)) { + $input = $(''); + } else if (inArray(index, dateCols)) { + $input = $(''); + } else { + $input = $(''); + } + if (!immediate) { + $cell.data('input', $input).data('html', html); + $input.attr('title', 'Hit Ctrl+Enter to finish editing, or Esc to cancel'); + } + $input.val(value); + if (inArray(index, disableCols)) { + $input.attr('readonly', '').css('filter', 'invert(25%)'); + } + $cell.empty().append($input); + if (cell === current) $input.focus(); + $input.css('width', '100%'); + + if (immediate) $input.on('blur', function(e) { + var valueNew = $input.val(); + if (valueNew !== value) { + _cell.data(valueNew); + if (HTMLWidgets.shinyMode) { + changeInput('cell_edit', [cellInfo(cell)], 'DT.cellInfo', null, {priority: 'event'}); + } + // for server-side processing, users have to call replaceData() to update the table + if (!server) table.draw(false); + } else { + $cell.html(html); + } + }).on('keyup', function(e) { + // hit Escape to cancel editing + if (e.keyCode === 27) $input.trigger('blur'); + }); + + // bulk edit (row, column, or all) + if (!immediate) $input.on('keyup', function(e) { + var removeInput = function($cell, restore) { + $cell.data('input').remove(); + if (restore) $cell.html($cell.data('html')); + } + if (e.keyCode === 27) { + for (var i = 0; i < target.length; i++) { + removeInput($(target[i]), true); + } + } else if (e.keyCode === 13 && e.ctrlKey) { + // Ctrl + Enter + var cell, $cell, _cell, cellData = []; + for (var i = 0; i < target.length; i++) { + cell = target[i]; $cell = $(cell); _cell = table.cell(cell); + _cell.data($cell.data('input').val()); + HTMLWidgets.shinyMode && cellData.push(cellInfo(cell)); + removeInput($cell, false); + } + if (HTMLWidgets.shinyMode) { + changeInput('cell_edit', cellData, 'DT.cellInfo', null, {priority: "event"}); + } + if (!server) table.draw(false); + } + }); + })(target[i], this); + } + }); + + // interaction with shiny + if (!HTMLWidgets.shinyMode && !crosstalkOptions.group) return; + + var methods = {}; + var shinyData = {}; + + methods.updateCaption = function(caption) { + if (!caption) return; + $table.children('caption').replaceWith(caption); + } + + // register clear functions to remove input values when the table is removed + instance.clearInputs = {}; + + var changeInput = function(id, value, type, noCrosstalk, opts) { + var event = id; + id = el.id + '_' + id; + if (type) id = id + ':' + type; + // do not update if the new value is the same as old value + if (event !== 'cell_edit' && !/_clicked$/.test(event) && shinyData.hasOwnProperty(id) && shinyData[id] === JSON.stringify(value)) + return; + shinyData[id] = JSON.stringify(value); + if (HTMLWidgets.shinyMode && Shiny.setInputValue) { + Shiny.setInputValue(id, value, opts); + if (!instance.clearInputs[id]) instance.clearInputs[id] = function() { + Shiny.setInputValue(id, null); + } + } + + // HACK + if (event === "rows_selected" && !noCrosstalk) { + if (crosstalkOptions.group) { + var keys = crosstalkOptions.key; + var selectedKeys = null; + if (value) { + selectedKeys = []; + for (var i = 0; i < value.length; i++) { + // The value array's contents use 1-based row numbers, so we must + // convert to 0-based before indexing into the keys array. + selectedKeys.push(keys[value[i] - 1]); + } + } + instance.ctselectHandle.set(selectedKeys); + } + } + }; + + var addOne = function(x) { + return x.map(function(i) { return 1 + i; }); + }; + + var unique = function(x) { + var ux = []; + $.each(x, function(i, el){ + if ($.inArray(el, ux) === -1) ux.push(el); + }); + return ux; + } + + // change the row index of a cell + var tweakCellIndex = function(cell) { + var info = cell.index(); + // some cell may not be valid. e.g, #759 + // when using the RowGroup extension, datatables will + // generate the row label and the cells are not part of + // the data thus contain no row/col info + if (info === undefined) + return {row: null, col: null}; + if (server) { + info.row = DT_rows_current[info.row]; + } else { + info.row += 1; + } + return {row: info.row, col: info.column}; + } + + var cleanSelectedValues = function() { + changeInput('rows_selected', []); + changeInput('columns_selected', []); + changeInput('cells_selected', transposeArray2D([]), 'shiny.matrix'); + } + // #828 we should clean the selection on the server-side when the table reloads + cleanSelectedValues(); + + // a flag to indicates if select extension is initialized or not + var flagSelectExt = table.settings()[0]._select !== undefined; + // the Select extension should only be used in the client mode and + // when the selection.mode is set to none + if (data.selection.mode === 'none' && !server && flagSelectExt) { + var updateRowsSelected = function() { + var rows = table.rows({selected: true}); + var selected = []; + $.each(rows.indexes().toArray(), function(i, v) { + selected.push(v + 1); + }); + changeInput('rows_selected', selected); + } + var updateColsSelected = function() { + var columns = table.columns({selected: true}); + changeInput('columns_selected', columns.indexes().toArray()); + } + var updateCellsSelected = function() { + var cells = table.cells({selected: true}); + var selected = []; + cells.every(function() { + var row = this.index().row; + var col = this.index().column; + selected = selected.concat([[row + 1, col]]); + }); + changeInput('cells_selected', transposeArray2D(selected), 'shiny.matrix'); + } + table.on('select deselect', function(e, dt, type, indexes) { + updateRowsSelected(); + updateColsSelected(); + updateCellsSelected(); + }) + updateRowsSelected(); + updateColsSelected(); + updateCellsSelected(); + } + + var selMode = data.selection.mode, selTarget = data.selection.target; + var selDisable = data.selection.selectable === false; + if (inArray(selMode, ['single', 'multiple'])) { + var selClass = inArray(data.style, ['bootstrap', 'bootstrap4']) ? 'active' : 'selected'; + // selected1: row indices; selected2: column indices + var initSel = function(x) { + if (x === null || typeof x === 'boolean' || selTarget === 'cell') { + return {rows: [], cols: []}; + } else if (selTarget === 'row') { + return {rows: $.makeArray(x), cols: []}; + } else if (selTarget === 'column') { + return {rows: [], cols: $.makeArray(x)}; + } else if (selTarget === 'row+column') { + return {rows: $.makeArray(x.rows), cols: $.makeArray(x.cols)}; + } + } + var selected = data.selection.selected; + var selected1 = initSel(selected).rows, selected2 = initSel(selected).cols; + // selectable should contain either all positive or all non-positive values, not both + // positive values indicate "selectable" while non-positive values means "nonselectable" + // the assertion is performed on R side. (only column indicides could be zero which indicates + // the row name) + var selectable = data.selection.selectable; + var selectable1 = initSel(selectable).rows, selectable2 = initSel(selectable).cols; + + // After users reorder the rows or filter the table, we cannot use the table index + // directly. Instead, we need this function to find out the rows between the two clicks. + // If user filter the table again between the start click and the end click, the behavior + // would be undefined, but it should not be a problem. + var shiftSelRowsIndex = function(start, end) { + var indexes = server ? DT_rows_all : table.rows({ search: 'applied' }).indexes().toArray(); + start = indexes.indexOf(start); end = indexes.indexOf(end); + // if start is larger than end, we need to swap + if (start > end) { + var tmp = end; end = start; start = tmp; + } + return indexes.slice(start, end + 1); + } + + var serverRowIndex = function(clientRowIndex) { + return server ? DT_rows_current[clientRowIndex] : clientRowIndex + 1; + } + + // row, column, or cell selection + var lastClickedRow; + if (inArray(selTarget, ['row', 'row+column'])) { + // Get the current selected rows. It will also + // update the selected1's value based on the current row selection state + // Note we can't put this function inside selectRows() directly, + // the reason is method.selectRows() will override selected1's value but this + // function will add rows to selected1 (keep the existing selection), which is + // inconsistent with column and cell selection. + var selectedRows = function() { + var rows = table.rows('.' + selClass); + var idx = rows.indexes().toArray(); + if (!server) { + selected1 = addOne(idx); + return selected1; + } + idx = idx.map(function(i) { + return DT_rows_current[i]; + }); + selected1 = selMode === 'multiple' ? unique(selected1.concat(idx)) : idx; + return selected1; + } + // Change selected1's value based on selectable1, then refresh the row state + var onlyKeepSelectableRows = function() { + if (selDisable) { // users can't select; useful when only want backend select + selected1 = []; + return; + } + if (selectable1.length === 0) return; + var nonselectable = selectable1[0] <= 0; + if (nonselectable) { + // should make selectable1 positive + selected1 = $(selected1).not(selectable1.map(function(i) { return -i; })).get(); + } else { + selected1 = $(selected1).filter(selectable1).get(); + } + } + // Change selected1's value based on selectable1, then + // refresh the row selection state according to values in selected1 + var selectRows = function(ignoreSelectable) { + if (!ignoreSelectable) onlyKeepSelectableRows(); + table.$('tr.' + selClass).removeClass(selClass); + if (selected1.length === 0) return; + if (server) { + table.rows({page: 'current'}).every(function() { + if (inArray(DT_rows_current[this.index()], selected1)) { + $(this.node()).addClass(selClass); + } + }); + } else { + var selected0 = selected1.map(function(i) { return i - 1; }); + $(table.rows(selected0).nodes()).addClass(selClass); + } + } + table.on('mousedown.dt', 'tbody tr', function(e) { + var $this = $(this), thisRow = table.row(this); + if (selMode === 'multiple') { + if (e.shiftKey && lastClickedRow !== undefined) { + // select or de-select depends on the last clicked row's status + var flagSel = !$this.hasClass(selClass); + var crtClickedRow = serverRowIndex(thisRow.index()); + if (server) { + var rowsIndex = shiftSelRowsIndex(lastClickedRow, crtClickedRow); + // update current page's selClass + rowsIndex.map(function(i) { + var rowIndex = DT_rows_current.indexOf(i); + if (rowIndex >= 0) { + var row = table.row(rowIndex).nodes().to$(); + var flagRowSel = !row.hasClass(selClass); + if (flagSel === flagRowSel) row.toggleClass(selClass); + } + }); + // update selected1 + if (flagSel) { + selected1 = unique(selected1.concat(rowsIndex)); + } else { + selected1 = selected1.filter(function(index) { + return !inArray(index, rowsIndex); + }); + } + } else { + // js starts from 0 + shiftSelRowsIndex(lastClickedRow - 1, crtClickedRow - 1).map(function(value) { + var row = table.row(value).nodes().to$(); + var flagRowSel = !row.hasClass(selClass); + if (flagSel === flagRowSel) row.toggleClass(selClass); + }); + } + e.preventDefault(); + } else { + $this.toggleClass(selClass); + } + } else { + if ($this.hasClass(selClass)) { + $this.removeClass(selClass); + } else { + table.$('tr.' + selClass).removeClass(selClass); + $this.addClass(selClass); + } + } + if (server && !$this.hasClass(selClass)) { + var id = DT_rows_current[thisRow.index()]; + // remove id from selected1 since its class .selected has been removed + if (inArray(id, selected1)) selected1.splice($.inArray(id, selected1), 1); + } + selectedRows(); // update selected1's value based on selClass + selectRows(false); // only keep the selectable rows + changeInput('rows_selected', selected1); + changeInput('row_last_clicked', serverRowIndex(thisRow.index()), null, null, {priority: 'event'}); + lastClickedRow = serverRowIndex(thisRow.index()); + }); + selectRows(false); // in case users have specified pre-selected rows + // restore selected rows after the table is redrawn (e.g. sort/search/page); + // client-side tables will preserve the selections automatically; for + // server-side tables, we have to *real* row indices are in `selected1` + changeInput('rows_selected', selected1); + if (server) table.on('draw.dt', function(e) { selectRows(false); }); + methods.selectRows = function(selected, ignoreSelectable) { + selected1 = $.makeArray(selected); + selectRows(ignoreSelectable); + changeInput('rows_selected', selected1); + } + } + + if (inArray(selTarget, ['column', 'row+column'])) { + if (selTarget === 'row+column') { + $(table.columns().footer()).css('cursor', 'pointer'); + } + // update selected2's value based on selectable2 + var onlyKeepSelectableCols = function() { + if (selDisable) { // users can't select; useful when only want backend select + selected2 = []; + return; + } + if (selectable2.length === 0) return; + var nonselectable = selectable2[0] <= 0; + if (nonselectable) { + // need to make selectable2 positive + selected2 = $(selected2).not(selectable2.map(function(i) { return -i; })).get(); + } else { + selected2 = $(selected2).filter(selectable2).get(); + } + } + // update selected2 and then + // refresh the col selection state according to values in selected2 + var selectCols = function(ignoreSelectable) { + if (!ignoreSelectable) onlyKeepSelectableCols(); + // if selected2 is not a valide index (e.g., larger than the column number) + // table.columns(selected2) will fail and result in a blank table + // this is different from the table.rows(), where the out-of-range indexes + // doesn't affect at all + selected2 = $(selected2).filter(table.columns().indexes()).get(); + table.columns().nodes().flatten().to$().removeClass(selClass); + if (selected2.length > 0) + table.columns(selected2).nodes().flatten().to$().addClass(selClass); + } + var callback = function() { + var colIdx = selTarget === 'column' ? table.cell(this).index().column : + $.inArray(this, table.columns().footer()), + thisCol = $(table.column(colIdx).nodes()); + if (colIdx === -1) return; + if (thisCol.hasClass(selClass)) { + thisCol.removeClass(selClass); + selected2.splice($.inArray(colIdx, selected2), 1); + } else { + if (selMode === 'single') $(table.cells().nodes()).removeClass(selClass); + thisCol.addClass(selClass); + selected2 = selMode === 'single' ? [colIdx] : unique(selected2.concat([colIdx])); + } + selectCols(false); // update selected2 based on selectable + changeInput('columns_selected', selected2); + } + if (selTarget === 'column') { + $(table.table().body()).on('click.dt', 'td', callback); + } else { + $(table.table().footer()).on('click.dt', 'tr th', callback); + } + selectCols(false); // in case users have specified pre-selected columns + changeInput('columns_selected', selected2); + if (server) table.on('draw.dt', function(e) { selectCols(false); }); + methods.selectColumns = function(selected, ignoreSelectable) { + selected2 = $.makeArray(selected); + selectCols(ignoreSelectable); + changeInput('columns_selected', selected2); + } + } + + if (selTarget === 'cell') { + var selected3 = [], selectable3 = []; + if (selected !== null) selected3 = selected; + if (selectable !== null && typeof selectable !== 'boolean') selectable3 = selectable; + var findIndex = function(ij, sel) { + for (var i = 0; i < sel.length; i++) { + if (ij[0] === sel[i][0] && ij[1] === sel[i][1]) return i; + } + return -1; + } + // Change selected3's value based on selectable3, then refresh the cell state + var onlyKeepSelectableCells = function() { + if (selDisable) { // users can't select; useful when only want backend select + selected3 = []; + return; + } + if (selectable3.length === 0) return; + var nonselectable = selectable3[0][0] <= 0; + var out = []; + if (nonselectable) { + selected3.map(function(ij) { + // should make selectable3 positive + if (findIndex([-ij[0], -ij[1]], selectable3) === -1) { out.push(ij); } + }); + } else { + selected3.map(function(ij) { + if (findIndex(ij, selectable3) > -1) { out.push(ij); } + }); + } + selected3 = out; + } + // Change selected3's value based on selectable3, then + // refresh the cell selection state according to values in selected3 + var selectCells = function(ignoreSelectable) { + if (!ignoreSelectable) onlyKeepSelectableCells(); + table.$('td.' + selClass).removeClass(selClass); + if (selected3.length === 0) return; + if (server) { + table.cells({page: 'current'}).every(function() { + var info = tweakCellIndex(this); + if (findIndex([info.row, info.col], selected3) > -1) + $(this.node()).addClass(selClass); + }); + } else { + selected3.map(function(ij) { + $(table.cell(ij[0] - 1, ij[1]).node()).addClass(selClass); + }); + } + }; + table.on('click.dt', 'tbody td', function() { + var $this = $(this), info = tweakCellIndex(table.cell(this)); + if ($this.hasClass(selClass)) { + $this.removeClass(selClass); + selected3.splice(findIndex([info.row, info.col], selected3), 1); + } else { + if (selMode === 'single') $(table.cells().nodes()).removeClass(selClass); + $this.addClass(selClass); + selected3 = selMode === 'single' ? [[info.row, info.col]] : + unique(selected3.concat([[info.row, info.col]])); + } + selectCells(false); // must call this to update selected3 based on selectable3 + changeInput('cells_selected', transposeArray2D(selected3), 'shiny.matrix'); + }); + selectCells(false); // in case users have specified pre-selected columns + changeInput('cells_selected', transposeArray2D(selected3), 'shiny.matrix'); + + if (server) table.on('draw.dt', function(e) { selectCells(false); }); + methods.selectCells = function(selected, ignoreSelectable) { + selected3 = selected ? selected : []; + selectCells(ignoreSelectable); + changeInput('cells_selected', transposeArray2D(selected3), 'shiny.matrix'); + } + } + } + + // expose some table info to Shiny + var updateTableInfo = function(e, settings) { + // TODO: is anyone interested in the page info? + // changeInput('page_info', table.page.info()); + var updateRowInfo = function(id, modifier) { + var idx; + if (server) { + idx = modifier.page === 'current' ? DT_rows_current : DT_rows_all; + } else { + var rows = table.rows($.extend({ + search: 'applied', + page: 'all' + }, modifier)); + idx = addOne(rows.indexes().toArray()); + } + changeInput('rows' + '_' + id, idx); + }; + updateRowInfo('current', {page: 'current'}); + updateRowInfo('all', {}); + } + table.on('draw.dt', updateTableInfo); + updateTableInfo(); + + // state info + table.on('draw.dt column-visibility.dt', function() { + changeInput('state', table.state()); + }); + changeInput('state', table.state()); + + // search info + var updateSearchInfo = function() { + changeInput('search', table.search()); + if (filterRow) changeInput('search_columns', filterRow.toArray().map(function(td) { + return $(td).find('input').first().val(); + })); + } + table.on('draw.dt', updateSearchInfo); + updateSearchInfo(); + + var cellInfo = function(thiz) { + var info = tweakCellIndex(table.cell(thiz)); + info.value = table.cell(thiz).data(); + return info; + } + // the current cell clicked on + table.on('click.dt', 'tbody td', function() { + changeInput('cell_clicked', cellInfo(this), null, null, {priority: 'event'}); + }) + changeInput('cell_clicked', {}); + + // do not trigger table selection when clicking on links unless they have classes + table.on('mousedown.dt', 'tbody td a', function(e) { + if (this.className === '') e.stopPropagation(); + }); + + methods.addRow = function(data, rowname, resetPaging) { + var n = table.columns().indexes().length, d = n - data.length; + if (d === 1) { + data = rowname.concat(data) + } else if (d !== 0) { + console.log(data); + console.log(table.columns().indexes()); + throw 'New data must be of the same length as current data (' + n + ')'; + }; + table.row.add(data).draw(resetPaging); + } + + methods.updateSearch = function(keywords) { + if (keywords.global !== null) + $(table.table().container()).find('input[type=search]').first() + .val(keywords.global).trigger('input'); + var columns = keywords.columns; + if (!filterRow || columns === null) return; + filterRow.toArray().map(function(td, i) { + var v = typeof columns === 'string' ? columns : columns[i]; + if (typeof v === 'undefined') { + console.log('The search keyword for column ' + i + ' is undefined') + return; + } + // Update column search string and values on linked filter widgets. + // 'input' for factor and char filters, 'change' for numeric filters. + $(td).find('input').first().val(v).trigger('input', [true]).trigger('change'); + }); + table.draw(); + } + + methods.hideCols = function(hide, reset) { + if (reset) table.columns().visible(true, false); + table.columns(hide).visible(false); + } + + methods.showCols = function(show, reset) { + if (reset) table.columns().visible(false, false); + table.columns(show).visible(true); + } + + methods.colReorder = function(order, origOrder) { + table.colReorder.order(order, origOrder); + } + + methods.selectPage = function(page) { + if (table.page.info().pages < page || page < 1) { + throw 'Selected page is out of range'; + }; + table.page(page - 1).draw(false); + } + + methods.reloadData = function(resetPaging, clearSelection) { + // empty selections first if necessary + if (methods.selectRows && inArray('row', clearSelection)) methods.selectRows([]); + if (methods.selectColumns && inArray('column', clearSelection)) methods.selectColumns([]); + if (methods.selectCells && inArray('cell', clearSelection)) methods.selectCells([]); + table.ajax.reload(null, resetPaging); + } + + // update table filters (set new limits of sliders) + methods.updateFilters = function(newProps) { + // loop through each filter in the filter row + filterRow.each(function(i, td) { + var k = i; + if (filterRow.length > newProps.length) { + if (i === 0) return; // first column is row names + k = i - 1; + } + // Update the filters to reflect the updated data. + // Allow "falsy" (e.g. NULL) to signify a no-op. + if (newProps[k]) { + setFilterProps(td, newProps[k]); + } + }); + }; + + table.shinyMethods = methods; + }, + resize: function(el, width, height, instance) { + if (instance.data) this.renderValue(el, instance.data, instance); + + // dynamically adjust height if fillContainer = TRUE + if (instance.fillContainer) + this.fillAvailableHeight(el, height); + + this.adjustWidth(el); + }, + + // dynamically set the scroll body to fill available height + // (used with fillContainer = TRUE) + fillAvailableHeight: function(el, availableHeight) { + + // see how much of the table is occupied by header/footer elements + // and use that to compute a target scroll body height + var dtWrapper = $(el).find('div.dataTables_wrapper'); + var dtScrollBody = $(el).find($('div.dataTables_scrollBody')); + var framingHeight = dtWrapper.innerHeight() - dtScrollBody.innerHeight(); + var scrollBodyHeight = availableHeight - framingHeight; + + // we need to set `max-height` to none as datatables library now sets this + // to a fixed height, disabling the ability to resize to fill the window, + // as it will be set to a fixed 100px under such circumstances, e.g., RStudio IDE, + // or FlexDashboard + // see https://github.com/rstudio/DT/issues/951#issuecomment-1026464509 + dtScrollBody.css('max-height', 'none'); + // set the height + dtScrollBody.height(scrollBodyHeight + 'px'); + }, + + // adjust the width of columns; remove the hard-coded widths on table and the + // scroll header when scrollX/Y are enabled + adjustWidth: function(el) { + var $el = $(el), table = $el.data('datatable'); + if (table) table.columns.adjust(); + $el.find('.dataTables_scrollHeadInner').css('width', '') + .children('table').css('margin-left', ''); + } +}); + + if (!HTMLWidgets.shinyMode) return; + + Shiny.addCustomMessageHandler('datatable-calls', function(data) { + var id = data.id; + var el = document.getElementById(id); + var table = el ? $(el).data('datatable') : null; + if (!table) { + console.log("Couldn't find table with id " + id); + return; + } + + var methods = table.shinyMethods, call = data.call; + if (methods[call.method]) { + methods[call.method].apply(table, call.args); + } else { + console.log("Unknown method " + call.method); + } + }); + +})(); diff --git a/docs/articles/custom-variables_files/datatables-css-0.0.0/datatables-crosstalk.css b/docs/articles/custom-variables_files/datatables-css-0.0.0/datatables-crosstalk.css new file mode 100644 index 00000000..bd1159c8 --- /dev/null +++ b/docs/articles/custom-variables_files/datatables-css-0.0.0/datatables-crosstalk.css @@ -0,0 +1,32 @@ +.dt-crosstalk-fade { + opacity: 0.2; +} + +html body div.DTS div.dataTables_scrollBody { + background: none; +} + + +/* +Fix https://github.com/rstudio/DT/issues/563 +If the `table.display` is set to "block" (e.g., pkgdown), the browser will display +datatable objects strangely. The search panel and the page buttons will still be +in full-width but the table body will be "compact" and shorter. +In therory, having this attributes will affect `dom="t"` +with `display: block` users. But in reality, there should be no one. +We may remove the below lines in the future if the upstream agree to have this there. +See https://github.com/DataTables/DataTablesSrc/issues/160 +*/ + +table.dataTable { + display: table; +} + + +/* +When DTOutput(fill = TRUE), it receives a .html-fill-item class (via htmltools::bindFillRole()), which effectively amounts to `flex: 1 1 auto`. That's mostly fine, but the case where `fillContainer=TRUE`+`height:auto`+`flex-basis:auto` and the container (e.g., a bslib::card()) doesn't have a defined height is a bit problematic since the table wants to fit the parent but the parent wants to fit the table, which results pretty small table height (maybe because there is a minimum height somewhere?). It seems better in this case to impose a 400px height default for the table, which we can do by setting `flex-basis` to 400px (the table is still allowed to grow/shrink when the container has an opinionated height). +*/ + +.html-fill-container > .html-fill-item.datatables { + flex-basis: 400px; +} diff --git a/docs/articles/custom-variables_files/dt-core-1.13.6/css/jquery.dataTables.extra.css b/docs/articles/custom-variables_files/dt-core-1.13.6/css/jquery.dataTables.extra.css new file mode 100644 index 00000000..b2dd141f --- /dev/null +++ b/docs/articles/custom-variables_files/dt-core-1.13.6/css/jquery.dataTables.extra.css @@ -0,0 +1,28 @@ +/* Selected rows/cells */ +table.dataTable tr.selected td, table.dataTable td.selected { + background-color: #b0bed9 !important; +} +/* In case of scrollX/Y or FixedHeader */ +.dataTables_scrollBody .dataTables_sizing { + visibility: hidden; +} + +/* The datatables' theme CSS file doesn't define +the color but with white background. It leads to an issue that +when the HTML's body color is set to 'white', the user can't +see the text since the background is white. One case happens in the +RStudio's IDE when inline viewing the DT table inside an Rmd file, +if the IDE theme is set to "Cobalt". + +See https://github.com/rstudio/DT/issues/447 for more info + +This fixes should have little side-effects because all the other elements +of the default theme use the #333 font color. + +TODO: The upstream may use relative colors for both the table background +and the color. It means the table can display well without this patch +then. At that time, we need to remove the below CSS attributes. +*/ +div.datatables { + color: #333; +} diff --git a/docs/articles/custom-variables_files/dt-core-1.13.6/css/jquery.dataTables.min.css b/docs/articles/custom-variables_files/dt-core-1.13.6/css/jquery.dataTables.min.css new file mode 100644 index 00000000..ad59f843 --- /dev/null +++ b/docs/articles/custom-variables_files/dt-core-1.13.6/css/jquery.dataTables.min.css @@ -0,0 +1 @@ +:root{--dt-row-selected: 13, 110, 253;--dt-row-selected-text: 255, 255, 255;--dt-row-selected-link: 9, 10, 11;--dt-row-stripe: 0, 0, 0;--dt-row-hover: 0, 0, 0;--dt-column-ordering: 0, 0, 0;--dt-html-background: white}:root.dark{--dt-html-background: rgb(33, 37, 41)}table.dataTable td.dt-control{text-align:center;cursor:pointer}table.dataTable td.dt-control:before{display:inline-block;color:rgba(0, 0, 0, 0.5);content:"►"}table.dataTable tr.dt-hasChild td.dt-control:before{content:"▼"}html.dark table.dataTable td.dt-control:before{color:rgba(255, 255, 255, 0.5)}html.dark table.dataTable tr.dt-hasChild td.dt-control:before{color:rgba(255, 255, 255, 0.5)}table.dataTable thead>tr>th.sorting,table.dataTable thead>tr>th.sorting_asc,table.dataTable thead>tr>th.sorting_desc,table.dataTable thead>tr>th.sorting_asc_disabled,table.dataTable thead>tr>th.sorting_desc_disabled,table.dataTable thead>tr>td.sorting,table.dataTable thead>tr>td.sorting_asc,table.dataTable thead>tr>td.sorting_desc,table.dataTable thead>tr>td.sorting_asc_disabled,table.dataTable thead>tr>td.sorting_desc_disabled{cursor:pointer;position:relative;padding-right:26px}table.dataTable thead>tr>th.sorting:before,table.dataTable thead>tr>th.sorting:after,table.dataTable thead>tr>th.sorting_asc:before,table.dataTable thead>tr>th.sorting_asc:after,table.dataTable thead>tr>th.sorting_desc:before,table.dataTable thead>tr>th.sorting_desc:after,table.dataTable thead>tr>th.sorting_asc_disabled:before,table.dataTable thead>tr>th.sorting_asc_disabled:after,table.dataTable thead>tr>th.sorting_desc_disabled:before,table.dataTable thead>tr>th.sorting_desc_disabled:after,table.dataTable thead>tr>td.sorting:before,table.dataTable thead>tr>td.sorting:after,table.dataTable thead>tr>td.sorting_asc:before,table.dataTable thead>tr>td.sorting_asc:after,table.dataTable thead>tr>td.sorting_desc:before,table.dataTable thead>tr>td.sorting_desc:after,table.dataTable thead>tr>td.sorting_asc_disabled:before,table.dataTable thead>tr>td.sorting_asc_disabled:after,table.dataTable thead>tr>td.sorting_desc_disabled:before,table.dataTable thead>tr>td.sorting_desc_disabled:after{position:absolute;display:block;opacity:.125;right:10px;line-height:9px;font-size:.8em}table.dataTable thead>tr>th.sorting:before,table.dataTable thead>tr>th.sorting_asc:before,table.dataTable thead>tr>th.sorting_desc:before,table.dataTable thead>tr>th.sorting_asc_disabled:before,table.dataTable thead>tr>th.sorting_desc_disabled:before,table.dataTable thead>tr>td.sorting:before,table.dataTable thead>tr>td.sorting_asc:before,table.dataTable thead>tr>td.sorting_desc:before,table.dataTable thead>tr>td.sorting_asc_disabled:before,table.dataTable thead>tr>td.sorting_desc_disabled:before{bottom:50%;content:"▲";content:"▲"/""}table.dataTable thead>tr>th.sorting:after,table.dataTable thead>tr>th.sorting_asc:after,table.dataTable thead>tr>th.sorting_desc:after,table.dataTable thead>tr>th.sorting_asc_disabled:after,table.dataTable thead>tr>th.sorting_desc_disabled:after,table.dataTable thead>tr>td.sorting:after,table.dataTable thead>tr>td.sorting_asc:after,table.dataTable thead>tr>td.sorting_desc:after,table.dataTable thead>tr>td.sorting_asc_disabled:after,table.dataTable thead>tr>td.sorting_desc_disabled:after{top:50%;content:"▼";content:"▼"/""}table.dataTable thead>tr>th.sorting_asc:before,table.dataTable thead>tr>th.sorting_desc:after,table.dataTable thead>tr>td.sorting_asc:before,table.dataTable thead>tr>td.sorting_desc:after{opacity:.6}table.dataTable thead>tr>th.sorting_desc_disabled:after,table.dataTable thead>tr>th.sorting_asc_disabled:before,table.dataTable thead>tr>td.sorting_desc_disabled:after,table.dataTable thead>tr>td.sorting_asc_disabled:before{display:none}table.dataTable thead>tr>th:active,table.dataTable thead>tr>td:active{outline:none}div.dataTables_scrollBody>table.dataTable>thead>tr>th:before,div.dataTables_scrollBody>table.dataTable>thead>tr>th:after,div.dataTables_scrollBody>table.dataTable>thead>tr>td:before,div.dataTables_scrollBody>table.dataTable>thead>tr>td:after{display:none}div.dataTables_processing{position:absolute;top:50%;left:50%;width:200px;margin-left:-100px;margin-top:-26px;text-align:center;padding:2px}div.dataTables_processing>div:last-child{position:relative;width:80px;height:15px;margin:1em auto}div.dataTables_processing>div:last-child>div{position:absolute;top:0;width:13px;height:13px;border-radius:50%;background:rgb(13, 110, 253);background:rgb(var(--dt-row-selected));animation-timing-function:cubic-bezier(0, 1, 1, 0)}div.dataTables_processing>div:last-child>div:nth-child(1){left:8px;animation:datatables-loader-1 .6s infinite}div.dataTables_processing>div:last-child>div:nth-child(2){left:8px;animation:datatables-loader-2 .6s infinite}div.dataTables_processing>div:last-child>div:nth-child(3){left:32px;animation:datatables-loader-2 .6s infinite}div.dataTables_processing>div:last-child>div:nth-child(4){left:56px;animation:datatables-loader-3 .6s infinite}@keyframes datatables-loader-1{0%{transform:scale(0)}100%{transform:scale(1)}}@keyframes datatables-loader-3{0%{transform:scale(1)}100%{transform:scale(0)}}@keyframes datatables-loader-2{0%{transform:translate(0, 0)}100%{transform:translate(24px, 0)}}table.dataTable.nowrap th,table.dataTable.nowrap td{white-space:nowrap}table.dataTable th.dt-left,table.dataTable td.dt-left{text-align:left}table.dataTable th.dt-center,table.dataTable td.dt-center,table.dataTable td.dataTables_empty{text-align:center}table.dataTable th.dt-right,table.dataTable td.dt-right{text-align:right}table.dataTable th.dt-justify,table.dataTable td.dt-justify{text-align:justify}table.dataTable th.dt-nowrap,table.dataTable td.dt-nowrap{white-space:nowrap}table.dataTable thead th,table.dataTable thead td,table.dataTable tfoot th,table.dataTable tfoot td{text-align:left}table.dataTable thead th.dt-head-left,table.dataTable thead td.dt-head-left,table.dataTable tfoot th.dt-head-left,table.dataTable tfoot td.dt-head-left{text-align:left}table.dataTable thead th.dt-head-center,table.dataTable thead td.dt-head-center,table.dataTable tfoot th.dt-head-center,table.dataTable tfoot td.dt-head-center{text-align:center}table.dataTable thead th.dt-head-right,table.dataTable thead td.dt-head-right,table.dataTable tfoot th.dt-head-right,table.dataTable tfoot td.dt-head-right{text-align:right}table.dataTable thead th.dt-head-justify,table.dataTable thead td.dt-head-justify,table.dataTable tfoot th.dt-head-justify,table.dataTable tfoot td.dt-head-justify{text-align:justify}table.dataTable thead th.dt-head-nowrap,table.dataTable thead td.dt-head-nowrap,table.dataTable tfoot th.dt-head-nowrap,table.dataTable tfoot td.dt-head-nowrap{white-space:nowrap}table.dataTable tbody th.dt-body-left,table.dataTable tbody td.dt-body-left{text-align:left}table.dataTable tbody th.dt-body-center,table.dataTable tbody td.dt-body-center{text-align:center}table.dataTable tbody th.dt-body-right,table.dataTable tbody td.dt-body-right{text-align:right}table.dataTable tbody th.dt-body-justify,table.dataTable tbody td.dt-body-justify{text-align:justify}table.dataTable tbody th.dt-body-nowrap,table.dataTable tbody td.dt-body-nowrap{white-space:nowrap}table.dataTable{width:100%;margin:0 auto;clear:both;border-collapse:separate;border-spacing:0}table.dataTable thead th,table.dataTable tfoot th{font-weight:bold}table.dataTable>thead>tr>th,table.dataTable>thead>tr>td{padding:10px;border-bottom:1px solid rgba(0, 0, 0, 0.3)}table.dataTable>thead>tr>th:active,table.dataTable>thead>tr>td:active{outline:none}table.dataTable>tfoot>tr>th,table.dataTable>tfoot>tr>td{padding:10px 10px 6px 10px;border-top:1px solid rgba(0, 0, 0, 0.3)}table.dataTable tbody tr{background-color:transparent}table.dataTable tbody tr.selected>*{box-shadow:inset 0 0 0 9999px rgba(13, 110, 253, 0.9);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.9);color:rgb(255, 255, 255);color:rgb(var(--dt-row-selected-text))}table.dataTable tbody tr.selected a{color:rgb(9, 10, 11);color:rgb(var(--dt-row-selected-link))}table.dataTable tbody th,table.dataTable tbody td{padding:8px 10px}table.dataTable.row-border>tbody>tr>th,table.dataTable.row-border>tbody>tr>td,table.dataTable.display>tbody>tr>th,table.dataTable.display>tbody>tr>td{border-top:1px solid rgba(0, 0, 0, 0.15)}table.dataTable.row-border>tbody>tr:first-child>th,table.dataTable.row-border>tbody>tr:first-child>td,table.dataTable.display>tbody>tr:first-child>th,table.dataTable.display>tbody>tr:first-child>td{border-top:none}table.dataTable.row-border>tbody>tr.selected+tr.selected>td,table.dataTable.display>tbody>tr.selected+tr.selected>td{border-top-color:#0262ef}table.dataTable.cell-border>tbody>tr>th,table.dataTable.cell-border>tbody>tr>td{border-top:1px solid rgba(0, 0, 0, 0.15);border-right:1px solid rgba(0, 0, 0, 0.15)}table.dataTable.cell-border>tbody>tr>th:first-child,table.dataTable.cell-border>tbody>tr>td:first-child{border-left:1px solid rgba(0, 0, 0, 0.15)}table.dataTable.cell-border>tbody>tr:first-child>th,table.dataTable.cell-border>tbody>tr:first-child>td{border-top:none}table.dataTable.stripe>tbody>tr.odd>*,table.dataTable.display>tbody>tr.odd>*{box-shadow:inset 0 0 0 9999px rgba(0, 0, 0, 0.023);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-stripe), 0.023)}table.dataTable.stripe>tbody>tr.odd.selected>*,table.dataTable.display>tbody>tr.odd.selected>*{box-shadow:inset 0 0 0 9999px rgba(13, 110, 253, 0.923);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.923)}table.dataTable.hover>tbody>tr:hover>*,table.dataTable.display>tbody>tr:hover>*{box-shadow:inset 0 0 0 9999px rgba(0, 0, 0, 0.035);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-hover), 0.035)}table.dataTable.hover>tbody>tr.selected:hover>*,table.dataTable.display>tbody>tr.selected:hover>*{box-shadow:inset 0 0 0 9999px #0d6efd !important;box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 1) !important}table.dataTable.order-column>tbody tr>.sorting_1,table.dataTable.order-column>tbody tr>.sorting_2,table.dataTable.order-column>tbody tr>.sorting_3,table.dataTable.display>tbody tr>.sorting_1,table.dataTable.display>tbody tr>.sorting_2,table.dataTable.display>tbody tr>.sorting_3{box-shadow:inset 0 0 0 9999px rgba(0, 0, 0, 0.019);box-shadow:inset 0 0 0 9999px rgba(var(--dt-column-ordering), 0.019)}table.dataTable.order-column>tbody tr.selected>.sorting_1,table.dataTable.order-column>tbody tr.selected>.sorting_2,table.dataTable.order-column>tbody tr.selected>.sorting_3,table.dataTable.display>tbody tr.selected>.sorting_1,table.dataTable.display>tbody tr.selected>.sorting_2,table.dataTable.display>tbody tr.selected>.sorting_3{box-shadow:inset 0 0 0 9999px rgba(13, 110, 253, 0.919);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.919)}table.dataTable.display>tbody>tr.odd>.sorting_1,table.dataTable.order-column.stripe>tbody>tr.odd>.sorting_1{box-shadow:inset 0 0 0 9999px rgba(0, 0, 0, 0.054);box-shadow:inset 0 0 0 9999px rgba(var(--dt-column-ordering), 0.054)}table.dataTable.display>tbody>tr.odd>.sorting_2,table.dataTable.order-column.stripe>tbody>tr.odd>.sorting_2{box-shadow:inset 0 0 0 9999px rgba(0, 0, 0, 0.047);box-shadow:inset 0 0 0 9999px rgba(var(--dt-column-ordering), 0.047)}table.dataTable.display>tbody>tr.odd>.sorting_3,table.dataTable.order-column.stripe>tbody>tr.odd>.sorting_3{box-shadow:inset 0 0 0 9999px rgba(0, 0, 0, 0.039);box-shadow:inset 0 0 0 9999px rgba(var(--dt-column-ordering), 0.039)}table.dataTable.display>tbody>tr.odd.selected>.sorting_1,table.dataTable.order-column.stripe>tbody>tr.odd.selected>.sorting_1{box-shadow:inset 0 0 0 9999px rgba(13, 110, 253, 0.954);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.954)}table.dataTable.display>tbody>tr.odd.selected>.sorting_2,table.dataTable.order-column.stripe>tbody>tr.odd.selected>.sorting_2{box-shadow:inset 0 0 0 9999px rgba(13, 110, 253, 0.947);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.947)}table.dataTable.display>tbody>tr.odd.selected>.sorting_3,table.dataTable.order-column.stripe>tbody>tr.odd.selected>.sorting_3{box-shadow:inset 0 0 0 9999px rgba(13, 110, 253, 0.939);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.939)}table.dataTable.display>tbody>tr.even>.sorting_1,table.dataTable.order-column.stripe>tbody>tr.even>.sorting_1{box-shadow:inset 0 0 0 9999px rgba(0, 0, 0, 0.019);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.019)}table.dataTable.display>tbody>tr.even>.sorting_2,table.dataTable.order-column.stripe>tbody>tr.even>.sorting_2{box-shadow:inset 0 0 0 9999px rgba(0, 0, 0, 0.011);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.011)}table.dataTable.display>tbody>tr.even>.sorting_3,table.dataTable.order-column.stripe>tbody>tr.even>.sorting_3{box-shadow:inset 0 0 0 9999px rgba(0, 0, 0, 0.003);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.003)}table.dataTable.display>tbody>tr.even.selected>.sorting_1,table.dataTable.order-column.stripe>tbody>tr.even.selected>.sorting_1{box-shadow:inset 0 0 0 9999px rgba(13, 110, 253, 0.919);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.919)}table.dataTable.display>tbody>tr.even.selected>.sorting_2,table.dataTable.order-column.stripe>tbody>tr.even.selected>.sorting_2{box-shadow:inset 0 0 0 9999px rgba(13, 110, 253, 0.911);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.911)}table.dataTable.display>tbody>tr.even.selected>.sorting_3,table.dataTable.order-column.stripe>tbody>tr.even.selected>.sorting_3{box-shadow:inset 0 0 0 9999px rgba(13, 110, 253, 0.903);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.903)}table.dataTable.display tbody tr:hover>.sorting_1,table.dataTable.order-column.hover tbody tr:hover>.sorting_1{box-shadow:inset 0 0 0 9999px rgba(0, 0, 0, 0.082);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-hover), 0.082)}table.dataTable.display tbody tr:hover>.sorting_2,table.dataTable.order-column.hover tbody tr:hover>.sorting_2{box-shadow:inset 0 0 0 9999px rgba(0, 0, 0, 0.074);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-hover), 0.074)}table.dataTable.display tbody tr:hover>.sorting_3,table.dataTable.order-column.hover tbody tr:hover>.sorting_3{box-shadow:inset 0 0 0 9999px rgba(0, 0, 0, 0.062);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-hover), 0.062)}table.dataTable.display tbody tr:hover.selected>.sorting_1,table.dataTable.order-column.hover tbody tr:hover.selected>.sorting_1{box-shadow:inset 0 0 0 9999px rgba(13, 110, 253, 0.982);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.982)}table.dataTable.display tbody tr:hover.selected>.sorting_2,table.dataTable.order-column.hover tbody tr:hover.selected>.sorting_2{box-shadow:inset 0 0 0 9999px rgba(13, 110, 253, 0.974);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.974)}table.dataTable.display tbody tr:hover.selected>.sorting_3,table.dataTable.order-column.hover tbody tr:hover.selected>.sorting_3{box-shadow:inset 0 0 0 9999px rgba(13, 110, 253, 0.962);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.962)}table.dataTable.no-footer{border-bottom:1px solid rgba(0, 0, 0, 0.3)}table.dataTable.compact thead th,table.dataTable.compact thead td,table.dataTable.compact tfoot th,table.dataTable.compact tfoot td,table.dataTable.compact tbody th,table.dataTable.compact tbody td{padding:4px}table.dataTable th,table.dataTable td{box-sizing:content-box}.dataTables_wrapper{position:relative;clear:both}.dataTables_wrapper .dataTables_length{float:left}.dataTables_wrapper .dataTables_length select{border:1px solid #aaa;border-radius:3px;padding:5px;background-color:transparent;color:inherit;padding:4px}.dataTables_wrapper .dataTables_filter{float:right;text-align:right}.dataTables_wrapper .dataTables_filter input{border:1px solid #aaa;border-radius:3px;padding:5px;background-color:transparent;color:inherit;margin-left:3px}.dataTables_wrapper .dataTables_info{clear:both;float:left;padding-top:.755em}.dataTables_wrapper .dataTables_paginate{float:right;text-align:right;padding-top:.25em}.dataTables_wrapper .dataTables_paginate .paginate_button{box-sizing:border-box;display:inline-block;min-width:1.5em;padding:.5em 1em;margin-left:2px;text-align:center;text-decoration:none !important;cursor:pointer;color:inherit !important;border:1px solid transparent;border-radius:2px;background:transparent}.dataTables_wrapper .dataTables_paginate .paginate_button.current,.dataTables_wrapper .dataTables_paginate .paginate_button.current:hover{color:inherit !important;border:1px solid rgba(0, 0, 0, 0.3);background-color:rgba(0, 0, 0, 0.05);background:-webkit-gradient(linear, left top, left bottom, color-stop(0%, rgba(230, 230, 230, 0.05)), color-stop(100%, rgba(0, 0, 0, 0.05)));background:-webkit-linear-gradient(top, rgba(230, 230, 230, 0.05) 0%, rgba(0, 0, 0, 0.05) 100%);background:-moz-linear-gradient(top, rgba(230, 230, 230, 0.05) 0%, rgba(0, 0, 0, 0.05) 100%);background:-ms-linear-gradient(top, rgba(230, 230, 230, 0.05) 0%, rgba(0, 0, 0, 0.05) 100%);background:-o-linear-gradient(top, rgba(230, 230, 230, 0.05) 0%, rgba(0, 0, 0, 0.05) 100%);background:linear-gradient(to bottom, rgba(230, 230, 230, 0.05) 0%, rgba(0, 0, 0, 0.05) 100%)}.dataTables_wrapper .dataTables_paginate .paginate_button.disabled,.dataTables_wrapper .dataTables_paginate .paginate_button.disabled:hover,.dataTables_wrapper .dataTables_paginate .paginate_button.disabled:active{cursor:default;color:#666 !important;border:1px solid transparent;background:transparent;box-shadow:none}.dataTables_wrapper .dataTables_paginate .paginate_button:hover{color:white !important;border:1px solid #111;background-color:#111;background:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #585858), color-stop(100%, #111));background:-webkit-linear-gradient(top, #585858 0%, #111 100%);background:-moz-linear-gradient(top, #585858 0%, #111 100%);background:-ms-linear-gradient(top, #585858 0%, #111 100%);background:-o-linear-gradient(top, #585858 0%, #111 100%);background:linear-gradient(to bottom, #585858 0%, #111 100%)}.dataTables_wrapper .dataTables_paginate .paginate_button:active{outline:none;background-color:#0c0c0c;background:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #2b2b2b), color-stop(100%, #0c0c0c));background:-webkit-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);background:-moz-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);background:-ms-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);background:-o-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);background:linear-gradient(to bottom, #2b2b2b 0%, #0c0c0c 100%);box-shadow:inset 0 0 3px #111}.dataTables_wrapper .dataTables_paginate .ellipsis{padding:0 1em}.dataTables_wrapper .dataTables_length,.dataTables_wrapper .dataTables_filter,.dataTables_wrapper .dataTables_info,.dataTables_wrapper .dataTables_processing,.dataTables_wrapper .dataTables_paginate{color:inherit}.dataTables_wrapper .dataTables_scroll{clear:both}.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody{-webkit-overflow-scrolling:touch}.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>thead>tr>th,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>thead>tr>td,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>tbody>tr>th,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>tbody>tr>td{vertical-align:middle}.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>thead>tr>th>div.dataTables_sizing,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>thead>tr>td>div.dataTables_sizing,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>tbody>tr>th>div.dataTables_sizing,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>tbody>tr>td>div.dataTables_sizing{height:0;overflow:hidden;margin:0 !important;padding:0 !important}.dataTables_wrapper.no-footer .dataTables_scrollBody{border-bottom:1px solid rgba(0, 0, 0, 0.3)}.dataTables_wrapper.no-footer div.dataTables_scrollHead table.dataTable,.dataTables_wrapper.no-footer div.dataTables_scrollBody>table{border-bottom:none}.dataTables_wrapper:after{visibility:hidden;display:block;content:"";clear:both;height:0}@media screen and (max-width: 767px){.dataTables_wrapper .dataTables_info,.dataTables_wrapper .dataTables_paginate{float:none;text-align:center}.dataTables_wrapper .dataTables_paginate{margin-top:.5em}}@media screen and (max-width: 640px){.dataTables_wrapper .dataTables_length,.dataTables_wrapper .dataTables_filter{float:none;text-align:center}.dataTables_wrapper .dataTables_filter{margin-top:.5em}}html.dark{--dt-row-hover: 255, 255, 255;--dt-row-stripe: 255, 255, 255;--dt-column-ordering: 255, 255, 255}html.dark table.dataTable>thead>tr>th,html.dark table.dataTable>thead>tr>td{border-bottom:1px solid rgb(89, 91, 94)}html.dark table.dataTable>thead>tr>th:active,html.dark table.dataTable>thead>tr>td:active{outline:none}html.dark table.dataTable>tfoot>tr>th,html.dark table.dataTable>tfoot>tr>td{border-top:1px solid rgb(89, 91, 94)}html.dark table.dataTable.row-border>tbody>tr>th,html.dark table.dataTable.row-border>tbody>tr>td,html.dark table.dataTable.display>tbody>tr>th,html.dark table.dataTable.display>tbody>tr>td{border-top:1px solid rgb(64, 67, 70)}html.dark table.dataTable.row-border>tbody>tr.selected+tr.selected>td,html.dark table.dataTable.display>tbody>tr.selected+tr.selected>td{border-top-color:#0257d5}html.dark table.dataTable.cell-border>tbody>tr>th,html.dark table.dataTable.cell-border>tbody>tr>td{border-top:1px solid rgb(64, 67, 70);border-right:1px solid rgb(64, 67, 70)}html.dark table.dataTable.cell-border>tbody>tr>th:first-child,html.dark table.dataTable.cell-border>tbody>tr>td:first-child{border-left:1px solid rgb(64, 67, 70)}html.dark .dataTables_wrapper .dataTables_filter input,html.dark .dataTables_wrapper .dataTables_length select{border:1px solid rgba(255, 255, 255, 0.2);background-color:var(--dt-html-background)}html.dark .dataTables_wrapper .dataTables_paginate .paginate_button.current,html.dark .dataTables_wrapper .dataTables_paginate .paginate_button.current:hover{border:1px solid rgb(89, 91, 94);background:rgba(255, 255, 255, 0.15)}html.dark .dataTables_wrapper .dataTables_paginate .paginate_button.disabled,html.dark .dataTables_wrapper .dataTables_paginate .paginate_button.disabled:hover,html.dark .dataTables_wrapper .dataTables_paginate .paginate_button.disabled:active{color:#666 !important}html.dark .dataTables_wrapper .dataTables_paginate .paginate_button:hover{border:1px solid rgb(53, 53, 53);background:rgb(53, 53, 53)}html.dark .dataTables_wrapper .dataTables_paginate .paginate_button:active{background:#3a3a3a} diff --git a/docs/articles/custom-variables_files/dt-core-1.13.6/js/jquery.dataTables.min.js b/docs/articles/custom-variables_files/dt-core-1.13.6/js/jquery.dataTables.min.js new file mode 100644 index 00000000..f786b0da --- /dev/null +++ b/docs/articles/custom-variables_files/dt-core-1.13.6/js/jquery.dataTables.min.js @@ -0,0 +1,4 @@ +/*! DataTables 1.13.6 + * ©2008-2023 SpryMedia Ltd - datatables.net/license + */ +!function(n){"use strict";var a;"function"==typeof define&&define.amd?define(["jquery"],function(t){return n(t,window,document)}):"object"==typeof exports?(a=require("jquery"),"undefined"==typeof window?module.exports=function(t,e){return t=t||window,e=e||a(t),n(e,t,t.document)}:n(a,window,window.document)):window.DataTable=n(jQuery,window,document)}(function(P,j,v,H){"use strict";function d(t){var e=parseInt(t,10);return!isNaN(e)&&isFinite(t)?e:null}function l(t,e,n){var a=typeof t,r="string"==a;return"number"==a||"bigint"==a||!!h(t)||(e&&r&&(t=$(t,e)),n&&r&&(t=t.replace(q,"")),!isNaN(parseFloat(t))&&isFinite(t))}function a(t,e,n){var a;return!!h(t)||(h(a=t)||"string"==typeof a)&&!!l(t.replace(V,"").replace(/ + - - + +
@@ -122,119 +113,161 @@

Derived variables

- Source: vignettes/derived_variables.Rmd + Source: vignettes/derived_variables.Rmd
-
-

-Introduction

-

recodeflow supports the use of derived variables. Derived variables can be any custom function as long as the variable can be calculated on a per row basis. Functions requiring operations across rows or on the full data set are not supported.

+
+

Introduction +

+

recodeflow supports the use of derived variables. Derived +variables can be any custom function as long as the variable can be +calculated on a per row basis. Functions requiring operations across +rows or on the full data set are not supported.

The two most common uses for derived variables are:

  • Variables derived from two or more variables,
  • -
  • Variables that are derived using math equations (e.g., BMI is calculated by dividing weight by the square of height).
  • +
  • Variables that are derived using math equations (e.g., BMI is +calculated by dividing weight by the square of height).

To create derived variables, you need to complete two steps:

  1. Create and load a customized function.
  2. -
  3. Add the derived variable to the variable_details and variables worksheets.
  4. +
  5. Add the derived variable to the variable_details and variables +worksheets.
-
-

-Example of a derived function

-

We’ll walk through an example of creating a derived variable with our example data.

-

Our customized derived function is multiplying the blood concentration of cholesterol (chol) with the blood concentration of bilirunbin (bili).

-
-

-1. Create and load a customized function for your derived variables.

-

Create the custom function: Here is the customized function for our derived variable (chol*bili):

+
+

Example of a derived function +

+

We’ll walk through an example of creating a derived variable with our +example data.

+

Our customized derived function is multiplying the blood +concentration of cholesterol (chol) with the blood +concentration of bilirunbin (bili).

+
+

1. Create and load a customized function for your derived +variables. +

+

Create the custom function: Here is the customized +function for our derived variable +(chol*bili):

-#example_der_fun caluclates chol*bili
-#@param chol the row value for chol
-#@param bili the row value for bili
-#@export 
-example_der_fun <- function(chol, bili){
-  # as numeric is used to coerce in case categorical numeric variables are used.
-  # Warning either chol or bili being NA will result in NA return
-  example_der <- as.numeric(chol)*as.numeric(bili)
-  
-  return(example_der)
-}
-

Note: You must use roxygen2 documentation for custom functions otherwise the function cannot be attached to a package. See roxygen2 on how to format and document your function.

-

Load the custom function into your R environment. Load the customized function by either:

+#example_der_fun caluclates chol*bili +#@param chol the row value for chol +#@param bili the row value for bili +#@export +example_der_fun <- function(chol, bili){ + # as numeric is used to coerce in case categorical numeric variables are used. + # Warning either chol or bili being NA will result in NA return + example_der <- as.numeric(chol)*as.numeric(bili) + + return(example_der) +}
+

Note: You must use roxygen2 +documentation for custom functions otherwise the function cannot be +attached to a package. See roxygen2 +on how to format and document your function.

+

Load the custom function into your R environment. +Load the customized function by either:

    -
  • entering your functions into the console and running the code, or
  • -
  • attaching the functions to your own package using the build and install tool. Then load your package using “library(”name of package“)” or by using the rec_with_table parameter to pass the path to your function R script.
  • +
  • entering your functions into the console and running the code, +or
  • +
  • attaching the functions to your own package using the build and +install tool. Then load your package using “library(”name of package”)” +or by using the rec_with_table parameter to pass the path +to your function R script.
-

If you don’t load the customized function you cannot create the derived variable.

+

If you don’t load the customized function you cannot create the +derived variable.

-
-

-2. Add the derived variable to the variable_details and variables worksheets.

-

Add the derived variable to the variables worksheet. You’ll use the same nomenclature as any other variable. See the article variables_sheet for nomenclature rules.

-

Add the derived variable to the variable_details. See the article variable_details for nomenclature rules.

+
+

2. Add the derived variable to the variable_details and +variables worksheets. +

+

Add the derived variable to the variables worksheet. +You’ll use the same nomenclature as any other variable. See the article +variables_sheet +for nomenclature rules.

+

Add the derived variable to the variable_details. See the article variable_details +for nomenclature rules.

-
-

-3. Recode the derived variable

-

Use the function rec_with_table to recode your derived function.

+
+

3. Recode the derived variable +

+

Use the function rec_with_table to recode your derived +function.

  1. Load recodeflow
-#Load the package
-library(recodeflow)
+#Load the package +library(recodeflow)
    -
  1. Recode the underlying variables (chol and bili) and the derived variable (example_der).
  2. +
  3. Recode the underlying variables (chol and +bili) and the derived variable +(example_der).
-derived1 <- rec_with_table(data = tester1,
-                          variables = c("chol", "bili","example_der"),
-                          variable_details = variable_details,
-                          log = TRUE)
-
## Using the passed data variable name as database_name
-
## NOTE for bili: This is sample survival pbc data
-
## The variable bili was recoded into bili for the database tester1 the following recodes were made:
-
##   value_to   From rows_recoded
-## 1     copy [0,28]          209
-## 2     <NA>   else            0
-
## NOTE for chol: This is sample survival pbc data
-
## NOTE for chol: This is sample survival pbc data
-
## The variable chol was recoded into chol for the database tester1 the following recodes were made:
-
##   value_to        From rows_recoded
-## 1     copy [120, 1775]          186
-## 2    Na::a          NA            0
-## 3     <NA>        else           23
+derived1 <- rec_with_table( + data = pbc, + variables = c("chol", "bili","example_der"), + variable_details = recodeflow::tester_variable_details, + database_name = 'tester1', + log = TRUE)
+
## The variable bili was recoded into bili for the database tester1 the following recodes were made:
+
## # A tibble: 2 × 3
+##   value_to From    rows_recoded
+##   <chr>    <chr>          <int>
+## 1 copy     [0,100]          418
+## 2 NA       else               0
+
## The variable chol was recoded into chol for the database tester1 the following recodes were made:
+
## # A tibble: 3 × 3
+##   value_to From       rows_recoded
+##   <chr>    <chr>             <int>
+## 1 copy     [100,2000]          284
+## 2 NA::a    9999                  0
+## 3 NA       else                134
+
+print(head(derived1))
+
##   bili chol example_der
+## 1 14.5  261      3784.5
+## 2  1.1  302       332.2
+## 3  1.4  176       246.4
+## 4  1.8  244       439.2
+## 5  3.4  279       948.6
+## 6  0.8  248       198.4
+ +
-

Site built with pkgdown 1.6.1.

+

+

Site built with pkgdown 2.1.1.

- + + + diff --git a/docs/articles/derived_variables_files/header-attrs-2.29/header-attrs.js b/docs/articles/derived_variables_files/header-attrs-2.29/header-attrs.js new file mode 100644 index 00000000..dd57d92e --- /dev/null +++ b/docs/articles/derived_variables_files/header-attrs-2.29/header-attrs.js @@ -0,0 +1,12 @@ +// Pandoc 2.9 adds attributes on both header and div. We remove the former (to +// be compatible with the behavior of Pandoc < 2.8). +document.addEventListener('DOMContentLoaded', function(e) { + var hs = document.querySelectorAll("div.section[class*='level'] > :first-child"); + var i, h, a; + for (i = 0; i < hs.length; i++) { + h = hs[i]; + if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6 + a = h.attributes; + while (a.length > 0) h.removeAttribute(a[0].name); + } +}); diff --git a/docs/articles/how_to_install.html b/docs/articles/how_to_install.html index 90e9fc43..b2d16ccf 100644 --- a/docs/articles/how_to_install.html +++ b/docs/articles/how_to_install.html @@ -5,27 +5,27 @@ -Install • recodeflow +How to install recodeflow • recodeflow - + - - - + + +
-
-

-Install and load recodeflow -

-
-

-Install recodeflow +
+

Install and load recodeflow

+
+

Install recodeflow +

-# Install release version from CRAN
-install.packages("recodeflow")
-
-# Install the most recent version from GitHub
-devtools::install_github("Big-Life-Lab/recodeflow")
+# Install release version from CRAN +install.packages("recodeflow") + +# Install the most recent version from GitHub +devtools::install_github("Big-Life-Lab/recodeflow")
-
-

-Load recodeflow -

+
+

Load recodeflow +

-#Load the package
-library(recodeflow)
+#Load the package +library(recodeflow)
-
-

-Additional packages

-

Depending on how you use recodeflow you may need to load the following packages:

+
+

Additional packages +

+

Depending on how you use recodeflow you may need to load +the following packages:

  • dplyr: to combine datasets
  • tidyr: to reorganize datasets
  • @@ -169,26 +158,29 @@

+ +

-

Site built with pkgdown 1.6.1.

+

+

Site built with pkgdown 2.1.1.

- + + + diff --git a/docs/articles/how_to_install_files/header-attrs-2.29/header-attrs.js b/docs/articles/how_to_install_files/header-attrs-2.29/header-attrs.js new file mode 100644 index 00000000..dd57d92e --- /dev/null +++ b/docs/articles/how_to_install_files/header-attrs-2.29/header-attrs.js @@ -0,0 +1,12 @@ +// Pandoc 2.9 adds attributes on both header and div. We remove the former (to +// be compatible with the behavior of Pandoc < 2.8). +document.addEventListener('DOMContentLoaded', function(e) { + var hs = document.querySelectorAll("div.section[class*='level'] > :first-child"); + var i, h, a; + for (i = 0; i < hs.length; i++) { + h = hs[i]; + if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6 + a = h.attributes; + while (a.length > 0) h.removeAttribute(a[0].name); + } +}); diff --git a/docs/articles/how_to_recode.html b/docs/articles/how_to_recode.html index a15e4cd2..c820a410 100644 --- a/docs/articles/how_to_recode.html +++ b/docs/articles/how_to_recode.html @@ -5,27 +5,27 @@ -Recode variables • recodeflow +How to recode variables • recodeflow - + - - - + + +
-

We have examples to demonstrate how to recode variables with the recodeflow function rec_with_table()

+

We have examples to demonstrate how to recode variables with the +recodeflow function rec_with_table()

Our examples use following packages:

Package recodeflow

Steps on how to install recodeflow are in how to install

-#Load the package
-library(recodeflow)
-

Package dplyr to combine datasets (function: bind_rows).

+#Load the package +library(recodeflow)
+

Package dplyr +to combine datasets (function: bind_rows).

+library(dplyr)

Our examples use example data

-

Our examples use the dataset pbc from the package survival. We’ve split this dataset in two (tester1 and tester2) to mimic real data e.g., the same survey preformed in separate years. For our examples, we’ve also added columns (agegrp5 and agegrp10) to this dataset.

-
-

-Example 1. Recode a single variable from a single dataset

-

In our example datasets, the variable sex contains the values: m for males and f for females.

-

Using dataset tester1, we’ll recode the variable sex into a harmonized sex variable. The harmonized sex variable has the values: 0 for males and 1 for females.

+

Our examples use the dataset pbc from the package survival. +We’ve split this dataset in two (tester1 and tester2) to mimic real data +e.g., the same survey preformed in separate years. For our examples, +we’ve also added columns (agegrp5 and +agegrp10) to this dataset.

+
+test1 <- survival::pbc[1:209,]
+test2 <- survival::pbc[210:418,]
+
+#Adapting the data for How To examples. Breaking cont age variable into categories - 5 and 10 year age groups.
+agegrp <- cut(test1$age, breaks = c(25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80), right = FALSE)
+agegrp <- as.numeric(agegrp)
+tester1 <- cbind(test1, agegrp)
+
+agegrp <- cut(test2$age, breaks = c(20, 30, 40, 50, 60, 70, 80), right = FALSE)
+agegrp <- as.numeric(agegrp)
+tester2 <- cbind(test2, agegrp)
+
+

Example 1. Recode a single variable from a single dataset +

+

In our example datasets, the variable sex contains the +values: m for males and f for females.

+

Using dataset tester1, we’ll recode the variable sex +into a harmonized sex variable. The harmonized +sex variable has the values: 0 for males and 1 for +females.

  1. Recode the sex variable in tester1.
-
-sex_1 <- rec_with_table(data = tester1, 
-                        variables = "sex", 
-                        variable_details = variable_details,
-                        log = TRUE,
-                        var_labels = c(sex = "sex")
-                        )
-#> Using the passed data variable name as database_name
-#> Warning in recode_call(variables = variables, data = data, database_name
-#> = database_name, : is missing from variable details therefore cannot be
-#> recoded
-#> NOTE for sex: This is sample survival pbc data
-#> NOTE for sex: This is sample survival pbc data
-#> The variable sex was recoded into sex for the database tester1 the following recodes were made:
-#>   value_to From rows_recoded
-#> 1        0    m           27
-#> 2        1    f          182
-#> 3    NA(b) else            0
-
#>   sex
-#> 1   1
-#> 2   1
-#> 3   0
-#> 4   1
-#> 5   1
-#> 6   1
+
+sex_1 <- rec_with_table(data = tester1, 
+                        variables = "sex", 
+                        variable_details = recodeflow::tester_variable_details,
+                        log = TRUE,
+                        var_labels = c(sex = "sex"),
+                        database_name = 'tester1'
+                        )
+#> The variable sex was recoded into sex for the database tester1 the following recodes were made:
+#> # A tibble: 4 × 3
+#>   value_to From  rows_recoded
+#>   <chr>    <chr>        <int>
+#> 1 m        m               27
+#> 2 f        f              182
+#> 3 NA::a    9                0
+#> 4 NA(b)    else             0
+
#>   sex
+#> 1   f
+#> 2   f
+#> 3   m
+#> 4   f
+#> 5   f
+#> 6   f
-
-

-Example 2. Recode a single variable across multiple datasets

-

We’ll recode and combine the variable sex for our two datasets.

+
+

Example 2. Recode a single variable across multiple datasets +

+

We’ll recode and combine the variable sex for our two +datasets.

  1. Recode the sex variable in tester1 and tester2.
-
-sex_1 <- rec_with_table(data = tester1, 
-                        variables = "sex", 
-                        variable_details = variable_details, 
-                        log = TRUE,
-                        var_labels = c(sex = "Sex")
-                        )
-#> Using the passed data variable name as database_name
-#> NOTE for sex: This is sample survival pbc data
-#> NOTE for sex: This is sample survival pbc data
-#> The variable sex was recoded into sex for the database tester1 the following recodes were made:
-#>   value_to From rows_recoded
-#> 1        0    m           27
-#> 2        1    f          182
-#> 3    NA(b) else            0
-head(sex_1)
-#>   sex
-#> 1   1
-#> 2   1
-#> 3   0
-#> 4   1
-#> 5   1
-#> 6   1
-
-sex_2 <- rec_with_table(data = tester2, 
-                        variables = "sex", 
-                        variable_details = variable_details, 
-                        log = TRUE,
-                        var_labels = c(sex = "Sex")
-                        )
-#> Using the passed data variable name as database_name
-#> NOTE for sex: This is sample survival pbc data
-#> NOTE for sex: This is sample survival pbc data
-#> The variable sex was recoded into sex for the database tester2 the following recodes were made:
-#>   value_to From rows_recoded
-#> 1        0    m           17
-#> 2        1    f          192
-#> 3    NA(b) else            0
-tail(sex_2)
-#>     sex
-#> 413   1
-#> 414   1
-#> 415   1
-#> 416   1
-#> 417   1
-#> 418   1
+
+sex_1 <- rec_with_table(data = tester1, 
+                        variables = "sex", 
+                        variable_details = recodeflow::tester_variable_details,
+                        log = TRUE,
+                        var_labels = c(sex = "Sex"),
+                        database_name = 'tester1'
+                        )
+#> The variable sex was recoded into sex for the database tester1 the following recodes were made:
+#> # A tibble: 4 × 3
+#>   value_to From  rows_recoded
+#>   <chr>    <chr>        <int>
+#> 1 m        m               27
+#> 2 f        f              182
+#> 3 NA::a    9                0
+#> 4 NA(b)    else             0
+head(sex_1)
+#>   sex
+#> 1   f
+#> 2   f
+#> 3   m
+#> 4   f
+#> 5   f
+#> 6   f
+
+sex_2 <- rec_with_table(data = tester2, 
+                        variables = "sex", 
+                        variable_details = recodeflow::tester_variable_details,
+                        log = TRUE,
+                        var_labels = c(sex = "Sex"),
+                        database_name = 'tester2'
+                        )
+#> The variable sex was recoded into sex for the database tester2 the following recodes were made:
+#> # A tibble: 4 × 3
+#>   value_to From  rows_recoded
+#>   <chr>    <chr>        <int>
+#> 1 m        m               17
+#> 2 f        f              192
+#> 3 NA::a    9                0
+#> 4 NA(b)    else             0
+tail(sex_2)
+#>     sex
+#> 413   f
+#> 414   f
+#> 415   f
+#> 416   f
+#> 417   f
+#> 418   f
    -
  1. Combine the harmonized sex variable from tester1 to the harmonized sex variable in tester2.
  2. +
  3. Combine the harmonized sex variable from tester1 to the harmonized +sex variable in tester2.
-
-sex_combined <- bind_rows(sex_1, sex_2)
-
#>   sex
-#> 1   1
-#> 2   1
-#> 3   0
-#> 4   1
-#> 5   1
-#> 6   1
-#>     sex
-#> 413   1
-#> 414   1
-#> 415   1
-#> 416   1
-#> 417   1
-#> 418   1
+
+sex_combined <- bind_rows(sex_1, sex_2)
+
#>   sex
+#> 1   f
+#> 2   f
+#> 3   m
+#> 4   f
+#> 5   f
+#> 6   f
+#>     sex
+#> 413   f
+#> 414   f
+#> 415   f
+#> 416   f
+#> 417   f
+#> 418   f
  1. Set labels

Labels are lost during the database merging.

-

Use set_data_labels() to label the variables in your final dataset. set_data_labels() sets the labels with the original information in variables and variable_details.

-
-labeled_sex_combined <- set_data_labels(
-  data_to_label = sex_combined,
-  variable_details = variable_details,
-  variables_sheet = variables
-)
+

Use set_data_labels() to label the variables in your +final dataset. set_data_labels() sets the labels with the +original information in variables and +variable_details.

+
+labeled_sex_combined <- set_data_labels(
+  data_to_label = sex_combined,
+  variable_details = recodeflow::tester_variable_details,
+  variables_sheet = recodeflow::tester_variables
+)
-
-

-Example 3. Recode a single variable, with different categories, from multiple datasets

-

You could have a situation where a variable is the same across datasets but its categories change.

-

In our example data the variable agegrp is different in tester1 and tester2.

+
+

Example 3. Recode a single variable, with different categories, from +multiple datasets +

+

You could have a situation where a variable is the same across +datasets but its categories change.

+

In our example data the variable agegrp is different in +tester1 and tester2.

    -
  • In tester1 the agegrp variable is 5-year age groups: 20-24, 25-29, 30-34, etc.
  • -
  • In tester2 the agegrp variable is 10-year age groups: 20-29, 30-39, 40-49, etc.
  • +
  • In tester1 the agegrp variable is 5-year age groups: +20-24, 25-29, 30-34, etc.
  • +
  • In tester2 the agegrp variable is 10-year age groups: +20-29, 30-39, 40-49, etc.
-

There are three options to facilitate the use of variables with inconsistent categories across datasets.

-
-

-Option 1: recode category agegrp variable into a common variable for only datasets with the same category responses

-

Recode the agegrp variable into a common variable only in datasets were the categories are the same. If the categories are different between datasets, separate columns will be created.

-

The categories in the agegrp variable in tester1 are different than the categories of agegrp in tester2. Therefore, it is not possible to have the same agegrp categories across our example data sets.

+

There are three options to facilitate the use of variables with +inconsistent categories across datasets.

+
+

Option 1: recode category agegrp variable into a common +variable for only datasets with the same category responses +

+

Recode the agegrp variable into a common variable only +in datasets were the categories are the same. If the categories are +different between datasets, separate columns will be created.

+

The categories in the agegrp variable in tester1 are +different than the categories of agegrp in tester2. +Therefore, it is not possible to have the same agegrp +categories across our example data sets.

    -
  1. Recode agegrp5 in tester1 and recode agegrp10 in tester2.
  2. +
  3. Recode agegrp5 in tester1 and recode +agegrp10 in tester2.
-
-agegrp_1 <- rec_with_table(data = tester1, 
-                           variables = "agegrp5", 
-                           variable_details = variable_details, 
-                           log = TRUE, 
-                           )
-#> Using the passed data variable name as database_name
-#> NOTE for agegrp5: adapted from sample survival pbc data
-#> NOTE for agegrp5: adapted from sample survival pbc data
-#> NOTE for agegrp5: adapted from sample survival pbc data
-#> NOTE for agegrp5: adapted from sample survival pbc data
-#> NOTE for agegrp5: adapted from sample survival pbc data
-#> NOTE for agegrp5: adapted from sample survival pbc data
-#> NOTE for agegrp5: adapted from sample survival pbc data
-#> NOTE for agegrp5: adapted from sample survival pbc data
-#> NOTE for agegrp5: adapted from sample survival pbc data
-#> NOTE for agegrp5: adapted from sample survival pbc data
-#> NOTE for agegrp5: adapted from sample survival pbc data
-#> NOTE for agegrp5: adapted from sample survival pbc data
-#> The variable agegrp was recoded into agegrp5 for the database tester1 the following recodes were made:
-#>    value_to  From rows_recoded
-#> 1         1     1            2
-#> 2         2     2           12
-#> 3         3     3           15
-#> 4         4     4           37
-#> 5         5     5           37
-#> 6         6     6           40
-#> 7         7     7           28
-#> 8         8     8           21
-#> 9         9     9            9
-#> 10       10    10            6
-#> 11       11    11            2
-#> 12    Na::b Na::b            0
-head(agegrp_1)
-#>   agegrp5
-#> 1       7
-#> 2       7
-#> 3      10
-#> 4       6
-#> 5       3
-#> 6       9
-
-
-agegrp_2 <- rec_with_table(data = tester2, 
-                             variables = "agegrp10", 
-                             variable_details = variable_details, 
-                             log = TRUE)
-#> Using the passed data variable name as database_name
-#> NOTE for agegrp10: adapted from sample survival pbc data
-#> NOTE for agegrp10: adapted from sample survival pbc data
-#> NOTE for agegrp10: adapted from sample survival pbc data
-#> NOTE for agegrp10: adapted from sample survival pbc data
-#> NOTE for agegrp10: adapted from sample survival pbc data
-#> NOTE for agegrp10: adapted from sample survival pbc data
-#> The variable agegrp was recoded into agegrp10 for the database tester2 the following recodes were made:
-#>   value_to From rows_recoded
-#> 1        1    1            1
-#> 2        2    2           39
-#> 3        3    3           52
-#> 4        4    4           67
-#> 5        5    5           45
-#> 6        6    6            5
-#> 7    Na::b else            0
-head(agegrp_2)
-#>     agegrp10
-#> 210        3
-#> 211        4
-#> 212        3
-#> 213        4
-#> 214        5
-#> 215        3
+
+agegrp_1 <- rec_with_table(data = tester1, 
+                           variables = "agegrp5", 
+                           variable_details = recodeflow::tester_variable_details,
+                           log = TRUE,
+                           database_name = 'tester1'
+                           )
+#> The variable agegrp was recoded into agegrp5 for the database tester1 the following recodes were made:
+#> # A tibble: 12 × 3
+#>    value_to From  rows_recoded
+#>    <chr>    <chr>        <int>
+#>  1 1        1                2
+#>  2 2        2               12
+#>  3 3        3               15
+#>  4 4        4               37
+#>  5 5        5               37
+#>  6 6        6               40
+#>  7 7        7               28
+#>  8 8        8               21
+#>  9 9        9                9
+#> 10 10       10               6
+#> 11 11       11               2
+#> 12 Na::b    else             0
+head(agegrp_1)
+#>   agegrp5
+#> 1       7
+#> 2       7
+#> 3      10
+#> 4       6
+#> 5       3
+#> 6       9
+
+
+agegrp_2 <- rec_with_table(data = tester2, 
+                             variables = "agegrp10", 
+                             variable_details = recodeflow::tester_variable_details,
+                             log = TRUE,
+                           database_name = 'tester2')
+#> The variable agegrp was recoded into agegrp10 for the database tester2 the following recodes were made:
+#> # A tibble: 7 × 3
+#>   value_to From  rows_recoded
+#>   <chr>    <chr>        <int>
+#> 1 1        1                1
+#> 2 2        2               39
+#> 3 3        3               52
+#> 4 4        4               67
+#> 5 5        5               45
+#> 6 6        6                5
+#> 7 NA(b)    else             0
+head(agegrp_2)
+#>     agegrp10
+#> 210        3
+#> 211        4
+#> 212        3
+#> 213        4
+#> 214        5
+#> 215        3
    -
  1. Combine the harmonized variable agegrp5 in tester1 with the harmonized agegrp10 in tester2.
  2. +
  3. Combine the harmonized variable agegrp5 in tester1 with +the harmonized agegrp10 in tester2.
-
-agegrp_combined <- bind_rows(agegrp_1, agegrp_2)
-
#>   agegrp5 agegrp10
-#> 1       7     <NA>
-#> 2       7     <NA>
-#> 3      10     <NA>
-#> 4       6     <NA>
-#> 5       3     <NA>
-#> 6       9     <NA>
-#>     agegrp5 agegrp10
-#> 413    <NA>        2
-#> 414    <NA>        5
-#> 415    <NA>        2
-#> 416    <NA>        4
-#> 417    <NA>        4
-#> 418    <NA>        4
+
+agegrp_combined <- bind_rows(agegrp_1, agegrp_2)
+
#>   agegrp5 agegrp10
+#> 1       7     <NA>
+#> 2       7     <NA>
+#> 3      10     <NA>
+#> 4       6     <NA>
+#> 5       3     <NA>
+#> 6       9     <NA>
+#>     agegrp5 agegrp10
+#> 413    <NA>        2
+#> 414    <NA>        5
+#> 415    <NA>        2
+#> 416    <NA>        4
+#> 417    <NA>        4
+#> 418    <NA>        4
-
-

-Option 2: recode the categorical agegrp variable into a continuous age_cont variable

-

Recode categorical variable agegrp into a single harmonized continuous variable age_cont.

-

age_cont takes the midpoint age of each category for ‘agegrp’ across datasets. With this option, the categorical variable ‘agegrp’ from each dataset can be combined into a single dataset.

+
+

Option 2: recode the categorical agegrp variable into a +continuous age_cont variable +

+

Recode categorical variable agegrp into a single +harmonized continuous variable age_cont.

+

age_cont takes the midpoint age of each category for +‘agegrp’ across datasets. With this option, the categorical variable +‘agegrp’ from each dataset can be combined into a single dataset.

    -
  1. Recode variable agegrp in tester1 and agegrp in tester2 to the harmonized continuous variable age_cont.
  2. +
  3. Recode variable agegrp in tester1 and +agegrp in tester2 to the harmonized continuous variable +age_cont.
-
-agegrp_1_cont <- rec_with_table(data = tester1, 
-                             variables = "age_cont", 
-                             variable_details = variable_details, 
-                             log = TRUE)
-#> Using the passed data variable name as database_name
-#> NOTE for age_cont: adapted from sample survival pbc data
-#> NOTE for age_cont: adapted from sample survival pbc data
-#> NOTE for age_cont: adapted from sample survival pbc data
-#> NOTE for age_cont: adapted from sample survival pbc data
-#> NOTE for age_cont: adapted from sample survival pbc data
-#> NOTE for age_cont: adapted from sample survival pbc data
-#> NOTE for age_cont: adapted from sample survival pbc data
-#> NOTE for age_cont: adapted from sample survival pbc data
-#> NOTE for age_cont: adapted from sample survival pbc data
-#> NOTE for age_cont: adapted from sample survival pbc data
-#> NOTE for age_cont: adapted from sample survival pbc data
-#> NOTE for age_cont: adapted from sample survival pbc data
-#> The variable agegrp was recoded into age_cont for the database tester1 the following recodes were made:
-#>    value_to  From rows_recoded
-#> 1        27     1            2
-#> 2        32     2           12
-#> 3        37     3           15
-#> 4        42     4           37
-#> 5        47     5           37
-#> 6        52     6           40
-#> 7        57     7           28
-#> 8        62     8           21
-#> 9        67     9            9
-#> 10       72    10            6
-#> 11       77    11            2
-#> 12    Na::b Na::b            0
-head(agegrp_1_cont)
-#>   age_cont
-#> 1       57
-#> 2       57
-#> 3       72
-#> 4       52
-#> 5       37
-#> 6       67
-
-
-agegrp_2_cont <- rec_with_table(data = tester2, 
-                             variables = "age_cont", 
-                             variable_details = variable_details, 
-                             log = TRUE)
-#> Using the passed data variable name as database_name
-#> NOTE for age_cont: adapted from sample survival pbc data
-#> NOTE for age_cont: adapted from sample survival pbc data
-#> NOTE for age_cont: adapted from sample survival pbc data
-#> NOTE for age_cont: adapted from sample survival pbc data
-#> NOTE for age_cont: adapted from sample survival pbc data
-#> NOTE for age_cont: adapted from sample survival pbc data
-#> NOTE for age_cont: adapted from sample survival pbc data
-#> The variable agegrp was recoded into age_cont for the database tester2 the following recodes were made:
-#>   value_to  From rows_recoded
-#> 1       25     1            1
-#> 2       35     2           39
-#> 3       45     3           52
-#> 4       55     4           67
-#> 5       65     5           45
-#> 6       75     6            5
-#> 7    Na::b Na::b            0
-head(agegrp_2_cont)
-#>     age_cont
-#> 210       45
-#> 211       55
-#> 212       45
-#> 213       55
-#> 214       65
-#> 215       45
+
+agegrp_1_cont <- rec_with_table(data = tester1, 
+                             variables = "age_cont", 
+                             variable_details = recodeflow::tester_variable_details,
+                             log = TRUE,
+                           database_name = 'tester1')
+#> The variable agegrp was recoded into age_cont for the database tester1 the following recodes were made:
+#> # A tibble: 12 × 3
+#>    value_to From  rows_recoded
+#>    <chr>    <chr>        <int>
+#>  1 27       1                2
+#>  2 32       2               12
+#>  3 37       3               15
+#>  4 42       4               37
+#>  5 47       5               37
+#>  6 52       6               40
+#>  7 57       7               28
+#>  8 62       8               21
+#>  9 67       9                9
+#> 10 72       10               6
+#> 11 77       11               2
+#> 12 NA       else             0
+head(agegrp_1_cont)
+#>   age_cont
+#> 1       57
+#> 2       57
+#> 3       72
+#> 4       52
+#> 5       37
+#> 6       67
+
+
+agegrp_2_cont <- rec_with_table(data = tester2, 
+                             variables = "age_cont", 
+                             variable_details = recodeflow::tester_variable_details,
+                             log = TRUE,
+                           database_name = 'tester2')
+#> The variable agegrp was recoded into age_cont for the database tester2 the following recodes were made:
+#> # A tibble: 7 × 3
+#>   value_to From  rows_recoded
+#>   <chr>    <chr>        <int>
+#> 1 25       1                1
+#> 2 35       2               39
+#> 3 45       3               52
+#> 4 55       4               67
+#> 5 65       5               45
+#> 6 75       6                5
+#> 7 NA       else             0
+head(agegrp_2_cont)
+#>     age_cont
+#> 210       45
+#> 211       55
+#> 212       45
+#> 213       55
+#> 214       65
+#> 215       45
    -
  1. Combine the harmonized continous variable age_cont from tester1 and tester2.
  2. +
  3. Combine the harmonized continous variable age_cont from +tester1 and tester2.
-
-agegrp_cont_combined <- bind_rows(agegrp_1_cont, agegrp_2_cont)
-
#>   age_cont
-#> 1       57
-#> 2       57
-#> 3       72
-#> 4       52
-#> 5       37
-#> 6       67
-#>     age_cont
-#> 413       35
-#> 414       65
-#> 415       35
-#> 416       55
-#> 417       55
-#> 418       55
+
+agegrp_cont_combined <- bind_rows(agegrp_1_cont, agegrp_2_cont)
+
#>   age_cont
+#> 1       57
+#> 2       57
+#> 3       72
+#> 4       52
+#> 5       37
+#> 6       67
+#>     age_cont
+#> 413       35
+#> 414       65
+#> 415       35
+#> 416       55
+#> 417       55
+#> 418       55
-
-

-Option 3: recode the categorical agegrp variable into a harmonized categorical variable

-

Dataset tester1 has 5-year age groups (e.g., 30-34, 35-39), and tester2 has 10-year age groups (e.g., 30-39). Therefore, we can collapse the 5-year age groups in dataset tester1 to the same 10-year age groups in dataset tester2.

+
+

Option 3: recode the categorical agegrp variable into a +harmonized categorical variable +

+

Dataset tester1 has 5-year age groups (e.g., 30-34, 35-39), and +tester2 has 10-year age groups (e.g., 30-39). Therefore, we can collapse +the 5-year age groups in dataset tester1 to the same 10-year age groups +in dataset tester2.

    -
  1. Recode variable agegrp in tester1 into agegrp10. recode variable agegrp in tester2 into agegrp10.
  2. +
  3. Recode variable agegrp in tester1 into +agegrp10. recode variable agegrp in tester2 +into agegrp10.
-
-agegrp10_1 <- rec_with_table(data = tester1, 
-                             variables = "agegrp10", 
-                             variable_details = variable_details, 
-                             log = TRUE)
-#> Using the passed data variable name as database_name
-#> NOTE for agegrp10: adapted from sample survival pbc data
-#> NOTE for agegrp10: adapted from sample survival pbc data
-#> NOTE for agegrp10: adapted from sample survival pbc data
-#> NOTE for agegrp10: adapted from sample survival pbc data
-#> NOTE for agegrp10: adapted from sample survival pbc data
-#> NOTE for agegrp10: adapted from sample survival pbc data
-#> NOTE for agegrp10: adapted from sample survival pbc data
-#> NOTE for agegrp10: adapted from sample survival pbc data
-#> NOTE for agegrp10: adapted from sample survival pbc data
-#> NOTE for agegrp10: adapted from sample survival pbc data
-#> NOTE for agegrp10: adapted from sample survival pbc data
-#> NOTE for agegrp10: adapted from sample survival pbc data
-#> The variable agegrp was recoded into agegrp10 for the database tester1 the following recodes were made:
-#>    value_to  From rows_recoded
-#> 1         1     1            2
-#> 2         2     2           12
-#> 3         2     3           15
-#> 4         3     4           37
-#> 5         3     5           37
-#> 6         4     6           40
-#> 7         4     7           28
-#> 8         5     8           21
-#> 9         5     9            9
-#> 10        6    10            6
-#> 11        6    11            2
-#> 12    Na::b Na::b            0
-head(agegrp10_1)
-#>   agegrp10
-#> 1        4
-#> 2        4
-#> 3        6
-#> 4        4
-#> 5        2
-#> 6        5
-
-
-agegrp10_2 <- rec_with_table(data = tester2, 
-                             variables = "agegrp10", 
-                             variable_details = variable_details, 
-                             log = TRUE)
-#> Using the passed data variable name as database_name
-#> NOTE for agegrp10: adapted from sample survival pbc data
-#> NOTE for agegrp10: adapted from sample survival pbc data
-#> NOTE for agegrp10: adapted from sample survival pbc data
-#> NOTE for agegrp10: adapted from sample survival pbc data
-#> NOTE for agegrp10: adapted from sample survival pbc data
-#> NOTE for agegrp10: adapted from sample survival pbc data
-#> The variable agegrp was recoded into agegrp10 for the database tester2 the following recodes were made:
-#>   value_to From rows_recoded
-#> 1        1    1            1
-#> 2        2    2           39
-#> 3        3    3           52
-#> 4        4    4           67
-#> 5        5    5           45
-#> 6        6    6            5
-#> 7    Na::b else            0
-head(agegrp10_2)
-#>     agegrp10
-#> 210        3
-#> 211        4
-#> 212        3
-#> 213        4
-#> 214        5
-#> 215        3
+
+agegrp10_1 <- rec_with_table(data = tester1, 
+                             variables = "agegrp10", 
+                             variable_details = recodeflow::tester_variable_details,
+                             log = TRUE,
+                           database_name = 'tester1')
+#> The variable agegrp was recoded into agegrp10 for the database tester1 the following recodes were made:
+#> # A tibble: 12 × 3
+#>    value_to From  rows_recoded
+#>    <chr>    <chr>        <int>
+#>  1 1        1                2
+#>  2 2        2               12
+#>  3 2        3               15
+#>  4 3        4               37
+#>  5 3        5               37
+#>  6 4        6               40
+#>  7 4        7               28
+#>  8 5        8               21
+#>  9 5        9                9
+#> 10 6        10               6
+#> 11 6        11               2
+#> 12 NA(b)    else             0
+head(agegrp10_1)
+#>   agegrp10
+#> 1        4
+#> 2        4
+#> 3        6
+#> 4        4
+#> 5        2
+#> 6        5
+
+
+agegrp10_2 <- rec_with_table(data = tester2, 
+                             variables = "agegrp10", 
+                             variable_details = recodeflow::tester_variable_details,
+                             log = TRUE,
+                            database_name = 'tester2')
+#> The variable agegrp was recoded into agegrp10 for the database tester2 the following recodes were made:
+#> # A tibble: 7 × 3
+#>   value_to From  rows_recoded
+#>   <chr>    <chr>        <int>
+#> 1 1        1                1
+#> 2 2        2               39
+#> 3 3        3               52
+#> 4 4        4               67
+#> 5 5        5               45
+#> 6 6        6                5
+#> 7 NA(b)    else             0
+head(agegrp10_2)
+#>     agegrp10
+#> 210        3
+#> 211        4
+#> 212        3
+#> 213        4
+#> 214        5
+#> 215        3
    -
  1. Combine the harmonized categorical variable age_cat from tester1 and tester2.
  2. +
  3. Combine the harmonized categorical variable age_cat +from tester1 and tester2.
-
-agegrp10_combined <- bind_rows(agegrp10_1, agegrp10_2)
-
#>   agegrp10
-#> 1        4
-#> 2        4
-#> 3        6
-#> 4        4
-#> 5        2
-#> 6        5
-#>     agegrp10
-#> 413        2
-#> 414        5
-#> 415        2
-#> 416        4
-#> 417        4
-#> 418        4
+
+agegrp10_combined <- bind_rows(agegrp10_1, agegrp10_2)
+
#>   agegrp10
+#> 1        4
+#> 2        4
+#> 3        6
+#> 4        4
+#> 5        2
+#> 6        5
+#>     agegrp10
+#> 413        2
+#> 414        5
+#> 415        2
+#> 416        4
+#> 417        4
+#> 418        4
-
-

-Example 4. Recode multiple variables from multiple datasets

-

The variables argument in rec_with_table() allows multiple variables to be recoded from a dataset.

-

In this example, the age and sex variables from the tester1 and tester2 datasets will be recoded and labeled using rec_with_table().

-

We’ll then combine the two recoded datasets into a single dataset and labeled using set_data_labels().

+
+

Example 4. Recode multiple variables from multiple datasets +

+

The variables argument in rec_with_table() allows +multiple variables to be recoded from a dataset.

+

In this example, the age and sex variables +from the tester1 and tester2 datasets will be recoded and labeled using +rec_with_table().

+

We’ll then combine the two recoded datasets into a single dataset and +labeled using set_data_labels().

    -
  1. Recode age and sex in dataset tester1 and tester2
  2. +
  3. Recode age and sex in dataset tester1 and +tester2
-
-age_sex_1 <- rec_with_table(data = tester1, 
-                            variables = c("age", "sex"), 
-                            variable_details = variable_details,
-                            log = TRUE, 
-                            var_labels = c(age = "Age", sex = "Sex")
-                            )
-#> Using the passed data variable name as database_name
-#> NOTE for age: This is sample survival pbc data
-#> The variable age was recoded into age for the database tester1 the following recodes were made:
-#>   value_to    From rows_recoded
-#> 1     copy [25,79]          209
-#> 2     <NA>    else            0
-#> NOTE for sex: This is sample survival pbc data
-#> NOTE for sex: This is sample survival pbc data
-#> The variable sex was recoded into sex for the database tester1 the following recodes were made:
-#>   value_to From rows_recoded
-#> 1        0    m           27
-#> 2        1    f          182
-#> 3    NA(b) else            0
-head(age_sex_1)
-#>        age sex
-#> 1 58.76523   1
-#> 2 56.44627   1
-#> 3 70.07255   0
-#> 4 54.74059   1
-#> 5 38.10541   1
-#> 6 66.25873   1
-
-age_sex_2 <- rec_with_table(data = tester2, 
-                            variables = c("age", "sex"), 
-                            variable_details = variable_details,
-                            log = TRUE, 
-                            var_labels = c(age = "Age", sex = "Sex")
-                            )
-#> Using the passed data variable name as database_name
-#> NOTE for age: This is sample survival pbc data
-#> The variable age was recoded into age for the database tester2 the following recodes were made:
-#>   value_to    From rows_recoded
-#> 1     copy [25,79]          209
-#> 2     <NA>    else            0
-#> NOTE for sex: This is sample survival pbc data
-#> NOTE for sex: This is sample survival pbc data
-#> The variable sex was recoded into sex for the database tester2 the following recodes were made:
-#>   value_to From rows_recoded
-#> 1        0    m           17
-#> 2        1    f          192
-#> 3    NA(b) else            0
-head(age_sex_2)
-#>          age sex
-#> 210 49.76318   0
-#> 211 52.91444   1
-#> 212 47.26352   1
-#> 213 50.20397   1
-#> 214 69.34702   1
-#> 215 41.16906   1
+
+age_sex_1 <- rec_with_table(data = tester1, 
+                            variables = c("age", "sex"), 
+                            variable_details = recodeflow::tester_variable_details,
+                            log = TRUE, 
+                            var_labels = c(age = "Age", sex = "Sex"),
+                            database_name = 'tester1')
+#> The variable age was recoded into age for the database tester1 the following recodes were made:
+#> # A tibble: 3 × 3
+#>   value_to From    rows_recoded
+#>   <chr>    <chr>          <int>
+#> 1 copy     [20,80]          209
+#> 2 NA::a    999                0
+#> 3 NA       else               0
+#> The variable sex was recoded into sex for the database tester1 the following recodes were made:
+#> # A tibble: 4 × 3
+#>   value_to From  rows_recoded
+#>   <chr>    <chr>        <int>
+#> 1 m        m               27
+#> 2 f        f              182
+#> 3 NA::a    9                0
+#> 4 NA(b)    else             0
+head(age_sex_1)
+#>        age sex
+#> 1 58.76523   f
+#> 2 56.44627   f
+#> 3 70.07255   m
+#> 4 54.74059   f
+#> 5 38.10541   f
+#> 6 66.25873   f
+
+age_sex_2 <- rec_with_table(data = tester2, 
+                            variables = c("age", "sex"), 
+                            variable_details = recodeflow::tester_variable_details,
+                            log = TRUE, 
+                            var_labels = c(age = "Age", sex = "Sex"),
+                            database_name = 'tester2'
+                            )
+#> The variable age was recoded into age for the database tester2 the following recodes were made:
+#> # A tibble: 3 × 3
+#>   value_to From    rows_recoded
+#>   <chr>    <chr>          <int>
+#> 1 copy     [20,80]          209
+#> 2 NA::a    999                0
+#> 3 NA       else               0
+#> The variable sex was recoded into sex for the database tester2 the following recodes were made:
+#> # A tibble: 4 × 3
+#>   value_to From  rows_recoded
+#>   <chr>    <chr>        <int>
+#> 1 m        m               17
+#> 2 f        f              192
+#> 3 NA::a    9                0
+#> 4 NA(b)    else             0
+head(age_sex_2)
+#>          age sex
+#> 210 49.76318   m
+#> 211 52.91444   f
+#> 212 47.26352   f
+#> 213 50.20397   f
+#> 214 69.34702   f
+#> 215 41.16906   f
    -
  1. Combine the harmonized variables age and sex from tester1 and tester2.
  2. +
  3. Combine the harmonized variables age and +sex from tester1 and tester2.
-
-combined_age_sex <- bind_rows(age_sex_1, age_sex_2)
-head(combined_age_sex)
-#>        age sex
-#> 1 58.76523   1
-#> 2 56.44627   1
-#> 3 70.07255   0
-#> 4 54.74059   1
-#> 5 38.10541   1
-#> 6 66.25873   1
+
+combined_age_sex <- bind_rows(age_sex_1, age_sex_2)
+head(combined_age_sex)
+#>        age sex
+#> 1 58.76523   f
+#> 2 56.44627   f
+#> 3 70.07255   m
+#> 4 54.74059   f
+#> 5 38.10541   f
+#> 6 66.25873   f
  1. Set labels
-

Use set_data_labels() to label the variables in your final dataset. set_data_labels() sets the labels with the original information in variables and variable_details.

-

var_labels can be used all the variables in variables.csv or a subset of variables.

-
-labeled_combined_age_sex <- 
-  set_data_labels(
-      data_to_label = combined_age_sex,
-      variable_details = variable_details, 
-      variables_sheet = variables
-      )
-

You can check if labels have been added to your recoded dataset by using get_label().

+

Use set_data_labels() to label the variables in your +final dataset. set_data_labels() sets the labels with the +original information in variables and +variable_details.

+

var_labels can be used all the variables in +variables.csv or a subset of variables.

-library(sjlabelled) 
-#> 
-#> Attaching package: 'sjlabelled'
-#> The following object is masked from 'package:dplyr':
-#> 
-#>     as_label
-get_label(labeled_combined_age_sex)
-#>   age   sex 
-#> "age" "sex"
-

For more information on get_label() and other label helper functions, please refer to the sjlabelled package.

+labeled_combined_age_sex <- + set_data_labels( + data_to_label = combined_age_sex, + variable_details = recodeflow::tester_variable_details, + variables_sheet = recodeflow::tester_variables + )
+

You can check if labels have been added to your recoded dataset by +using get_label().

+
+library(sjlabelled) 
+#> 
+#> Attaching package: 'sjlabelled'
+#> The following object is masked from 'package:dplyr':
+#> 
+#>     as_label
+get_label(labeled_combined_age_sex)
+#>   age   sex 
+#> "age" "sex"
+

For more information on get_label() and other label +helper functions, please refer to the sjlabelled +package.

-
-

-Example 5. Recode all variables in the variables worksheet

-

All the variables listed in variables worksheet can be recoded with rec_with_table().

-

In this example, all variables specified in the variables worksheet will be recoded and combined for the datasets tester1 and tester2.

+
+

Example 5. Recode all variables in the variables worksheet +

+

All the variables listed in variables worksheet can be +recoded with rec_with_table().

+

In this example, all variables specified in the +variables worksheet will be recoded and combined for the +datasets tester1 and tester2.

    -
  1. Recode all variables listed in the variables worksheet, for dataset tester1 and dataset tester2
  2. +
  3. Recode all variables listed in the variables worksheet, for dataset +tester1 and dataset tester2
-
-recoded1 <- rec_with_table(data = tester1,
-                          variables = variables,
-                          variable_details = variable_details,
-                          log = TRUE,
-                          )
-#> Using the passed data variable name as database_name
-#> NOTE for age: This is sample survival pbc data
-#> The variable age was recoded into age for the database tester1 the following recodes were made:
-#>   value_to    From rows_recoded
-#> 1     copy [25,79]          209
-#> 2     <NA>    else            0
-#> NOTE for age_cont: adapted from sample survival pbc data
-#> NOTE for age_cont: adapted from sample survival pbc data
-#> NOTE for age_cont: adapted from sample survival pbc data
-#> NOTE for age_cont: adapted from sample survival pbc data
-#> NOTE for age_cont: adapted from sample survival pbc data
-#> NOTE for age_cont: adapted from sample survival pbc data
-#> NOTE for age_cont: adapted from sample survival pbc data
-#> NOTE for age_cont: adapted from sample survival pbc data
-#> NOTE for age_cont: adapted from sample survival pbc data
-#> NOTE for age_cont: adapted from sample survival pbc data
-#> NOTE for age_cont: adapted from sample survival pbc data
-#> NOTE for age_cont: adapted from sample survival pbc data
-#> The variable agegrp was recoded into age_cont for the database tester1 the following recodes were made:
-#>    value_to  From rows_recoded
-#> 1        52     6           40
-#> 2        27     1            2
-#> 3        32     2           12
-#> 4        37     3           15
-#> 5        42     4           37
-#> 6        47     5           37
-#> 7        57     7           28
-#> 8        62     8           21
-#> 9        67     9            9
-#> 10       72    10            6
-#> 11       77    11            2
-#> 12    Na::b Na::b            0
-#> NOTE for agegrp10: adapted from sample survival pbc data
-#> NOTE for agegrp10: adapted from sample survival pbc data
-#> NOTE for agegrp10: adapted from sample survival pbc data
-#> NOTE for agegrp10: adapted from sample survival pbc data
-#> NOTE for agegrp10: adapted from sample survival pbc data
-#> NOTE for agegrp10: adapted from sample survival pbc data
-#> NOTE for agegrp10: adapted from sample survival pbc data
-#> NOTE for agegrp10: adapted from sample survival pbc data
-#> NOTE for agegrp10: adapted from sample survival pbc data
-#> NOTE for agegrp10: adapted from sample survival pbc data
-#> NOTE for agegrp10: adapted from sample survival pbc data
-#> NOTE for agegrp10: adapted from sample survival pbc data
-#> The variable agegrp was recoded into agegrp10 for the database tester1 the following recodes were made:
-#>    value_to  From rows_recoded
-#> 1         5     8           21
-#> 2         5     9            9
-#> 3         6    10            6
-#> 4         6    11            2
-#> 5     Na::b Na::b            0
-#> 6         3     4           37
-#> 7         1     1            2
-#> 8         2     2           12
-#> 9         2     3           15
-#> 10        3     5           37
-#> 11        4     6           40
-#> 12        4     7           28
-#> NOTE for agegrp5: adapted from sample survival pbc data
-#> NOTE for agegrp5: adapted from sample survival pbc data
-#> NOTE for agegrp5: adapted from sample survival pbc data
-#> NOTE for agegrp5: adapted from sample survival pbc data
-#> NOTE for agegrp5: adapted from sample survival pbc data
-#> NOTE for agegrp5: adapted from sample survival pbc data
-#> NOTE for agegrp5: adapted from sample survival pbc data
-#> NOTE for agegrp5: adapted from sample survival pbc data
-#> NOTE for agegrp5: adapted from sample survival pbc data
-#> NOTE for agegrp5: adapted from sample survival pbc data
-#> NOTE for agegrp5: adapted from sample survival pbc data
-#> NOTE for agegrp5: adapted from sample survival pbc data
-#> The variable agegrp was recoded into agegrp5 for the database tester1 the following recodes were made:
-#>    value_to  From rows_recoded
-#> 1         1     1            2
-#> 2         2     2           12
-#> 3         3     3           15
-#> 4         4     4           37
-#> 5         5     5           37
-#> 6         6     6           40
-#> 7         7     7           28
-#> 8         8     8           21
-#> 9         9     9            9
-#> 10       10    10            6
-#> 11       11    11            2
-#> 12    Na::b Na::b            0
-#> NOTE for albumin: This is sample survival pbc data
-#> The variable albumin was recoded into albumin for the database tester1 the following recodes were made:
-#>   value_to          From rows_recoded
-#> 1     copy [1.960, 4.64]          209
-#> 2     <NA>          else            0
-#> NOTE for alk.phos: This is sample survival pbc data
-#> NOTE for alk.phos: This is sample survival pbc data
-#> The variable alk.phos was recoded into alk.phos for the database tester1 the following recodes were made:
-#>   value_to         From rows_recoded
-#> 1     copy [289, 13863]          209
-#> 2    Na::a           NA            0
-#> 3     <NA>         else            0
-#> NOTE for ascites: This is sample survival pbc data
-#> NOTE for ascites: This is sample survival pbc data
-#> NOTE for ascites: This is sample survival pbc data
-#> The variable ascites was recoded into ascites for the database tester1 the following recodes were made:
-#>   value_to From rows_recoded
-#> 1        0    0          191
-#> 2        1    1           18
-#> 3    NA::a   NA            0
-#> 4    NA(b) else            0
-#> NOTE for ast: This is sample survival pbc data
-#> NOTE for ast: This is sample survival pbc data
-#> The variable ast was recoded into ast for the database tester1 the following recodes were made:
-#>   value_to      From rows_recoded
-#> 1     copy [26, 458]          209
-#> 2    Na::a        NA            0
-#> 3     <NA>      else            0
-#> NOTE for bili: This is sample survival pbc data
-#> The variable bili was recoded into bili for the database tester1 the following recodes were made:
-#>   value_to   From rows_recoded
-#> 1     copy [0,28]          209
-#> 2     <NA>   else            0
-#> NOTE for chol: This is sample survival pbc data
-#> NOTE for chol: This is sample survival pbc data
-#> The variable chol was recoded into chol for the database tester1 the following recodes were made:
-#>   value_to        From rows_recoded
-#> 1     copy [120, 1775]          186
-#> 2    Na::a          NA            0
-#> 3     <NA>        else           23
-#> NOTE for copper: This is sample survival pbc data
-#> NOTE for copper: This is sample survival pbc data
-#> The variable copper was recoded into copper for the database tester1 the following recodes were made:
-#>   value_to    From rows_recoded
-#> 1     copy [4,588]          208
-#> 2    Na::a      NA            0
-#> 3     <NA>    else            1
-#> NOTE for edema: This is sample survival pbc data
-#> NOTE for edema: This is sample survival pbc data
-#> NOTE for edema: This is sample survival pbc data
-#> The variable edema was recoded into edema for the database tester1 the following recodes were made:
-#>   value_to From rows_recoded
-#> 1      0.0  0.0          171
-#> 2      0.5  0.5           22
-#> 3      1.0  1.0           16
-#> 4    Na::b else            0
-#> NOTE for hepato: This is sample survival pbc data
-#> NOTE for hepato: This is sample survival pbc data
-#> NOTE for hepato: This is sample survival pbc data
-#> The variable hepato was recoded into hepato for the database tester1 the following recodes were made:
-#>   value_to From rows_recoded
-#> 1        0    0          102
-#> 2        1    1          107
-#> 3    NA::a   NA            0
-#> 4    NA(b) else            0
-#> NOTE for platelet: This is sample survival pbc data
-#> NOTE for platelet: This is sample survival pbc data
-#> The variable platelet was recoded into platelet for the database tester1 the following recodes were made:
-#>   value_to      From rows_recoded
-#> 1     copy [62, 721]          205
-#> 2    Na::a        NA            0
-#> 3     <NA>      else            4
-#> NOTE for protime: This is sample survival pbc data
-#> NOTE for protime: This is sample survival pbc data
-#> The variable protime was recoded into protime for the database tester1 the following recodes were made:
-#>   value_to   From rows_recoded
-#> 1     copy [9,18]          209
-#> 2    Na::a     NA            0
-#> 3     <NA>   else            0
-#> NOTE for sex: This is sample survival pbc data
-#> NOTE for sex: This is sample survival pbc data
-#> The variable sex was recoded into sex for the database tester1 the following recodes were made:
-#>   value_to From rows_recoded
-#> 1        0    m           27
-#> 2        1    f          182
-#> 3    NA(b) else            0
-#> NOTE for spiders: This is sample survival pbc data
-#> NOTE for spiders: This is sample survival pbc data
-#> NOTE for spiders: This is sample survival pbc data
-#> The variable spiders was recoded into spiders for the database tester1 the following recodes were made:
-#>   value_to From rows_recoded
-#> 1        0    0          145
-#> 2        1    1           64
-#> 3    NA::a   NA            0
-#> 4    NA(b) else            0
-#> NOTE for stage: This is sample survival pbc data
-#> NOTE for stage: This is sample survival pbc data
-#> NOTE for stage: This is sample survival pbc data
-#> NOTE for stage: This is sample survival pbc data
-#> NOTE for stage: This is sample survival pbc data
-#> The variable stage was recoded into stage for the database tester1 the following recodes were made:
-#>   value_to From rows_recoded
-#> 1        1    1           12
-#> 2        2    2           46
-#> 3        3    3           77
-#> 4        4    4           74
-#> 5    Na::a   Na            0
-#> 6    NA(b) else            0
-#> NOTE for status: This is sample survival pbc data
-#> NOTE for status: This is sample survival pbc data
-#> NOTE for status: This is sample survival pbc data
-#> The variable status was recoded into status for the database tester1 the following recodes were made:
-#>   value_to From rows_recoded
-#> 1        0    0           94
-#> 2        1    1            7
-#> 3        2    2          108
-#> 4    NA(b) else            0
-#> NOTE for time: This is sample survival pbc data
-#> The variable time was recoded into time for the database tester1 the following recodes were made:
-#>   value_to     From rows_recoded
-#> 1     copy [0,4556]          209
-#> 2     <NA>     else            0
-#> NOTE for trig: This is sample survival pbc data
-#> NOTE for trig: This is sample survival pbc data
-#> The variable trig was recoded into trig for the database tester1 the following recodes were made:
-#>   value_to      From rows_recoded
-#> 1     copy [33, 598]          185
-#> 2    Na::a        NA            0
-#> 3     <NA>      else           24
-#> NOTE for trt: This is sample survival pbc data
-#> NOTE for trt: This is sample survival pbc data
-#> NOTE for trt: This is sample survival pbc data
-#> NOTE for trt: This is sample survival pbc data
-#> The variable trt was recoded into trt for the database tester1 the following recodes were made:
-#>   value_to From rows_recoded
-#> 1        1    1          106
-#> 2        2    2          103
-#> 3        3    3            0
-#> 4    NA::a   NA            0
-#> 5    NA(b) else            0
-
-recoded2 <- rec_with_table(data = tester2,
-                          variables = variables,
-                          variable_details = variable_details,
-                          log = TRUE,
-                          )
-#> Using the passed data variable name as database_name
-#> NOTE for age: This is sample survival pbc data
-#> The variable age was recoded into age for the database tester2 the following recodes were made:
-#>   value_to    From rows_recoded
-#> 1     copy [25,79]          209
-#> 2     <NA>    else            0
-#> NOTE for age_cont: adapted from sample survival pbc data
-#> NOTE for age_cont: adapted from sample survival pbc data
-#> NOTE for age_cont: adapted from sample survival pbc data
-#> NOTE for age_cont: adapted from sample survival pbc data
-#> NOTE for age_cont: adapted from sample survival pbc data
-#> NOTE for age_cont: adapted from sample survival pbc data
-#> NOTE for age_cont: adapted from sample survival pbc data
-#> The variable agegrp was recoded into age_cont for the database tester2 the following recodes were made:
-#>   value_to  From rows_recoded
-#> 1    Na::b Na::b            0
-#> 2       25     1            1
-#> 3       35     2           39
-#> 4       45     3           52
-#> 5       55     4           67
-#> 6       65     5           45
-#> 7       75     6            5
-#> NOTE for agegrp10: adapted from sample survival pbc data
-#> NOTE for agegrp10: adapted from sample survival pbc data
-#> NOTE for agegrp10: adapted from sample survival pbc data
-#> NOTE for agegrp10: adapted from sample survival pbc data
-#> NOTE for agegrp10: adapted from sample survival pbc data
-#> NOTE for agegrp10: adapted from sample survival pbc data
-#> The variable agegrp was recoded into agegrp10 for the database tester2 the following recodes were made:
-#>   value_to From rows_recoded
-#> 1        1    1            1
-#> 2        2    2           39
-#> 3        3    3           52
-#> 4        4    4           67
-#> 5        5    5           45
-#> 6        6    6            5
-#> 7    Na::b else            0
-#> NOTE for albumin: This is sample survival pbc data
-#> The variable albumin was recoded into albumin for the database tester2 the following recodes were made:
-#>   value_to          From rows_recoded
-#> 1     copy [1.960, 4.64]          209
-#> 2     <NA>          else            0
-#> NOTE for alk.phos: This is sample survival pbc data
-#> NOTE for alk.phos: This is sample survival pbc data
-#> The variable alk.phos was recoded into alk.phos for the database tester2 the following recodes were made:
-#>   value_to         From rows_recoded
-#> 1     copy [289, 13863]          103
-#> 2    Na::a           NA            0
-#> 3     <NA>         else          106
-#> NOTE for ascites: This is sample survival pbc data
-#> NOTE for ascites: This is sample survival pbc data
-#> NOTE for ascites: This is sample survival pbc data
-#> The variable ascites was recoded into ascites for the database tester2 the following recodes were made:
-#>   value_to From rows_recoded
-#> 1        0    0           97
-#> 2        1    1            6
-#> 3    NA::a   NA            0
-#> 4    NA(b) else          106
-#> NOTE for ast: This is sample survival pbc data
-#> NOTE for ast: This is sample survival pbc data
-#> The variable ast was recoded into ast for the database tester2 the following recodes were made:
-#>   value_to      From rows_recoded
-#> 1     copy [26, 458]          103
-#> 2    Na::a        NA            0
-#> 3     <NA>      else          106
-#> NOTE for bili: This is sample survival pbc data
-#> The variable bili was recoded into bili for the database tester2 the following recodes were made:
-#>   value_to   From rows_recoded
-#> 1     copy [0,28]          209
-#> 2     <NA>   else            0
-#> NOTE for chol: This is sample survival pbc data
-#> NOTE for chol: This is sample survival pbc data
-#> The variable chol was recoded into chol for the database tester2 the following recodes were made:
-#>   value_to        From rows_recoded
-#> 1     copy [120, 1775]           98
-#> 2    Na::a          NA            0
-#> 3     <NA>        else          111
-#> NOTE for copper: This is sample survival pbc data
-#> NOTE for copper: This is sample survival pbc data
-#> The variable copper was recoded into copper for the database tester2 the following recodes were made:
-#>   value_to    From rows_recoded
-#> 1     copy [4,588]          102
-#> 2    Na::a      NA            0
-#> 3     <NA>    else          107
-#> NOTE for edema: This is sample survival pbc data
-#> NOTE for edema: This is sample survival pbc data
-#> NOTE for edema: This is sample survival pbc data
-#> The variable edema was recoded into edema for the database tester2 the following recodes were made:
-#>   value_to From rows_recoded
-#> 1      0.0  0.0          183
-#> 2      0.5  0.5           22
-#> 3      1.0  1.0            4
-#> 4    Na::b else            0
-#> NOTE for hepato: This is sample survival pbc data
-#> NOTE for hepato: This is sample survival pbc data
-#> NOTE for hepato: This is sample survival pbc data
-#> The variable hepato was recoded into hepato for the database tester2 the following recodes were made:
-#>   value_to From rows_recoded
-#> 1        0    0           50
-#> 2        1    1           53
-#> 3    NA::a   NA            0
-#> 4    NA(b) else          106
-#> NOTE for platelet: This is sample survival pbc data
-#> NOTE for platelet: This is sample survival pbc data
-#> The variable platelet was recoded into platelet for the database tester2 the following recodes were made:
-#>   value_to      From rows_recoded
-#> 1     copy [62, 721]          202
-#> 2    Na::a        NA            0
-#> 3     <NA>      else            7
-#> NOTE for protime: This is sample survival pbc data
-#> NOTE for protime: This is sample survival pbc data
-#> The variable protime was recoded into protime for the database tester2 the following recodes were made:
-#>   value_to   From rows_recoded
-#> 1     copy [9,18]          207
-#> 2    Na::a     NA            0
-#> 3     <NA>   else            2
-#> NOTE for sex: This is sample survival pbc data
-#> NOTE for sex: This is sample survival pbc data
-#> The variable sex was recoded into sex for the database tester2 the following recodes were made:
-#>   value_to From rows_recoded
-#> 1        0    m           17
-#> 2        1    f          192
-#> 3    NA(b) else            0
-#> NOTE for spiders: This is sample survival pbc data
-#> NOTE for spiders: This is sample survival pbc data
-#> NOTE for spiders: This is sample survival pbc data
-#> The variable spiders was recoded into spiders for the database tester2 the following recodes were made:
-#>   value_to From rows_recoded
-#> 1        0    0           77
-#> 2        1    1           26
-#> 3    NA::a   NA            0
-#> 4    NA(b) else          106
-#> NOTE for stage: This is sample survival pbc data
-#> NOTE for stage: This is sample survival pbc data
-#> NOTE for stage: This is sample survival pbc data
-#> NOTE for stage: This is sample survival pbc data
-#> NOTE for stage: This is sample survival pbc data
-#> The variable stage was recoded into stage for the database tester2 the following recodes were made:
-#>   value_to From rows_recoded
-#> 1        1    1            9
-#> 2        2    2           46
-#> 3        3    3           78
-#> 4        4    4           70
-#> 5    Na::a   Na            0
-#> 6    NA(b) else            6
-#> NOTE for status: This is sample survival pbc data
-#> NOTE for status: This is sample survival pbc data
-#> NOTE for status: This is sample survival pbc data
-#> The variable status was recoded into status for the database tester2 the following recodes were made:
-#>   value_to From rows_recoded
-#> 1        0    0          138
-#> 2        1    1           18
-#> 3        2    2           53
-#> 4    NA(b) else            0
-#> NOTE for time: This is sample survival pbc data
-#> The variable time was recoded into time for the database tester2 the following recodes were made:
-#>   value_to     From rows_recoded
-#> 1     copy [0,4556]          208
-#> 2     <NA>     else            1
-#> NOTE for trig: This is sample survival pbc data
-#> NOTE for trig: This is sample survival pbc data
-#> The variable trig was recoded into trig for the database tester2 the following recodes were made:
-#>   value_to      From rows_recoded
-#> 1     copy [33, 598]           97
-#> 2    Na::a        NA            0
-#> 3     <NA>      else          112
-#> NOTE for trt: This is sample survival pbc data
-#> NOTE for trt: This is sample survival pbc data
-#> NOTE for trt: This is sample survival pbc data
-#> NOTE for trt: This is sample survival pbc data
-#> The variable trt was recoded into trt for the database tester2 the following recodes were made:
-#>   value_to From rows_recoded
-#> 1        1    1           52
-#> 2        2    2           51
-#> 3        3    3            0
-#> 4    NA::a   NA            0
-#> 5    NA(b) else          106
+
+recoded1 <- rec_with_table(data = tester1,
+                           variables = recodeflow::tester_variables,
+                           variable_details = recodeflow::tester_variable_details,
+                          log = TRUE,
+                           database_name = 'tester1'
+                          )
+#> The variable age was recoded into age for the database tester1 the following recodes were made:
+#>   value_to    From rows_recoded
+#> 1     copy [20,80]          209
+#> 2    NA::a     999            0
+#> 3     <NA>    else            0
+#> The variable agegrp was recoded into age_cont for the database tester1 the following recodes were made:
+#>    value_to From rows_recoded
+#> 1        52    6           40
+#> 2        27    1            2
+#> 3        32    2           12
+#> 4        37    3           15
+#> 5        42    4           37
+#> 6        47    5           37
+#> 7        57    7           28
+#> 8        62    8           21
+#> 9        67    9            9
+#> 10       72   10            6
+#> 11       77   11            2
+#> 12     <NA> else            0
+#> The variable agegrp was recoded into agegrp10 for the database tester1 the following recodes were made:
+#>    value_to From rows_recoded
+#> 1         6   10            6
+#> 2         6   11            2
+#> 3         2    3           15
+#> 4         3    4           37
+#> 5         1    1            2
+#> 6         2    2           12
+#> 7         4    7           28
+#> 8         5    8           21
+#> 9         3    5           37
+#> 10        4    6           40
+#> 11        5    9            9
+#> 12    NA(b) else            0
+#> The variable agegrp was recoded into agegrp5 for the database tester1 the following recodes were made:
+#>    value_to From rows_recoded
+#> 1         4    4           37
+#> 2         5    5           37
+#> 3         1    1            2
+#> 4         2    2           12
+#> 5         3    3           15
+#> 6         9    9            9
+#> 7         6    6           40
+#> 8         7    7           28
+#> 9         8    8           21
+#> 10       10   10            6
+#> 11       11   11            2
+#> 12    Na::b else            0
+#> The variable albumin was recoded into albumin for the database tester1 the following recodes were made:
+#>   value_to  From rows_recoded
+#> 1     copy [1,5]          209
+#> 2    NA::a    99            0
+#> 3     <NA>  else            0
+#> The variable alk.phos was recoded into alk.phos for the database tester1 the following recodes were made:
+#>   value_to        From rows_recoded
+#> 1     copy [200,15000]          209
+#> 2    NA::a       99999            0
+#> 3     <NA>        else            0
+#> The variable ascites was recoded into ascites for the database tester1 the following recodes were made:
+#>   value_to From rows_recoded
+#> 1        1    1           18
+#> 2    NA::a    9            0
+#> 3        0    0          191
+#> 4    NA(b) else            0
+#> The variable ast was recoded into ast for the database tester1 the following recodes were made:
+#>   value_to     From rows_recoded
+#> 1     copy [20,500]          209
+#> 2    NA::a     9999            0
+#> 3     <NA>     else            0
+#> The variable bili was recoded into bili for the database tester1 the following recodes were made:
+#>   value_to    From rows_recoded
+#> 1     copy [0,100]          209
+#> 2     <NA>    else            0
+#> The variable chol was recoded into chol for the database tester1 the following recodes were made:
+#>   value_to       From rows_recoded
+#> 1     copy [100,2000]          186
+#> 2    NA::a       9999            0
+#> 3     <NA>       else           23
+#> The variable copper was recoded into copper for the database tester1 the following recodes were made:
+#>   value_to     From rows_recoded
+#> 1     copy [0,1000]          208
+#> 2    NA::a     9999            0
+#> 3     <NA>     else            1
+#> The variable edema was recoded into edema for the database tester1 the following recodes were made:
+#>   value_to From rows_recoded
+#> 1      0.5  0.5           22
+#> 2        1    1           16
+#> 3        0    0          171
+#> 4    NA::a    9            0
+#> 5    NA(b) else            0
+#> The variable hepato was recoded into hepato for the database tester1 the following recodes were made:
+#>   value_to From rows_recoded
+#> 1        0    0          102
+#> 2        1    1          107
+#> 3    NA::a    9            0
+#> 4    NA(b) else            0
+#> The variable platelet was recoded into platelet for the database tester1 the following recodes were made:
+#>   value_to     From rows_recoded
+#> 1     copy [0,1000]          205
+#> 2    NA::a     9999            0
+#> 3     <NA>     else            4
+#> The variable protime was recoded into protime for the database tester1 the following recodes were made:
+#>   value_to    From rows_recoded
+#> 1     copy [5, 30]          209
+#> 2    NA::a      99            0
+#> 3     <NA>    else            0
+#> The variable sex was recoded into sex for the database tester1 the following recodes were made:
+#>   value_to From rows_recoded
+#> 1        m    m           27
+#> 2    NA::a    9            0
+#> 3        f    f          182
+#> 4    NA(b) else            0
+#> The variable spiders was recoded into spiders for the database tester1 the following recodes were made:
+#>   value_to From rows_recoded
+#> 1        0    0          145
+#> 2    NA::a    9            0
+#> 3        1    1           64
+#> 4    NA(b) else            0
+#> The variable stage was recoded into stage for the database tester1 the following recodes were made:
+#>   value_to From rows_recoded
+#> 1        1    1           12
+#> 2        2    2           46
+#> 3        4    4           74
+#> 4    NA::a    9            0
+#> 5        3    3           77
+#> 6    NA(b) else            0
+#> The variable status was recoded into status for the database tester1 the following recodes were made:
+#>   value_to From rows_recoded
+#> 1        1    1            7
+#> 2        2    2          108
+#> 3        0    0           94
+#> 4    NA::a    9            0
+#> 5    NA(b) else            0
+#> The variable time was recoded into time for the database tester1 the following recodes were made:
+#>   value_to     From rows_recoded
+#> 1     copy [0,5000]          209
+#> 2    NA::a     9999            0
+#> 3     <NA>     else            0
+#> The variable trig was recoded into trig for the database tester1 the following recodes were made:
+#>   value_to     From rows_recoded
+#> 1     copy [0,1000]          185
+#> 2    NA::a     9999            0
+#> 3     <NA>     else           24
+#> The variable trt was recoded into trt for the database tester1 the following recodes were made:
+#>   value_to From rows_recoded
+#> 1        2    2          103
+#> 2    NA::a    9            0
+#> 3        1    1          106
+#> 4    NA(b) else            0
+
+recoded2 <- rec_with_table(data = tester2,
+                           variables = recodeflow::tester_variables,
+                           variable_details = recodeflow::tester_variable_details,
+                          log = TRUE,
+                           database_name = 'tester2'
+                          )
+#> The variable age was recoded into age for the database tester2 the following recodes were made:
+#>   value_to    From rows_recoded
+#> 1     copy [20,80]          209
+#> 2    NA::a     999            0
+#> 3     <NA>    else            0
+#> The variable agegrp was recoded into age_cont for the database tester2 the following recodes were made:
+#>   value_to From rows_recoded
+#> 1       25    1            1
+#> 2       35    2           39
+#> 3       45    3           52
+#> 4       55    4           67
+#> 5       65    5           45
+#> 6       75    6            5
+#> 7     <NA> else            0
+#> The variable agegrp was recoded into agegrp10 for the database tester2 the following recodes were made:
+#>   value_to From rows_recoded
+#> 1        1    1            1
+#> 2        2    2           39
+#> 3        3    3           52
+#> 4        4    4           67
+#> 5        5    5           45
+#> 6        6    6            5
+#> 7    NA(b) else            0
+#> The variable albumin was recoded into albumin for the database tester2 the following recodes were made:
+#>   value_to  From rows_recoded
+#> 1     copy [1,5]          209
+#> 2    NA::a    99            0
+#> 3     <NA>  else            0
+#> The variable alk.phos was recoded into alk.phos for the database tester2 the following recodes were made:
+#>   value_to        From rows_recoded
+#> 1     copy [200,15000]          103
+#> 2    NA::a       99999            0
+#> 3     <NA>        else          106
+#> The variable ascites was recoded into ascites for the database tester2 the following recodes were made:
+#>   value_to From rows_recoded
+#> 1        1    1            6
+#> 2    NA::a    9            0
+#> 3        0    0           97
+#> 4    NA(b) else          106
+#> The variable ast was recoded into ast for the database tester2 the following recodes were made:
+#>   value_to     From rows_recoded
+#> 1     copy [20,500]          103
+#> 2    NA::a     9999            0
+#> 3     <NA>     else          106
+#> The variable bili was recoded into bili for the database tester2 the following recodes were made:
+#>   value_to    From rows_recoded
+#> 1     copy [0,100]          209
+#> 2     <NA>    else            0
+#> The variable chol was recoded into chol for the database tester2 the following recodes were made:
+#>   value_to       From rows_recoded
+#> 1     copy [100,2000]           98
+#> 2    NA::a       9999            0
+#> 3     <NA>       else          111
+#> The variable copper was recoded into copper for the database tester2 the following recodes were made:
+#>   value_to     From rows_recoded
+#> 1     copy [0,1000]          102
+#> 2    NA::a     9999            0
+#> 3     <NA>     else          107
+#> The variable edema was recoded into edema for the database tester2 the following recodes were made:
+#>   value_to From rows_recoded
+#> 1      0.5  0.5           22
+#> 2        1    1            4
+#> 3        0    0          183
+#> 4    NA::a    9            0
+#> 5    NA(b) else            0
+#> The variable hepato was recoded into hepato for the database tester2 the following recodes were made:
+#>   value_to From rows_recoded
+#> 1        0    0           50
+#> 2        1    1           53
+#> 3    NA::a    9            0
+#> 4    NA(b) else          106
+#> The variable platelet was recoded into platelet for the database tester2 the following recodes were made:
+#>   value_to     From rows_recoded
+#> 1     copy [0,1000]          202
+#> 2    NA::a     9999            0
+#> 3     <NA>     else            7
+#> The variable protime was recoded into protime for the database tester2 the following recodes were made:
+#>   value_to    From rows_recoded
+#> 1     copy [5, 30]          207
+#> 2    NA::a      99            0
+#> 3     <NA>    else            2
+#> The variable sex was recoded into sex for the database tester2 the following recodes were made:
+#>   value_to From rows_recoded
+#> 1        m    m           17
+#> 2    NA::a    9            0
+#> 3        f    f          192
+#> 4    NA(b) else            0
+#> The variable spiders was recoded into spiders for the database tester2 the following recodes were made:
+#>   value_to From rows_recoded
+#> 1        0    0           77
+#> 2    NA::a    9            0
+#> 3        1    1           26
+#> 4    NA(b) else          106
+#> The variable stage was recoded into stage for the database tester2 the following recodes were made:
+#>   value_to From rows_recoded
+#> 1        1    1            9
+#> 2        2    2           46
+#> 3        4    4           70
+#> 4    NA::a    9            0
+#> 5        3    3           78
+#> 6    NA(b) else            6
+#> The variable status was recoded into status for the database tester2 the following recodes were made:
+#>   value_to From rows_recoded
+#> 1        1    1           18
+#> 2        2    2           53
+#> 3        0    0          138
+#> 4    NA::a    9            0
+#> 5    NA(b) else            0
+#> The variable time was recoded into time for the database tester2 the following recodes were made:
+#>   value_to     From rows_recoded
+#> 1     copy [0,5000]          209
+#> 2    NA::a     9999            0
+#> 3     <NA>     else            0
+#> The variable trig was recoded into trig for the database tester2 the following recodes were made:
+#>   value_to     From rows_recoded
+#> 1     copy [0,1000]           97
+#> 2    NA::a     9999            0
+#> 3     <NA>     else          112
+#> The variable trt was recoded into trt for the database tester2 the following recodes were made:
+#>   value_to From rows_recoded
+#> 1        2    2           51
+#> 2    NA::a    9            0
+#> 3        1    1           52
+#> 4    NA(b) else          106
  1. Combine recoded datasets
-
-combined_dataset <- bind_rows(recoded1, recoded2)
+
+combined_dataset <- bind_rows(recoded1, recoded2)
  1. Set labels for the combined recoded dataset
-
-labeled_combined <- set_data_labels(data_to_label = combined_dataset,
-                                    variable_details = variable_details,
-                                    variables_sheet = variables
-                                    )
+
+labeled_combined <- set_data_labels(data_to_label = combined_dataset,
+                                    variable_details = recodeflow::tester_variable_details,
+                                    variables_sheet = recodeflow::tester_variables
+                                    )
-
-

-Example 6: Add the data origin in combined datasets

-

To know the origin of each row of data, you can use the rec_with_table argument attach_data_name. When the argument attach_data_name is set to true it will add a column with the name of the dataset the row is from.

+
+

Example 6: Add the data origin in combined datasets +

+

To know the origin of each row of data, you can use the +rec_with_table argument attach_data_name. When +the argument attach_data_name is set to true it will add a +column with the name of the dataset the row is from.

    -
  1. Recode variables age and sex and attach dataset name for tester1 and tester2.
  2. +
  3. Recode variables age and sex and attach +dataset name for tester1 and tester2.
-
-age_sex_1 <- rec_with_table(data = tester1,
-                            variables = c("age", "sex"), 
-                            variable_details = variable_details,
-                            var_labels = c(age = "Age", sex = "Sex"),
-                            log = TRUE,
-                            attach_data_name = TRUE
-                            )
-#> Using the passed data variable name as database_name
-#> NOTE for age: This is sample survival pbc data
-#> The variable age was recoded into age for the database tester1 the following recodes were made:
-#>   value_to    From rows_recoded
-#> 1     copy [25,79]          209
-#> 2     <NA>    else            0
-#> NOTE for sex: This is sample survival pbc data
-#> NOTE for sex: This is sample survival pbc data
-#> The variable sex was recoded into sex for the database tester1 the following recodes were made:
-#>   value_to From rows_recoded
-#> 1        0    m           27
-#> 2        1    f          182
-#> 3    NA(b) else            0
-
-age_sex_2 <- rec_with_table(data = tester2,
-                            variables = c("age", "sex"), 
-                            variable_details = variable_details,
-                            var_labels = c(age = "Age", sex = "Sex"),
-                            log = TRUE,
-                            attach_data_name = TRUE
-                            )
-#> Using the passed data variable name as database_name
-#> NOTE for age: This is sample survival pbc data
-#> The variable age was recoded into age for the database tester2 the following recodes were made:
-#>   value_to    From rows_recoded
-#> 1     copy [25,79]          209
-#> 2     <NA>    else            0
-#> NOTE for sex: This is sample survival pbc data
-#> NOTE for sex: This is sample survival pbc data
-#> The variable sex was recoded into sex for the database tester2 the following recodes were made:
-#>   value_to From rows_recoded
-#> 1        0    m           17
-#> 2        1    f          192
-#> 3    NA(b) else            0
+
+age_sex_1 <- rec_with_table(data = tester1,
+                            variables = c("age", "sex"), 
+                            variable_details = recodeflow::tester_variable_details,
+                            var_labels = c(age = "Age", sex = "Sex"),
+                            log = TRUE,
+                            attach_data_name = TRUE,
+                           database_name = 'tester1'
+                            )
+#> The variable age was recoded into age for the database tester1 the following recodes were made:
+#> # A tibble: 3 × 3
+#>   value_to From    rows_recoded
+#>   <chr>    <chr>          <int>
+#> 1 copy     [20,80]          209
+#> 2 NA::a    999                0
+#> 3 NA       else               0
+#> The variable sex was recoded into sex for the database tester1 the following recodes were made:
+#> # A tibble: 4 × 3
+#>   value_to From  rows_recoded
+#>   <chr>    <chr>        <int>
+#> 1 m        m               27
+#> 2 f        f              182
+#> 3 NA::a    9                0
+#> 4 NA(b)    else             0
+
+age_sex_2 <- rec_with_table(data = tester2,
+                            variables = c("age", "sex"), 
+                            variable_details = recodeflow::tester_variable_details,
+                            var_labels = c(age = "Age", sex = "Sex"),
+                            log = TRUE,
+                            attach_data_name = TRUE,
+                           database_name = 'tester2'
+                            )
+#> The variable age was recoded into age for the database tester2 the following recodes were made:
+#> # A tibble: 3 × 3
+#>   value_to From    rows_recoded
+#>   <chr>    <chr>          <int>
+#> 1 copy     [20,80]          209
+#> 2 NA::a    999                0
+#> 3 NA       else               0
+#> The variable sex was recoded into sex for the database tester2 the following recodes were made:
+#> # A tibble: 4 × 3
+#>   value_to From  rows_recoded
+#>   <chr>    <chr>        <int>
+#> 1 m        m               17
+#> 2 f        f              192
+#> 3 NA::a    9                0
+#> 4 NA(b)    else             0
  1. Combine the harmonized datasets
-
-combined_age_sex <- bind_rows(age_sex_1, age_sex_2)
-
-head(combined_age_sex)
-#>        age sex data_name
-#> 1 58.76523   1   tester1
-#> 2 56.44627   1   tester1
-#> 3 70.07255   0   tester1
-#> 4 54.74059   1   tester1
-#> 5 38.10541   1   tester1
-#> 6 66.25873   1   tester1
-tail(combined_age_sex)
-#>          age sex data_name
-#> 413 35.00068   1   tester2
-#> 414 67.00068   1   tester2
-#> 415 39.00068   1   tester2
-#> 416 56.99932   1   tester2
-#> 417 58.00137   1   tester2
-#> 418 52.99932   1   tester2
+
+combined_age_sex <- bind_rows(age_sex_1, age_sex_2)
+
+head(combined_age_sex)
+#>        age sex data_name
+#> 1 58.76523   f   tester1
+#> 2 56.44627   f   tester1
+#> 3 70.07255   m   tester1
+#> 4 54.74059   f   tester1
+#> 5 38.10541   f   tester1
+#> 6 66.25873   f   tester1
+tail(combined_age_sex)
+#>          age sex data_name
+#> 413 35.00068   f   tester2
+#> 414 67.00068   f   tester2
+#> 415 39.00068   f   tester2
+#> 416 56.99932   f   tester2
+#> 417 58.00137   f   tester2
+#> 418 52.99932   f   tester2
-
-

-Example 7. Recode derived variables

-

Derived variables are variables that are not in the original dataset; rather they are created using variables from the original dataset.

+
+

Example 7. Recode derived variables +

+

Derived variables are variables that are not in the original dataset; +rather they are created using variables from the original dataset.

Descriptions of derived functions are in the article derived functions

To recode a derived variable, you must:

  • create a customized function,
  • -
  • defined the derived variable on the worksheets variables and variable_details,
  • +
  • defined the derived variable on the worksheets +variables and variable_details,
  • recode the variables that make up the derived variable.
-

Our example derived variable example_der equals chol times bili.

+

Our example derived variable example_der equals +chol times bili.

    -
  1. Recode the underlying variables: chol and bili and the derived variable example_der for tester1 and tester2.
  2. +
  3. Recode the underlying variables: chol and +bili and the derived variable example_der for +tester1 and tester2.
-
-derived1 <- rec_with_table(data = tester1,
-                          variables = c("chol", "bili","example_der"),
-                          variable_details = variable_details,
-                          log = TRUE)
-#> Using the passed data variable name as database_name
-#> NOTE for bili: This is sample survival pbc data
-#> The variable bili was recoded into bili for the database tester1 the following recodes were made:
-#>   value_to   From rows_recoded
-#> 1     copy [0,28]          209
-#> 2     <NA>   else            0
-#> NOTE for chol: This is sample survival pbc data
-#> NOTE for chol: This is sample survival pbc data
-#> The variable chol was recoded into chol for the database tester1 the following recodes were made:
-#>   value_to        From rows_recoded
-#> 1     copy [120, 1775]          186
-#> 2    Na::a          NA            0
-#> 3     <NA>        else           23
-
-derived2 <- rec_with_table(data = tester2,
-                          variables = c("chol", "bili","example_der"),
-                          variable_details = variable_details,
-                          log = TRUE)
-#> Using the passed data variable name as database_name
-#> NOTE for bili: This is sample survival pbc data
-#> The variable bili was recoded into bili for the database tester2 the following recodes were made:
-#>   value_to   From rows_recoded
-#> 1     copy [0,28]          209
-#> 2     <NA>   else            0
-#> NOTE for chol: This is sample survival pbc data
-#> NOTE for chol: This is sample survival pbc data
-#> The variable chol was recoded into chol for the database tester2 the following recodes were made:
-#>   value_to        From rows_recoded
-#> 1     copy [120, 1775]           98
-#> 2    Na::a          NA            0
-#> 3     <NA>        else          111
+
+derived1 <- rec_with_table(data = tester1,
+                          variables = c("chol", "bili","example_der"),
+                          variable_details = recodeflow::tester_variable_details,
+                          log = TRUE,
+                           database_name = 'tester1')
+#> The variable bili was recoded into bili for the database tester1 the following recodes were made:
+#> # A tibble: 2 × 3
+#>   value_to From    rows_recoded
+#>   <chr>    <chr>          <int>
+#> 1 copy     [0,100]          209
+#> 2 NA       else               0
+#> The variable chol was recoded into chol for the database tester1 the following recodes were made:
+#> # A tibble: 3 × 3
+#>   value_to From       rows_recoded
+#>   <chr>    <chr>             <int>
+#> 1 copy     [100,2000]          186
+#> 2 NA::a    9999                  0
+#> 3 NA       else                 23
+
+derived2 <- rec_with_table(data = tester2,
+                          variables = c("chol", "bili","example_der"),
+                          variable_details = recodeflow::tester_variable_details,
+                          log = TRUE,
+                           database_name = 'tester2')
+#> The variable bili was recoded into bili for the database tester2 the following recodes were made:
+#> # A tibble: 2 × 3
+#>   value_to From    rows_recoded
+#>   <chr>    <chr>          <int>
+#> 1 copy     [0,100]          209
+#> 2 NA       else               0
+#> The variable chol was recoded into chol for the database tester2 the following recodes were made:
+#> # A tibble: 3 × 3
+#>   value_to From       rows_recoded
+#>   <chr>    <chr>             <int>
+#> 1 copy     [100,2000]           98
+#> 2 NA::a    9999                  0
+#> 3 NA       else                111
    -
  1. Combine the harmonized variables: chol, bili, and exampler_der +
  2. Combine the harmonized variables: chol, +bili, and exampler_der
-
-combined_der <- bind_rows(derived1, derived2)
+
+combined_der <- bind_rows(derived1, derived2)
+ +
-

Site built with pkgdown 1.6.1.

+

+

Site built with pkgdown 2.1.1.

- + + + diff --git a/docs/articles/how_to_recode_files/header-attrs-2.29/header-attrs.js b/docs/articles/how_to_recode_files/header-attrs-2.29/header-attrs.js new file mode 100644 index 00000000..dd57d92e --- /dev/null +++ b/docs/articles/how_to_recode_files/header-attrs-2.29/header-attrs.js @@ -0,0 +1,12 @@ +// Pandoc 2.9 adds attributes on both header and div. We remove the former (to +// be compatible with the behavior of Pandoc < 2.8). +document.addEventListener('DOMContentLoaded', function(e) { + var hs = document.querySelectorAll("div.section[class*='level'] > :first-child"); + var i, h, a; + for (i = 0; i < hs.length; i++) { + h = hs[i]; + if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6 + a = h.attributes; + while (a.length > 0) h.removeAttribute(a[0].name); + } +}); diff --git a/docs/articles/how_to_use_recodeflow_with_your_data.html b/docs/articles/how_to_use_recodeflow_with_your_data.html index 63ac92f3..0f0b7f78 100644 --- a/docs/articles/how_to_use_recodeflow_with_your_data.html +++ b/docs/articles/how_to_use_recodeflow_with_your_data.html @@ -5,27 +5,27 @@ -Use recodeflow with your data • recodeflow +How to use recodeflow with your data • recodeflow - + - - - + + +
-

To use recodeflow with your data, you’ll need create the following worksheets:

+

To use recodeflow with your data, you’ll need create the +following worksheets:

  • -variable_details - mapping of variables across datasets and a list of instructions on how to recode variables, and
  • +variable_details - mapping of variables across datasets +and a list of instructions on how to recode variables, and
  • variables - a list of variables to recode
-

Files can either be a .csv file that you import to R or a dataframe created directly in R.

-

If you have derived variables, you will also need to create custom functions. For more information on custom functions see the article derived variables.

-
-

-Example data

-

Our examples use the dataset pbc from the package survival. We’ve split this dataset in two (tester1 and tester2) to mimic real data e.g., the same survey preformed in separate years. We’ve also added columns (agegrp5 and agegrp10) to this dataset for our examples.

-

We’ll use our example datasets and the variable stage. The variable stage captures the histologic stage of the patient’s disease (primary biliary cirrhosis (PBC)).

+

Files can either be a .csv file that you import to R or +a dataframe created directly in R.

+

If you have derived variables, you will also need to create custom +functions. For more information on custom functions see the article derived variables.

+
+

Example data +

+

Our examples use the dataset pbc from the package survival. +We’ve split this dataset in two (tester1 and tester2) to mimic real data +e.g., the same survey preformed in separate years. We’ve also added +columns (agegrp5 and agegrp10) to this dataset +for our examples.

+

We’ll use our example datasets and the variable stage. +The variable stage captures the histologic stage of the +patient’s disease (primary biliary cirrhosis (PBC)).

-
-

-How to create the variable_details worksheet

-

The variable_details worksheet does two important steps. First, it maps variables across datasets. Second, it gives instructions on how to recode the variables.

-

Note: additional information for the variable_details worksheet is in the article variable_details.

-

Note: additional details on how to add derived variables to the variable_detials worksheet is in the article derived variables.

-
-

-Rows

-

For the stage variable, there are the following six rows:

+
+

How to create the variable_details worksheet +

+

The variable_details worksheet does two important steps. +First, it maps variables across datasets. Second, it gives instructions +on how to recode the variables.

+

Note: additional information for the variable_details +worksheet is in the article variable_details.

+

Note: additional details on how to add derived variables to the +variable_detials worksheet is in the article derived variables.

+
+

Rows +

+

For the stage variable, there are the following six +rows:

    -
  • 4 rows for the 4 categories for the histological stage of the disease,
  • +
  • 4 rows for the 4 categories for the histological stage of the +disease,
  • 1 row for the not applicable responses, and
  • 1 row for else.
-

Since stage is coded consistently across the two datasets (tester1 and tester2) we only need one row per categorical response.

+

Since stage is coded consistently across the two +datasets (tester1 and tester2) we only need one row per categorical +response.

-
-

-Columns (14)

+
+

Columns (14) +

  1. -variable: the name of the final recoded variable. We’ll use the same name as in the original dataset stage though you could rename the variable.
  2. +variable: the name of the final recoded variable. +We’ll use the same name as in the original dataset stage +though you could rename the variable.
-

Write stage in the column variable in the six rows.

+

Write stage in the column variable in +the six rows.

- - + + - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
-variable -
variable
-stage -
-stage -
-stage -
-stage -
-stage -
-stage -
age
age
age
albumin
albumin
albumin
alk.phos
alk.phos
ascites
ascites
ascites
ascites
alk.phos
ast
ast
ast
bili
bili
chol
chol
chol
copper
copper
edema
edema
edema
edema
edema
hepato
hepato
hepato
copper
platelet
platelet
platelet
protime
protime
hepato
sex
sex
sex
sex
spiders
spiders
spiders
spiders
stage
stage
stage
stage
stage
stage
status
status
status
status
protime
time
time
time
trig
trig
status
trt
trt
trt
trt
trig
example_der
agegrp10
agegrp10
agegrp10
agegrp10
agegrp10
agegrp10
agegrp10
agegrp5
agegrp5
agegrp5
agegrp5
agegrp5
agegrp5
agegrp5
agegrp5
agegrp5
agegrp5
agegrp5
agegrp5
age_cont
age_cont
age_cont
age_cont
age_cont
age_cont
age_cont
age_cont
age_cont
age_cont
age_cont
age_cont
age_cont
age_cont
age_cont
age_cont
age_cont
age_cont
age_cont
agegrp10
agegrp10
agegrp10
agegrp10
agegrp10
agegrp10
agegrp10
agegrp10
agegrp10
agegrp10
agegrp10
agegrp10
  1. -typeEnd: indicates the type of variable (continous or categorical)for the recoded (final) variable. stage, which captures the stage of the disease, is a categorical variable in the original dataset and will remain a categorical variable after recoding.
  2. +typeEnd: indicates the type of variable (continous +or categorical)for the recoded (final) variable. stage, +which captures the stage of the disease, is a categorical variable in +the original dataset and will remain a categorical variable after +recoding.

Write ‘cat’ in the six rows.

- - - - ++++++++++++++++++ + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + - -
- -variable - -typeEnd -
variabledummyVariabletypeEndtypeStartdatabaseStartvariableStartvariableStartLabelnumValidCatrecEndcatLabelcatLabelLongunitsrecStartcatStartLabelvariableStartShortLabelnotes
-58 - -stage - -cat -
-59 - -stage - -cat -
-60 - -stage - -cat -
-61 - -stage - -cat -
-62 - -stage - -cat -
-63 - -stage - -cat -
ageNAcontconttester1; tester2[age]ageNAcopyNANANA[20,80]NAageNA
-
    -
  1. -typeStart: indicates the type of variable (continous or categorical) for the original variable. stage is a categorical variable in the original dataset.
  2. -
-

Write ‘cat’ in the six rows.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + - -
- -variable - -typeEnd - -typeStart -
-58 - -stage - -cat - -cat -
-59 - -stage - -cat - -cat -
-60 - -stage - -cat - -cat -
-61 - -stage - -cat - -cat -
-62 - -stage - -cat - -cat -
-63 - -stage - -cat - -cat -
ageNAcontconttester1; tester2[age]ageNANA::bmissingmissingNAelseNAageNA
-
    -
  1. -databaseStart: indicates the name of the database(s) from which the original variable(s) is(are) obtained.
  2. -
-

Write the dataset names, separated by a comma, in the six rows

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + - -
- -variable - -typeEnd - -typeStart - -databaseStart -
-58 - -stage - -cat - -cat - -tester1, tester2 -
-59 - -stage - -cat - -cat - -tester1, tester2 -
-60 - -stage - -cat - -cat - -tester1, tester2 -
-61 - -stage - -cat - -cat - -tester1, tester2 -
-62 - -stage - -cat - -cat - -tester1, tester2 -
-63 - -stage - -cat - -cat - -tester1, tester2 -
ageNAcontconttester1; tester2[age]ageNANA::anot applicablenot applicableNA999NAageNA
-
    -
  1. -variableStart: indicates the original variable name(s) in the database(s). In our example, both datasets have the start variable stage. Therefore we can indicate a single variable name here. If the variable names were different, we would need to indicate ‘dataset_name::variable_name’ separated by commas for each of the datasets.
  2. -
-

Write the variable name in squared brackets once per row, for all six rows.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + - -
- -variable - -typeEnd - -typeStart - -databaseStart - -variableStart -
-58 - -stage - -cat - -cat - -tester1, tester2 - -[stage] -
-59 - -stage - -cat - -cat - -tester1, tester2 - -[stage] -
-60 - -stage - -cat - -cat - -tester1, tester2 - -[stage] -
-61 - -stage - -cat - -cat - -tester1, tester2 - -[stage] -
-62 - -stage - -cat - -cat - -tester1, tester2 - -[stage] -
-63 - -stage - -cat - -cat - -tester1, tester2 - -[stage] -
albuminNAcontconttester1; tester2[albumin]albuminNAcopyNANANA[1,5]NAalbuminNA
-
    -
  1. -variableStartLabel: indicates the original variable lable
  2. -
-

Write “stage” in the 6 rows.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + - -
- -variable - -typeEnd - -typeStart - -databaseStart - -variableStart - -variableStartLabel -
-58 - -stage - -cat - -cat - -tester1, tester2 - -[stage] - -stage -
-59 - -stage - -cat - -cat - -tester1, tester2 - -[stage] - -stage -
-60 - -stage - -cat - -cat - -tester1, tester2 - -[stage] - -stage -
-61 - -stage - -cat - -cat - -tester1, tester2 - -[stage] - -stage -
-62 - -stage - -cat - -cat - -tester1, tester2 - -[stage] - -stage -
-63 - -stage - -cat - -cat - -tester1, tester2 - -[stage] - -stage -
albuminNAcontconttester1; tester2[albumin]albuminNANA::bmissingmissingNAelseNAalbuminNA
-
    -
  1. -numValidCat: indicates the number of valid categories for the final derived variable. In our example, there are four categories for stage: 1, 2, 3, and 4. Note that the categories ‘not applicable’, ‘missing’, and ‘else’ are not included in the category count.
  2. -
-

Write 4 in each of the six rows.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + - -
- -variable - -typeEnd - -typeStart - -databaseStart - -variableStart - -variableStartLabel - -numValidCat -
-58 - -stage - -cat - -cat - -tester1, tester2 - -[stage] - -stage - -4 -
-59 - -stage - -cat - -cat - -tester1, tester2 - -[stage] - -stage - -4 -
-60 - -stage - -cat - -cat - -tester1, tester2 - -[stage] - -stage - -4 -
-61 - -stage - -cat - -cat - -tester1, tester2 - -[stage] - -stage - -4 -
-62 - -stage - -cat - -cat - -tester1, tester2 - -[stage] - -stage - -4 -
-63 - -stage - -cat - -cat - -tester1, tester2 - -[stage] - -stage - -4 -
albuminNAcontconttester1; tester2[albumin]albuminNANA::anot applicablenot applicableNA99NAalbuminNA
-
    -
  1. -recEnd: indicates the category to which you are recoding each row. For the not applicable rows NA::a is written. For the missing and else rows NA::b is written. The haven package is used for tagging NA in numeric variables.
  2. -
-

We are not changing the categories stage, therefore, the recEnd values for these rows will be the same as the the original data. For the not applicable rows write NA::a. For the missing and else rows write NA::b.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + - -
- -variable - -typeEnd - -typeStart - -databaseStart - -variableStart - -variableStartLabel - -numValidCat - -recEnd -
-58 - -stage - -cat - -cat - -tester1, tester2 - -[stage] - -stage - -4 - -1 -
-59 - -stage - -cat - -cat - -tester1, tester2 - -[stage] - -stage - -4 - -2 -
-60 - -stage - -cat - -cat - -tester1, tester2 - -[stage] - -stage - -4 - -3 -
-61 - -stage - -cat - -cat - -tester1, tester2 - -[stage] - -stage - -4 - -4 -
-62 - -stage - -cat - -cat - -tester1, tester2 - -[stage] - -stage - -4 - -Na::a -
-63 - -stage - -cat - -cat - -tester1, tester2 - -[stage] - -stage - -4 - -NA::b -
alk.phosNAcontconttester1; tester2[alk.phos]alk.phosNAcopyNANANA[200,15000]NAalk.phosNA
-
    -
  1. -catLabel: indicates the lable for the recoded categorical level.
  2. -
-

Write Stage 1, Stage 2, Stage 3, Stage 4, NA, and missing.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + - -
- -variable - -typeEnd - -typeStart - -databaseStart - -variableStart - -variableStartLabel - -numValidCat - -recEnd - -catLabel -
-58 - -stage - -cat - -cat - -tester1, tester2 - -[stage] - -stage - -4 - -1 - -stage 1 -
-59 - -stage - -cat - -cat - -tester1, tester2 - -[stage] - -stage - -4 - -2 - -stage 2 -
-60 - -stage - -cat - -cat - -tester1, tester2 - -[stage] - -stage - -4 - -3 - -stage 3 -
-61 - -stage - -cat - -cat - -tester1, tester2 - -[stage] - -stage - -4 - -4 - -stage 4 -
-62 - -stage - -cat - -cat - -tester1, tester2 - -[stage] - -stage - -4 - -Na::a - -NA -
-63 - -stage - -cat - -cat - -tester1, tester2 - -[stage] - -stage - -4 - -NA::b - -missing -
alk.phosNAcontconttester1; tester2[alk.phos]alk.phosNANA::bmissingmissingNAelseNAalk.phosNA
-
    -
  1. -catLabelLong: provides a more elaborate lable for the recoded categorical level. If not required, repeat the shorter catLabel.
  2. -
-

Copy values from catLabel

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + - -
- -variable - -typeEnd - -typeStart - -databaseStart - -variableStart - -variableStartLabel - -numValidCat - -recEnd - -catLabel - -catLabelLong -
-58 - -stage - -cat - -cat - -tester1, tester2 - -[stage] - -stage - -4 - -1 - -stage 1 - -stage 1 -
-59 - -stage - -cat - -cat - -tester1, tester2 - -[stage] - -stage - -4 - -2 - -stage 2 - -stage 2 -
-60 - -stage - -cat - -cat - -tester1, tester2 - -[stage] - -stage - -4 - -3 - -stage 3 - -stage 3 -
-61 - -stage - -cat - -cat - -tester1, tester2 - -[stage] - -stage - -4 - -4 - -stage 4 - -stage 4 -
-62 - -stage - -cat - -cat - -tester1, tester2 - -[stage] - -stage - -4 - -Na::a - -NA - -NA -
-63 - -stage - -cat - -cat - -tester1, tester2 - -[stage] - -stage - -4 - -NA::b - -missing - -missing -
ascitesascites_cat3_1catcattester1; tester2[ascites]ascites20ascites 0ascites 0NA0ascites 0ascitesNA
-
    -
  1. -units: indicates the unit of measure for the variable. The histologic stage of disease does not have a units of measurement.
  2. -
-

Write “N/A” in all six rows.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + - -
- -variable - -typeEnd - -typeStart - -databaseStart - -variableStart - -variableStartLabel - -numValidCat - -recEnd - -catLabel - -catLabelLong - -units -
-58 - -stage - -cat - -cat - -tester1, tester2 - -[stage] - -stage - -4 - -1 - -stage 1 - -stage 1 - -N/A -
-59 - -stage - -cat - -cat - -tester1, tester2 - -[stage] - -stage - -4 - -2 - -stage 2 - -stage 2 - -N/A -
-60 - -stage - -cat - -cat - -tester1, tester2 - -[stage] - -stage - -4 - -3 - -stage 3 - -stage 3 - -N/A -
-61 - -stage - -cat - -cat - -tester1, tester2 - -[stage] - -stage - -4 - -4 - -stage 4 - -stage 4 - -N/A -
-62 - -stage - -cat - -cat - -tester1, tester2 - -[stage] - -stage - -4 - -Na::a - -NA - -NA - -N/A -
-63 - -stage - -cat - -cat - -tester1, tester2 - -[stage] - -stage - -4 - -NA::b - -missing - -missing - -N/A -
ascitesascites_cat3_2catcattester1; tester2[ascites]ascites21ascites 1ascites 1NA1ascites 1ascitesNA
-
    -
  1. -recStart: indicates the category(ies) from which you are recoding each row. Since we are not combining levels of categories and we are keeping the category levels the same, the recStart column will be identical to recEnd. If multiple categories were being combined into a single category, the original categories would be indicated in square brackets, separated by commas.
  2. -
-

Write the category level you are recoding each row too. For the not applicable rows NA::a is written. For the missing and else rows NA::b is written.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + - -
- -variable - -typeEnd - -typeStart - -databaseStart - -variableStart - -variableStartLabel - -numValidCat - -recEnd - -catLabel - -catLabelLong - -units - -recStart -
-58 - -stage - -cat - -cat - -tester1, tester2 - -[stage] - -stage - -4 - -1 - -stage 1 - -stage 1 - -N/A - -1 -
-59 - -stage - -cat - -cat - -tester1, tester2 - -[stage] - -stage - -4 - -2 - -stage 2 - -stage 2 - -N/A - -2 -
-60 - -stage - -cat - -cat - -tester1, tester2 - -[stage] - -stage - -4 - -3 - -stage 3 - -stage 3 - -N/A - -3 -
-61 - -stage - -cat - -cat - -tester1, tester2 - -[stage] - -stage - -4 - -4 - -stage 4 - -stage 4 - -N/A - -4 -
-62 - -stage - -cat - -cat - -tester1, tester2 - -[stage] - -stage - -4 - -Na::a - -NA - -NA - -N/A - -Na -
-63 - -stage - -cat - -cat - -tester1, tester2 - -[stage] - -stage - -4 - -NA::b - -missing - -missing - -N/A - -else -
ascitesascites_cat3_NA::bcatcattester1; tester2[ascites]ascites2NA::bmissingmissingNAelseascites 0ascitesNA
-
    -
  1. -catStartLabel: indicates the original variable category label. The stage label should be identical to what is shown in the original data documentation. For the missing rows, each missing category is described along with their coded values.
  2. -
-

Write Stage 1, Stage 2, Stage 3, Stage 4, NA, and missing.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + - -
- -variable - -typeEnd - -typeStart - -databaseStart - -variableStart - -variableStartLabel - -numValidCat - -recEnd - -catLabel - -catLabelLong - -units - -recStart - -catStartLabel -
-58 - -stage - -cat - -cat - -tester1, tester2 - -[stage] - -stage - -4 - -1 - -stage 1 - -stage 1 - -N/A - -1 - -stage 1 -
-59 - -stage - -cat - -cat - -tester1, tester2 - -[stage] - -stage - -4 - -2 - -stage 2 - -stage 2 - -N/A - -2 - -stage 2 -
-60 - -stage - -cat - -cat - -tester1, tester2 - -[stage] - -stage - -4 - -3 - -stage 3 - -stage 3 - -N/A - -3 - -stage 3 -
-61 - -stage - -cat - -cat - -tester1, tester2 - -[stage] - -stage - -4 - -4 - -stage 4 - -stage 4 - -N/A - -4 - -stage 4 -
-62 - -stage - -cat - -cat - -tester1, tester2 - -[stage] - -stage - -4 - -Na::a - -NA - -NA - -N/A - -Na - -N/A -
-63 - -stage - -cat - -cat - -tester1, tester2 - -[stage] - -stage - -4 - -NA::b - -missing - -missing - -N/A - -else - -missing -
ascitesascites_cat3_NA::acatcattester1; tester2[ascites]ascites2NA::anot applicablenot applicableNA9not applicableNANA
-
    -
  1. -notes: Capture any important differences in a variable across datasets. For our example, there are no differences across datasets.
  2. -
-

Write “This is sample survival pbc data” in all six rows.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + - -
- -variable - -typeEnd - -typeStart - -databaseStart - -variableStart - -variableStartLabel - -numValidCat - -recEnd - -catLabel - -catLabelLong - -units - -recStart - -catStartLabel - -notes -
-58 - -stage - -cat - -cat - -tester1, tester2 - -[stage] - -stage - -4 - -1 - -stage 1 - -stage 1 - -N/A - -1 - -stage 1 - -This is sample survival pbc data -
-59 - -stage - -cat - -cat - -tester1, tester2 - -[stage] - -stage - -4 - -2 - -stage 2 - -stage 2 - -N/A - -2 - -stage 2 - -This is sample survival pbc data -
-60 - -stage - -cat - -cat - -tester1, tester2 - -[stage] - -stage - -4 - -3 - -stage 3 - -stage 3 - -N/A - -3 - -stage 3 - -This is sample survival pbc data -
-61 - -stage - -cat - -cat - -tester1, tester2 - -[stage] - -stage - -4 - -4 - -stage 4 - -stage 4 - -N/A - -4 - -stage 4 - -This is sample survival pbc data -
-62 - -stage - -cat - -cat - -tester1, tester2 - -[stage] - -stage - -4 - -Na::a - -NA - -NA - -N/A - -Na - -N/A - -This is sample survival pbc data -
-63 - -stage - -cat - -cat - -tester1, tester2 - -[stage] - -stage - -4 - -NA::b - -missing - -missing - -N/A - -else - -missing - -This is sample survival pbc data -
alk.phosNAcontconttester1; tester2[alk.phos]alk.phosNANA::anot applicablenot applicableNA99999NAalk.phosNA
-
-
-
-

-variable_details for dervived variables

-

The same naming convention applies to derived variables with the exception of two columns:

-
    -
  1. In variableStart, instead of database names being listed, DerivedVar:: is written followed with the list of original variables used inside square brackets.
  2. -
-
    -
  • DerivedVar::[var1, var2, var3]
  • -
-
    -
  1. In recEnd, write Func:: followed with the exact name of the custom function used to create the derived variable.
  2. -
-
    -
  • Func::derivedFunction
  • -
-

A derived variable looks like this in variable_details.csv

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -variable - -typeEnd - -typeStart - -databaseStart - -variableStart - -variableStartLabel - -numValidCat - -recEnd - -catLabel - -catLabelLong - -units - -recStart - -catStartLabel - -notes -
-64 - -example_der - -cont - -cont - -tester1, tester2 - -DerivedVar::[chol, bili] - -example_der - -N/A - -Func::example_der_fun - -N/A - -N/A - -mg/dl - -else - -N/A - -This is sample survival pbc data -
-
-
-

-How to create the variables worksheet variables -

-

Once mapped and specified on variable_details, the stage variable can be specified on the variables worksheet: variables. Ensure that the names you used in the variable_details worksheet are identical to those listed in variables.

+ +ast +NA +cont +cont +tester1; tester2 +[ast] +ast +NA +copy +NA +NA +NA +[20,500] +NA +ast +NA + + +ast +NA +cont +cont +tester1; tester2 +[ast] +ast +NA +NA::b +missing +missing +NA +else +NA +ast +NA + + +ast +NA +cont +cont +tester1; tester2 +[ast] +ast +NA +NA::a +not applicable +not applicable +NA +9999 +NA +ast +NA + + +bili +NA +cont +cont +tester1; tester2 +[bili] +bili +NA +copy +NA +NA +NA +[0,100] +NA +bili +NA + + +bili +NA +cont +cont +tester1; tester2 +[bili] +bili +NA +NA::b +missing +missing +NA +else +NA +bili +NA + + +chol +NA +cont +cont +tester1; tester2 +[chol] +chol +NA +copy +NA +NA +NA +[100,2000] +NA +chol +NA + + +chol +NA +cont +cont +tester1; tester2 +[chol] +chol +NA +NA::b +missing +missing +NA +else +NA +chol +NA + + +chol +NA +cont +cont +tester1; tester2 +[chol] +chol +NA +NA::a +missing +missing +NA +9999 +NA +chol +NA + + +copper +NA +cont +cont +tester1; tester2 +[copper] +copper +NA +copy +NA +NA +NA +[0,1000] +NA +copper +NA + + +copper +NA +cont +cont +tester1; tester2 +[copper] +copper +NA +NA::b +missing +missing +NA +else +NA +copper +NA + + +edema +edema_cat3_1 +cat +cat +tester1; tester2 +[edema] +edema +3 +0 +edema 0.0 +edema 0.0 +NA +0 +edema 0.0 +edema +NA + + +edema +edema_cat3_2 +cat +cat +tester1; tester2 +[edema] +edema +3 +0.5 +edema 0.5 +edema 0.5 +NA +0.5 +edema 0.5 +edema +NA + + +edema +edema_cat3_3 +cat +cat +tester1; tester2 +[edema] +edema +3 +1 +edema 1.0 +edema 1.0 +NA +1 +edema 1.0 +edema +NA + + +edema +edema_cat3_NA::b +cat +cat +tester1; tester2 +[edema] +edema +3 +NA::b +missing +missing +NA +else +missing +edema +NA + + +edema +edema_cat3_NA::a +cat +cat +tester1; tester2 +[edema] +edema +3 +NA::a +not applicable +not applicable +NA +9 +not applicable +edema +NA + + +hepato +heapto_cat3_1 +cat +cat +tester1; tester2 +[hepato] +hepato +2 +0 +hepato 0 +hepato 0 +NA +0 +hepato 0 +hepato +NA + + +hepato +heapto_cat3_1 +cat +cat +tester1; tester2 +[hepato] +hepato +2 +1 +hepato 1 +hepato 1 +NA +1 +hepato 1 +hepato +NA + + +hepato +heapto_cat3_NA::a +cat +cat +tester1; tester2 +[hepato] +hepato +2 +NA::b +missing +missing +NA +else +missing +hepato +NA + + +copper +NA +cont +cont +tester1; tester2 +[copper] +copper +NA +NA::a +missing +missing +NA +9999 +NA +copper +NA + + +platelet +NA +cont +cont +tester1; tester2 +[platelet] +platelet +NA +copy +NA +NA +NA +[0,1000] +NA +platelet +NA + + +platelet +NA +cont +cont +tester1; tester2 +[platelet] +platelet +NA +NA::b +missing +missing +NA +else +NA +platelet +NA + + +platelet +NA +cont +cont +tester1; tester2 +[platelet] +platelet +NA +NA::a +not applicable +not applicable +NA +9999 +NA +platelet +NA + + +protime +NA +cont +cont +tester1; tester2 +[protime] +protime +NA +copy +NA +NA +NA +[5, 30] +NA +protime +NA + + +protime +NA +cont +cont +tester1; tester2 +[protime] +protime +NA +NA::b +missing +missing +NA +else +NA +protime +NA + + +hepato +heapto_cat3_NA::b +cat +cat +tester1; tester2 +[hepato] +hepato +2 +NA::a +not applicable +not applicable +NA +9 +not applicable +hepato +NA + + +sex +sex_cat2_1 +cat +cat +tester1; tester2 +[sex] +sex +2 +m +sex m +sex m +NA +m +sex m +sex +NA + + +sex +sex_cat2_2 +cat +cat +tester1; tester2 +[sex] +sex +2 +f +sex f +sex f +NA +f +sex f +sex +NA + + +sex +sex_cat2_NA::b +cat +cat +tester1; tester2 +[sex] +sex +2 +NA::b +missing +missing +NA +else +sex m +sex +NA + + +sex +sex_cat2_NA::a +cat +cat +tester1; tester2 +[sex] +sex +2 +NA::a +not applicable +not applicable +NA +9 +sex m +sex +NA + + +spiders +spiders0 +cat +cat +tester1; tester2 +[spiders] +spiders +2 +0 +spiders 0 +spiders 0 +NA +0 +spiders 0 +spiders +NA + + +spiders +spiders1 +cat +cat +tester1; tester2 +[spiders] +spiders +2 +1 +spiders 1 +spiders 1 +NA +1 +spiders 1 +spiders +NA + + +spiders +spiders_NA::b +cat +cat +tester1; tester2 +[spiders] +spiders +2 +NA::b +missing +missing +NA +else +spiders 0 +spiders +NA + + +spiders +spiders_NA::a +cat +cat +tester1; tester2 +[spiders] +spiders +2 +NA::a +not applicable +not applicable +NA +9 +not applicable +spiders +NA + + +stage +stage1 +cat +cat +tester1; tester2 +[stage] +stage +4 +1 +stage 1 +stage 1 +NA +1 +stage 1 +stage +NA + + +stage +stage2 +cat +cat +tester1; tester2 +[stage] +stage +4 +2 +stage 2 +stage 2 +NA +2 +stage 2 +stage +NA + + +stage +stage3 +cat +cat +tester1; tester2 +[stage] +stage +4 +3 +stage 3 +stage 3 +NA +3 +stage 3 +stage +NA + + +stage +stage4 +cat +cat +tester1; tester2 +[stage] +stage +4 +4 +stage 4 +stage 4 +NA +4 +stage 4 +stage +NA + + +stage +stage_NA::b +cat +cat +tester1; tester2 +[stage] +stage +4 +NA::b +missing +missing +NA +else +missing +stage +NA + + +stage +stage_NA::a +cat +cat +tester1; tester2 +[stage] +stage +4 +NA::a +not applicable +not applicable +NA +9 +not applicable +stage +NA + + +status +status0 +cat +cat +tester1; tester2 +[status] +status +3 +0 +status 0 +status 0 +NA +0 +status 0 +status +NA + + +status +status1 +cat +cat +tester1; tester2 +[status] +status +3 +1 +status 1 +status 1 +NA +1 +status 1 +status +NA + + +status +status2 +cat +cat +tester1; tester2 +[status] +status +3 +2 +status 2 +status 2 +NA +2 +status 2 +status +NA + + +status +status_NA::b +cat +cat +tester1; tester2 +[status] +status +3 +NA::b +missing +missing +NA +else +status 0 +status +NA + + +protime +NA +cont +cont +tester1; tester2 +[protime] +protime +NA +NA::a +not applicable +not applicable +NA +99 +NA +protime +NA + + +time +NA +cont +cont +tester1; tester2 +[time] +time +NA +copy +NA +NA +NA +[0,5000] +NA +time +NA + + +time +NA +cont +cont +tester1; tester2 +[time] +time +NA +NA::b +missing +missing +NA +else +NA +time +NA + + +time +NA +cont +cont +tester1; tester2 +[time] +time +NA +NA::a +not applicable +not applicable +NA +9999 +NA +time +NA + + +trig +NA +cont +cont +tester1; tester2 +[trig] +trig +NA +copy +NA +NA +NA +[0,1000] +NA +trig +NA + + +trig +NA +cont +cont +tester1; tester2 +[trig] +trig +NA +NA::b +missing +missing +NA +else +NA +trig +NA + + +status +status_NA::a +cat +cat +tester1; tester2 +[status] +status +3 +NA::a +not applicable +not applicable +NA +9 +not applicable +status +NA + + +trt +trt1 +cat +cat +tester1; tester2 +[trt] +trt +2 +1 +trt 1 +trt 1 +NA +1 +trt 1 +trt +NA + + +trt +trt2 +cat +cat +tester1; tester2 +[trt] +trt +2 +2 +trt 2 +trt 2 +NA +2 +trt 2 +trt +NA + + +trt +trt_NA::b +cat +cat +tester1; tester2 +[trt] +trt +2 +NA::b +missing +missing +NA +else +trt 1 +trt +NA + + +trt +trt_NA::a +cat +cat +tester1; tester2 +[trt] +trt +2 +NA::a +not applicable +not applicable +NA +9 +not applicable +trt +NA + + +trig +NA +cont +cont +tester1; tester2 +[trig] +trig +NA +NA::a +missing +missing +NA +9999 +NA +trig +NA + + +example_der +NA +cont +cont +tester1; tester2 +DerivedVar::[chol, bili] +example_der +NA +Func::example_der_fun +N/A +N/A +NA +else +N/A +example_der +A test derived variable + + +agegrp10 +agegrp10_cat6_1 +cat +cat +tester2 +tester2::agegrp +grouped age +6 +1 +20-29 +20-29 +years +1 +20-29 +grouped age +NA + + +agegrp10 +agegrp10_cat6_2 +cat +cat +tester2 +tester2::agegrp +grouped age +6 +2 +30-39 +30-39 +years +2 +30-39 +grouped age +NA + + +agegrp10 +agegrp10_cat6_3 +cat +cat +tester2 +tester2::agegrp +grouped age +6 +3 +40-49 +40-49 +years +3 +40-49 +grouped age +NA + + +agegrp10 +agegrp10_cat6_4 +cat +cat +tester2 +tester2::agegrp +grouped age +6 +4 +50-59 +50-59 +years +4 +50-59 +grouped age +NA + + +agegrp10 +agegrp10_cat6_5 +cat +cat +tester2 +tester2::agegrp +grouped age +6 +5 +60-69 +60-69 +years +5 +60-69 +grouped age +NA + + +agegrp10 +agegrp10_cat6_6 +cat +cat +tester2 +tester2::agegrp +grouped age +6 +6 +70-79 +70-79 +years +6 +70-79 +grouped age +NA + + +agegrp10 +agegrp10_cat6_NA::b +cat +cat +tester2 +tester2::agegrp +grouped age +6 +NA::b +missing +missing +years +else +missing +grouped age +NA + + +agegrp5 +agegrp5_cat11_1 +cat +cat +tester1 +tester1::agegrp +grouped age +11 +1 +25-29 +25-29 +years +1 +20-29 +grouped age +NA + + +agegrp5 +agegrp5_cat11_2 +cat +cat +tester1 +tester1::agegrp +grouped age +11 +2 +30-34 +30-34 +years +2 +30-39 +grouped age +NA + + +agegrp5 +agegrp5_cat11_3 +cat +cat +tester1 +tester1::agegrp +grouped age +11 +3 +35-39 +35-39 +years +3 +30-39 +grouped age +NA + + +agegrp5 +agegrp5_cat11_4 +cat +cat +tester1 +tester1::agegrp +grouped age +11 +4 +40-44 +40-44 +years +4 +40-49 +grouped age +NA + + +agegrp5 +agegrp5_cat11_5 +cat +cat +tester1 +tester1::agegrp +grouped age +11 +5 +45-49 +45-49 +years +5 +40-49 +grouped age +NA + + +agegrp5 +agegrp5_cat11_6 +cat +cat +tester1 +tester1::agegrp +grouped age +11 +6 +50-54 +50-54 +years +6 +50-59 +grouped age +NA + + +agegrp5 +agegrp5_cat11_7 +cat +cat +tester1 +tester1::agegrp +grouped age +11 +7 +55-59 +55-59 +years +7 +50-59 +grouped age +NA + + +agegrp5 +agegrp5_cat11_8 +cat +cat +tester1 +tester1::agegrp +grouped age +11 +8 +60-64 +60-64 +years +8 +60-69 +grouped age +NA + + +agegrp5 +agegrp5_cat11_9 +cat +cat +tester1 +tester1::agegrp +grouped age +11 +9 +65-69 +65-69 +years +9 +60-69 +grouped age +NA + + +agegrp5 +agegrp5_cat11_10 +cat +cat +tester1 +tester1::agegrp +grouped age +11 +10 +70-74 +70-74 +years +10 +70-79 +grouped age +NA + + +agegrp5 +agegrp5_cat11_11 +cat +cat +tester1 +tester1::agegrp +grouped age +11 +11 +75-79 +75-79 +years +11 +70-79 +grouped age +NA + + +agegrp5 +agegrp5_cat11_NA::b +cat +cat +tester1 +tester1::agegrp +grouped age +11 +Na::b +missing +missing +years +else +missing +grouped age +NA + + +age_cont +NA +cont +cat +tester1 +tester1::agegrp +grouped age +NA +27 +NA +NA +years +1 +20-29 +grouped age +NA + + +age_cont +NA +cont +cat +tester1 +tester1::agegrp +grouped age +NA +32 +NA +NA +years +2 +30-39 +grouped age +NA + + +age_cont +NA +cont +cat +tester1 +tester1::agegrp +grouped age +NA +37 +NA +NA +years +3 +30-39 +grouped age +NA + + +age_cont +NA +cont +cat +tester1 +tester1::agegrp +grouped age +NA +42 +NA +NA +years +4 +40-49 +grouped age +NA + + +age_cont +NA +cont +cat +tester1 +tester1::agegrp +grouped age +NA +47 +NA +NA +years +5 +40-49 +grouped age +NA + + +age_cont +NA +cont +cat +tester1 +tester1::agegrp +grouped age +NA +52 +NA +NA +years +6 +50-59 +grouped age +NA + + +age_cont +NA +cont +cat +tester1 +tester1::agegrp +grouped age +NA +57 +NA +NA +years +7 +50-59 +grouped age +NA + + +age_cont +NA +cont +cat +tester1 +tester1::agegrp +grouped age +NA +62 +NA +NA +years +8 +60-69 +grouped age +NA + + +age_cont +NA +cont +cat +tester1 +tester1::agegrp +grouped age +NA +67 +NA +NA +years +9 +60-69 +grouped age +NA + + +age_cont +NA +cont +cat +tester1 +tester1::agegrp +grouped age +NA +72 +NA +NA +years +10 +70-79 +grouped age +NA + + +age_cont +NA +cont +cat +tester1 +tester1::agegrp +grouped age +NA +77 +NA +NA +years +11 +70-79 +grouped age +NA + + +age_cont +NA +cont +cat +tester1 +tester1::agegrp +grouped age +NA +NA::b +NA +NA +years +else +missing +grouped age +NA + + +age_cont +NA +cont +cat +tester2 +tester2::agegrp +grouped age +NA +25 +NA +NA +years +1 +20-29 +grouped age +NA + + +age_cont +NA +cont +cat +tester2 +tester2::agegrp +grouped age +NA +35 +NA +NA +years +2 +30-39 +grouped age +NA + + +age_cont +NA +cont +cat +tester2 +tester2::agegrp +grouped age +NA +45 +NA +NA +years +3 +40-49 +grouped age +NA + + +age_cont +NA +cont +cat +tester2 +tester2::agegrp +grouped age +NA +55 +NA +NA +years +4 +50-59 +grouped age +NA + + +age_cont +NA +cont +cat +tester2 +tester2::agegrp +grouped age +NA +65 +NA +NA +years +5 +60-69 +grouped age +NA + + +age_cont +NA +cont +cat +tester2 +tester2::agegrp +grouped age +NA +75 +NA +NA +years +6 +70-79 +grouped age +NA + + +age_cont +NA +cont +cat +tester2 +tester2::agegrp +grouped age +6 +NA::b +NA +NA +years +else +missing +grouped age +NA + + +agegrp10 +agegrp10_cat6_1 +cat +cat +tester1 +tester1::agegrp +grouped age +6 +1 +20-29 +20-29 +years +1 +20-29 +grouped age +NA + + +agegrp10 +agegrp10_cat6_2 +cat +cat +tester1 +tester1::agegrp +grouped age +6 +2 +30-39 +30-39 +years +2 +30-39 +grouped age +NA + + +agegrp10 +agegrp10_cat6_2 +cat +cat +tester1 +tester1::agegrp +grouped age +6 +2 +30-39 +30-39 +years +3 +30-39 +grouped age +NA + + +agegrp10 +agegrp10_cat6_3 +cat +cat +tester1 +tester1::agegrp +grouped age +6 +3 +40-49 +40-49 +years +4 +40-49 +grouped age +NA + + +agegrp10 +agegrp10_cat6_3 +cat +cat +tester1 +tester1::agegrp +grouped age +6 +3 +40-49 +40-49 +years +5 +40-49 +grouped age +NA + + +agegrp10 +agegrp10_cat6_4 +cat +cat +tester1 +tester1::agegrp +grouped age +6 +4 +50-59 +50-59 +years +6 +50-59 +grouped age +NA + + +agegrp10 +agegrp10_cat6_4 +cat +cat +tester1 +tester1::agegrp +grouped age +6 +4 +50-59 +50-59 +years +7 +50-59 +grouped age +NA + + +agegrp10 +agegrp10_cat6_5 +cat +cat +tester1 +tester1::agegrp +grouped age +6 +5 +60-69 +60-69 +years +8 +60-69 +grouped age +NA + + +agegrp10 +agegrp10_cat6_5 +cat +cat +tester1 +tester1::agegrp +grouped age +6 +5 +60-69 +60-69 +years +9 +60-69 +grouped age +NA + + +agegrp10 +agegrp10_cat6_6 +cat +cat +tester1 +tester1::agegrp +grouped age +6 +6 +70-79 +70-79 +years +10 +70-79 +grouped age +NA + + +agegrp10 +agegrp10_cat6_6 +cat +cat +tester1 +tester1::agegrp +grouped age +6 +6 +70-79 +70-79 +years +11 +70-79 +grouped age +NA + + +agegrp10 +agegrp10_cat6_NA::b +cat +cat +tester1 +tester1::agegrp +grouped age +6 +NA::b +missing +missing +years +else +missing +grouped age +NA + + + +
    +
  1. +typeStart: indicates the type of variable +(continous or categorical) for the original variable. stage +is a categorical variable in the original dataset.
  2. +
+

Write ‘cat’ in the six rows.

+ ++++++++++++++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
variabledummyVariabletypeEndtypeStartdatabaseStartvariableStartvariableStartLabelnumValidCatrecEndcatLabelcatLabelLongunitsrecStartcatStartLabelvariableStartShortLabelnotes
ageNAcontconttester1; tester2[age]ageNAcopyNANANA[20,80]NAageNA
ageNAcontconttester1; tester2[age]ageNANA::bmissingmissingNAelseNAageNA
ageNAcontconttester1; tester2[age]ageNANA::anot applicablenot applicableNA999NAageNA
albuminNAcontconttester1; tester2[albumin]albuminNAcopyNANANA[1,5]NAalbuminNA
albuminNAcontconttester1; tester2[albumin]albuminNANA::bmissingmissingNAelseNAalbuminNA
albuminNAcontconttester1; tester2[albumin]albuminNANA::anot applicablenot applicableNA99NAalbuminNA
alk.phosNAcontconttester1; tester2[alk.phos]alk.phosNAcopyNANANA[200,15000]NAalk.phosNA
alk.phosNAcontconttester1; tester2[alk.phos]alk.phosNANA::bmissingmissingNAelseNAalk.phosNA
ascitesascites_cat3_1catcattester1; tester2[ascites]ascites20ascites 0ascites 0NA0ascites 0ascitesNA
ascitesascites_cat3_2catcattester1; tester2[ascites]ascites21ascites 1ascites 1NA1ascites 1ascitesNA
ascitesascites_cat3_NA::bcatcattester1; tester2[ascites]ascites2NA::bmissingmissingNAelseascites 0ascitesNA
ascitesascites_cat3_NA::acatcattester1; tester2[ascites]ascites2NA::anot applicablenot applicableNA9not applicableNANA
alk.phosNAcontconttester1; tester2[alk.phos]alk.phosNANA::anot applicablenot applicableNA99999NAalk.phosNA
astNAcontconttester1; tester2[ast]astNAcopyNANANA[20,500]NAastNA
astNAcontconttester1; tester2[ast]astNANA::bmissingmissingNAelseNAastNA
astNAcontconttester1; tester2[ast]astNANA::anot applicablenot applicableNA9999NAastNA
biliNAcontconttester1; tester2[bili]biliNAcopyNANANA[0,100]NAbiliNA
biliNAcontconttester1; tester2[bili]biliNANA::bmissingmissingNAelseNAbiliNA
cholNAcontconttester1; tester2[chol]cholNAcopyNANANA[100,2000]NAcholNA
cholNAcontconttester1; tester2[chol]cholNANA::bmissingmissingNAelseNAcholNA
cholNAcontconttester1; tester2[chol]cholNANA::amissingmissingNA9999NAcholNA
copperNAcontconttester1; tester2[copper]copperNAcopyNANANA[0,1000]NAcopperNA
copperNAcontconttester1; tester2[copper]copperNANA::bmissingmissingNAelseNAcopperNA
edemaedema_cat3_1catcattester1; tester2[edema]edema30edema 0.0edema 0.0NA0edema 0.0edemaNA
edemaedema_cat3_2catcattester1; tester2[edema]edema30.5edema 0.5edema 0.5NA0.5edema 0.5edemaNA
edemaedema_cat3_3catcattester1; tester2[edema]edema31edema 1.0edema 1.0NA1edema 1.0edemaNA
edemaedema_cat3_NA::bcatcattester1; tester2[edema]edema3NA::bmissingmissingNAelsemissingedemaNA
edemaedema_cat3_NA::acatcattester1; tester2[edema]edema3NA::anot applicablenot applicableNA9not applicableedemaNA
hepatoheapto_cat3_1catcattester1; tester2[hepato]hepato20hepato 0hepato 0NA0hepato 0hepatoNA
hepatoheapto_cat3_1catcattester1; tester2[hepato]hepato21hepato 1hepato 1NA1hepato 1hepatoNA
hepatoheapto_cat3_NA::acatcattester1; tester2[hepato]hepato2NA::bmissingmissingNAelsemissinghepatoNA
copperNAcontconttester1; tester2[copper]copperNANA::amissingmissingNA9999NAcopperNA
plateletNAcontconttester1; tester2[platelet]plateletNAcopyNANANA[0,1000]NAplateletNA
plateletNAcontconttester1; tester2[platelet]plateletNANA::bmissingmissingNAelseNAplateletNA
plateletNAcontconttester1; tester2[platelet]plateletNANA::anot applicablenot applicableNA9999NAplateletNA
protimeNAcontconttester1; tester2[protime]protimeNAcopyNANANA[5, 30]NAprotimeNA
protimeNAcontconttester1; tester2[protime]protimeNANA::bmissingmissingNAelseNAprotimeNA
hepatoheapto_cat3_NA::bcatcattester1; tester2[hepato]hepato2NA::anot applicablenot applicableNA9not applicablehepatoNA
sexsex_cat2_1catcattester1; tester2[sex]sex2msex msex mNAmsex msexNA
sexsex_cat2_2catcattester1; tester2[sex]sex2fsex fsex fNAfsex fsexNA
sexsex_cat2_NA::bcatcattester1; tester2[sex]sex2NA::bmissingmissingNAelsesex msexNA
sexsex_cat2_NA::acatcattester1; tester2[sex]sex2NA::anot applicablenot applicableNA9sex msexNA
spidersspiders0catcattester1; tester2[spiders]spiders20spiders 0spiders 0NA0spiders 0spidersNA
spidersspiders1catcattester1; tester2[spiders]spiders21spiders 1spiders 1NA1spiders 1spidersNA
spidersspiders_NA::bcatcattester1; tester2[spiders]spiders2NA::bmissingmissingNAelsespiders 0spidersNA
spidersspiders_NA::acatcattester1; tester2[spiders]spiders2NA::anot applicablenot applicableNA9not applicablespidersNA
stagestage1catcattester1; tester2[stage]stage41stage 1stage 1NA1stage 1stageNA
stagestage2catcattester1; tester2[stage]stage42stage 2stage 2NA2stage 2stageNA
stagestage3catcattester1; tester2[stage]stage43stage 3stage 3NA3stage 3stageNA
stagestage4catcattester1; tester2[stage]stage44stage 4stage 4NA4stage 4stageNA
stagestage_NA::bcatcattester1; tester2[stage]stage4NA::bmissingmissingNAelsemissingstageNA
stagestage_NA::acatcattester1; tester2[stage]stage4NA::anot applicablenot applicableNA9not applicablestageNA
statusstatus0catcattester1; tester2[status]status30status 0status 0NA0status 0statusNA
statusstatus1catcattester1; tester2[status]status31status 1status 1NA1status 1statusNA
statusstatus2catcattester1; tester2[status]status32status 2status 2NA2status 2statusNA
statusstatus_NA::bcatcattester1; tester2[status]status3NA::bmissingmissingNAelsestatus 0statusNA
protimeNAcontconttester1; tester2[protime]protimeNANA::anot applicablenot applicableNA99NAprotimeNA
timeNAcontconttester1; tester2[time]timeNAcopyNANANA[0,5000]NAtimeNA
timeNAcontconttester1; tester2[time]timeNANA::bmissingmissingNAelseNAtimeNA
timeNAcontconttester1; tester2[time]timeNANA::anot applicablenot applicableNA9999NAtimeNA
trigNAcontconttester1; tester2[trig]trigNAcopyNANANA[0,1000]NAtrigNA
trigNAcontconttester1; tester2[trig]trigNANA::bmissingmissingNAelseNAtrigNA
statusstatus_NA::acatcattester1; tester2[status]status3NA::anot applicablenot applicableNA9not applicablestatusNA
trttrt1catcattester1; tester2[trt]trt21trt 1trt 1NA1trt 1trtNA
trttrt2catcattester1; tester2[trt]trt22trt 2trt 2NA2trt 2trtNA
trttrt_NA::bcatcattester1; tester2[trt]trt2NA::bmissingmissingNAelsetrt 1trtNA
trttrt_NA::acatcattester1; tester2[trt]trt2NA::anot applicablenot applicableNA9not applicabletrtNA
trigNAcontconttester1; tester2[trig]trigNANA::amissingmissingNA9999NAtrigNA
example_derNAcontconttester1; tester2DerivedVar::[chol, bili]example_derNAFunc::example_der_funN/AN/ANAelseN/Aexample_derA test derived variable
agegrp10agegrp10_cat6_1catcattester2tester2::agegrpgrouped age6120-2920-29years120-29grouped ageNA
agegrp10agegrp10_cat6_2catcattester2tester2::agegrpgrouped age6230-3930-39years230-39grouped ageNA
agegrp10agegrp10_cat6_3catcattester2tester2::agegrpgrouped age6340-4940-49years340-49grouped ageNA
agegrp10agegrp10_cat6_4catcattester2tester2::agegrpgrouped age6450-5950-59years450-59grouped ageNA
agegrp10agegrp10_cat6_5catcattester2tester2::agegrpgrouped age6560-6960-69years560-69grouped ageNA
agegrp10agegrp10_cat6_6catcattester2tester2::agegrpgrouped age6670-7970-79years670-79grouped ageNA
agegrp10agegrp10_cat6_NA::bcatcattester2tester2::agegrpgrouped age6NA::bmissingmissingyearselsemissinggrouped ageNA
agegrp5agegrp5_cat11_1catcattester1tester1::agegrpgrouped age11125-2925-29years120-29grouped ageNA
agegrp5agegrp5_cat11_2catcattester1tester1::agegrpgrouped age11230-3430-34years230-39grouped ageNA
agegrp5agegrp5_cat11_3catcattester1tester1::agegrpgrouped age11335-3935-39years330-39grouped ageNA
agegrp5agegrp5_cat11_4catcattester1tester1::agegrpgrouped age11440-4440-44years440-49grouped ageNA
agegrp5agegrp5_cat11_5catcattester1tester1::agegrpgrouped age11545-4945-49years540-49grouped ageNA
agegrp5agegrp5_cat11_6catcattester1tester1::agegrpgrouped age11650-5450-54years650-59grouped ageNA
agegrp5agegrp5_cat11_7catcattester1tester1::agegrpgrouped age11755-5955-59years750-59grouped ageNA
agegrp5agegrp5_cat11_8catcattester1tester1::agegrpgrouped age11860-6460-64years860-69grouped ageNA
agegrp5agegrp5_cat11_9catcattester1tester1::agegrpgrouped age11965-6965-69years960-69grouped ageNA
agegrp5agegrp5_cat11_10catcattester1tester1::agegrpgrouped age111070-7470-74years1070-79grouped ageNA
agegrp5agegrp5_cat11_11catcattester1tester1::agegrpgrouped age111175-7975-79years1170-79grouped ageNA
agegrp5agegrp5_cat11_NA::bcatcattester1tester1::agegrpgrouped age11Na::bmissingmissingyearselsemissinggrouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA27NANAyears120-29grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA32NANAyears230-39grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA37NANAyears330-39grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA42NANAyears440-49grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA47NANAyears540-49grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA52NANAyears650-59grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA57NANAyears750-59grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA62NANAyears860-69grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA67NANAyears960-69grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA72NANAyears1070-79grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA77NANAyears1170-79grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNANA::bNANAyearselsemissinggrouped ageNA
age_contNAcontcattester2tester2::agegrpgrouped ageNA25NANAyears120-29grouped ageNA
age_contNAcontcattester2tester2::agegrpgrouped ageNA35NANAyears230-39grouped ageNA
age_contNAcontcattester2tester2::agegrpgrouped ageNA45NANAyears340-49grouped ageNA
age_contNAcontcattester2tester2::agegrpgrouped ageNA55NANAyears450-59grouped ageNA
age_contNAcontcattester2tester2::agegrpgrouped ageNA65NANAyears560-69grouped ageNA
age_contNAcontcattester2tester2::agegrpgrouped ageNA75NANAyears670-79grouped ageNA
age_contNAcontcattester2tester2::agegrpgrouped age6NA::bNANAyearselsemissinggrouped ageNA
agegrp10agegrp10_cat6_1catcattester1tester1::agegrpgrouped age6120-2920-29years120-29grouped ageNA
agegrp10agegrp10_cat6_2catcattester1tester1::agegrpgrouped age6230-3930-39years230-39grouped ageNA
agegrp10agegrp10_cat6_2catcattester1tester1::agegrpgrouped age6230-3930-39years330-39grouped ageNA
agegrp10agegrp10_cat6_3catcattester1tester1::agegrpgrouped age6340-4940-49years440-49grouped ageNA
agegrp10agegrp10_cat6_3catcattester1tester1::agegrpgrouped age6340-4940-49years540-49grouped ageNA
agegrp10agegrp10_cat6_4catcattester1tester1::agegrpgrouped age6450-5950-59years650-59grouped ageNA
agegrp10agegrp10_cat6_4catcattester1tester1::agegrpgrouped age6450-5950-59years750-59grouped ageNA
agegrp10agegrp10_cat6_5catcattester1tester1::agegrpgrouped age6560-6960-69years860-69grouped ageNA
agegrp10agegrp10_cat6_5catcattester1tester1::agegrpgrouped age6560-6960-69years960-69grouped ageNA
agegrp10agegrp10_cat6_6catcattester1tester1::agegrpgrouped age6670-7970-79years1070-79grouped ageNA
agegrp10agegrp10_cat6_6catcattester1tester1::agegrpgrouped age6670-7970-79years1170-79grouped ageNA
agegrp10agegrp10_cat6_NA::bcatcattester1tester1::agegrpgrouped age6NA::bmissingmissingyearselsemissinggrouped ageNA
+
    +
  1. +databaseStart: indicates the name of the +database(s) from which the original variable(s) is(are) obtained.
  2. +
+

Write the dataset names, separated by a comma, in the six rows

+ ++++++++++++++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
variabledummyVariabletypeEndtypeStartdatabaseStartvariableStartvariableStartLabelnumValidCatrecEndcatLabelcatLabelLongunitsrecStartcatStartLabelvariableStartShortLabelnotes
ageNAcontconttester1; tester2[age]ageNAcopyNANANA[20,80]NAageNA
ageNAcontconttester1; tester2[age]ageNANA::bmissingmissingNAelseNAageNA
ageNAcontconttester1; tester2[age]ageNANA::anot applicablenot applicableNA999NAageNA
albuminNAcontconttester1; tester2[albumin]albuminNAcopyNANANA[1,5]NAalbuminNA
albuminNAcontconttester1; tester2[albumin]albuminNANA::bmissingmissingNAelseNAalbuminNA
albuminNAcontconttester1; tester2[albumin]albuminNANA::anot applicablenot applicableNA99NAalbuminNA
alk.phosNAcontconttester1; tester2[alk.phos]alk.phosNAcopyNANANA[200,15000]NAalk.phosNA
alk.phosNAcontconttester1; tester2[alk.phos]alk.phosNANA::bmissingmissingNAelseNAalk.phosNA
ascitesascites_cat3_1catcattester1; tester2[ascites]ascites20ascites 0ascites 0NA0ascites 0ascitesNA
ascitesascites_cat3_2catcattester1; tester2[ascites]ascites21ascites 1ascites 1NA1ascites 1ascitesNA
ascitesascites_cat3_NA::bcatcattester1; tester2[ascites]ascites2NA::bmissingmissingNAelseascites 0ascitesNA
ascitesascites_cat3_NA::acatcattester1; tester2[ascites]ascites2NA::anot applicablenot applicableNA9not applicableNANA
alk.phosNAcontconttester1; tester2[alk.phos]alk.phosNANA::anot applicablenot applicableNA99999NAalk.phosNA
astNAcontconttester1; tester2[ast]astNAcopyNANANA[20,500]NAastNA
astNAcontconttester1; tester2[ast]astNANA::bmissingmissingNAelseNAastNA
astNAcontconttester1; tester2[ast]astNANA::anot applicablenot applicableNA9999NAastNA
biliNAcontconttester1; tester2[bili]biliNAcopyNANANA[0,100]NAbiliNA
biliNAcontconttester1; tester2[bili]biliNANA::bmissingmissingNAelseNAbiliNA
cholNAcontconttester1; tester2[chol]cholNAcopyNANANA[100,2000]NAcholNA
cholNAcontconttester1; tester2[chol]cholNANA::bmissingmissingNAelseNAcholNA
cholNAcontconttester1; tester2[chol]cholNANA::amissingmissingNA9999NAcholNA
copperNAcontconttester1; tester2[copper]copperNAcopyNANANA[0,1000]NAcopperNA
copperNAcontconttester1; tester2[copper]copperNANA::bmissingmissingNAelseNAcopperNA
edemaedema_cat3_1catcattester1; tester2[edema]edema30edema 0.0edema 0.0NA0edema 0.0edemaNA
edemaedema_cat3_2catcattester1; tester2[edema]edema30.5edema 0.5edema 0.5NA0.5edema 0.5edemaNA
edemaedema_cat3_3catcattester1; tester2[edema]edema31edema 1.0edema 1.0NA1edema 1.0edemaNA
edemaedema_cat3_NA::bcatcattester1; tester2[edema]edema3NA::bmissingmissingNAelsemissingedemaNA
edemaedema_cat3_NA::acatcattester1; tester2[edema]edema3NA::anot applicablenot applicableNA9not applicableedemaNA
hepatoheapto_cat3_1catcattester1; tester2[hepato]hepato20hepato 0hepato 0NA0hepato 0hepatoNA
hepatoheapto_cat3_1catcattester1; tester2[hepato]hepato21hepato 1hepato 1NA1hepato 1hepatoNA
hepatoheapto_cat3_NA::acatcattester1; tester2[hepato]hepato2NA::bmissingmissingNAelsemissinghepatoNA
copperNAcontconttester1; tester2[copper]copperNANA::amissingmissingNA9999NAcopperNA
plateletNAcontconttester1; tester2[platelet]plateletNAcopyNANANA[0,1000]NAplateletNA
plateletNAcontconttester1; tester2[platelet]plateletNANA::bmissingmissingNAelseNAplateletNA
plateletNAcontconttester1; tester2[platelet]plateletNANA::anot applicablenot applicableNA9999NAplateletNA
protimeNAcontconttester1; tester2[protime]protimeNAcopyNANANA[5, 30]NAprotimeNA
protimeNAcontconttester1; tester2[protime]protimeNANA::bmissingmissingNAelseNAprotimeNA
hepatoheapto_cat3_NA::bcatcattester1; tester2[hepato]hepato2NA::anot applicablenot applicableNA9not applicablehepatoNA
sexsex_cat2_1catcattester1; tester2[sex]sex2msex msex mNAmsex msexNA
sexsex_cat2_2catcattester1; tester2[sex]sex2fsex fsex fNAfsex fsexNA
sexsex_cat2_NA::bcatcattester1; tester2[sex]sex2NA::bmissingmissingNAelsesex msexNA
sexsex_cat2_NA::acatcattester1; tester2[sex]sex2NA::anot applicablenot applicableNA9sex msexNA
spidersspiders0catcattester1; tester2[spiders]spiders20spiders 0spiders 0NA0spiders 0spidersNA
spidersspiders1catcattester1; tester2[spiders]spiders21spiders 1spiders 1NA1spiders 1spidersNA
spidersspiders_NA::bcatcattester1; tester2[spiders]spiders2NA::bmissingmissingNAelsespiders 0spidersNA
spidersspiders_NA::acatcattester1; tester2[spiders]spiders2NA::anot applicablenot applicableNA9not applicablespidersNA
stagestage1catcattester1; tester2[stage]stage41stage 1stage 1NA1stage 1stageNA
stagestage2catcattester1; tester2[stage]stage42stage 2stage 2NA2stage 2stageNA
stagestage3catcattester1; tester2[stage]stage43stage 3stage 3NA3stage 3stageNA
stagestage4catcattester1; tester2[stage]stage44stage 4stage 4NA4stage 4stageNA
stagestage_NA::bcatcattester1; tester2[stage]stage4NA::bmissingmissingNAelsemissingstageNA
stagestage_NA::acatcattester1; tester2[stage]stage4NA::anot applicablenot applicableNA9not applicablestageNA
statusstatus0catcattester1; tester2[status]status30status 0status 0NA0status 0statusNA
statusstatus1catcattester1; tester2[status]status31status 1status 1NA1status 1statusNA
statusstatus2catcattester1; tester2[status]status32status 2status 2NA2status 2statusNA
statusstatus_NA::bcatcattester1; tester2[status]status3NA::bmissingmissingNAelsestatus 0statusNA
protimeNAcontconttester1; tester2[protime]protimeNANA::anot applicablenot applicableNA99NAprotimeNA
timeNAcontconttester1; tester2[time]timeNAcopyNANANA[0,5000]NAtimeNA
timeNAcontconttester1; tester2[time]timeNANA::bmissingmissingNAelseNAtimeNA
timeNAcontconttester1; tester2[time]timeNANA::anot applicablenot applicableNA9999NAtimeNA
trigNAcontconttester1; tester2[trig]trigNAcopyNANANA[0,1000]NAtrigNA
trigNAcontconttester1; tester2[trig]trigNANA::bmissingmissingNAelseNAtrigNA
statusstatus_NA::acatcattester1; tester2[status]status3NA::anot applicablenot applicableNA9not applicablestatusNA
trttrt1catcattester1; tester2[trt]trt21trt 1trt 1NA1trt 1trtNA
trttrt2catcattester1; tester2[trt]trt22trt 2trt 2NA2trt 2trtNA
trttrt_NA::bcatcattester1; tester2[trt]trt2NA::bmissingmissingNAelsetrt 1trtNA
trttrt_NA::acatcattester1; tester2[trt]trt2NA::anot applicablenot applicableNA9not applicabletrtNA
trigNAcontconttester1; tester2[trig]trigNANA::amissingmissingNA9999NAtrigNA
example_derNAcontconttester1; tester2DerivedVar::[chol, bili]example_derNAFunc::example_der_funN/AN/ANAelseN/Aexample_derA test derived variable
agegrp10agegrp10_cat6_1catcattester2tester2::agegrpgrouped age6120-2920-29years120-29grouped ageNA
agegrp10agegrp10_cat6_2catcattester2tester2::agegrpgrouped age6230-3930-39years230-39grouped ageNA
agegrp10agegrp10_cat6_3catcattester2tester2::agegrpgrouped age6340-4940-49years340-49grouped ageNA
agegrp10agegrp10_cat6_4catcattester2tester2::agegrpgrouped age6450-5950-59years450-59grouped ageNA
agegrp10agegrp10_cat6_5catcattester2tester2::agegrpgrouped age6560-6960-69years560-69grouped ageNA
agegrp10agegrp10_cat6_6catcattester2tester2::agegrpgrouped age6670-7970-79years670-79grouped ageNA
agegrp10agegrp10_cat6_NA::bcatcattester2tester2::agegrpgrouped age6NA::bmissingmissingyearselsemissinggrouped ageNA
agegrp5agegrp5_cat11_1catcattester1tester1::agegrpgrouped age11125-2925-29years120-29grouped ageNA
agegrp5agegrp5_cat11_2catcattester1tester1::agegrpgrouped age11230-3430-34years230-39grouped ageNA
agegrp5agegrp5_cat11_3catcattester1tester1::agegrpgrouped age11335-3935-39years330-39grouped ageNA
agegrp5agegrp5_cat11_4catcattester1tester1::agegrpgrouped age11440-4440-44years440-49grouped ageNA
agegrp5agegrp5_cat11_5catcattester1tester1::agegrpgrouped age11545-4945-49years540-49grouped ageNA
agegrp5agegrp5_cat11_6catcattester1tester1::agegrpgrouped age11650-5450-54years650-59grouped ageNA
agegrp5agegrp5_cat11_7catcattester1tester1::agegrpgrouped age11755-5955-59years750-59grouped ageNA
agegrp5agegrp5_cat11_8catcattester1tester1::agegrpgrouped age11860-6460-64years860-69grouped ageNA
agegrp5agegrp5_cat11_9catcattester1tester1::agegrpgrouped age11965-6965-69years960-69grouped ageNA
agegrp5agegrp5_cat11_10catcattester1tester1::agegrpgrouped age111070-7470-74years1070-79grouped ageNA
agegrp5agegrp5_cat11_11catcattester1tester1::agegrpgrouped age111175-7975-79years1170-79grouped ageNA
agegrp5agegrp5_cat11_NA::bcatcattester1tester1::agegrpgrouped age11Na::bmissingmissingyearselsemissinggrouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA27NANAyears120-29grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA32NANAyears230-39grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA37NANAyears330-39grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA42NANAyears440-49grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA47NANAyears540-49grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA52NANAyears650-59grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA57NANAyears750-59grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA62NANAyears860-69grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA67NANAyears960-69grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA72NANAyears1070-79grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA77NANAyears1170-79grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNANA::bNANAyearselsemissinggrouped ageNA
age_contNAcontcattester2tester2::agegrpgrouped ageNA25NANAyears120-29grouped ageNA
age_contNAcontcattester2tester2::agegrpgrouped ageNA35NANAyears230-39grouped ageNA
age_contNAcontcattester2tester2::agegrpgrouped ageNA45NANAyears340-49grouped ageNA
age_contNAcontcattester2tester2::agegrpgrouped ageNA55NANAyears450-59grouped ageNA
age_contNAcontcattester2tester2::agegrpgrouped ageNA65NANAyears560-69grouped ageNA
age_contNAcontcattester2tester2::agegrpgrouped ageNA75NANAyears670-79grouped ageNA
age_contNAcontcattester2tester2::agegrpgrouped age6NA::bNANAyearselsemissinggrouped ageNA
agegrp10agegrp10_cat6_1catcattester1tester1::agegrpgrouped age6120-2920-29years120-29grouped ageNA
agegrp10agegrp10_cat6_2catcattester1tester1::agegrpgrouped age6230-3930-39years230-39grouped ageNA
agegrp10agegrp10_cat6_2catcattester1tester1::agegrpgrouped age6230-3930-39years330-39grouped ageNA
agegrp10agegrp10_cat6_3catcattester1tester1::agegrpgrouped age6340-4940-49years440-49grouped ageNA
agegrp10agegrp10_cat6_3catcattester1tester1::agegrpgrouped age6340-4940-49years540-49grouped ageNA
agegrp10agegrp10_cat6_4catcattester1tester1::agegrpgrouped age6450-5950-59years650-59grouped ageNA
agegrp10agegrp10_cat6_4catcattester1tester1::agegrpgrouped age6450-5950-59years750-59grouped ageNA
agegrp10agegrp10_cat6_5catcattester1tester1::agegrpgrouped age6560-6960-69years860-69grouped ageNA
agegrp10agegrp10_cat6_5catcattester1tester1::agegrpgrouped age6560-6960-69years960-69grouped ageNA
agegrp10agegrp10_cat6_6catcattester1tester1::agegrpgrouped age6670-7970-79years1070-79grouped ageNA
agegrp10agegrp10_cat6_6catcattester1tester1::agegrpgrouped age6670-7970-79years1170-79grouped ageNA
agegrp10agegrp10_cat6_NA::bcatcattester1tester1::agegrpgrouped age6NA::bmissingmissingyearselsemissinggrouped ageNA
+
    +
  1. +variableStart: indicates the original variable +name(s) in the database(s). In our example, both datasets have the start +variable stage. Therefore we can indicate a single variable +name here. If the variable names were different, we would need to +indicate ‘dataset_name::variable_name’ separated by commas for each of +the datasets.
  2. +
+

Write the variable name in squared brackets once per row, for all six +rows.

+ ++++++++++++++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
variabledummyVariabletypeEndtypeStartdatabaseStartvariableStartvariableStartLabelnumValidCatrecEndcatLabelcatLabelLongunitsrecStartcatStartLabelvariableStartShortLabelnotes
ageNAcontconttester1; tester2[age]ageNAcopyNANANA[20,80]NAageNA
ageNAcontconttester1; tester2[age]ageNANA::bmissingmissingNAelseNAageNA
ageNAcontconttester1; tester2[age]ageNANA::anot applicablenot applicableNA999NAageNA
albuminNAcontconttester1; tester2[albumin]albuminNAcopyNANANA[1,5]NAalbuminNA
albuminNAcontconttester1; tester2[albumin]albuminNANA::bmissingmissingNAelseNAalbuminNA
albuminNAcontconttester1; tester2[albumin]albuminNANA::anot applicablenot applicableNA99NAalbuminNA
alk.phosNAcontconttester1; tester2[alk.phos]alk.phosNAcopyNANANA[200,15000]NAalk.phosNA
alk.phosNAcontconttester1; tester2[alk.phos]alk.phosNANA::bmissingmissingNAelseNAalk.phosNA
ascitesascites_cat3_1catcattester1; tester2[ascites]ascites20ascites 0ascites 0NA0ascites 0ascitesNA
ascitesascites_cat3_2catcattester1; tester2[ascites]ascites21ascites 1ascites 1NA1ascites 1ascitesNA
ascitesascites_cat3_NA::bcatcattester1; tester2[ascites]ascites2NA::bmissingmissingNAelseascites 0ascitesNA
ascitesascites_cat3_NA::acatcattester1; tester2[ascites]ascites2NA::anot applicablenot applicableNA9not applicableNANA
alk.phosNAcontconttester1; tester2[alk.phos]alk.phosNANA::anot applicablenot applicableNA99999NAalk.phosNA
astNAcontconttester1; tester2[ast]astNAcopyNANANA[20,500]NAastNA
astNAcontconttester1; tester2[ast]astNANA::bmissingmissingNAelseNAastNA
astNAcontconttester1; tester2[ast]astNANA::anot applicablenot applicableNA9999NAastNA
biliNAcontconttester1; tester2[bili]biliNAcopyNANANA[0,100]NAbiliNA
biliNAcontconttester1; tester2[bili]biliNANA::bmissingmissingNAelseNAbiliNA
cholNAcontconttester1; tester2[chol]cholNAcopyNANANA[100,2000]NAcholNA
cholNAcontconttester1; tester2[chol]cholNANA::bmissingmissingNAelseNAcholNA
cholNAcontconttester1; tester2[chol]cholNANA::amissingmissingNA9999NAcholNA
copperNAcontconttester1; tester2[copper]copperNAcopyNANANA[0,1000]NAcopperNA
copperNAcontconttester1; tester2[copper]copperNANA::bmissingmissingNAelseNAcopperNA
edemaedema_cat3_1catcattester1; tester2[edema]edema30edema 0.0edema 0.0NA0edema 0.0edemaNA
edemaedema_cat3_2catcattester1; tester2[edema]edema30.5edema 0.5edema 0.5NA0.5edema 0.5edemaNA
edemaedema_cat3_3catcattester1; tester2[edema]edema31edema 1.0edema 1.0NA1edema 1.0edemaNA
edemaedema_cat3_NA::bcatcattester1; tester2[edema]edema3NA::bmissingmissingNAelsemissingedemaNA
edemaedema_cat3_NA::acatcattester1; tester2[edema]edema3NA::anot applicablenot applicableNA9not applicableedemaNA
hepatoheapto_cat3_1catcattester1; tester2[hepato]hepato20hepato 0hepato 0NA0hepato 0hepatoNA
hepatoheapto_cat3_1catcattester1; tester2[hepato]hepato21hepato 1hepato 1NA1hepato 1hepatoNA
hepatoheapto_cat3_NA::acatcattester1; tester2[hepato]hepato2NA::bmissingmissingNAelsemissinghepatoNA
copperNAcontconttester1; tester2[copper]copperNANA::amissingmissingNA9999NAcopperNA
plateletNAcontconttester1; tester2[platelet]plateletNAcopyNANANA[0,1000]NAplateletNA
plateletNAcontconttester1; tester2[platelet]plateletNANA::bmissingmissingNAelseNAplateletNA
plateletNAcontconttester1; tester2[platelet]plateletNANA::anot applicablenot applicableNA9999NAplateletNA
protimeNAcontconttester1; tester2[protime]protimeNAcopyNANANA[5, 30]NAprotimeNA
protimeNAcontconttester1; tester2[protime]protimeNANA::bmissingmissingNAelseNAprotimeNA
hepatoheapto_cat3_NA::bcatcattester1; tester2[hepato]hepato2NA::anot applicablenot applicableNA9not applicablehepatoNA
sexsex_cat2_1catcattester1; tester2[sex]sex2msex msex mNAmsex msexNA
sexsex_cat2_2catcattester1; tester2[sex]sex2fsex fsex fNAfsex fsexNA
sexsex_cat2_NA::bcatcattester1; tester2[sex]sex2NA::bmissingmissingNAelsesex msexNA
sexsex_cat2_NA::acatcattester1; tester2[sex]sex2NA::anot applicablenot applicableNA9sex msexNA
spidersspiders0catcattester1; tester2[spiders]spiders20spiders 0spiders 0NA0spiders 0spidersNA
spidersspiders1catcattester1; tester2[spiders]spiders21spiders 1spiders 1NA1spiders 1spidersNA
spidersspiders_NA::bcatcattester1; tester2[spiders]spiders2NA::bmissingmissingNAelsespiders 0spidersNA
spidersspiders_NA::acatcattester1; tester2[spiders]spiders2NA::anot applicablenot applicableNA9not applicablespidersNA
stagestage1catcattester1; tester2[stage]stage41stage 1stage 1NA1stage 1stageNA
stagestage2catcattester1; tester2[stage]stage42stage 2stage 2NA2stage 2stageNA
stagestage3catcattester1; tester2[stage]stage43stage 3stage 3NA3stage 3stageNA
stagestage4catcattester1; tester2[stage]stage44stage 4stage 4NA4stage 4stageNA
stagestage_NA::bcatcattester1; tester2[stage]stage4NA::bmissingmissingNAelsemissingstageNA
stagestage_NA::acatcattester1; tester2[stage]stage4NA::anot applicablenot applicableNA9not applicablestageNA
statusstatus0catcattester1; tester2[status]status30status 0status 0NA0status 0statusNA
statusstatus1catcattester1; tester2[status]status31status 1status 1NA1status 1statusNA
statusstatus2catcattester1; tester2[status]status32status 2status 2NA2status 2statusNA
statusstatus_NA::bcatcattester1; tester2[status]status3NA::bmissingmissingNAelsestatus 0statusNA
protimeNAcontconttester1; tester2[protime]protimeNANA::anot applicablenot applicableNA99NAprotimeNA
timeNAcontconttester1; tester2[time]timeNAcopyNANANA[0,5000]NAtimeNA
timeNAcontconttester1; tester2[time]timeNANA::bmissingmissingNAelseNAtimeNA
timeNAcontconttester1; tester2[time]timeNANA::anot applicablenot applicableNA9999NAtimeNA
trigNAcontconttester1; tester2[trig]trigNAcopyNANANA[0,1000]NAtrigNA
trigNAcontconttester1; tester2[trig]trigNANA::bmissingmissingNAelseNAtrigNA
statusstatus_NA::acatcattester1; tester2[status]status3NA::anot applicablenot applicableNA9not applicablestatusNA
trttrt1catcattester1; tester2[trt]trt21trt 1trt 1NA1trt 1trtNA
trttrt2catcattester1; tester2[trt]trt22trt 2trt 2NA2trt 2trtNA
trttrt_NA::bcatcattester1; tester2[trt]trt2NA::bmissingmissingNAelsetrt 1trtNA
trttrt_NA::acatcattester1; tester2[trt]trt2NA::anot applicablenot applicableNA9not applicabletrtNA
trigNAcontconttester1; tester2[trig]trigNANA::amissingmissingNA9999NAtrigNA
example_derNAcontconttester1; tester2DerivedVar::[chol, bili]example_derNAFunc::example_der_funN/AN/ANAelseN/Aexample_derA test derived variable
agegrp10agegrp10_cat6_1catcattester2tester2::agegrpgrouped age6120-2920-29years120-29grouped ageNA
agegrp10agegrp10_cat6_2catcattester2tester2::agegrpgrouped age6230-3930-39years230-39grouped ageNA
agegrp10agegrp10_cat6_3catcattester2tester2::agegrpgrouped age6340-4940-49years340-49grouped ageNA
agegrp10agegrp10_cat6_4catcattester2tester2::agegrpgrouped age6450-5950-59years450-59grouped ageNA
agegrp10agegrp10_cat6_5catcattester2tester2::agegrpgrouped age6560-6960-69years560-69grouped ageNA
agegrp10agegrp10_cat6_6catcattester2tester2::agegrpgrouped age6670-7970-79years670-79grouped ageNA
agegrp10agegrp10_cat6_NA::bcatcattester2tester2::agegrpgrouped age6NA::bmissingmissingyearselsemissinggrouped ageNA
agegrp5agegrp5_cat11_1catcattester1tester1::agegrpgrouped age11125-2925-29years120-29grouped ageNA
agegrp5agegrp5_cat11_2catcattester1tester1::agegrpgrouped age11230-3430-34years230-39grouped ageNA
agegrp5agegrp5_cat11_3catcattester1tester1::agegrpgrouped age11335-3935-39years330-39grouped ageNA
agegrp5agegrp5_cat11_4catcattester1tester1::agegrpgrouped age11440-4440-44years440-49grouped ageNA
agegrp5agegrp5_cat11_5catcattester1tester1::agegrpgrouped age11545-4945-49years540-49grouped ageNA
agegrp5agegrp5_cat11_6catcattester1tester1::agegrpgrouped age11650-5450-54years650-59grouped ageNA
agegrp5agegrp5_cat11_7catcattester1tester1::agegrpgrouped age11755-5955-59years750-59grouped ageNA
agegrp5agegrp5_cat11_8catcattester1tester1::agegrpgrouped age11860-6460-64years860-69grouped ageNA
agegrp5agegrp5_cat11_9catcattester1tester1::agegrpgrouped age11965-6965-69years960-69grouped ageNA
agegrp5agegrp5_cat11_10catcattester1tester1::agegrpgrouped age111070-7470-74years1070-79grouped ageNA
agegrp5agegrp5_cat11_11catcattester1tester1::agegrpgrouped age111175-7975-79years1170-79grouped ageNA
agegrp5agegrp5_cat11_NA::bcatcattester1tester1::agegrpgrouped age11Na::bmissingmissingyearselsemissinggrouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA27NANAyears120-29grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA32NANAyears230-39grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA37NANAyears330-39grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA42NANAyears440-49grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA47NANAyears540-49grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA52NANAyears650-59grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA57NANAyears750-59grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA62NANAyears860-69grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA67NANAyears960-69grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA72NANAyears1070-79grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA77NANAyears1170-79grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNANA::bNANAyearselsemissinggrouped ageNA
age_contNAcontcattester2tester2::agegrpgrouped ageNA25NANAyears120-29grouped ageNA
age_contNAcontcattester2tester2::agegrpgrouped ageNA35NANAyears230-39grouped ageNA
age_contNAcontcattester2tester2::agegrpgrouped ageNA45NANAyears340-49grouped ageNA
age_contNAcontcattester2tester2::agegrpgrouped ageNA55NANAyears450-59grouped ageNA
age_contNAcontcattester2tester2::agegrpgrouped ageNA65NANAyears560-69grouped ageNA
age_contNAcontcattester2tester2::agegrpgrouped ageNA75NANAyears670-79grouped ageNA
age_contNAcontcattester2tester2::agegrpgrouped age6NA::bNANAyearselsemissinggrouped ageNA
agegrp10agegrp10_cat6_1catcattester1tester1::agegrpgrouped age6120-2920-29years120-29grouped ageNA
agegrp10agegrp10_cat6_2catcattester1tester1::agegrpgrouped age6230-3930-39years230-39grouped ageNA
agegrp10agegrp10_cat6_2catcattester1tester1::agegrpgrouped age6230-3930-39years330-39grouped ageNA
agegrp10agegrp10_cat6_3catcattester1tester1::agegrpgrouped age6340-4940-49years440-49grouped ageNA
agegrp10agegrp10_cat6_3catcattester1tester1::agegrpgrouped age6340-4940-49years540-49grouped ageNA
agegrp10agegrp10_cat6_4catcattester1tester1::agegrpgrouped age6450-5950-59years650-59grouped ageNA
agegrp10agegrp10_cat6_4catcattester1tester1::agegrpgrouped age6450-5950-59years750-59grouped ageNA
agegrp10agegrp10_cat6_5catcattester1tester1::agegrpgrouped age6560-6960-69years860-69grouped ageNA
agegrp10agegrp10_cat6_5catcattester1tester1::agegrpgrouped age6560-6960-69years960-69grouped ageNA
agegrp10agegrp10_cat6_6catcattester1tester1::agegrpgrouped age6670-7970-79years1070-79grouped ageNA
agegrp10agegrp10_cat6_6catcattester1tester1::agegrpgrouped age6670-7970-79years1170-79grouped ageNA
agegrp10agegrp10_cat6_NA::bcatcattester1tester1::agegrpgrouped age6NA::bmissingmissingyearselsemissinggrouped ageNA
+
    +
  1. +variableStartLabel: indicates the original variable +lable
  2. +
+

Write “stage” in the 6 rows.

+ ++++++++++++++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
variabledummyVariabletypeEndtypeStartdatabaseStartvariableStartvariableStartLabelnumValidCatrecEndcatLabelcatLabelLongunitsrecStartcatStartLabelvariableStartShortLabelnotes
ageNAcontconttester1; tester2[age]ageNAcopyNANANA[20,80]NAageNA
ageNAcontconttester1; tester2[age]ageNANA::bmissingmissingNAelseNAageNA
ageNAcontconttester1; tester2[age]ageNANA::anot applicablenot applicableNA999NAageNA
albuminNAcontconttester1; tester2[albumin]albuminNAcopyNANANA[1,5]NAalbuminNA
albuminNAcontconttester1; tester2[albumin]albuminNANA::bmissingmissingNAelseNAalbuminNA
albuminNAcontconttester1; tester2[albumin]albuminNANA::anot applicablenot applicableNA99NAalbuminNA
alk.phosNAcontconttester1; tester2[alk.phos]alk.phosNAcopyNANANA[200,15000]NAalk.phosNA
alk.phosNAcontconttester1; tester2[alk.phos]alk.phosNANA::bmissingmissingNAelseNAalk.phosNA
ascitesascites_cat3_1catcattester1; tester2[ascites]ascites20ascites 0ascites 0NA0ascites 0ascitesNA
ascitesascites_cat3_2catcattester1; tester2[ascites]ascites21ascites 1ascites 1NA1ascites 1ascitesNA
ascitesascites_cat3_NA::bcatcattester1; tester2[ascites]ascites2NA::bmissingmissingNAelseascites 0ascitesNA
ascitesascites_cat3_NA::acatcattester1; tester2[ascites]ascites2NA::anot applicablenot applicableNA9not applicableNANA
alk.phosNAcontconttester1; tester2[alk.phos]alk.phosNANA::anot applicablenot applicableNA99999NAalk.phosNA
astNAcontconttester1; tester2[ast]astNAcopyNANANA[20,500]NAastNA
astNAcontconttester1; tester2[ast]astNANA::bmissingmissingNAelseNAastNA
astNAcontconttester1; tester2[ast]astNANA::anot applicablenot applicableNA9999NAastNA
biliNAcontconttester1; tester2[bili]biliNAcopyNANANA[0,100]NAbiliNA
biliNAcontconttester1; tester2[bili]biliNANA::bmissingmissingNAelseNAbiliNA
cholNAcontconttester1; tester2[chol]cholNAcopyNANANA[100,2000]NAcholNA
cholNAcontconttester1; tester2[chol]cholNANA::bmissingmissingNAelseNAcholNA
cholNAcontconttester1; tester2[chol]cholNANA::amissingmissingNA9999NAcholNA
copperNAcontconttester1; tester2[copper]copperNAcopyNANANA[0,1000]NAcopperNA
copperNAcontconttester1; tester2[copper]copperNANA::bmissingmissingNAelseNAcopperNA
edemaedema_cat3_1catcattester1; tester2[edema]edema30edema 0.0edema 0.0NA0edema 0.0edemaNA
edemaedema_cat3_2catcattester1; tester2[edema]edema30.5edema 0.5edema 0.5NA0.5edema 0.5edemaNA
edemaedema_cat3_3catcattester1; tester2[edema]edema31edema 1.0edema 1.0NA1edema 1.0edemaNA
edemaedema_cat3_NA::bcatcattester1; tester2[edema]edema3NA::bmissingmissingNAelsemissingedemaNA
edemaedema_cat3_NA::acatcattester1; tester2[edema]edema3NA::anot applicablenot applicableNA9not applicableedemaNA
hepatoheapto_cat3_1catcattester1; tester2[hepato]hepato20hepato 0hepato 0NA0hepato 0hepatoNA
hepatoheapto_cat3_1catcattester1; tester2[hepato]hepato21hepato 1hepato 1NA1hepato 1hepatoNA
hepatoheapto_cat3_NA::acatcattester1; tester2[hepato]hepato2NA::bmissingmissingNAelsemissinghepatoNA
copperNAcontconttester1; tester2[copper]copperNANA::amissingmissingNA9999NAcopperNA
plateletNAcontconttester1; tester2[platelet]plateletNAcopyNANANA[0,1000]NAplateletNA
plateletNAcontconttester1; tester2[platelet]plateletNANA::bmissingmissingNAelseNAplateletNA
plateletNAcontconttester1; tester2[platelet]plateletNANA::anot applicablenot applicableNA9999NAplateletNA
protimeNAcontconttester1; tester2[protime]protimeNAcopyNANANA[5, 30]NAprotimeNA
protimeNAcontconttester1; tester2[protime]protimeNANA::bmissingmissingNAelseNAprotimeNA
hepatoheapto_cat3_NA::bcatcattester1; tester2[hepato]hepato2NA::anot applicablenot applicableNA9not applicablehepatoNA
sexsex_cat2_1catcattester1; tester2[sex]sex2msex msex mNAmsex msexNA
sexsex_cat2_2catcattester1; tester2[sex]sex2fsex fsex fNAfsex fsexNA
sexsex_cat2_NA::bcatcattester1; tester2[sex]sex2NA::bmissingmissingNAelsesex msexNA
sexsex_cat2_NA::acatcattester1; tester2[sex]sex2NA::anot applicablenot applicableNA9sex msexNA
spidersspiders0catcattester1; tester2[spiders]spiders20spiders 0spiders 0NA0spiders 0spidersNA
spidersspiders1catcattester1; tester2[spiders]spiders21spiders 1spiders 1NA1spiders 1spidersNA
spidersspiders_NA::bcatcattester1; tester2[spiders]spiders2NA::bmissingmissingNAelsespiders 0spidersNA
spidersspiders_NA::acatcattester1; tester2[spiders]spiders2NA::anot applicablenot applicableNA9not applicablespidersNA
stagestage1catcattester1; tester2[stage]stage41stage 1stage 1NA1stage 1stageNA
stagestage2catcattester1; tester2[stage]stage42stage 2stage 2NA2stage 2stageNA
stagestage3catcattester1; tester2[stage]stage43stage 3stage 3NA3stage 3stageNA
stagestage4catcattester1; tester2[stage]stage44stage 4stage 4NA4stage 4stageNA
stagestage_NA::bcatcattester1; tester2[stage]stage4NA::bmissingmissingNAelsemissingstageNA
stagestage_NA::acatcattester1; tester2[stage]stage4NA::anot applicablenot applicableNA9not applicablestageNA
statusstatus0catcattester1; tester2[status]status30status 0status 0NA0status 0statusNA
statusstatus1catcattester1; tester2[status]status31status 1status 1NA1status 1statusNA
statusstatus2catcattester1; tester2[status]status32status 2status 2NA2status 2statusNA
statusstatus_NA::bcatcattester1; tester2[status]status3NA::bmissingmissingNAelsestatus 0statusNA
protimeNAcontconttester1; tester2[protime]protimeNANA::anot applicablenot applicableNA99NAprotimeNA
timeNAcontconttester1; tester2[time]timeNAcopyNANANA[0,5000]NAtimeNA
timeNAcontconttester1; tester2[time]timeNANA::bmissingmissingNAelseNAtimeNA
timeNAcontconttester1; tester2[time]timeNANA::anot applicablenot applicableNA9999NAtimeNA
trigNAcontconttester1; tester2[trig]trigNAcopyNANANA[0,1000]NAtrigNA
trigNAcontconttester1; tester2[trig]trigNANA::bmissingmissingNAelseNAtrigNA
statusstatus_NA::acatcattester1; tester2[status]status3NA::anot applicablenot applicableNA9not applicablestatusNA
trttrt1catcattester1; tester2[trt]trt21trt 1trt 1NA1trt 1trtNA
trttrt2catcattester1; tester2[trt]trt22trt 2trt 2NA2trt 2trtNA
trttrt_NA::bcatcattester1; tester2[trt]trt2NA::bmissingmissingNAelsetrt 1trtNA
trttrt_NA::acatcattester1; tester2[trt]trt2NA::anot applicablenot applicableNA9not applicabletrtNA
trigNAcontconttester1; tester2[trig]trigNANA::amissingmissingNA9999NAtrigNA
example_derNAcontconttester1; tester2DerivedVar::[chol, bili]example_derNAFunc::example_der_funN/AN/ANAelseN/Aexample_derA test derived variable
agegrp10agegrp10_cat6_1catcattester2tester2::agegrpgrouped age6120-2920-29years120-29grouped ageNA
agegrp10agegrp10_cat6_2catcattester2tester2::agegrpgrouped age6230-3930-39years230-39grouped ageNA
agegrp10agegrp10_cat6_3catcattester2tester2::agegrpgrouped age6340-4940-49years340-49grouped ageNA
agegrp10agegrp10_cat6_4catcattester2tester2::agegrpgrouped age6450-5950-59years450-59grouped ageNA
agegrp10agegrp10_cat6_5catcattester2tester2::agegrpgrouped age6560-6960-69years560-69grouped ageNA
agegrp10agegrp10_cat6_6catcattester2tester2::agegrpgrouped age6670-7970-79years670-79grouped ageNA
agegrp10agegrp10_cat6_NA::bcatcattester2tester2::agegrpgrouped age6NA::bmissingmissingyearselsemissinggrouped ageNA
agegrp5agegrp5_cat11_1catcattester1tester1::agegrpgrouped age11125-2925-29years120-29grouped ageNA
agegrp5agegrp5_cat11_2catcattester1tester1::agegrpgrouped age11230-3430-34years230-39grouped ageNA
agegrp5agegrp5_cat11_3catcattester1tester1::agegrpgrouped age11335-3935-39years330-39grouped ageNA
agegrp5agegrp5_cat11_4catcattester1tester1::agegrpgrouped age11440-4440-44years440-49grouped ageNA
agegrp5agegrp5_cat11_5catcattester1tester1::agegrpgrouped age11545-4945-49years540-49grouped ageNA
agegrp5agegrp5_cat11_6catcattester1tester1::agegrpgrouped age11650-5450-54years650-59grouped ageNA
agegrp5agegrp5_cat11_7catcattester1tester1::agegrpgrouped age11755-5955-59years750-59grouped ageNA
agegrp5agegrp5_cat11_8catcattester1tester1::agegrpgrouped age11860-6460-64years860-69grouped ageNA
agegrp5agegrp5_cat11_9catcattester1tester1::agegrpgrouped age11965-6965-69years960-69grouped ageNA
agegrp5agegrp5_cat11_10catcattester1tester1::agegrpgrouped age111070-7470-74years1070-79grouped ageNA
agegrp5agegrp5_cat11_11catcattester1tester1::agegrpgrouped age111175-7975-79years1170-79grouped ageNA
agegrp5agegrp5_cat11_NA::bcatcattester1tester1::agegrpgrouped age11Na::bmissingmissingyearselsemissinggrouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA27NANAyears120-29grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA32NANAyears230-39grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA37NANAyears330-39grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA42NANAyears440-49grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA47NANAyears540-49grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA52NANAyears650-59grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA57NANAyears750-59grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA62NANAyears860-69grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA67NANAyears960-69grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA72NANAyears1070-79grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA77NANAyears1170-79grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNANA::bNANAyearselsemissinggrouped ageNA
age_contNAcontcattester2tester2::agegrpgrouped ageNA25NANAyears120-29grouped ageNA
age_contNAcontcattester2tester2::agegrpgrouped ageNA35NANAyears230-39grouped ageNA
age_contNAcontcattester2tester2::agegrpgrouped ageNA45NANAyears340-49grouped ageNA
age_contNAcontcattester2tester2::agegrpgrouped ageNA55NANAyears450-59grouped ageNA
age_contNAcontcattester2tester2::agegrpgrouped ageNA65NANAyears560-69grouped ageNA
age_contNAcontcattester2tester2::agegrpgrouped ageNA75NANAyears670-79grouped ageNA
age_contNAcontcattester2tester2::agegrpgrouped age6NA::bNANAyearselsemissinggrouped ageNA
agegrp10agegrp10_cat6_1catcattester1tester1::agegrpgrouped age6120-2920-29years120-29grouped ageNA
agegrp10agegrp10_cat6_2catcattester1tester1::agegrpgrouped age6230-3930-39years230-39grouped ageNA
agegrp10agegrp10_cat6_2catcattester1tester1::agegrpgrouped age6230-3930-39years330-39grouped ageNA
agegrp10agegrp10_cat6_3catcattester1tester1::agegrpgrouped age6340-4940-49years440-49grouped ageNA
agegrp10agegrp10_cat6_3catcattester1tester1::agegrpgrouped age6340-4940-49years540-49grouped ageNA
agegrp10agegrp10_cat6_4catcattester1tester1::agegrpgrouped age6450-5950-59years650-59grouped ageNA
agegrp10agegrp10_cat6_4catcattester1tester1::agegrpgrouped age6450-5950-59years750-59grouped ageNA
agegrp10agegrp10_cat6_5catcattester1tester1::agegrpgrouped age6560-6960-69years860-69grouped ageNA
agegrp10agegrp10_cat6_5catcattester1tester1::agegrpgrouped age6560-6960-69years960-69grouped ageNA
agegrp10agegrp10_cat6_6catcattester1tester1::agegrpgrouped age6670-7970-79years1070-79grouped ageNA
agegrp10agegrp10_cat6_6catcattester1tester1::agegrpgrouped age6670-7970-79years1170-79grouped ageNA
agegrp10agegrp10_cat6_NA::bcatcattester1tester1::agegrpgrouped age6NA::bmissingmissingyearselsemissinggrouped ageNA
+
    +
  1. +numValidCat: indicates the number of valid +categories for the final derived variable. In our example, there are +four categories for stage: 1, 2, 3, and 4. Note that the +categories ‘not applicable’, ‘missing’, and ‘else’ are not included in +the category count.
  2. +
+

Write 4 in each of the six rows.

+ ++++++++++++++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
variabledummyVariabletypeEndtypeStartdatabaseStartvariableStartvariableStartLabelnumValidCatrecEndcatLabelcatLabelLongunitsrecStartcatStartLabelvariableStartShortLabelnotes
ageNAcontconttester1; tester2[age]ageNAcopyNANANA[20,80]NAageNA
ageNAcontconttester1; tester2[age]ageNANA::bmissingmissingNAelseNAageNA
ageNAcontconttester1; tester2[age]ageNANA::anot applicablenot applicableNA999NAageNA
albuminNAcontconttester1; tester2[albumin]albuminNAcopyNANANA[1,5]NAalbuminNA
albuminNAcontconttester1; tester2[albumin]albuminNANA::bmissingmissingNAelseNAalbuminNA
albuminNAcontconttester1; tester2[albumin]albuminNANA::anot applicablenot applicableNA99NAalbuminNA
alk.phosNAcontconttester1; tester2[alk.phos]alk.phosNAcopyNANANA[200,15000]NAalk.phosNA
alk.phosNAcontconttester1; tester2[alk.phos]alk.phosNANA::bmissingmissingNAelseNAalk.phosNA
ascitesascites_cat3_1catcattester1; tester2[ascites]ascites20ascites 0ascites 0NA0ascites 0ascitesNA
ascitesascites_cat3_2catcattester1; tester2[ascites]ascites21ascites 1ascites 1NA1ascites 1ascitesNA
ascitesascites_cat3_NA::bcatcattester1; tester2[ascites]ascites2NA::bmissingmissingNAelseascites 0ascitesNA
ascitesascites_cat3_NA::acatcattester1; tester2[ascites]ascites2NA::anot applicablenot applicableNA9not applicableNANA
alk.phosNAcontconttester1; tester2[alk.phos]alk.phosNANA::anot applicablenot applicableNA99999NAalk.phosNA
astNAcontconttester1; tester2[ast]astNAcopyNANANA[20,500]NAastNA
astNAcontconttester1; tester2[ast]astNANA::bmissingmissingNAelseNAastNA
astNAcontconttester1; tester2[ast]astNANA::anot applicablenot applicableNA9999NAastNA
biliNAcontconttester1; tester2[bili]biliNAcopyNANANA[0,100]NAbiliNA
biliNAcontconttester1; tester2[bili]biliNANA::bmissingmissingNAelseNAbiliNA
cholNAcontconttester1; tester2[chol]cholNAcopyNANANA[100,2000]NAcholNA
cholNAcontconttester1; tester2[chol]cholNANA::bmissingmissingNAelseNAcholNA
cholNAcontconttester1; tester2[chol]cholNANA::amissingmissingNA9999NAcholNA
copperNAcontconttester1; tester2[copper]copperNAcopyNANANA[0,1000]NAcopperNA
copperNAcontconttester1; tester2[copper]copperNANA::bmissingmissingNAelseNAcopperNA
edemaedema_cat3_1catcattester1; tester2[edema]edema30edema 0.0edema 0.0NA0edema 0.0edemaNA
edemaedema_cat3_2catcattester1; tester2[edema]edema30.5edema 0.5edema 0.5NA0.5edema 0.5edemaNA
edemaedema_cat3_3catcattester1; tester2[edema]edema31edema 1.0edema 1.0NA1edema 1.0edemaNA
edemaedema_cat3_NA::bcatcattester1; tester2[edema]edema3NA::bmissingmissingNAelsemissingedemaNA
edemaedema_cat3_NA::acatcattester1; tester2[edema]edema3NA::anot applicablenot applicableNA9not applicableedemaNA
hepatoheapto_cat3_1catcattester1; tester2[hepato]hepato20hepato 0hepato 0NA0hepato 0hepatoNA
hepatoheapto_cat3_1catcattester1; tester2[hepato]hepato21hepato 1hepato 1NA1hepato 1hepatoNA
hepatoheapto_cat3_NA::acatcattester1; tester2[hepato]hepato2NA::bmissingmissingNAelsemissinghepatoNA
copperNAcontconttester1; tester2[copper]copperNANA::amissingmissingNA9999NAcopperNA
plateletNAcontconttester1; tester2[platelet]plateletNAcopyNANANA[0,1000]NAplateletNA
plateletNAcontconttester1; tester2[platelet]plateletNANA::bmissingmissingNAelseNAplateletNA
plateletNAcontconttester1; tester2[platelet]plateletNANA::anot applicablenot applicableNA9999NAplateletNA
protimeNAcontconttester1; tester2[protime]protimeNAcopyNANANA[5, 30]NAprotimeNA
protimeNAcontconttester1; tester2[protime]protimeNANA::bmissingmissingNAelseNAprotimeNA
hepatoheapto_cat3_NA::bcatcattester1; tester2[hepato]hepato2NA::anot applicablenot applicableNA9not applicablehepatoNA
sexsex_cat2_1catcattester1; tester2[sex]sex2msex msex mNAmsex msexNA
sexsex_cat2_2catcattester1; tester2[sex]sex2fsex fsex fNAfsex fsexNA
sexsex_cat2_NA::bcatcattester1; tester2[sex]sex2NA::bmissingmissingNAelsesex msexNA
sexsex_cat2_NA::acatcattester1; tester2[sex]sex2NA::anot applicablenot applicableNA9sex msexNA
spidersspiders0catcattester1; tester2[spiders]spiders20spiders 0spiders 0NA0spiders 0spidersNA
spidersspiders1catcattester1; tester2[spiders]spiders21spiders 1spiders 1NA1spiders 1spidersNA
spidersspiders_NA::bcatcattester1; tester2[spiders]spiders2NA::bmissingmissingNAelsespiders 0spidersNA
spidersspiders_NA::acatcattester1; tester2[spiders]spiders2NA::anot applicablenot applicableNA9not applicablespidersNA
stagestage1catcattester1; tester2[stage]stage41stage 1stage 1NA1stage 1stageNA
stagestage2catcattester1; tester2[stage]stage42stage 2stage 2NA2stage 2stageNA
stagestage3catcattester1; tester2[stage]stage43stage 3stage 3NA3stage 3stageNA
stagestage4catcattester1; tester2[stage]stage44stage 4stage 4NA4stage 4stageNA
stagestage_NA::bcatcattester1; tester2[stage]stage4NA::bmissingmissingNAelsemissingstageNA
stagestage_NA::acatcattester1; tester2[stage]stage4NA::anot applicablenot applicableNA9not applicablestageNA
statusstatus0catcattester1; tester2[status]status30status 0status 0NA0status 0statusNA
statusstatus1catcattester1; tester2[status]status31status 1status 1NA1status 1statusNA
statusstatus2catcattester1; tester2[status]status32status 2status 2NA2status 2statusNA
statusstatus_NA::bcatcattester1; tester2[status]status3NA::bmissingmissingNAelsestatus 0statusNA
protimeNAcontconttester1; tester2[protime]protimeNANA::anot applicablenot applicableNA99NAprotimeNA
timeNAcontconttester1; tester2[time]timeNAcopyNANANA[0,5000]NAtimeNA
timeNAcontconttester1; tester2[time]timeNANA::bmissingmissingNAelseNAtimeNA
timeNAcontconttester1; tester2[time]timeNANA::anot applicablenot applicableNA9999NAtimeNA
trigNAcontconttester1; tester2[trig]trigNAcopyNANANA[0,1000]NAtrigNA
trigNAcontconttester1; tester2[trig]trigNANA::bmissingmissingNAelseNAtrigNA
statusstatus_NA::acatcattester1; tester2[status]status3NA::anot applicablenot applicableNA9not applicablestatusNA
trttrt1catcattester1; tester2[trt]trt21trt 1trt 1NA1trt 1trtNA
trttrt2catcattester1; tester2[trt]trt22trt 2trt 2NA2trt 2trtNA
trttrt_NA::bcatcattester1; tester2[trt]trt2NA::bmissingmissingNAelsetrt 1trtNA
trttrt_NA::acatcattester1; tester2[trt]trt2NA::anot applicablenot applicableNA9not applicabletrtNA
trigNAcontconttester1; tester2[trig]trigNANA::amissingmissingNA9999NAtrigNA
example_derNAcontconttester1; tester2DerivedVar::[chol, bili]example_derNAFunc::example_der_funN/AN/ANAelseN/Aexample_derA test derived variable
agegrp10agegrp10_cat6_1catcattester2tester2::agegrpgrouped age6120-2920-29years120-29grouped ageNA
agegrp10agegrp10_cat6_2catcattester2tester2::agegrpgrouped age6230-3930-39years230-39grouped ageNA
agegrp10agegrp10_cat6_3catcattester2tester2::agegrpgrouped age6340-4940-49years340-49grouped ageNA
agegrp10agegrp10_cat6_4catcattester2tester2::agegrpgrouped age6450-5950-59years450-59grouped ageNA
agegrp10agegrp10_cat6_5catcattester2tester2::agegrpgrouped age6560-6960-69years560-69grouped ageNA
agegrp10agegrp10_cat6_6catcattester2tester2::agegrpgrouped age6670-7970-79years670-79grouped ageNA
agegrp10agegrp10_cat6_NA::bcatcattester2tester2::agegrpgrouped age6NA::bmissingmissingyearselsemissinggrouped ageNA
agegrp5agegrp5_cat11_1catcattester1tester1::agegrpgrouped age11125-2925-29years120-29grouped ageNA
agegrp5agegrp5_cat11_2catcattester1tester1::agegrpgrouped age11230-3430-34years230-39grouped ageNA
agegrp5agegrp5_cat11_3catcattester1tester1::agegrpgrouped age11335-3935-39years330-39grouped ageNA
agegrp5agegrp5_cat11_4catcattester1tester1::agegrpgrouped age11440-4440-44years440-49grouped ageNA
agegrp5agegrp5_cat11_5catcattester1tester1::agegrpgrouped age11545-4945-49years540-49grouped ageNA
agegrp5agegrp5_cat11_6catcattester1tester1::agegrpgrouped age11650-5450-54years650-59grouped ageNA
agegrp5agegrp5_cat11_7catcattester1tester1::agegrpgrouped age11755-5955-59years750-59grouped ageNA
agegrp5agegrp5_cat11_8catcattester1tester1::agegrpgrouped age11860-6460-64years860-69grouped ageNA
agegrp5agegrp5_cat11_9catcattester1tester1::agegrpgrouped age11965-6965-69years960-69grouped ageNA
agegrp5agegrp5_cat11_10catcattester1tester1::agegrpgrouped age111070-7470-74years1070-79grouped ageNA
agegrp5agegrp5_cat11_11catcattester1tester1::agegrpgrouped age111175-7975-79years1170-79grouped ageNA
agegrp5agegrp5_cat11_NA::bcatcattester1tester1::agegrpgrouped age11Na::bmissingmissingyearselsemissinggrouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA27NANAyears120-29grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA32NANAyears230-39grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA37NANAyears330-39grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA42NANAyears440-49grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA47NANAyears540-49grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA52NANAyears650-59grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA57NANAyears750-59grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA62NANAyears860-69grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA67NANAyears960-69grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA72NANAyears1070-79grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA77NANAyears1170-79grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNANA::bNANAyearselsemissinggrouped ageNA
age_contNAcontcattester2tester2::agegrpgrouped ageNA25NANAyears120-29grouped ageNA
age_contNAcontcattester2tester2::agegrpgrouped ageNA35NANAyears230-39grouped ageNA
age_contNAcontcattester2tester2::agegrpgrouped ageNA45NANAyears340-49grouped ageNA
age_contNAcontcattester2tester2::agegrpgrouped ageNA55NANAyears450-59grouped ageNA
age_contNAcontcattester2tester2::agegrpgrouped ageNA65NANAyears560-69grouped ageNA
age_contNAcontcattester2tester2::agegrpgrouped ageNA75NANAyears670-79grouped ageNA
age_contNAcontcattester2tester2::agegrpgrouped age6NA::bNANAyearselsemissinggrouped ageNA
agegrp10agegrp10_cat6_1catcattester1tester1::agegrpgrouped age6120-2920-29years120-29grouped ageNA
agegrp10agegrp10_cat6_2catcattester1tester1::agegrpgrouped age6230-3930-39years230-39grouped ageNA
agegrp10agegrp10_cat6_2catcattester1tester1::agegrpgrouped age6230-3930-39years330-39grouped ageNA
agegrp10agegrp10_cat6_3catcattester1tester1::agegrpgrouped age6340-4940-49years440-49grouped ageNA
agegrp10agegrp10_cat6_3catcattester1tester1::agegrpgrouped age6340-4940-49years540-49grouped ageNA
agegrp10agegrp10_cat6_4catcattester1tester1::agegrpgrouped age6450-5950-59years650-59grouped ageNA
agegrp10agegrp10_cat6_4catcattester1tester1::agegrpgrouped age6450-5950-59years750-59grouped ageNA
agegrp10agegrp10_cat6_5catcattester1tester1::agegrpgrouped age6560-6960-69years860-69grouped ageNA
agegrp10agegrp10_cat6_5catcattester1tester1::agegrpgrouped age6560-6960-69years960-69grouped ageNA
agegrp10agegrp10_cat6_6catcattester1tester1::agegrpgrouped age6670-7970-79years1070-79grouped ageNA
agegrp10agegrp10_cat6_6catcattester1tester1::agegrpgrouped age6670-7970-79years1170-79grouped ageNA
agegrp10agegrp10_cat6_NA::bcatcattester1tester1::agegrpgrouped age6NA::bmissingmissingyearselsemissinggrouped ageNA
+
    +
  1. +recEnd: indicates the category to which you are +recoding each row. For the not applicable rows NA::a is +written. For the missing and else rows NA::b is written. +The haven package is used for tagging NA in numeric +variables.
  2. +
+

We are not changing the categories stage, therefore, the +recEnd values for these rows will be the same as the the original data. +For the not applicable rows write NA::a. For the missing +and else rows write NA::b.

+ ++++++++++++++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
variabledummyVariabletypeEndtypeStartdatabaseStartvariableStartvariableStartLabelnumValidCatrecEndcatLabelcatLabelLongunitsrecStartcatStartLabelvariableStartShortLabelnotes
ageNAcontconttester1; tester2[age]ageNAcopyNANANA[20,80]NAageNA
ageNAcontconttester1; tester2[age]ageNANA::bmissingmissingNAelseNAageNA
ageNAcontconttester1; tester2[age]ageNANA::anot applicablenot applicableNA999NAageNA
albuminNAcontconttester1; tester2[albumin]albuminNAcopyNANANA[1,5]NAalbuminNA
albuminNAcontconttester1; tester2[albumin]albuminNANA::bmissingmissingNAelseNAalbuminNA
albuminNAcontconttester1; tester2[albumin]albuminNANA::anot applicablenot applicableNA99NAalbuminNA
alk.phosNAcontconttester1; tester2[alk.phos]alk.phosNAcopyNANANA[200,15000]NAalk.phosNA
alk.phosNAcontconttester1; tester2[alk.phos]alk.phosNANA::bmissingmissingNAelseNAalk.phosNA
ascitesascites_cat3_1catcattester1; tester2[ascites]ascites20ascites 0ascites 0NA0ascites 0ascitesNA
ascitesascites_cat3_2catcattester1; tester2[ascites]ascites21ascites 1ascites 1NA1ascites 1ascitesNA
ascitesascites_cat3_NA::bcatcattester1; tester2[ascites]ascites2NA::bmissingmissingNAelseascites 0ascitesNA
ascitesascites_cat3_NA::acatcattester1; tester2[ascites]ascites2NA::anot applicablenot applicableNA9not applicableNANA
alk.phosNAcontconttester1; tester2[alk.phos]alk.phosNANA::anot applicablenot applicableNA99999NAalk.phosNA
astNAcontconttester1; tester2[ast]astNAcopyNANANA[20,500]NAastNA
astNAcontconttester1; tester2[ast]astNANA::bmissingmissingNAelseNAastNA
astNAcontconttester1; tester2[ast]astNANA::anot applicablenot applicableNA9999NAastNA
biliNAcontconttester1; tester2[bili]biliNAcopyNANANA[0,100]NAbiliNA
biliNAcontconttester1; tester2[bili]biliNANA::bmissingmissingNAelseNAbiliNA
cholNAcontconttester1; tester2[chol]cholNAcopyNANANA[100,2000]NAcholNA
cholNAcontconttester1; tester2[chol]cholNANA::bmissingmissingNAelseNAcholNA
cholNAcontconttester1; tester2[chol]cholNANA::amissingmissingNA9999NAcholNA
copperNAcontconttester1; tester2[copper]copperNAcopyNANANA[0,1000]NAcopperNA
copperNAcontconttester1; tester2[copper]copperNANA::bmissingmissingNAelseNAcopperNA
edemaedema_cat3_1catcattester1; tester2[edema]edema30edema 0.0edema 0.0NA0edema 0.0edemaNA
edemaedema_cat3_2catcattester1; tester2[edema]edema30.5edema 0.5edema 0.5NA0.5edema 0.5edemaNA
edemaedema_cat3_3catcattester1; tester2[edema]edema31edema 1.0edema 1.0NA1edema 1.0edemaNA
edemaedema_cat3_NA::bcatcattester1; tester2[edema]edema3NA::bmissingmissingNAelsemissingedemaNA
edemaedema_cat3_NA::acatcattester1; tester2[edema]edema3NA::anot applicablenot applicableNA9not applicableedemaNA
hepatoheapto_cat3_1catcattester1; tester2[hepato]hepato20hepato 0hepato 0NA0hepato 0hepatoNA
hepatoheapto_cat3_1catcattester1; tester2[hepato]hepato21hepato 1hepato 1NA1hepato 1hepatoNA
hepatoheapto_cat3_NA::acatcattester1; tester2[hepato]hepato2NA::bmissingmissingNAelsemissinghepatoNA
copperNAcontconttester1; tester2[copper]copperNANA::amissingmissingNA9999NAcopperNA
plateletNAcontconttester1; tester2[platelet]plateletNAcopyNANANA[0,1000]NAplateletNA
plateletNAcontconttester1; tester2[platelet]plateletNANA::bmissingmissingNAelseNAplateletNA
plateletNAcontconttester1; tester2[platelet]plateletNANA::anot applicablenot applicableNA9999NAplateletNA
protimeNAcontconttester1; tester2[protime]protimeNAcopyNANANA[5, 30]NAprotimeNA
protimeNAcontconttester1; tester2[protime]protimeNANA::bmissingmissingNAelseNAprotimeNA
hepatoheapto_cat3_NA::bcatcattester1; tester2[hepato]hepato2NA::anot applicablenot applicableNA9not applicablehepatoNA
sexsex_cat2_1catcattester1; tester2[sex]sex2msex msex mNAmsex msexNA
sexsex_cat2_2catcattester1; tester2[sex]sex2fsex fsex fNAfsex fsexNA
sexsex_cat2_NA::bcatcattester1; tester2[sex]sex2NA::bmissingmissingNAelsesex msexNA
sexsex_cat2_NA::acatcattester1; tester2[sex]sex2NA::anot applicablenot applicableNA9sex msexNA
spidersspiders0catcattester1; tester2[spiders]spiders20spiders 0spiders 0NA0spiders 0spidersNA
spidersspiders1catcattester1; tester2[spiders]spiders21spiders 1spiders 1NA1spiders 1spidersNA
spidersspiders_NA::bcatcattester1; tester2[spiders]spiders2NA::bmissingmissingNAelsespiders 0spidersNA
spidersspiders_NA::acatcattester1; tester2[spiders]spiders2NA::anot applicablenot applicableNA9not applicablespidersNA
stagestage1catcattester1; tester2[stage]stage41stage 1stage 1NA1stage 1stageNA
stagestage2catcattester1; tester2[stage]stage42stage 2stage 2NA2stage 2stageNA
stagestage3catcattester1; tester2[stage]stage43stage 3stage 3NA3stage 3stageNA
stagestage4catcattester1; tester2[stage]stage44stage 4stage 4NA4stage 4stageNA
stagestage_NA::bcatcattester1; tester2[stage]stage4NA::bmissingmissingNAelsemissingstageNA
stagestage_NA::acatcattester1; tester2[stage]stage4NA::anot applicablenot applicableNA9not applicablestageNA
statusstatus0catcattester1; tester2[status]status30status 0status 0NA0status 0statusNA
statusstatus1catcattester1; tester2[status]status31status 1status 1NA1status 1statusNA
statusstatus2catcattester1; tester2[status]status32status 2status 2NA2status 2statusNA
statusstatus_NA::bcatcattester1; tester2[status]status3NA::bmissingmissingNAelsestatus 0statusNA
protimeNAcontconttester1; tester2[protime]protimeNANA::anot applicablenot applicableNA99NAprotimeNA
timeNAcontconttester1; tester2[time]timeNAcopyNANANA[0,5000]NAtimeNA
timeNAcontconttester1; tester2[time]timeNANA::bmissingmissingNAelseNAtimeNA
timeNAcontconttester1; tester2[time]timeNANA::anot applicablenot applicableNA9999NAtimeNA
trigNAcontconttester1; tester2[trig]trigNAcopyNANANA[0,1000]NAtrigNA
trigNAcontconttester1; tester2[trig]trigNANA::bmissingmissingNAelseNAtrigNA
statusstatus_NA::acatcattester1; tester2[status]status3NA::anot applicablenot applicableNA9not applicablestatusNA
trttrt1catcattester1; tester2[trt]trt21trt 1trt 1NA1trt 1trtNA
trttrt2catcattester1; tester2[trt]trt22trt 2trt 2NA2trt 2trtNA
trttrt_NA::bcatcattester1; tester2[trt]trt2NA::bmissingmissingNAelsetrt 1trtNA
trttrt_NA::acatcattester1; tester2[trt]trt2NA::anot applicablenot applicableNA9not applicabletrtNA
trigNAcontconttester1; tester2[trig]trigNANA::amissingmissingNA9999NAtrigNA
example_derNAcontconttester1; tester2DerivedVar::[chol, bili]example_derNAFunc::example_der_funN/AN/ANAelseN/Aexample_derA test derived variable
agegrp10agegrp10_cat6_1catcattester2tester2::agegrpgrouped age6120-2920-29years120-29grouped ageNA
agegrp10agegrp10_cat6_2catcattester2tester2::agegrpgrouped age6230-3930-39years230-39grouped ageNA
agegrp10agegrp10_cat6_3catcattester2tester2::agegrpgrouped age6340-4940-49years340-49grouped ageNA
agegrp10agegrp10_cat6_4catcattester2tester2::agegrpgrouped age6450-5950-59years450-59grouped ageNA
agegrp10agegrp10_cat6_5catcattester2tester2::agegrpgrouped age6560-6960-69years560-69grouped ageNA
agegrp10agegrp10_cat6_6catcattester2tester2::agegrpgrouped age6670-7970-79years670-79grouped ageNA
agegrp10agegrp10_cat6_NA::bcatcattester2tester2::agegrpgrouped age6NA::bmissingmissingyearselsemissinggrouped ageNA
agegrp5agegrp5_cat11_1catcattester1tester1::agegrpgrouped age11125-2925-29years120-29grouped ageNA
agegrp5agegrp5_cat11_2catcattester1tester1::agegrpgrouped age11230-3430-34years230-39grouped ageNA
agegrp5agegrp5_cat11_3catcattester1tester1::agegrpgrouped age11335-3935-39years330-39grouped ageNA
agegrp5agegrp5_cat11_4catcattester1tester1::agegrpgrouped age11440-4440-44years440-49grouped ageNA
agegrp5agegrp5_cat11_5catcattester1tester1::agegrpgrouped age11545-4945-49years540-49grouped ageNA
agegrp5agegrp5_cat11_6catcattester1tester1::agegrpgrouped age11650-5450-54years650-59grouped ageNA
agegrp5agegrp5_cat11_7catcattester1tester1::agegrpgrouped age11755-5955-59years750-59grouped ageNA
agegrp5agegrp5_cat11_8catcattester1tester1::agegrpgrouped age11860-6460-64years860-69grouped ageNA
agegrp5agegrp5_cat11_9catcattester1tester1::agegrpgrouped age11965-6965-69years960-69grouped ageNA
agegrp5agegrp5_cat11_10catcattester1tester1::agegrpgrouped age111070-7470-74years1070-79grouped ageNA
agegrp5agegrp5_cat11_11catcattester1tester1::agegrpgrouped age111175-7975-79years1170-79grouped ageNA
agegrp5agegrp5_cat11_NA::bcatcattester1tester1::agegrpgrouped age11Na::bmissingmissingyearselsemissinggrouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA27NANAyears120-29grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA32NANAyears230-39grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA37NANAyears330-39grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA42NANAyears440-49grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA47NANAyears540-49grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA52NANAyears650-59grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA57NANAyears750-59grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA62NANAyears860-69grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA67NANAyears960-69grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA72NANAyears1070-79grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA77NANAyears1170-79grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNANA::bNANAyearselsemissinggrouped ageNA
age_contNAcontcattester2tester2::agegrpgrouped ageNA25NANAyears120-29grouped ageNA
age_contNAcontcattester2tester2::agegrpgrouped ageNA35NANAyears230-39grouped ageNA
age_contNAcontcattester2tester2::agegrpgrouped ageNA45NANAyears340-49grouped ageNA
age_contNAcontcattester2tester2::agegrpgrouped ageNA55NANAyears450-59grouped ageNA
age_contNAcontcattester2tester2::agegrpgrouped ageNA65NANAyears560-69grouped ageNA
age_contNAcontcattester2tester2::agegrpgrouped ageNA75NANAyears670-79grouped ageNA
age_contNAcontcattester2tester2::agegrpgrouped age6NA::bNANAyearselsemissinggrouped ageNA
agegrp10agegrp10_cat6_1catcattester1tester1::agegrpgrouped age6120-2920-29years120-29grouped ageNA
agegrp10agegrp10_cat6_2catcattester1tester1::agegrpgrouped age6230-3930-39years230-39grouped ageNA
agegrp10agegrp10_cat6_2catcattester1tester1::agegrpgrouped age6230-3930-39years330-39grouped ageNA
agegrp10agegrp10_cat6_3catcattester1tester1::agegrpgrouped age6340-4940-49years440-49grouped ageNA
agegrp10agegrp10_cat6_3catcattester1tester1::agegrpgrouped age6340-4940-49years540-49grouped ageNA
agegrp10agegrp10_cat6_4catcattester1tester1::agegrpgrouped age6450-5950-59years650-59grouped ageNA
agegrp10agegrp10_cat6_4catcattester1tester1::agegrpgrouped age6450-5950-59years750-59grouped ageNA
agegrp10agegrp10_cat6_5catcattester1tester1::agegrpgrouped age6560-6960-69years860-69grouped ageNA
agegrp10agegrp10_cat6_5catcattester1tester1::agegrpgrouped age6560-6960-69years960-69grouped ageNA
agegrp10agegrp10_cat6_6catcattester1tester1::agegrpgrouped age6670-7970-79years1070-79grouped ageNA
agegrp10agegrp10_cat6_6catcattester1tester1::agegrpgrouped age6670-7970-79years1170-79grouped ageNA
agegrp10agegrp10_cat6_NA::bcatcattester1tester1::agegrpgrouped age6NA::bmissingmissingyearselsemissinggrouped ageNA
+
    +
  1. +catLabel: indicates the lable for the recoded +categorical level.
  2. +
+

Write Stage 1, Stage 2, Stage 3, Stage 4, NA, and missing.

+ ++++++++++++++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
variabledummyVariabletypeEndtypeStartdatabaseStartvariableStartvariableStartLabelnumValidCatrecEndcatLabelcatLabelLongunitsrecStartcatStartLabelvariableStartShortLabelnotes
ageNAcontconttester1; tester2[age]ageNAcopyNANANA[20,80]NAageNA
ageNAcontconttester1; tester2[age]ageNANA::bmissingmissingNAelseNAageNA
ageNAcontconttester1; tester2[age]ageNANA::anot applicablenot applicableNA999NAageNA
albuminNAcontconttester1; tester2[albumin]albuminNAcopyNANANA[1,5]NAalbuminNA
albuminNAcontconttester1; tester2[albumin]albuminNANA::bmissingmissingNAelseNAalbuminNA
albuminNAcontconttester1; tester2[albumin]albuminNANA::anot applicablenot applicableNA99NAalbuminNA
alk.phosNAcontconttester1; tester2[alk.phos]alk.phosNAcopyNANANA[200,15000]NAalk.phosNA
alk.phosNAcontconttester1; tester2[alk.phos]alk.phosNANA::bmissingmissingNAelseNAalk.phosNA
ascitesascites_cat3_1catcattester1; tester2[ascites]ascites20ascites 0ascites 0NA0ascites 0ascitesNA
ascitesascites_cat3_2catcattester1; tester2[ascites]ascites21ascites 1ascites 1NA1ascites 1ascitesNA
ascitesascites_cat3_NA::bcatcattester1; tester2[ascites]ascites2NA::bmissingmissingNAelseascites 0ascitesNA
ascitesascites_cat3_NA::acatcattester1; tester2[ascites]ascites2NA::anot applicablenot applicableNA9not applicableNANA
alk.phosNAcontconttester1; tester2[alk.phos]alk.phosNANA::anot applicablenot applicableNA99999NAalk.phosNA
astNAcontconttester1; tester2[ast]astNAcopyNANANA[20,500]NAastNA
astNAcontconttester1; tester2[ast]astNANA::bmissingmissingNAelseNAastNA
astNAcontconttester1; tester2[ast]astNANA::anot applicablenot applicableNA9999NAastNA
biliNAcontconttester1; tester2[bili]biliNAcopyNANANA[0,100]NAbiliNA
biliNAcontconttester1; tester2[bili]biliNANA::bmissingmissingNAelseNAbiliNA
cholNAcontconttester1; tester2[chol]cholNAcopyNANANA[100,2000]NAcholNA
cholNAcontconttester1; tester2[chol]cholNANA::bmissingmissingNAelseNAcholNA
cholNAcontconttester1; tester2[chol]cholNANA::amissingmissingNA9999NAcholNA
copperNAcontconttester1; tester2[copper]copperNAcopyNANANA[0,1000]NAcopperNA
copperNAcontconttester1; tester2[copper]copperNANA::bmissingmissingNAelseNAcopperNA
edemaedema_cat3_1catcattester1; tester2[edema]edema30edema 0.0edema 0.0NA0edema 0.0edemaNA
edemaedema_cat3_2catcattester1; tester2[edema]edema30.5edema 0.5edema 0.5NA0.5edema 0.5edemaNA
edemaedema_cat3_3catcattester1; tester2[edema]edema31edema 1.0edema 1.0NA1edema 1.0edemaNA
edemaedema_cat3_NA::bcatcattester1; tester2[edema]edema3NA::bmissingmissingNAelsemissingedemaNA
edemaedema_cat3_NA::acatcattester1; tester2[edema]edema3NA::anot applicablenot applicableNA9not applicableedemaNA
hepatoheapto_cat3_1catcattester1; tester2[hepato]hepato20hepato 0hepato 0NA0hepato 0hepatoNA
hepatoheapto_cat3_1catcattester1; tester2[hepato]hepato21hepato 1hepato 1NA1hepato 1hepatoNA
hepatoheapto_cat3_NA::acatcattester1; tester2[hepato]hepato2NA::bmissingmissingNAelsemissinghepatoNA
copperNAcontconttester1; tester2[copper]copperNANA::amissingmissingNA9999NAcopperNA
plateletNAcontconttester1; tester2[platelet]plateletNAcopyNANANA[0,1000]NAplateletNA
plateletNAcontconttester1; tester2[platelet]plateletNANA::bmissingmissingNAelseNAplateletNA
plateletNAcontconttester1; tester2[platelet]plateletNANA::anot applicablenot applicableNA9999NAplateletNA
protimeNAcontconttester1; tester2[protime]protimeNAcopyNANANA[5, 30]NAprotimeNA
protimeNAcontconttester1; tester2[protime]protimeNANA::bmissingmissingNAelseNAprotimeNA
hepatoheapto_cat3_NA::bcatcattester1; tester2[hepato]hepato2NA::anot applicablenot applicableNA9not applicablehepatoNA
sexsex_cat2_1catcattester1; tester2[sex]sex2msex msex mNAmsex msexNA
sexsex_cat2_2catcattester1; tester2[sex]sex2fsex fsex fNAfsex fsexNA
sexsex_cat2_NA::bcatcattester1; tester2[sex]sex2NA::bmissingmissingNAelsesex msexNA
sexsex_cat2_NA::acatcattester1; tester2[sex]sex2NA::anot applicablenot applicableNA9sex msexNA
spidersspiders0catcattester1; tester2[spiders]spiders20spiders 0spiders 0NA0spiders 0spidersNA
spidersspiders1catcattester1; tester2[spiders]spiders21spiders 1spiders 1NA1spiders 1spidersNA
spidersspiders_NA::bcatcattester1; tester2[spiders]spiders2NA::bmissingmissingNAelsespiders 0spidersNA
spidersspiders_NA::acatcattester1; tester2[spiders]spiders2NA::anot applicablenot applicableNA9not applicablespidersNA
stagestage1catcattester1; tester2[stage]stage41stage 1stage 1NA1stage 1stageNA
stagestage2catcattester1; tester2[stage]stage42stage 2stage 2NA2stage 2stageNA
stagestage3catcattester1; tester2[stage]stage43stage 3stage 3NA3stage 3stageNA
stagestage4catcattester1; tester2[stage]stage44stage 4stage 4NA4stage 4stageNA
stagestage_NA::bcatcattester1; tester2[stage]stage4NA::bmissingmissingNAelsemissingstageNA
stagestage_NA::acatcattester1; tester2[stage]stage4NA::anot applicablenot applicableNA9not applicablestageNA
statusstatus0catcattester1; tester2[status]status30status 0status 0NA0status 0statusNA
statusstatus1catcattester1; tester2[status]status31status 1status 1NA1status 1statusNA
statusstatus2catcattester1; tester2[status]status32status 2status 2NA2status 2statusNA
statusstatus_NA::bcatcattester1; tester2[status]status3NA::bmissingmissingNAelsestatus 0statusNA
protimeNAcontconttester1; tester2[protime]protimeNANA::anot applicablenot applicableNA99NAprotimeNA
timeNAcontconttester1; tester2[time]timeNAcopyNANANA[0,5000]NAtimeNA
timeNAcontconttester1; tester2[time]timeNANA::bmissingmissingNAelseNAtimeNA
timeNAcontconttester1; tester2[time]timeNANA::anot applicablenot applicableNA9999NAtimeNA
trigNAcontconttester1; tester2[trig]trigNAcopyNANANA[0,1000]NAtrigNA
trigNAcontconttester1; tester2[trig]trigNANA::bmissingmissingNAelseNAtrigNA
statusstatus_NA::acatcattester1; tester2[status]status3NA::anot applicablenot applicableNA9not applicablestatusNA
trttrt1catcattester1; tester2[trt]trt21trt 1trt 1NA1trt 1trtNA
trttrt2catcattester1; tester2[trt]trt22trt 2trt 2NA2trt 2trtNA
trttrt_NA::bcatcattester1; tester2[trt]trt2NA::bmissingmissingNAelsetrt 1trtNA
trttrt_NA::acatcattester1; tester2[trt]trt2NA::anot applicablenot applicableNA9not applicabletrtNA
trigNAcontconttester1; tester2[trig]trigNANA::amissingmissingNA9999NAtrigNA
example_derNAcontconttester1; tester2DerivedVar::[chol, bili]example_derNAFunc::example_der_funN/AN/ANAelseN/Aexample_derA test derived variable
agegrp10agegrp10_cat6_1catcattester2tester2::agegrpgrouped age6120-2920-29years120-29grouped ageNA
agegrp10agegrp10_cat6_2catcattester2tester2::agegrpgrouped age6230-3930-39years230-39grouped ageNA
agegrp10agegrp10_cat6_3catcattester2tester2::agegrpgrouped age6340-4940-49years340-49grouped ageNA
agegrp10agegrp10_cat6_4catcattester2tester2::agegrpgrouped age6450-5950-59years450-59grouped ageNA
agegrp10agegrp10_cat6_5catcattester2tester2::agegrpgrouped age6560-6960-69years560-69grouped ageNA
agegrp10agegrp10_cat6_6catcattester2tester2::agegrpgrouped age6670-7970-79years670-79grouped ageNA
agegrp10agegrp10_cat6_NA::bcatcattester2tester2::agegrpgrouped age6NA::bmissingmissingyearselsemissinggrouped ageNA
agegrp5agegrp5_cat11_1catcattester1tester1::agegrpgrouped age11125-2925-29years120-29grouped ageNA
agegrp5agegrp5_cat11_2catcattester1tester1::agegrpgrouped age11230-3430-34years230-39grouped ageNA
agegrp5agegrp5_cat11_3catcattester1tester1::agegrpgrouped age11335-3935-39years330-39grouped ageNA
agegrp5agegrp5_cat11_4catcattester1tester1::agegrpgrouped age11440-4440-44years440-49grouped ageNA
agegrp5agegrp5_cat11_5catcattester1tester1::agegrpgrouped age11545-4945-49years540-49grouped ageNA
agegrp5agegrp5_cat11_6catcattester1tester1::agegrpgrouped age11650-5450-54years650-59grouped ageNA
agegrp5agegrp5_cat11_7catcattester1tester1::agegrpgrouped age11755-5955-59years750-59grouped ageNA
agegrp5agegrp5_cat11_8catcattester1tester1::agegrpgrouped age11860-6460-64years860-69grouped ageNA
agegrp5agegrp5_cat11_9catcattester1tester1::agegrpgrouped age11965-6965-69years960-69grouped ageNA
agegrp5agegrp5_cat11_10catcattester1tester1::agegrpgrouped age111070-7470-74years1070-79grouped ageNA
agegrp5agegrp5_cat11_11catcattester1tester1::agegrpgrouped age111175-7975-79years1170-79grouped ageNA
agegrp5agegrp5_cat11_NA::bcatcattester1tester1::agegrpgrouped age11Na::bmissingmissingyearselsemissinggrouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA27NANAyears120-29grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA32NANAyears230-39grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA37NANAyears330-39grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA42NANAyears440-49grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA47NANAyears540-49grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA52NANAyears650-59grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA57NANAyears750-59grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA62NANAyears860-69grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA67NANAyears960-69grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA72NANAyears1070-79grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA77NANAyears1170-79grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNANA::bNANAyearselsemissinggrouped ageNA
age_contNAcontcattester2tester2::agegrpgrouped ageNA25NANAyears120-29grouped ageNA
age_contNAcontcattester2tester2::agegrpgrouped ageNA35NANAyears230-39grouped ageNA
age_contNAcontcattester2tester2::agegrpgrouped ageNA45NANAyears340-49grouped ageNA
age_contNAcontcattester2tester2::agegrpgrouped ageNA55NANAyears450-59grouped ageNA
age_contNAcontcattester2tester2::agegrpgrouped ageNA65NANAyears560-69grouped ageNA
age_contNAcontcattester2tester2::agegrpgrouped ageNA75NANAyears670-79grouped ageNA
age_contNAcontcattester2tester2::agegrpgrouped age6NA::bNANAyearselsemissinggrouped ageNA
agegrp10agegrp10_cat6_1catcattester1tester1::agegrpgrouped age6120-2920-29years120-29grouped ageNA
agegrp10agegrp10_cat6_2catcattester1tester1::agegrpgrouped age6230-3930-39years230-39grouped ageNA
agegrp10agegrp10_cat6_2catcattester1tester1::agegrpgrouped age6230-3930-39years330-39grouped ageNA
agegrp10agegrp10_cat6_3catcattester1tester1::agegrpgrouped age6340-4940-49years440-49grouped ageNA
agegrp10agegrp10_cat6_3catcattester1tester1::agegrpgrouped age6340-4940-49years540-49grouped ageNA
agegrp10agegrp10_cat6_4catcattester1tester1::agegrpgrouped age6450-5950-59years650-59grouped ageNA
agegrp10agegrp10_cat6_4catcattester1tester1::agegrpgrouped age6450-5950-59years750-59grouped ageNA
agegrp10agegrp10_cat6_5catcattester1tester1::agegrpgrouped age6560-6960-69years860-69grouped ageNA
agegrp10agegrp10_cat6_5catcattester1tester1::agegrpgrouped age6560-6960-69years960-69grouped ageNA
agegrp10agegrp10_cat6_6catcattester1tester1::agegrpgrouped age6670-7970-79years1070-79grouped ageNA
agegrp10agegrp10_cat6_6catcattester1tester1::agegrpgrouped age6670-7970-79years1170-79grouped ageNA
agegrp10agegrp10_cat6_NA::bcatcattester1tester1::agegrpgrouped age6NA::bmissingmissingyearselsemissinggrouped ageNA
+
    +
  1. +catLabelLong: provides a more elaborate lable for +the recoded categorical level. If not required, repeat the shorter +catLabel.
  2. +
+

Copy values from catLabel

+ ++++++++++++++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
variabledummyVariabletypeEndtypeStartdatabaseStartvariableStartvariableStartLabelnumValidCatrecEndcatLabelcatLabelLongunitsrecStartcatStartLabelvariableStartShortLabelnotes
ageNAcontconttester1; tester2[age]ageNAcopyNANANA[20,80]NAageNA
ageNAcontconttester1; tester2[age]ageNANA::bmissingmissingNAelseNAageNA
ageNAcontconttester1; tester2[age]ageNANA::anot applicablenot applicableNA999NAageNA
albuminNAcontconttester1; tester2[albumin]albuminNAcopyNANANA[1,5]NAalbuminNA
albuminNAcontconttester1; tester2[albumin]albuminNANA::bmissingmissingNAelseNAalbuminNA
albuminNAcontconttester1; tester2[albumin]albuminNANA::anot applicablenot applicableNA99NAalbuminNA
alk.phosNAcontconttester1; tester2[alk.phos]alk.phosNAcopyNANANA[200,15000]NAalk.phosNA
alk.phosNAcontconttester1; tester2[alk.phos]alk.phosNANA::bmissingmissingNAelseNAalk.phosNA
ascitesascites_cat3_1catcattester1; tester2[ascites]ascites20ascites 0ascites 0NA0ascites 0ascitesNA
ascitesascites_cat3_2catcattester1; tester2[ascites]ascites21ascites 1ascites 1NA1ascites 1ascitesNA
ascitesascites_cat3_NA::bcatcattester1; tester2[ascites]ascites2NA::bmissingmissingNAelseascites 0ascitesNA
ascitesascites_cat3_NA::acatcattester1; tester2[ascites]ascites2NA::anot applicablenot applicableNA9not applicableNANA
alk.phosNAcontconttester1; tester2[alk.phos]alk.phosNANA::anot applicablenot applicableNA99999NAalk.phosNA
astNAcontconttester1; tester2[ast]astNAcopyNANANA[20,500]NAastNA
astNAcontconttester1; tester2[ast]astNANA::bmissingmissingNAelseNAastNA
astNAcontconttester1; tester2[ast]astNANA::anot applicablenot applicableNA9999NAastNA
biliNAcontconttester1; tester2[bili]biliNAcopyNANANA[0,100]NAbiliNA
biliNAcontconttester1; tester2[bili]biliNANA::bmissingmissingNAelseNAbiliNA
cholNAcontconttester1; tester2[chol]cholNAcopyNANANA[100,2000]NAcholNA
cholNAcontconttester1; tester2[chol]cholNANA::bmissingmissingNAelseNAcholNA
cholNAcontconttester1; tester2[chol]cholNANA::amissingmissingNA9999NAcholNA
copperNAcontconttester1; tester2[copper]copperNAcopyNANANA[0,1000]NAcopperNA
copperNAcontconttester1; tester2[copper]copperNANA::bmissingmissingNAelseNAcopperNA
edemaedema_cat3_1catcattester1; tester2[edema]edema30edema 0.0edema 0.0NA0edema 0.0edemaNA
edemaedema_cat3_2catcattester1; tester2[edema]edema30.5edema 0.5edema 0.5NA0.5edema 0.5edemaNA
edemaedema_cat3_3catcattester1; tester2[edema]edema31edema 1.0edema 1.0NA1edema 1.0edemaNA
edemaedema_cat3_NA::bcatcattester1; tester2[edema]edema3NA::bmissingmissingNAelsemissingedemaNA
edemaedema_cat3_NA::acatcattester1; tester2[edema]edema3NA::anot applicablenot applicableNA9not applicableedemaNA
hepatoheapto_cat3_1catcattester1; tester2[hepato]hepato20hepato 0hepato 0NA0hepato 0hepatoNA
hepatoheapto_cat3_1catcattester1; tester2[hepato]hepato21hepato 1hepato 1NA1hepato 1hepatoNA
hepatoheapto_cat3_NA::acatcattester1; tester2[hepato]hepato2NA::bmissingmissingNAelsemissinghepatoNA
copperNAcontconttester1; tester2[copper]copperNANA::amissingmissingNA9999NAcopperNA
plateletNAcontconttester1; tester2[platelet]plateletNAcopyNANANA[0,1000]NAplateletNA
plateletNAcontconttester1; tester2[platelet]plateletNANA::bmissingmissingNAelseNAplateletNA
plateletNAcontconttester1; tester2[platelet]plateletNANA::anot applicablenot applicableNA9999NAplateletNA
protimeNAcontconttester1; tester2[protime]protimeNAcopyNANANA[5, 30]NAprotimeNA
protimeNAcontconttester1; tester2[protime]protimeNANA::bmissingmissingNAelseNAprotimeNA
hepatoheapto_cat3_NA::bcatcattester1; tester2[hepato]hepato2NA::anot applicablenot applicableNA9not applicablehepatoNA
sexsex_cat2_1catcattester1; tester2[sex]sex2msex msex mNAmsex msexNA
sexsex_cat2_2catcattester1; tester2[sex]sex2fsex fsex fNAfsex fsexNA
sexsex_cat2_NA::bcatcattester1; tester2[sex]sex2NA::bmissingmissingNAelsesex msexNA
sexsex_cat2_NA::acatcattester1; tester2[sex]sex2NA::anot applicablenot applicableNA9sex msexNA
spidersspiders0catcattester1; tester2[spiders]spiders20spiders 0spiders 0NA0spiders 0spidersNA
spidersspiders1catcattester1; tester2[spiders]spiders21spiders 1spiders 1NA1spiders 1spidersNA
spidersspiders_NA::bcatcattester1; tester2[spiders]spiders2NA::bmissingmissingNAelsespiders 0spidersNA
spidersspiders_NA::acatcattester1; tester2[spiders]spiders2NA::anot applicablenot applicableNA9not applicablespidersNA
stagestage1catcattester1; tester2[stage]stage41stage 1stage 1NA1stage 1stageNA
stagestage2catcattester1; tester2[stage]stage42stage 2stage 2NA2stage 2stageNA
stagestage3catcattester1; tester2[stage]stage43stage 3stage 3NA3stage 3stageNA
stagestage4catcattester1; tester2[stage]stage44stage 4stage 4NA4stage 4stageNA
stagestage_NA::bcatcattester1; tester2[stage]stage4NA::bmissingmissingNAelsemissingstageNA
stagestage_NA::acatcattester1; tester2[stage]stage4NA::anot applicablenot applicableNA9not applicablestageNA
statusstatus0catcattester1; tester2[status]status30status 0status 0NA0status 0statusNA
statusstatus1catcattester1; tester2[status]status31status 1status 1NA1status 1statusNA
statusstatus2catcattester1; tester2[status]status32status 2status 2NA2status 2statusNA
statusstatus_NA::bcatcattester1; tester2[status]status3NA::bmissingmissingNAelsestatus 0statusNA
protimeNAcontconttester1; tester2[protime]protimeNANA::anot applicablenot applicableNA99NAprotimeNA
timeNAcontconttester1; tester2[time]timeNAcopyNANANA[0,5000]NAtimeNA
timeNAcontconttester1; tester2[time]timeNANA::bmissingmissingNAelseNAtimeNA
timeNAcontconttester1; tester2[time]timeNANA::anot applicablenot applicableNA9999NAtimeNA
trigNAcontconttester1; tester2[trig]trigNAcopyNANANA[0,1000]NAtrigNA
trigNAcontconttester1; tester2[trig]trigNANA::bmissingmissingNAelseNAtrigNA
statusstatus_NA::acatcattester1; tester2[status]status3NA::anot applicablenot applicableNA9not applicablestatusNA
trttrt1catcattester1; tester2[trt]trt21trt 1trt 1NA1trt 1trtNA
trttrt2catcattester1; tester2[trt]trt22trt 2trt 2NA2trt 2trtNA
trttrt_NA::bcatcattester1; tester2[trt]trt2NA::bmissingmissingNAelsetrt 1trtNA
trttrt_NA::acatcattester1; tester2[trt]trt2NA::anot applicablenot applicableNA9not applicabletrtNA
trigNAcontconttester1; tester2[trig]trigNANA::amissingmissingNA9999NAtrigNA
example_derNAcontconttester1; tester2DerivedVar::[chol, bili]example_derNAFunc::example_der_funN/AN/ANAelseN/Aexample_derA test derived variable
agegrp10agegrp10_cat6_1catcattester2tester2::agegrpgrouped age6120-2920-29years120-29grouped ageNA
agegrp10agegrp10_cat6_2catcattester2tester2::agegrpgrouped age6230-3930-39years230-39grouped ageNA
agegrp10agegrp10_cat6_3catcattester2tester2::agegrpgrouped age6340-4940-49years340-49grouped ageNA
agegrp10agegrp10_cat6_4catcattester2tester2::agegrpgrouped age6450-5950-59years450-59grouped ageNA
agegrp10agegrp10_cat6_5catcattester2tester2::agegrpgrouped age6560-6960-69years560-69grouped ageNA
agegrp10agegrp10_cat6_6catcattester2tester2::agegrpgrouped age6670-7970-79years670-79grouped ageNA
agegrp10agegrp10_cat6_NA::bcatcattester2tester2::agegrpgrouped age6NA::bmissingmissingyearselsemissinggrouped ageNA
agegrp5agegrp5_cat11_1catcattester1tester1::agegrpgrouped age11125-2925-29years120-29grouped ageNA
agegrp5agegrp5_cat11_2catcattester1tester1::agegrpgrouped age11230-3430-34years230-39grouped ageNA
agegrp5agegrp5_cat11_3catcattester1tester1::agegrpgrouped age11335-3935-39years330-39grouped ageNA
agegrp5agegrp5_cat11_4catcattester1tester1::agegrpgrouped age11440-4440-44years440-49grouped ageNA
agegrp5agegrp5_cat11_5catcattester1tester1::agegrpgrouped age11545-4945-49years540-49grouped ageNA
agegrp5agegrp5_cat11_6catcattester1tester1::agegrpgrouped age11650-5450-54years650-59grouped ageNA
agegrp5agegrp5_cat11_7catcattester1tester1::agegrpgrouped age11755-5955-59years750-59grouped ageNA
agegrp5agegrp5_cat11_8catcattester1tester1::agegrpgrouped age11860-6460-64years860-69grouped ageNA
agegrp5agegrp5_cat11_9catcattester1tester1::agegrpgrouped age11965-6965-69years960-69grouped ageNA
agegrp5agegrp5_cat11_10catcattester1tester1::agegrpgrouped age111070-7470-74years1070-79grouped ageNA
agegrp5agegrp5_cat11_11catcattester1tester1::agegrpgrouped age111175-7975-79years1170-79grouped ageNA
agegrp5agegrp5_cat11_NA::bcatcattester1tester1::agegrpgrouped age11Na::bmissingmissingyearselsemissinggrouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA27NANAyears120-29grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA32NANAyears230-39grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA37NANAyears330-39grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA42NANAyears440-49grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA47NANAyears540-49grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA52NANAyears650-59grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA57NANAyears750-59grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA62NANAyears860-69grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA67NANAyears960-69grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA72NANAyears1070-79grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA77NANAyears1170-79grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNANA::bNANAyearselsemissinggrouped ageNA
age_contNAcontcattester2tester2::agegrpgrouped ageNA25NANAyears120-29grouped ageNA
age_contNAcontcattester2tester2::agegrpgrouped ageNA35NANAyears230-39grouped ageNA
age_contNAcontcattester2tester2::agegrpgrouped ageNA45NANAyears340-49grouped ageNA
age_contNAcontcattester2tester2::agegrpgrouped ageNA55NANAyears450-59grouped ageNA
age_contNAcontcattester2tester2::agegrpgrouped ageNA65NANAyears560-69grouped ageNA
age_contNAcontcattester2tester2::agegrpgrouped ageNA75NANAyears670-79grouped ageNA
age_contNAcontcattester2tester2::agegrpgrouped age6NA::bNANAyearselsemissinggrouped ageNA
agegrp10agegrp10_cat6_1catcattester1tester1::agegrpgrouped age6120-2920-29years120-29grouped ageNA
agegrp10agegrp10_cat6_2catcattester1tester1::agegrpgrouped age6230-3930-39years230-39grouped ageNA
agegrp10agegrp10_cat6_2catcattester1tester1::agegrpgrouped age6230-3930-39years330-39grouped ageNA
agegrp10agegrp10_cat6_3catcattester1tester1::agegrpgrouped age6340-4940-49years440-49grouped ageNA
agegrp10agegrp10_cat6_3catcattester1tester1::agegrpgrouped age6340-4940-49years540-49grouped ageNA
agegrp10agegrp10_cat6_4catcattester1tester1::agegrpgrouped age6450-5950-59years650-59grouped ageNA
agegrp10agegrp10_cat6_4catcattester1tester1::agegrpgrouped age6450-5950-59years750-59grouped ageNA
agegrp10agegrp10_cat6_5catcattester1tester1::agegrpgrouped age6560-6960-69years860-69grouped ageNA
agegrp10agegrp10_cat6_5catcattester1tester1::agegrpgrouped age6560-6960-69years960-69grouped ageNA
agegrp10agegrp10_cat6_6catcattester1tester1::agegrpgrouped age6670-7970-79years1070-79grouped ageNA
agegrp10agegrp10_cat6_6catcattester1tester1::agegrpgrouped age6670-7970-79years1170-79grouped ageNA
agegrp10agegrp10_cat6_NA::bcatcattester1tester1::agegrpgrouped age6NA::bmissingmissingyearselsemissinggrouped ageNA
+
    +
  1. +units: indicates the unit of measure for the +variable. The histologic stage of disease does not have a units of +measurement.
  2. +
+

Write “N/A” in all six rows.

+ ++++++++++++++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
variabledummyVariabletypeEndtypeStartdatabaseStartvariableStartvariableStartLabelnumValidCatrecEndcatLabelcatLabelLongunitsrecStartcatStartLabelvariableStartShortLabelnotes
ageNAcontconttester1; tester2[age]ageNAcopyNANANA[20,80]NAageNA
ageNAcontconttester1; tester2[age]ageNANA::bmissingmissingNAelseNAageNA
ageNAcontconttester1; tester2[age]ageNANA::anot applicablenot applicableNA999NAageNA
albuminNAcontconttester1; tester2[albumin]albuminNAcopyNANANA[1,5]NAalbuminNA
albuminNAcontconttester1; tester2[albumin]albuminNANA::bmissingmissingNAelseNAalbuminNA
albuminNAcontconttester1; tester2[albumin]albuminNANA::anot applicablenot applicableNA99NAalbuminNA
alk.phosNAcontconttester1; tester2[alk.phos]alk.phosNAcopyNANANA[200,15000]NAalk.phosNA
alk.phosNAcontconttester1; tester2[alk.phos]alk.phosNANA::bmissingmissingNAelseNAalk.phosNA
ascitesascites_cat3_1catcattester1; tester2[ascites]ascites20ascites 0ascites 0NA0ascites 0ascitesNA
ascitesascites_cat3_2catcattester1; tester2[ascites]ascites21ascites 1ascites 1NA1ascites 1ascitesNA
ascitesascites_cat3_NA::bcatcattester1; tester2[ascites]ascites2NA::bmissingmissingNAelseascites 0ascitesNA
ascitesascites_cat3_NA::acatcattester1; tester2[ascites]ascites2NA::anot applicablenot applicableNA9not applicableNANA
alk.phosNAcontconttester1; tester2[alk.phos]alk.phosNANA::anot applicablenot applicableNA99999NAalk.phosNA
astNAcontconttester1; tester2[ast]astNAcopyNANANA[20,500]NAastNA
astNAcontconttester1; tester2[ast]astNANA::bmissingmissingNAelseNAastNA
astNAcontconttester1; tester2[ast]astNANA::anot applicablenot applicableNA9999NAastNA
biliNAcontconttester1; tester2[bili]biliNAcopyNANANA[0,100]NAbiliNA
biliNAcontconttester1; tester2[bili]biliNANA::bmissingmissingNAelseNAbiliNA
cholNAcontconttester1; tester2[chol]cholNAcopyNANANA[100,2000]NAcholNA
cholNAcontconttester1; tester2[chol]cholNANA::bmissingmissingNAelseNAcholNA
cholNAcontconttester1; tester2[chol]cholNANA::amissingmissingNA9999NAcholNA
copperNAcontconttester1; tester2[copper]copperNAcopyNANANA[0,1000]NAcopperNA
copperNAcontconttester1; tester2[copper]copperNANA::bmissingmissingNAelseNAcopperNA
edemaedema_cat3_1catcattester1; tester2[edema]edema30edema 0.0edema 0.0NA0edema 0.0edemaNA
edemaedema_cat3_2catcattester1; tester2[edema]edema30.5edema 0.5edema 0.5NA0.5edema 0.5edemaNA
edemaedema_cat3_3catcattester1; tester2[edema]edema31edema 1.0edema 1.0NA1edema 1.0edemaNA
edemaedema_cat3_NA::bcatcattester1; tester2[edema]edema3NA::bmissingmissingNAelsemissingedemaNA
edemaedema_cat3_NA::acatcattester1; tester2[edema]edema3NA::anot applicablenot applicableNA9not applicableedemaNA
hepatoheapto_cat3_1catcattester1; tester2[hepato]hepato20hepato 0hepato 0NA0hepato 0hepatoNA
hepatoheapto_cat3_1catcattester1; tester2[hepato]hepato21hepato 1hepato 1NA1hepato 1hepatoNA
hepatoheapto_cat3_NA::acatcattester1; tester2[hepato]hepato2NA::bmissingmissingNAelsemissinghepatoNA
copperNAcontconttester1; tester2[copper]copperNANA::amissingmissingNA9999NAcopperNA
plateletNAcontconttester1; tester2[platelet]plateletNAcopyNANANA[0,1000]NAplateletNA
plateletNAcontconttester1; tester2[platelet]plateletNANA::bmissingmissingNAelseNAplateletNA
plateletNAcontconttester1; tester2[platelet]plateletNANA::anot applicablenot applicableNA9999NAplateletNA
protimeNAcontconttester1; tester2[protime]protimeNAcopyNANANA[5, 30]NAprotimeNA
protimeNAcontconttester1; tester2[protime]protimeNANA::bmissingmissingNAelseNAprotimeNA
hepatoheapto_cat3_NA::bcatcattester1; tester2[hepato]hepato2NA::anot applicablenot applicableNA9not applicablehepatoNA
sexsex_cat2_1catcattester1; tester2[sex]sex2msex msex mNAmsex msexNA
sexsex_cat2_2catcattester1; tester2[sex]sex2fsex fsex fNAfsex fsexNA
sexsex_cat2_NA::bcatcattester1; tester2[sex]sex2NA::bmissingmissingNAelsesex msexNA
sexsex_cat2_NA::acatcattester1; tester2[sex]sex2NA::anot applicablenot applicableNA9sex msexNA
spidersspiders0catcattester1; tester2[spiders]spiders20spiders 0spiders 0NA0spiders 0spidersNA
spidersspiders1catcattester1; tester2[spiders]spiders21spiders 1spiders 1NA1spiders 1spidersNA
spidersspiders_NA::bcatcattester1; tester2[spiders]spiders2NA::bmissingmissingNAelsespiders 0spidersNA
spidersspiders_NA::acatcattester1; tester2[spiders]spiders2NA::anot applicablenot applicableNA9not applicablespidersNA
stagestage1catcattester1; tester2[stage]stage41stage 1stage 1NA1stage 1stageNA
stagestage2catcattester1; tester2[stage]stage42stage 2stage 2NA2stage 2stageNA
stagestage3catcattester1; tester2[stage]stage43stage 3stage 3NA3stage 3stageNA
stagestage4catcattester1; tester2[stage]stage44stage 4stage 4NA4stage 4stageNA
stagestage_NA::bcatcattester1; tester2[stage]stage4NA::bmissingmissingNAelsemissingstageNA
stagestage_NA::acatcattester1; tester2[stage]stage4NA::anot applicablenot applicableNA9not applicablestageNA
statusstatus0catcattester1; tester2[status]status30status 0status 0NA0status 0statusNA
statusstatus1catcattester1; tester2[status]status31status 1status 1NA1status 1statusNA
statusstatus2catcattester1; tester2[status]status32status 2status 2NA2status 2statusNA
statusstatus_NA::bcatcattester1; tester2[status]status3NA::bmissingmissingNAelsestatus 0statusNA
protimeNAcontconttester1; tester2[protime]protimeNANA::anot applicablenot applicableNA99NAprotimeNA
timeNAcontconttester1; tester2[time]timeNAcopyNANANA[0,5000]NAtimeNA
timeNAcontconttester1; tester2[time]timeNANA::bmissingmissingNAelseNAtimeNA
timeNAcontconttester1; tester2[time]timeNANA::anot applicablenot applicableNA9999NAtimeNA
trigNAcontconttester1; tester2[trig]trigNAcopyNANANA[0,1000]NAtrigNA
trigNAcontconttester1; tester2[trig]trigNANA::bmissingmissingNAelseNAtrigNA
statusstatus_NA::acatcattester1; tester2[status]status3NA::anot applicablenot applicableNA9not applicablestatusNA
trttrt1catcattester1; tester2[trt]trt21trt 1trt 1NA1trt 1trtNA
trttrt2catcattester1; tester2[trt]trt22trt 2trt 2NA2trt 2trtNA
trttrt_NA::bcatcattester1; tester2[trt]trt2NA::bmissingmissingNAelsetrt 1trtNA
trttrt_NA::acatcattester1; tester2[trt]trt2NA::anot applicablenot applicableNA9not applicabletrtNA
trigNAcontconttester1; tester2[trig]trigNANA::amissingmissingNA9999NAtrigNA
example_derNAcontconttester1; tester2DerivedVar::[chol, bili]example_derNAFunc::example_der_funN/AN/ANAelseN/Aexample_derA test derived variable
agegrp10agegrp10_cat6_1catcattester2tester2::agegrpgrouped age6120-2920-29years120-29grouped ageNA
agegrp10agegrp10_cat6_2catcattester2tester2::agegrpgrouped age6230-3930-39years230-39grouped ageNA
agegrp10agegrp10_cat6_3catcattester2tester2::agegrpgrouped age6340-4940-49years340-49grouped ageNA
agegrp10agegrp10_cat6_4catcattester2tester2::agegrpgrouped age6450-5950-59years450-59grouped ageNA
agegrp10agegrp10_cat6_5catcattester2tester2::agegrpgrouped age6560-6960-69years560-69grouped ageNA
agegrp10agegrp10_cat6_6catcattester2tester2::agegrpgrouped age6670-7970-79years670-79grouped ageNA
agegrp10agegrp10_cat6_NA::bcatcattester2tester2::agegrpgrouped age6NA::bmissingmissingyearselsemissinggrouped ageNA
agegrp5agegrp5_cat11_1catcattester1tester1::agegrpgrouped age11125-2925-29years120-29grouped ageNA
agegrp5agegrp5_cat11_2catcattester1tester1::agegrpgrouped age11230-3430-34years230-39grouped ageNA
agegrp5agegrp5_cat11_3catcattester1tester1::agegrpgrouped age11335-3935-39years330-39grouped ageNA
agegrp5agegrp5_cat11_4catcattester1tester1::agegrpgrouped age11440-4440-44years440-49grouped ageNA
agegrp5agegrp5_cat11_5catcattester1tester1::agegrpgrouped age11545-4945-49years540-49grouped ageNA
agegrp5agegrp5_cat11_6catcattester1tester1::agegrpgrouped age11650-5450-54years650-59grouped ageNA
agegrp5agegrp5_cat11_7catcattester1tester1::agegrpgrouped age11755-5955-59years750-59grouped ageNA
agegrp5agegrp5_cat11_8catcattester1tester1::agegrpgrouped age11860-6460-64years860-69grouped ageNA
agegrp5agegrp5_cat11_9catcattester1tester1::agegrpgrouped age11965-6965-69years960-69grouped ageNA
agegrp5agegrp5_cat11_10catcattester1tester1::agegrpgrouped age111070-7470-74years1070-79grouped ageNA
agegrp5agegrp5_cat11_11catcattester1tester1::agegrpgrouped age111175-7975-79years1170-79grouped ageNA
agegrp5agegrp5_cat11_NA::bcatcattester1tester1::agegrpgrouped age11Na::bmissingmissingyearselsemissinggrouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA27NANAyears120-29grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA32NANAyears230-39grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA37NANAyears330-39grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA42NANAyears440-49grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA47NANAyears540-49grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA52NANAyears650-59grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA57NANAyears750-59grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA62NANAyears860-69grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA67NANAyears960-69grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA72NANAyears1070-79grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA77NANAyears1170-79grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNANA::bNANAyearselsemissinggrouped ageNA
age_contNAcontcattester2tester2::agegrpgrouped ageNA25NANAyears120-29grouped ageNA
age_contNAcontcattester2tester2::agegrpgrouped ageNA35NANAyears230-39grouped ageNA
age_contNAcontcattester2tester2::agegrpgrouped ageNA45NANAyears340-49grouped ageNA
age_contNAcontcattester2tester2::agegrpgrouped ageNA55NANAyears450-59grouped ageNA
age_contNAcontcattester2tester2::agegrpgrouped ageNA65NANAyears560-69grouped ageNA
age_contNAcontcattester2tester2::agegrpgrouped ageNA75NANAyears670-79grouped ageNA
age_contNAcontcattester2tester2::agegrpgrouped age6NA::bNANAyearselsemissinggrouped ageNA
agegrp10agegrp10_cat6_1catcattester1tester1::agegrpgrouped age6120-2920-29years120-29grouped ageNA
agegrp10agegrp10_cat6_2catcattester1tester1::agegrpgrouped age6230-3930-39years230-39grouped ageNA
agegrp10agegrp10_cat6_2catcattester1tester1::agegrpgrouped age6230-3930-39years330-39grouped ageNA
agegrp10agegrp10_cat6_3catcattester1tester1::agegrpgrouped age6340-4940-49years440-49grouped ageNA
agegrp10agegrp10_cat6_3catcattester1tester1::agegrpgrouped age6340-4940-49years540-49grouped ageNA
agegrp10agegrp10_cat6_4catcattester1tester1::agegrpgrouped age6450-5950-59years650-59grouped ageNA
agegrp10agegrp10_cat6_4catcattester1tester1::agegrpgrouped age6450-5950-59years750-59grouped ageNA
agegrp10agegrp10_cat6_5catcattester1tester1::agegrpgrouped age6560-6960-69years860-69grouped ageNA
agegrp10agegrp10_cat6_5catcattester1tester1::agegrpgrouped age6560-6960-69years960-69grouped ageNA
agegrp10agegrp10_cat6_6catcattester1tester1::agegrpgrouped age6670-7970-79years1070-79grouped ageNA
agegrp10agegrp10_cat6_6catcattester1tester1::agegrpgrouped age6670-7970-79years1170-79grouped ageNA
agegrp10agegrp10_cat6_NA::bcatcattester1tester1::agegrpgrouped age6NA::bmissingmissingyearselsemissinggrouped ageNA
+
    +
  1. +recStart: indicates the category(ies) from which +you are recoding each row. Since we are not combining levels of +categories and we are keeping the category levels the same, the recStart +column will be identical to recEnd. If multiple categories were being +combined into a single category, the original categories would be +indicated in square brackets, separated by commas.
  2. +
+

Write the category level you are recoding each row too. For the not +applicable rows NA::a is written. For the missing and else +rows NA::b is written.

+ ++++++++++++++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
variabledummyVariabletypeEndtypeStartdatabaseStartvariableStartvariableStartLabelnumValidCatrecEndcatLabelcatLabelLongunitsrecStartcatStartLabelvariableStartShortLabelnotes
ageNAcontconttester1; tester2[age]ageNAcopyNANANA[20,80]NAageNA
ageNAcontconttester1; tester2[age]ageNANA::bmissingmissingNAelseNAageNA
ageNAcontconttester1; tester2[age]ageNANA::anot applicablenot applicableNA999NAageNA
albuminNAcontconttester1; tester2[albumin]albuminNAcopyNANANA[1,5]NAalbuminNA
albuminNAcontconttester1; tester2[albumin]albuminNANA::bmissingmissingNAelseNAalbuminNA
albuminNAcontconttester1; tester2[albumin]albuminNANA::anot applicablenot applicableNA99NAalbuminNA
alk.phosNAcontconttester1; tester2[alk.phos]alk.phosNAcopyNANANA[200,15000]NAalk.phosNA
alk.phosNAcontconttester1; tester2[alk.phos]alk.phosNANA::bmissingmissingNAelseNAalk.phosNA
ascitesascites_cat3_1catcattester1; tester2[ascites]ascites20ascites 0ascites 0NA0ascites 0ascitesNA
ascitesascites_cat3_2catcattester1; tester2[ascites]ascites21ascites 1ascites 1NA1ascites 1ascitesNA
ascitesascites_cat3_NA::bcatcattester1; tester2[ascites]ascites2NA::bmissingmissingNAelseascites 0ascitesNA
ascitesascites_cat3_NA::acatcattester1; tester2[ascites]ascites2NA::anot applicablenot applicableNA9not applicableNANA
alk.phosNAcontconttester1; tester2[alk.phos]alk.phosNANA::anot applicablenot applicableNA99999NAalk.phosNA
astNAcontconttester1; tester2[ast]astNAcopyNANANA[20,500]NAastNA
astNAcontconttester1; tester2[ast]astNANA::bmissingmissingNAelseNAastNA
astNAcontconttester1; tester2[ast]astNANA::anot applicablenot applicableNA9999NAastNA
biliNAcontconttester1; tester2[bili]biliNAcopyNANANA[0,100]NAbiliNA
biliNAcontconttester1; tester2[bili]biliNANA::bmissingmissingNAelseNAbiliNA
cholNAcontconttester1; tester2[chol]cholNAcopyNANANA[100,2000]NAcholNA
cholNAcontconttester1; tester2[chol]cholNANA::bmissingmissingNAelseNAcholNA
cholNAcontconttester1; tester2[chol]cholNANA::amissingmissingNA9999NAcholNA
copperNAcontconttester1; tester2[copper]copperNAcopyNANANA[0,1000]NAcopperNA
copperNAcontconttester1; tester2[copper]copperNANA::bmissingmissingNAelseNAcopperNA
edemaedema_cat3_1catcattester1; tester2[edema]edema30edema 0.0edema 0.0NA0edema 0.0edemaNA
edemaedema_cat3_2catcattester1; tester2[edema]edema30.5edema 0.5edema 0.5NA0.5edema 0.5edemaNA
edemaedema_cat3_3catcattester1; tester2[edema]edema31edema 1.0edema 1.0NA1edema 1.0edemaNA
edemaedema_cat3_NA::bcatcattester1; tester2[edema]edema3NA::bmissingmissingNAelsemissingedemaNA
edemaedema_cat3_NA::acatcattester1; tester2[edema]edema3NA::anot applicablenot applicableNA9not applicableedemaNA
hepatoheapto_cat3_1catcattester1; tester2[hepato]hepato20hepato 0hepato 0NA0hepato 0hepatoNA
hepatoheapto_cat3_1catcattester1; tester2[hepato]hepato21hepato 1hepato 1NA1hepato 1hepatoNA
hepatoheapto_cat3_NA::acatcattester1; tester2[hepato]hepato2NA::bmissingmissingNAelsemissinghepatoNA
copperNAcontconttester1; tester2[copper]copperNANA::amissingmissingNA9999NAcopperNA
plateletNAcontconttester1; tester2[platelet]plateletNAcopyNANANA[0,1000]NAplateletNA
plateletNAcontconttester1; tester2[platelet]plateletNANA::bmissingmissingNAelseNAplateletNA
plateletNAcontconttester1; tester2[platelet]plateletNANA::anot applicablenot applicableNA9999NAplateletNA
protimeNAcontconttester1; tester2[protime]protimeNAcopyNANANA[5, 30]NAprotimeNA
protimeNAcontconttester1; tester2[protime]protimeNANA::bmissingmissingNAelseNAprotimeNA
hepatoheapto_cat3_NA::bcatcattester1; tester2[hepato]hepato2NA::anot applicablenot applicableNA9not applicablehepatoNA
sexsex_cat2_1catcattester1; tester2[sex]sex2msex msex mNAmsex msexNA
sexsex_cat2_2catcattester1; tester2[sex]sex2fsex fsex fNAfsex fsexNA
sexsex_cat2_NA::bcatcattester1; tester2[sex]sex2NA::bmissingmissingNAelsesex msexNA
sexsex_cat2_NA::acatcattester1; tester2[sex]sex2NA::anot applicablenot applicableNA9sex msexNA
spidersspiders0catcattester1; tester2[spiders]spiders20spiders 0spiders 0NA0spiders 0spidersNA
spidersspiders1catcattester1; tester2[spiders]spiders21spiders 1spiders 1NA1spiders 1spidersNA
spidersspiders_NA::bcatcattester1; tester2[spiders]spiders2NA::bmissingmissingNAelsespiders 0spidersNA
spidersspiders_NA::acatcattester1; tester2[spiders]spiders2NA::anot applicablenot applicableNA9not applicablespidersNA
stagestage1catcattester1; tester2[stage]stage41stage 1stage 1NA1stage 1stageNA
stagestage2catcattester1; tester2[stage]stage42stage 2stage 2NA2stage 2stageNA
stagestage3catcattester1; tester2[stage]stage43stage 3stage 3NA3stage 3stageNA
stagestage4catcattester1; tester2[stage]stage44stage 4stage 4NA4stage 4stageNA
stagestage_NA::bcatcattester1; tester2[stage]stage4NA::bmissingmissingNAelsemissingstageNA
stagestage_NA::acatcattester1; tester2[stage]stage4NA::anot applicablenot applicableNA9not applicablestageNA
statusstatus0catcattester1; tester2[status]status30status 0status 0NA0status 0statusNA
statusstatus1catcattester1; tester2[status]status31status 1status 1NA1status 1statusNA
statusstatus2catcattester1; tester2[status]status32status 2status 2NA2status 2statusNA
statusstatus_NA::bcatcattester1; tester2[status]status3NA::bmissingmissingNAelsestatus 0statusNA
protimeNAcontconttester1; tester2[protime]protimeNANA::anot applicablenot applicableNA99NAprotimeNA
timeNAcontconttester1; tester2[time]timeNAcopyNANANA[0,5000]NAtimeNA
timeNAcontconttester1; tester2[time]timeNANA::bmissingmissingNAelseNAtimeNA
timeNAcontconttester1; tester2[time]timeNANA::anot applicablenot applicableNA9999NAtimeNA
trigNAcontconttester1; tester2[trig]trigNAcopyNANANA[0,1000]NAtrigNA
trigNAcontconttester1; tester2[trig]trigNANA::bmissingmissingNAelseNAtrigNA
statusstatus_NA::acatcattester1; tester2[status]status3NA::anot applicablenot applicableNA9not applicablestatusNA
trttrt1catcattester1; tester2[trt]trt21trt 1trt 1NA1trt 1trtNA
trttrt2catcattester1; tester2[trt]trt22trt 2trt 2NA2trt 2trtNA
trttrt_NA::bcatcattester1; tester2[trt]trt2NA::bmissingmissingNAelsetrt 1trtNA
trttrt_NA::acatcattester1; tester2[trt]trt2NA::anot applicablenot applicableNA9not applicabletrtNA
trigNAcontconttester1; tester2[trig]trigNANA::amissingmissingNA9999NAtrigNA
example_derNAcontconttester1; tester2DerivedVar::[chol, bili]example_derNAFunc::example_der_funN/AN/ANAelseN/Aexample_derA test derived variable
agegrp10agegrp10_cat6_1catcattester2tester2::agegrpgrouped age6120-2920-29years120-29grouped ageNA
agegrp10agegrp10_cat6_2catcattester2tester2::agegrpgrouped age6230-3930-39years230-39grouped ageNA
agegrp10agegrp10_cat6_3catcattester2tester2::agegrpgrouped age6340-4940-49years340-49grouped ageNA
agegrp10agegrp10_cat6_4catcattester2tester2::agegrpgrouped age6450-5950-59years450-59grouped ageNA
agegrp10agegrp10_cat6_5catcattester2tester2::agegrpgrouped age6560-6960-69years560-69grouped ageNA
agegrp10agegrp10_cat6_6catcattester2tester2::agegrpgrouped age6670-7970-79years670-79grouped ageNA
agegrp10agegrp10_cat6_NA::bcatcattester2tester2::agegrpgrouped age6NA::bmissingmissingyearselsemissinggrouped ageNA
agegrp5agegrp5_cat11_1catcattester1tester1::agegrpgrouped age11125-2925-29years120-29grouped ageNA
agegrp5agegrp5_cat11_2catcattester1tester1::agegrpgrouped age11230-3430-34years230-39grouped ageNA
agegrp5agegrp5_cat11_3catcattester1tester1::agegrpgrouped age11335-3935-39years330-39grouped ageNA
agegrp5agegrp5_cat11_4catcattester1tester1::agegrpgrouped age11440-4440-44years440-49grouped ageNA
agegrp5agegrp5_cat11_5catcattester1tester1::agegrpgrouped age11545-4945-49years540-49grouped ageNA
agegrp5agegrp5_cat11_6catcattester1tester1::agegrpgrouped age11650-5450-54years650-59grouped ageNA
agegrp5agegrp5_cat11_7catcattester1tester1::agegrpgrouped age11755-5955-59years750-59grouped ageNA
agegrp5agegrp5_cat11_8catcattester1tester1::agegrpgrouped age11860-6460-64years860-69grouped ageNA
agegrp5agegrp5_cat11_9catcattester1tester1::agegrpgrouped age11965-6965-69years960-69grouped ageNA
agegrp5agegrp5_cat11_10catcattester1tester1::agegrpgrouped age111070-7470-74years1070-79grouped ageNA
agegrp5agegrp5_cat11_11catcattester1tester1::agegrpgrouped age111175-7975-79years1170-79grouped ageNA
agegrp5agegrp5_cat11_NA::bcatcattester1tester1::agegrpgrouped age11Na::bmissingmissingyearselsemissinggrouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA27NANAyears120-29grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA32NANAyears230-39grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA37NANAyears330-39grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA42NANAyears440-49grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA47NANAyears540-49grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA52NANAyears650-59grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA57NANAyears750-59grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA62NANAyears860-69grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA67NANAyears960-69grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA72NANAyears1070-79grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA77NANAyears1170-79grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNANA::bNANAyearselsemissinggrouped ageNA
age_contNAcontcattester2tester2::agegrpgrouped ageNA25NANAyears120-29grouped ageNA
age_contNAcontcattester2tester2::agegrpgrouped ageNA35NANAyears230-39grouped ageNA
age_contNAcontcattester2tester2::agegrpgrouped ageNA45NANAyears340-49grouped ageNA
age_contNAcontcattester2tester2::agegrpgrouped ageNA55NANAyears450-59grouped ageNA
age_contNAcontcattester2tester2::agegrpgrouped ageNA65NANAyears560-69grouped ageNA
age_contNAcontcattester2tester2::agegrpgrouped ageNA75NANAyears670-79grouped ageNA
age_contNAcontcattester2tester2::agegrpgrouped age6NA::bNANAyearselsemissinggrouped ageNA
agegrp10agegrp10_cat6_1catcattester1tester1::agegrpgrouped age6120-2920-29years120-29grouped ageNA
agegrp10agegrp10_cat6_2catcattester1tester1::agegrpgrouped age6230-3930-39years230-39grouped ageNA
agegrp10agegrp10_cat6_2catcattester1tester1::agegrpgrouped age6230-3930-39years330-39grouped ageNA
agegrp10agegrp10_cat6_3catcattester1tester1::agegrpgrouped age6340-4940-49years440-49grouped ageNA
agegrp10agegrp10_cat6_3catcattester1tester1::agegrpgrouped age6340-4940-49years540-49grouped ageNA
agegrp10agegrp10_cat6_4catcattester1tester1::agegrpgrouped age6450-5950-59years650-59grouped ageNA
agegrp10agegrp10_cat6_4catcattester1tester1::agegrpgrouped age6450-5950-59years750-59grouped ageNA
agegrp10agegrp10_cat6_5catcattester1tester1::agegrpgrouped age6560-6960-69years860-69grouped ageNA
agegrp10agegrp10_cat6_5catcattester1tester1::agegrpgrouped age6560-6960-69years960-69grouped ageNA
agegrp10agegrp10_cat6_6catcattester1tester1::agegrpgrouped age6670-7970-79years1070-79grouped ageNA
agegrp10agegrp10_cat6_6catcattester1tester1::agegrpgrouped age6670-7970-79years1170-79grouped ageNA
agegrp10agegrp10_cat6_NA::bcatcattester1tester1::agegrpgrouped age6NA::bmissingmissingyearselsemissinggrouped ageNA
+
    +
  1. +catStartLabel: indicates the original variable +category label. The stage label should be identical to what +is shown in the original data documentation. For the missing rows, each +missing category is described along with their coded values.
  2. +
+

Write Stage 1, Stage 2, Stage 3, Stage 4, NA, and missing.

+ ++++++++++++++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
variabledummyVariabletypeEndtypeStartdatabaseStartvariableStartvariableStartLabelnumValidCatrecEndcatLabelcatLabelLongunitsrecStartcatStartLabelvariableStartShortLabelnotes
ageNAcontconttester1; tester2[age]ageNAcopyNANANA[20,80]NAageNA
ageNAcontconttester1; tester2[age]ageNANA::bmissingmissingNAelseNAageNA
ageNAcontconttester1; tester2[age]ageNANA::anot applicablenot applicableNA999NAageNA
albuminNAcontconttester1; tester2[albumin]albuminNAcopyNANANA[1,5]NAalbuminNA
albuminNAcontconttester1; tester2[albumin]albuminNANA::bmissingmissingNAelseNAalbuminNA
albuminNAcontconttester1; tester2[albumin]albuminNANA::anot applicablenot applicableNA99NAalbuminNA
alk.phosNAcontconttester1; tester2[alk.phos]alk.phosNAcopyNANANA[200,15000]NAalk.phosNA
alk.phosNAcontconttester1; tester2[alk.phos]alk.phosNANA::bmissingmissingNAelseNAalk.phosNA
ascitesascites_cat3_1catcattester1; tester2[ascites]ascites20ascites 0ascites 0NA0ascites 0ascitesNA
ascitesascites_cat3_2catcattester1; tester2[ascites]ascites21ascites 1ascites 1NA1ascites 1ascitesNA
ascitesascites_cat3_NA::bcatcattester1; tester2[ascites]ascites2NA::bmissingmissingNAelseascites 0ascitesNA
ascitesascites_cat3_NA::acatcattester1; tester2[ascites]ascites2NA::anot applicablenot applicableNA9not applicableNANA
alk.phosNAcontconttester1; tester2[alk.phos]alk.phosNANA::anot applicablenot applicableNA99999NAalk.phosNA
astNAcontconttester1; tester2[ast]astNAcopyNANANA[20,500]NAastNA
astNAcontconttester1; tester2[ast]astNANA::bmissingmissingNAelseNAastNA
astNAcontconttester1; tester2[ast]astNANA::anot applicablenot applicableNA9999NAastNA
biliNAcontconttester1; tester2[bili]biliNAcopyNANANA[0,100]NAbiliNA
biliNAcontconttester1; tester2[bili]biliNANA::bmissingmissingNAelseNAbiliNA
cholNAcontconttester1; tester2[chol]cholNAcopyNANANA[100,2000]NAcholNA
cholNAcontconttester1; tester2[chol]cholNANA::bmissingmissingNAelseNAcholNA
cholNAcontconttester1; tester2[chol]cholNANA::amissingmissingNA9999NAcholNA
copperNAcontconttester1; tester2[copper]copperNAcopyNANANA[0,1000]NAcopperNA
copperNAcontconttester1; tester2[copper]copperNANA::bmissingmissingNAelseNAcopperNA
edemaedema_cat3_1catcattester1; tester2[edema]edema30edema 0.0edema 0.0NA0edema 0.0edemaNA
edemaedema_cat3_2catcattester1; tester2[edema]edema30.5edema 0.5edema 0.5NA0.5edema 0.5edemaNA
edemaedema_cat3_3catcattester1; tester2[edema]edema31edema 1.0edema 1.0NA1edema 1.0edemaNA
edemaedema_cat3_NA::bcatcattester1; tester2[edema]edema3NA::bmissingmissingNAelsemissingedemaNA
edemaedema_cat3_NA::acatcattester1; tester2[edema]edema3NA::anot applicablenot applicableNA9not applicableedemaNA
hepatoheapto_cat3_1catcattester1; tester2[hepato]hepato20hepato 0hepato 0NA0hepato 0hepatoNA
hepatoheapto_cat3_1catcattester1; tester2[hepato]hepato21hepato 1hepato 1NA1hepato 1hepatoNA
hepatoheapto_cat3_NA::acatcattester1; tester2[hepato]hepato2NA::bmissingmissingNAelsemissinghepatoNA
copperNAcontconttester1; tester2[copper]copperNANA::amissingmissingNA9999NAcopperNA
plateletNAcontconttester1; tester2[platelet]plateletNAcopyNANANA[0,1000]NAplateletNA
plateletNAcontconttester1; tester2[platelet]plateletNANA::bmissingmissingNAelseNAplateletNA
plateletNAcontconttester1; tester2[platelet]plateletNANA::anot applicablenot applicableNA9999NAplateletNA
protimeNAcontconttester1; tester2[protime]protimeNAcopyNANANA[5, 30]NAprotimeNA
protimeNAcontconttester1; tester2[protime]protimeNANA::bmissingmissingNAelseNAprotimeNA
hepatoheapto_cat3_NA::bcatcattester1; tester2[hepato]hepato2NA::anot applicablenot applicableNA9not applicablehepatoNA
sexsex_cat2_1catcattester1; tester2[sex]sex2msex msex mNAmsex msexNA
sexsex_cat2_2catcattester1; tester2[sex]sex2fsex fsex fNAfsex fsexNA
sexsex_cat2_NA::bcatcattester1; tester2[sex]sex2NA::bmissingmissingNAelsesex msexNA
sexsex_cat2_NA::acatcattester1; tester2[sex]sex2NA::anot applicablenot applicableNA9sex msexNA
spidersspiders0catcattester1; tester2[spiders]spiders20spiders 0spiders 0NA0spiders 0spidersNA
spidersspiders1catcattester1; tester2[spiders]spiders21spiders 1spiders 1NA1spiders 1spidersNA
spidersspiders_NA::bcatcattester1; tester2[spiders]spiders2NA::bmissingmissingNAelsespiders 0spidersNA
spidersspiders_NA::acatcattester1; tester2[spiders]spiders2NA::anot applicablenot applicableNA9not applicablespidersNA
stagestage1catcattester1; tester2[stage]stage41stage 1stage 1NA1stage 1stageNA
stagestage2catcattester1; tester2[stage]stage42stage 2stage 2NA2stage 2stageNA
stagestage3catcattester1; tester2[stage]stage43stage 3stage 3NA3stage 3stageNA
stagestage4catcattester1; tester2[stage]stage44stage 4stage 4NA4stage 4stageNA
stagestage_NA::bcatcattester1; tester2[stage]stage4NA::bmissingmissingNAelsemissingstageNA
stagestage_NA::acatcattester1; tester2[stage]stage4NA::anot applicablenot applicableNA9not applicablestageNA
statusstatus0catcattester1; tester2[status]status30status 0status 0NA0status 0statusNA
statusstatus1catcattester1; tester2[status]status31status 1status 1NA1status 1statusNA
statusstatus2catcattester1; tester2[status]status32status 2status 2NA2status 2statusNA
statusstatus_NA::bcatcattester1; tester2[status]status3NA::bmissingmissingNAelsestatus 0statusNA
protimeNAcontconttester1; tester2[protime]protimeNANA::anot applicablenot applicableNA99NAprotimeNA
timeNAcontconttester1; tester2[time]timeNAcopyNANANA[0,5000]NAtimeNA
timeNAcontconttester1; tester2[time]timeNANA::bmissingmissingNAelseNAtimeNA
timeNAcontconttester1; tester2[time]timeNANA::anot applicablenot applicableNA9999NAtimeNA
trigNAcontconttester1; tester2[trig]trigNAcopyNANANA[0,1000]NAtrigNA
trigNAcontconttester1; tester2[trig]trigNANA::bmissingmissingNAelseNAtrigNA
statusstatus_NA::acatcattester1; tester2[status]status3NA::anot applicablenot applicableNA9not applicablestatusNA
trttrt1catcattester1; tester2[trt]trt21trt 1trt 1NA1trt 1trtNA
trttrt2catcattester1; tester2[trt]trt22trt 2trt 2NA2trt 2trtNA
trttrt_NA::bcatcattester1; tester2[trt]trt2NA::bmissingmissingNAelsetrt 1trtNA
trttrt_NA::acatcattester1; tester2[trt]trt2NA::anot applicablenot applicableNA9not applicabletrtNA
trigNAcontconttester1; tester2[trig]trigNANA::amissingmissingNA9999NAtrigNA
example_derNAcontconttester1; tester2DerivedVar::[chol, bili]example_derNAFunc::example_der_funN/AN/ANAelseN/Aexample_derA test derived variable
agegrp10agegrp10_cat6_1catcattester2tester2::agegrpgrouped age6120-2920-29years120-29grouped ageNA
agegrp10agegrp10_cat6_2catcattester2tester2::agegrpgrouped age6230-3930-39years230-39grouped ageNA
agegrp10agegrp10_cat6_3catcattester2tester2::agegrpgrouped age6340-4940-49years340-49grouped ageNA
agegrp10agegrp10_cat6_4catcattester2tester2::agegrpgrouped age6450-5950-59years450-59grouped ageNA
agegrp10agegrp10_cat6_5catcattester2tester2::agegrpgrouped age6560-6960-69years560-69grouped ageNA
agegrp10agegrp10_cat6_6catcattester2tester2::agegrpgrouped age6670-7970-79years670-79grouped ageNA
agegrp10agegrp10_cat6_NA::bcatcattester2tester2::agegrpgrouped age6NA::bmissingmissingyearselsemissinggrouped ageNA
agegrp5agegrp5_cat11_1catcattester1tester1::agegrpgrouped age11125-2925-29years120-29grouped ageNA
agegrp5agegrp5_cat11_2catcattester1tester1::agegrpgrouped age11230-3430-34years230-39grouped ageNA
agegrp5agegrp5_cat11_3catcattester1tester1::agegrpgrouped age11335-3935-39years330-39grouped ageNA
agegrp5agegrp5_cat11_4catcattester1tester1::agegrpgrouped age11440-4440-44years440-49grouped ageNA
agegrp5agegrp5_cat11_5catcattester1tester1::agegrpgrouped age11545-4945-49years540-49grouped ageNA
agegrp5agegrp5_cat11_6catcattester1tester1::agegrpgrouped age11650-5450-54years650-59grouped ageNA
agegrp5agegrp5_cat11_7catcattester1tester1::agegrpgrouped age11755-5955-59years750-59grouped ageNA
agegrp5agegrp5_cat11_8catcattester1tester1::agegrpgrouped age11860-6460-64years860-69grouped ageNA
agegrp5agegrp5_cat11_9catcattester1tester1::agegrpgrouped age11965-6965-69years960-69grouped ageNA
agegrp5agegrp5_cat11_10catcattester1tester1::agegrpgrouped age111070-7470-74years1070-79grouped ageNA
agegrp5agegrp5_cat11_11catcattester1tester1::agegrpgrouped age111175-7975-79years1170-79grouped ageNA
agegrp5agegrp5_cat11_NA::bcatcattester1tester1::agegrpgrouped age11Na::bmissingmissingyearselsemissinggrouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA27NANAyears120-29grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA32NANAyears230-39grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA37NANAyears330-39grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA42NANAyears440-49grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA47NANAyears540-49grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA52NANAyears650-59grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA57NANAyears750-59grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA62NANAyears860-69grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA67NANAyears960-69grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA72NANAyears1070-79grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA77NANAyears1170-79grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNANA::bNANAyearselsemissinggrouped ageNA
age_contNAcontcattester2tester2::agegrpgrouped ageNA25NANAyears120-29grouped ageNA
age_contNAcontcattester2tester2::agegrpgrouped ageNA35NANAyears230-39grouped ageNA
age_contNAcontcattester2tester2::agegrpgrouped ageNA45NANAyears340-49grouped ageNA
age_contNAcontcattester2tester2::agegrpgrouped ageNA55NANAyears450-59grouped ageNA
age_contNAcontcattester2tester2::agegrpgrouped ageNA65NANAyears560-69grouped ageNA
age_contNAcontcattester2tester2::agegrpgrouped ageNA75NANAyears670-79grouped ageNA
age_contNAcontcattester2tester2::agegrpgrouped age6NA::bNANAyearselsemissinggrouped ageNA
agegrp10agegrp10_cat6_1catcattester1tester1::agegrpgrouped age6120-2920-29years120-29grouped ageNA
agegrp10agegrp10_cat6_2catcattester1tester1::agegrpgrouped age6230-3930-39years230-39grouped ageNA
agegrp10agegrp10_cat6_2catcattester1tester1::agegrpgrouped age6230-3930-39years330-39grouped ageNA
agegrp10agegrp10_cat6_3catcattester1tester1::agegrpgrouped age6340-4940-49years440-49grouped ageNA
agegrp10agegrp10_cat6_3catcattester1tester1::agegrpgrouped age6340-4940-49years540-49grouped ageNA
agegrp10agegrp10_cat6_4catcattester1tester1::agegrpgrouped age6450-5950-59years650-59grouped ageNA
agegrp10agegrp10_cat6_4catcattester1tester1::agegrpgrouped age6450-5950-59years750-59grouped ageNA
agegrp10agegrp10_cat6_5catcattester1tester1::agegrpgrouped age6560-6960-69years860-69grouped ageNA
agegrp10agegrp10_cat6_5catcattester1tester1::agegrpgrouped age6560-6960-69years960-69grouped ageNA
agegrp10agegrp10_cat6_6catcattester1tester1::agegrpgrouped age6670-7970-79years1070-79grouped ageNA
agegrp10agegrp10_cat6_6catcattester1tester1::agegrpgrouped age6670-7970-79years1170-79grouped ageNA
agegrp10agegrp10_cat6_NA::bcatcattester1tester1::agegrpgrouped age6NA::bmissingmissingyearselsemissinggrouped ageNA
+
    +
  1. +notes: Capture any important differences in a +variable across datasets. For our example, there are no differences +across datasets.
  2. +
+

Write “This is sample survival pbc data” in all six rows.

+ ++++++++++++++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
variabledummyVariabletypeEndtypeStartdatabaseStartvariableStartvariableStartLabelnumValidCatrecEndcatLabelcatLabelLongunitsrecStartcatStartLabelvariableStartShortLabelnotes
ageNAcontconttester1; tester2[age]ageNAcopyNANANA[20,80]NAageNA
ageNAcontconttester1; tester2[age]ageNANA::bmissingmissingNAelseNAageNA
ageNAcontconttester1; tester2[age]ageNANA::anot applicablenot applicableNA999NAageNA
albuminNAcontconttester1; tester2[albumin]albuminNAcopyNANANA[1,5]NAalbuminNA
albuminNAcontconttester1; tester2[albumin]albuminNANA::bmissingmissingNAelseNAalbuminNA
albuminNAcontconttester1; tester2[albumin]albuminNANA::anot applicablenot applicableNA99NAalbuminNA
alk.phosNAcontconttester1; tester2[alk.phos]alk.phosNAcopyNANANA[200,15000]NAalk.phosNA
alk.phosNAcontconttester1; tester2[alk.phos]alk.phosNANA::bmissingmissingNAelseNAalk.phosNA
ascitesascites_cat3_1catcattester1; tester2[ascites]ascites20ascites 0ascites 0NA0ascites 0ascitesNA
ascitesascites_cat3_2catcattester1; tester2[ascites]ascites21ascites 1ascites 1NA1ascites 1ascitesNA
ascitesascites_cat3_NA::bcatcattester1; tester2[ascites]ascites2NA::bmissingmissingNAelseascites 0ascitesNA
ascitesascites_cat3_NA::acatcattester1; tester2[ascites]ascites2NA::anot applicablenot applicableNA9not applicableNANA
alk.phosNAcontconttester1; tester2[alk.phos]alk.phosNANA::anot applicablenot applicableNA99999NAalk.phosNA
astNAcontconttester1; tester2[ast]astNAcopyNANANA[20,500]NAastNA
astNAcontconttester1; tester2[ast]astNANA::bmissingmissingNAelseNAastNA
astNAcontconttester1; tester2[ast]astNANA::anot applicablenot applicableNA9999NAastNA
biliNAcontconttester1; tester2[bili]biliNAcopyNANANA[0,100]NAbiliNA
biliNAcontconttester1; tester2[bili]biliNANA::bmissingmissingNAelseNAbiliNA
cholNAcontconttester1; tester2[chol]cholNAcopyNANANA[100,2000]NAcholNA
cholNAcontconttester1; tester2[chol]cholNANA::bmissingmissingNAelseNAcholNA
cholNAcontconttester1; tester2[chol]cholNANA::amissingmissingNA9999NAcholNA
copperNAcontconttester1; tester2[copper]copperNAcopyNANANA[0,1000]NAcopperNA
copperNAcontconttester1; tester2[copper]copperNANA::bmissingmissingNAelseNAcopperNA
edemaedema_cat3_1catcattester1; tester2[edema]edema30edema 0.0edema 0.0NA0edema 0.0edemaNA
edemaedema_cat3_2catcattester1; tester2[edema]edema30.5edema 0.5edema 0.5NA0.5edema 0.5edemaNA
edemaedema_cat3_3catcattester1; tester2[edema]edema31edema 1.0edema 1.0NA1edema 1.0edemaNA
edemaedema_cat3_NA::bcatcattester1; tester2[edema]edema3NA::bmissingmissingNAelsemissingedemaNA
edemaedema_cat3_NA::acatcattester1; tester2[edema]edema3NA::anot applicablenot applicableNA9not applicableedemaNA
hepatoheapto_cat3_1catcattester1; tester2[hepato]hepato20hepato 0hepato 0NA0hepato 0hepatoNA
hepatoheapto_cat3_1catcattester1; tester2[hepato]hepato21hepato 1hepato 1NA1hepato 1hepatoNA
hepatoheapto_cat3_NA::acatcattester1; tester2[hepato]hepato2NA::bmissingmissingNAelsemissinghepatoNA
copperNAcontconttester1; tester2[copper]copperNANA::amissingmissingNA9999NAcopperNA
plateletNAcontconttester1; tester2[platelet]plateletNAcopyNANANA[0,1000]NAplateletNA
plateletNAcontconttester1; tester2[platelet]plateletNANA::bmissingmissingNAelseNAplateletNA
plateletNAcontconttester1; tester2[platelet]plateletNANA::anot applicablenot applicableNA9999NAplateletNA
protimeNAcontconttester1; tester2[protime]protimeNAcopyNANANA[5, 30]NAprotimeNA
protimeNAcontconttester1; tester2[protime]protimeNANA::bmissingmissingNAelseNAprotimeNA
hepatoheapto_cat3_NA::bcatcattester1; tester2[hepato]hepato2NA::anot applicablenot applicableNA9not applicablehepatoNA
sexsex_cat2_1catcattester1; tester2[sex]sex2msex msex mNAmsex msexNA
sexsex_cat2_2catcattester1; tester2[sex]sex2fsex fsex fNAfsex fsexNA
sexsex_cat2_NA::bcatcattester1; tester2[sex]sex2NA::bmissingmissingNAelsesex msexNA
sexsex_cat2_NA::acatcattester1; tester2[sex]sex2NA::anot applicablenot applicableNA9sex msexNA
spidersspiders0catcattester1; tester2[spiders]spiders20spiders 0spiders 0NA0spiders 0spidersNA
spidersspiders1catcattester1; tester2[spiders]spiders21spiders 1spiders 1NA1spiders 1spidersNA
spidersspiders_NA::bcatcattester1; tester2[spiders]spiders2NA::bmissingmissingNAelsespiders 0spidersNA
spidersspiders_NA::acatcattester1; tester2[spiders]spiders2NA::anot applicablenot applicableNA9not applicablespidersNA
stagestage1catcattester1; tester2[stage]stage41stage 1stage 1NA1stage 1stageNA
stagestage2catcattester1; tester2[stage]stage42stage 2stage 2NA2stage 2stageNA
stagestage3catcattester1; tester2[stage]stage43stage 3stage 3NA3stage 3stageNA
stagestage4catcattester1; tester2[stage]stage44stage 4stage 4NA4stage 4stageNA
stagestage_NA::bcatcattester1; tester2[stage]stage4NA::bmissingmissingNAelsemissingstageNA
stagestage_NA::acatcattester1; tester2[stage]stage4NA::anot applicablenot applicableNA9not applicablestageNA
statusstatus0catcattester1; tester2[status]status30status 0status 0NA0status 0statusNA
statusstatus1catcattester1; tester2[status]status31status 1status 1NA1status 1statusNA
statusstatus2catcattester1; tester2[status]status32status 2status 2NA2status 2statusNA
statusstatus_NA::bcatcattester1; tester2[status]status3NA::bmissingmissingNAelsestatus 0statusNA
protimeNAcontconttester1; tester2[protime]protimeNANA::anot applicablenot applicableNA99NAprotimeNA
timeNAcontconttester1; tester2[time]timeNAcopyNANANA[0,5000]NAtimeNA
timeNAcontconttester1; tester2[time]timeNANA::bmissingmissingNAelseNAtimeNA
timeNAcontconttester1; tester2[time]timeNANA::anot applicablenot applicableNA9999NAtimeNA
trigNAcontconttester1; tester2[trig]trigNAcopyNANANA[0,1000]NAtrigNA
trigNAcontconttester1; tester2[trig]trigNANA::bmissingmissingNAelseNAtrigNA
statusstatus_NA::acatcattester1; tester2[status]status3NA::anot applicablenot applicableNA9not applicablestatusNA
trttrt1catcattester1; tester2[trt]trt21trt 1trt 1NA1trt 1trtNA
trttrt2catcattester1; tester2[trt]trt22trt 2trt 2NA2trt 2trtNA
trttrt_NA::bcatcattester1; tester2[trt]trt2NA::bmissingmissingNAelsetrt 1trtNA
trttrt_NA::acatcattester1; tester2[trt]trt2NA::anot applicablenot applicableNA9not applicabletrtNA
trigNAcontconttester1; tester2[trig]trigNANA::amissingmissingNA9999NAtrigNA
example_derNAcontconttester1; tester2DerivedVar::[chol, bili]example_derNAFunc::example_der_funN/AN/ANAelseN/Aexample_derA test derived variable
agegrp10agegrp10_cat6_1catcattester2tester2::agegrpgrouped age6120-2920-29years120-29grouped ageNA
agegrp10agegrp10_cat6_2catcattester2tester2::agegrpgrouped age6230-3930-39years230-39grouped ageNA
agegrp10agegrp10_cat6_3catcattester2tester2::agegrpgrouped age6340-4940-49years340-49grouped ageNA
agegrp10agegrp10_cat6_4catcattester2tester2::agegrpgrouped age6450-5950-59years450-59grouped ageNA
agegrp10agegrp10_cat6_5catcattester2tester2::agegrpgrouped age6560-6960-69years560-69grouped ageNA
agegrp10agegrp10_cat6_6catcattester2tester2::agegrpgrouped age6670-7970-79years670-79grouped ageNA
agegrp10agegrp10_cat6_NA::bcatcattester2tester2::agegrpgrouped age6NA::bmissingmissingyearselsemissinggrouped ageNA
agegrp5agegrp5_cat11_1catcattester1tester1::agegrpgrouped age11125-2925-29years120-29grouped ageNA
agegrp5agegrp5_cat11_2catcattester1tester1::agegrpgrouped age11230-3430-34years230-39grouped ageNA
agegrp5agegrp5_cat11_3catcattester1tester1::agegrpgrouped age11335-3935-39years330-39grouped ageNA
agegrp5agegrp5_cat11_4catcattester1tester1::agegrpgrouped age11440-4440-44years440-49grouped ageNA
agegrp5agegrp5_cat11_5catcattester1tester1::agegrpgrouped age11545-4945-49years540-49grouped ageNA
agegrp5agegrp5_cat11_6catcattester1tester1::agegrpgrouped age11650-5450-54years650-59grouped ageNA
agegrp5agegrp5_cat11_7catcattester1tester1::agegrpgrouped age11755-5955-59years750-59grouped ageNA
agegrp5agegrp5_cat11_8catcattester1tester1::agegrpgrouped age11860-6460-64years860-69grouped ageNA
agegrp5agegrp5_cat11_9catcattester1tester1::agegrpgrouped age11965-6965-69years960-69grouped ageNA
agegrp5agegrp5_cat11_10catcattester1tester1::agegrpgrouped age111070-7470-74years1070-79grouped ageNA
agegrp5agegrp5_cat11_11catcattester1tester1::agegrpgrouped age111175-7975-79years1170-79grouped ageNA
agegrp5agegrp5_cat11_NA::bcatcattester1tester1::agegrpgrouped age11Na::bmissingmissingyearselsemissinggrouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA27NANAyears120-29grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA32NANAyears230-39grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA37NANAyears330-39grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA42NANAyears440-49grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA47NANAyears540-49grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA52NANAyears650-59grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA57NANAyears750-59grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA62NANAyears860-69grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA67NANAyears960-69grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA72NANAyears1070-79grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA77NANAyears1170-79grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNANA::bNANAyearselsemissinggrouped ageNA
age_contNAcontcattester2tester2::agegrpgrouped ageNA25NANAyears120-29grouped ageNA
age_contNAcontcattester2tester2::agegrpgrouped ageNA35NANAyears230-39grouped ageNA
age_contNAcontcattester2tester2::agegrpgrouped ageNA45NANAyears340-49grouped ageNA
age_contNAcontcattester2tester2::agegrpgrouped ageNA55NANAyears450-59grouped ageNA
age_contNAcontcattester2tester2::agegrpgrouped ageNA65NANAyears560-69grouped ageNA
age_contNAcontcattester2tester2::agegrpgrouped ageNA75NANAyears670-79grouped ageNA
age_contNAcontcattester2tester2::agegrpgrouped age6NA::bNANAyearselsemissinggrouped ageNA
agegrp10agegrp10_cat6_1catcattester1tester1::agegrpgrouped age6120-2920-29years120-29grouped ageNA
agegrp10agegrp10_cat6_2catcattester1tester1::agegrpgrouped age6230-3930-39years230-39grouped ageNA
agegrp10agegrp10_cat6_2catcattester1tester1::agegrpgrouped age6230-3930-39years330-39grouped ageNA
agegrp10agegrp10_cat6_3catcattester1tester1::agegrpgrouped age6340-4940-49years440-49grouped ageNA
agegrp10agegrp10_cat6_3catcattester1tester1::agegrpgrouped age6340-4940-49years540-49grouped ageNA
agegrp10agegrp10_cat6_4catcattester1tester1::agegrpgrouped age6450-5950-59years650-59grouped ageNA
agegrp10agegrp10_cat6_4catcattester1tester1::agegrpgrouped age6450-5950-59years750-59grouped ageNA
agegrp10agegrp10_cat6_5catcattester1tester1::agegrpgrouped age6560-6960-69years860-69grouped ageNA
agegrp10agegrp10_cat6_5catcattester1tester1::agegrpgrouped age6560-6960-69years960-69grouped ageNA
agegrp10agegrp10_cat6_6catcattester1tester1::agegrpgrouped age6670-7970-79years1070-79grouped ageNA
agegrp10agegrp10_cat6_6catcattester1tester1::agegrpgrouped age6670-7970-79years1170-79grouped ageNA
agegrp10agegrp10_cat6_NA::bcatcattester1tester1::agegrpgrouped age6NA::bmissingmissingyearselsemissinggrouped ageNA
+
+
+
+

+variable_details for dervived variables +

+

The same naming convention applies to derived variables with the +exception of two columns:

+
    +
  1. In variableStart, instead of database names being +listed, DerivedVar:: is written followed with the list +of original variables used inside square brackets.
  2. +
+
    +
  • DerivedVar::[var1, var2, var3]
  • +
+
    +
  1. In recEnd, write Func:: followed +with the exact name of the custom function used to create the derived +variable.
  2. +
+
    +
  • Func::derivedFunction
  • +
+

A derived variable looks like this in +variable_details.csv

+ ++++++++++++++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
variabledummyVariabletypeEndtypeStartdatabaseStartvariableStartvariableStartLabelnumValidCatrecEndcatLabelcatLabelLongunitsrecStartcatStartLabelvariableStartShortLabelnotes
ageNAcontconttester1; tester2[age]ageNAcopyNANANA[20,80]NAageNA
ageNAcontconttester1; tester2[age]ageNANA::bmissingmissingNAelseNAageNA
ageNAcontconttester1; tester2[age]ageNANA::anot applicablenot applicableNA999NAageNA
albuminNAcontconttester1; tester2[albumin]albuminNAcopyNANANA[1,5]NAalbuminNA
albuminNAcontconttester1; tester2[albumin]albuminNANA::bmissingmissingNAelseNAalbuminNA
albuminNAcontconttester1; tester2[albumin]albuminNANA::anot applicablenot applicableNA99NAalbuminNA
alk.phosNAcontconttester1; tester2[alk.phos]alk.phosNAcopyNANANA[200,15000]NAalk.phosNA
alk.phosNAcontconttester1; tester2[alk.phos]alk.phosNANA::bmissingmissingNAelseNAalk.phosNA
ascitesascites_cat3_1catcattester1; tester2[ascites]ascites20ascites 0ascites 0NA0ascites 0ascitesNA
ascitesascites_cat3_2catcattester1; tester2[ascites]ascites21ascites 1ascites 1NA1ascites 1ascitesNA
ascitesascites_cat3_NA::bcatcattester1; tester2[ascites]ascites2NA::bmissingmissingNAelseascites 0ascitesNA
ascitesascites_cat3_NA::acatcattester1; tester2[ascites]ascites2NA::anot applicablenot applicableNA9not applicableNANA
alk.phosNAcontconttester1; tester2[alk.phos]alk.phosNANA::anot applicablenot applicableNA99999NAalk.phosNA
astNAcontconttester1; tester2[ast]astNAcopyNANANA[20,500]NAastNA
astNAcontconttester1; tester2[ast]astNANA::bmissingmissingNAelseNAastNA
astNAcontconttester1; tester2[ast]astNANA::anot applicablenot applicableNA9999NAastNA
biliNAcontconttester1; tester2[bili]biliNAcopyNANANA[0,100]NAbiliNA
biliNAcontconttester1; tester2[bili]biliNANA::bmissingmissingNAelseNAbiliNA
cholNAcontconttester1; tester2[chol]cholNAcopyNANANA[100,2000]NAcholNA
cholNAcontconttester1; tester2[chol]cholNANA::bmissingmissingNAelseNAcholNA
cholNAcontconttester1; tester2[chol]cholNANA::amissingmissingNA9999NAcholNA
copperNAcontconttester1; tester2[copper]copperNAcopyNANANA[0,1000]NAcopperNA
copperNAcontconttester1; tester2[copper]copperNANA::bmissingmissingNAelseNAcopperNA
edemaedema_cat3_1catcattester1; tester2[edema]edema30edema 0.0edema 0.0NA0edema 0.0edemaNA
edemaedema_cat3_2catcattester1; tester2[edema]edema30.5edema 0.5edema 0.5NA0.5edema 0.5edemaNA
edemaedema_cat3_3catcattester1; tester2[edema]edema31edema 1.0edema 1.0NA1edema 1.0edemaNA
edemaedema_cat3_NA::bcatcattester1; tester2[edema]edema3NA::bmissingmissingNAelsemissingedemaNA
edemaedema_cat3_NA::acatcattester1; tester2[edema]edema3NA::anot applicablenot applicableNA9not applicableedemaNA
hepatoheapto_cat3_1catcattester1; tester2[hepato]hepato20hepato 0hepato 0NA0hepato 0hepatoNA
hepatoheapto_cat3_1catcattester1; tester2[hepato]hepato21hepato 1hepato 1NA1hepato 1hepatoNA
hepatoheapto_cat3_NA::acatcattester1; tester2[hepato]hepato2NA::bmissingmissingNAelsemissinghepatoNA
copperNAcontconttester1; tester2[copper]copperNANA::amissingmissingNA9999NAcopperNA
plateletNAcontconttester1; tester2[platelet]plateletNAcopyNANANA[0,1000]NAplateletNA
plateletNAcontconttester1; tester2[platelet]plateletNANA::bmissingmissingNAelseNAplateletNA
plateletNAcontconttester1; tester2[platelet]plateletNANA::anot applicablenot applicableNA9999NAplateletNA
protimeNAcontconttester1; tester2[protime]protimeNAcopyNANANA[5, 30]NAprotimeNA
protimeNAcontconttester1; tester2[protime]protimeNANA::bmissingmissingNAelseNAprotimeNA
hepatoheapto_cat3_NA::bcatcattester1; tester2[hepato]hepato2NA::anot applicablenot applicableNA9not applicablehepatoNA
sexsex_cat2_1catcattester1; tester2[sex]sex2msex msex mNAmsex msexNA
sexsex_cat2_2catcattester1; tester2[sex]sex2fsex fsex fNAfsex fsexNA
sexsex_cat2_NA::bcatcattester1; tester2[sex]sex2NA::bmissingmissingNAelsesex msexNA
sexsex_cat2_NA::acatcattester1; tester2[sex]sex2NA::anot applicablenot applicableNA9sex msexNA
spidersspiders0catcattester1; tester2[spiders]spiders20spiders 0spiders 0NA0spiders 0spidersNA
spidersspiders1catcattester1; tester2[spiders]spiders21spiders 1spiders 1NA1spiders 1spidersNA
spidersspiders_NA::bcatcattester1; tester2[spiders]spiders2NA::bmissingmissingNAelsespiders 0spidersNA
spidersspiders_NA::acatcattester1; tester2[spiders]spiders2NA::anot applicablenot applicableNA9not applicablespidersNA
stagestage1catcattester1; tester2[stage]stage41stage 1stage 1NA1stage 1stageNA
stagestage2catcattester1; tester2[stage]stage42stage 2stage 2NA2stage 2stageNA
stagestage3catcattester1; tester2[stage]stage43stage 3stage 3NA3stage 3stageNA
stagestage4catcattester1; tester2[stage]stage44stage 4stage 4NA4stage 4stageNA
stagestage_NA::bcatcattester1; tester2[stage]stage4NA::bmissingmissingNAelsemissingstageNA
stagestage_NA::acatcattester1; tester2[stage]stage4NA::anot applicablenot applicableNA9not applicablestageNA
statusstatus0catcattester1; tester2[status]status30status 0status 0NA0status 0statusNA
statusstatus1catcattester1; tester2[status]status31status 1status 1NA1status 1statusNA
statusstatus2catcattester1; tester2[status]status32status 2status 2NA2status 2statusNA
statusstatus_NA::bcatcattester1; tester2[status]status3NA::bmissingmissingNAelsestatus 0statusNA
protimeNAcontconttester1; tester2[protime]protimeNANA::anot applicablenot applicableNA99NAprotimeNA
timeNAcontconttester1; tester2[time]timeNAcopyNANANA[0,5000]NAtimeNA
timeNAcontconttester1; tester2[time]timeNANA::bmissingmissingNAelseNAtimeNA
timeNAcontconttester1; tester2[time]timeNANA::anot applicablenot applicableNA9999NAtimeNA
trigNAcontconttester1; tester2[trig]trigNAcopyNANANA[0,1000]NAtrigNA
trigNAcontconttester1; tester2[trig]trigNANA::bmissingmissingNAelseNAtrigNA
statusstatus_NA::acatcattester1; tester2[status]status3NA::anot applicablenot applicableNA9not applicablestatusNA
trttrt1catcattester1; tester2[trt]trt21trt 1trt 1NA1trt 1trtNA
trttrt2catcattester1; tester2[trt]trt22trt 2trt 2NA2trt 2trtNA
trttrt_NA::bcatcattester1; tester2[trt]trt2NA::bmissingmissingNAelsetrt 1trtNA
trttrt_NA::acatcattester1; tester2[trt]trt2NA::anot applicablenot applicableNA9not applicabletrtNA
trigNAcontconttester1; tester2[trig]trigNANA::amissingmissingNA9999NAtrigNA
example_derNAcontconttester1; tester2DerivedVar::[chol, bili]example_derNAFunc::example_der_funN/AN/ANAelseN/Aexample_derA test derived variable
agegrp10agegrp10_cat6_1catcattester2tester2::agegrpgrouped age6120-2920-29years120-29grouped ageNA
agegrp10agegrp10_cat6_2catcattester2tester2::agegrpgrouped age6230-3930-39years230-39grouped ageNA
agegrp10agegrp10_cat6_3catcattester2tester2::agegrpgrouped age6340-4940-49years340-49grouped ageNA
agegrp10agegrp10_cat6_4catcattester2tester2::agegrpgrouped age6450-5950-59years450-59grouped ageNA
agegrp10agegrp10_cat6_5catcattester2tester2::agegrpgrouped age6560-6960-69years560-69grouped ageNA
agegrp10agegrp10_cat6_6catcattester2tester2::agegrpgrouped age6670-7970-79years670-79grouped ageNA
agegrp10agegrp10_cat6_NA::bcatcattester2tester2::agegrpgrouped age6NA::bmissingmissingyearselsemissinggrouped ageNA
agegrp5agegrp5_cat11_1catcattester1tester1::agegrpgrouped age11125-2925-29years120-29grouped ageNA
agegrp5agegrp5_cat11_2catcattester1tester1::agegrpgrouped age11230-3430-34years230-39grouped ageNA
agegrp5agegrp5_cat11_3catcattester1tester1::agegrpgrouped age11335-3935-39years330-39grouped ageNA
agegrp5agegrp5_cat11_4catcattester1tester1::agegrpgrouped age11440-4440-44years440-49grouped ageNA
agegrp5agegrp5_cat11_5catcattester1tester1::agegrpgrouped age11545-4945-49years540-49grouped ageNA
agegrp5agegrp5_cat11_6catcattester1tester1::agegrpgrouped age11650-5450-54years650-59grouped ageNA
agegrp5agegrp5_cat11_7catcattester1tester1::agegrpgrouped age11755-5955-59years750-59grouped ageNA
agegrp5agegrp5_cat11_8catcattester1tester1::agegrpgrouped age11860-6460-64years860-69grouped ageNA
agegrp5agegrp5_cat11_9catcattester1tester1::agegrpgrouped age11965-6965-69years960-69grouped ageNA
agegrp5agegrp5_cat11_10catcattester1tester1::agegrpgrouped age111070-7470-74years1070-79grouped ageNA
agegrp5agegrp5_cat11_11catcattester1tester1::agegrpgrouped age111175-7975-79years1170-79grouped ageNA
agegrp5agegrp5_cat11_NA::bcatcattester1tester1::agegrpgrouped age11Na::bmissingmissingyearselsemissinggrouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA27NANAyears120-29grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA32NANAyears230-39grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA37NANAyears330-39grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA42NANAyears440-49grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA47NANAyears540-49grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA52NANAyears650-59grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA57NANAyears750-59grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA62NANAyears860-69grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA67NANAyears960-69grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA72NANAyears1070-79grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNA77NANAyears1170-79grouped ageNA
age_contNAcontcattester1tester1::agegrpgrouped ageNANA::bNANAyearselsemissinggrouped ageNA
age_contNAcontcattester2tester2::agegrpgrouped ageNA25NANAyears120-29grouped ageNA
age_contNAcontcattester2tester2::agegrpgrouped ageNA35NANAyears230-39grouped ageNA
age_contNAcontcattester2tester2::agegrpgrouped ageNA45NANAyears340-49grouped ageNA
age_contNAcontcattester2tester2::agegrpgrouped ageNA55NANAyears450-59grouped ageNA
age_contNAcontcattester2tester2::agegrpgrouped ageNA65NANAyears560-69grouped ageNA
age_contNAcontcattester2tester2::agegrpgrouped ageNA75NANAyears670-79grouped ageNA
age_contNAcontcattester2tester2::agegrpgrouped age6NA::bNANAyearselsemissinggrouped ageNA
agegrp10agegrp10_cat6_1catcattester1tester1::agegrpgrouped age6120-2920-29years120-29grouped ageNA
agegrp10agegrp10_cat6_2catcattester1tester1::agegrpgrouped age6230-3930-39years230-39grouped ageNA
agegrp10agegrp10_cat6_2catcattester1tester1::agegrpgrouped age6230-3930-39years330-39grouped ageNA
agegrp10agegrp10_cat6_3catcattester1tester1::agegrpgrouped age6340-4940-49years440-49grouped ageNA
agegrp10agegrp10_cat6_3catcattester1tester1::agegrpgrouped age6340-4940-49years540-49grouped ageNA
agegrp10agegrp10_cat6_4catcattester1tester1::agegrpgrouped age6450-5950-59years650-59grouped ageNA
agegrp10agegrp10_cat6_4catcattester1tester1::agegrpgrouped age6450-5950-59years750-59grouped ageNA
agegrp10agegrp10_cat6_5catcattester1tester1::agegrpgrouped age6560-6960-69years860-69grouped ageNA
agegrp10agegrp10_cat6_5catcattester1tester1::agegrpgrouped age6560-6960-69years960-69grouped ageNA
agegrp10agegrp10_cat6_6catcattester1tester1::agegrpgrouped age6670-7970-79years1070-79grouped ageNA
agegrp10agegrp10_cat6_6catcattester1tester1::agegrpgrouped age6670-7970-79years1170-79grouped ageNA
agegrp10agegrp10_cat6_NA::bcatcattester1tester1::agegrpgrouped age6NA::bmissingmissingyearselsemissinggrouped ageNA
+
+
+

How to create the variables worksheet variables +

+

Once mapped and specified on variable_details, the +stage variable can be specified on the variables worksheet: +variables. Ensure that the names you used in the +variable_details worksheet are identical to those listed in +variables.

    -
  1. variable: the name of the recoded variable (variable_details worksheet column: ‘variable’)

  2. -
  3. label: the shorthand label for the variable (variable_details worksheet column: ‘variableStartShortLabel’)

  4. -
  5. labelLong: a more detailed label for the variable (new column, it is not in the variable_details worksheet)

  6. -
  7. section: group of data to which the variable belongs (new column, it is not in the variable_details worksheet)

  8. -
  9. subject: sub-group of data to which the variable belongs (new column, it is not in the variable_details worksheet)

  10. -
  11. variableType: whether the recoded variable is categorical or continuous (variable_detail worksheet column: ‘typeEnd’)

  12. -
  13. units: unit of measurement for the variable (variable_detail worksheet column ‘units’)

  14. -
  15. databaseStart: the list of databases that contain the variable of interest (variable_detail worksheet column: ‘databaseStart’)

  16. -
  17. variableStart the original variable name (variable_detail worksheet column: ‘variableStart’)

  18. +
  19. variable: the name of the recoded variable +(variable_details worksheet column: ‘variable’)

  20. +
  21. label: the shorthand label for the variable +(variable_details worksheet column: +‘variableStartShortLabel’)

  22. +
  23. labelLong: a more detailed label for the +variable (new column, it is not in the variable_details +worksheet)

  24. +
  25. section: group of data to which the variable +belongs (new column, it is not in the variable_details +worksheet)

  26. +
  27. subject: sub-group of data to which the variable +belongs (new column, it is not in the variable_details +worksheet)

  28. +
  29. variableType: whether the recoded variable is +categorical or continuous (variable_detail worksheet column: +‘typeEnd’)

  30. +
  31. units: unit of measurement for the variable +(variable_detail worksheet column ‘units’)

  32. +
  33. databaseStart: the list of databases that +contain the variable of interest (variable_detail worksheet column: +‘databaseStart’)

  34. +
  35. variableStart the original variable name +(variable_detail worksheet column: ‘variableStart’)

- - - - - - - - - - - +++++++++++++ + + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
- -variable - -label - -labelLong - -subject - -section - -variableType - -databaseStart - -units - -variableStart -
variablelabellabelLongsubjectsectionvariableTypedatabaseStartunitsvariableStartnotesdescription
-19 - -stage - -stage - -histologic stage of disease - -lab test - -stage - -cat - -tester1, tester2 - -N/A - -[stage] -
ageagein yearsdemographicageconttester1;tester2years[age]NANA
age_contage_contcontinous age created from age groupsdemographicsageconttester1;tester2years[agegrp]NANA
agegrp10agegrp10ten year age groupsdemographicsagecattester2years[agegrp]NANA
agegrp5agegrp5five year age groupsdemographicsagecattester1yearstester1::agegrpNANA
albuminalbuminserum albuminlab testalbuminconttester1;tester2g/dl[albumin]NANA
alk.phosalk.phosalkaline phosphotaselab testalk.phosconttester1;tester2U/L[alk.phos]NANA
ascitesascitesprescence of ascitesphysical symptomascitescattester1;tester2N/A[ascites]NANA
astastaspartate aminotransferase, once called SGOTlab testastconttester1;tester2U/L[ast]NANA
bilibiliserum bilirunbinlab testbiliconttester1;tester2mg/dl[bili]NANA
cholcholserum cholesterollab testcholconttester1;tester2mg/dl[chol]NANA
coppercopperurine copperlab testcopperconttester1;tester2ug/dl[copper]NANA
edemaedemaedemaphysical symptomedemacattester1;tester2N/A[edema]NANA
example_derexample_derexample of dervived function: concentration of +cholestral * concentration of bilirunbinderivedexampleconttester1;tester2mg/dl[example_der]NANA
hepatohepatoprescence of hepatomegaly or enlarged liverphysical symptomhepatocattester1;tester2N/A[hepato]NANA
plateletplateletplatelet countlab testplateletconttester1;tester2N/A[platelet]NANA
protimeprotimestandarized blood clotting timelab testprotimeconttester1;tester2N/A[protime]NANA
sexsexsexdemographicsexcattester1;tester2N/A[sex]NANA
spidersspidersblood vessel malformations in the skinphysical symptomspiderscattester1;tester2N/A[spiders]NANA
stagestagehistologic stage of disease (needs biopsy)lab teststagecattester1;tester2N/A[stage]NANA
statusstatusstatus at endpointstudystatuscattester1;tester2N/A[status]NANA
timetimenumber of days between registration and the earlier of +death,
transplantion, or study analysis in July, 1986studytimeconttester1;tester2days[time]NANA
trigtrigtriglycerideslab testtrigconttester1;tester2mg/dl[trig]NANA
trttreatmenttreatmentexposuretrtcattester1;tester2N/A[trt]NANA
idcase numbercase numberstudy identifictionIDconttester1;tester2N/A[id]NANA
+ +
-

Site built with pkgdown 1.6.1.

+

+

Site built with pkgdown 2.1.1.

- + + + diff --git a/docs/articles/how_to_use_recodeflow_with_your_data_files/header-attrs-2.29/header-attrs.js b/docs/articles/how_to_use_recodeflow_with_your_data_files/header-attrs-2.29/header-attrs.js new file mode 100644 index 00000000..dd57d92e --- /dev/null +++ b/docs/articles/how_to_use_recodeflow_with_your_data_files/header-attrs-2.29/header-attrs.js @@ -0,0 +1,12 @@ +// Pandoc 2.9 adds attributes on both header and div. We remove the former (to +// be compatible with the behavior of Pandoc < 2.8). +document.addEventListener('DOMContentLoaded', function(e) { + var hs = document.querySelectorAll("div.section[class*='level'] > :first-child"); + var i, h, a; + for (i = 0; i < hs.length; i++) { + h = hs[i]; + if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6 + a = h.attributes; + while (a.length > 0) h.removeAttribute(a[0].name); + } +}); diff --git a/docs/articles/index.html b/docs/articles/index.html index 19412233..339f02d7 100644 --- a/docs/articles/index.html +++ b/docs/articles/index.html @@ -1,73 +1,12 @@ - - - - - - - -Articles • recodeflow - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Articles • recodeflow + - - - -
-
- - -
- -
- +
+ + - - - + diff --git a/docs/articles/missing_data_tagged_na.html b/docs/articles/missing_data_tagged_na.html new file mode 100644 index 00000000..d765f4a6 --- /dev/null +++ b/docs/articles/missing_data_tagged_na.html @@ -0,0 +1,225 @@ + + + + + + + +How to use tagged_na • recodeflow + + + + + + + + + + + + + + + + + +
+
+ + + + +
+
+ + + + +

Base R supports only one type of NA (‘not available’) to represent +missing values. However, your data may include several types of missing +data or incomplete category responses.

+

To address this issue of a singular “NA”, we use the +haven package tagged_na()

+

tagged_na() adds an additional character to any NA +values, enabling users to define additional missing data types. +tagged_na() applies only for numeric values; character +based values can use any string to represent NA or missing data.

+
+

recodeflow approach to coding missing data +

+

recodeflow recodes missing data categories values into 3 +NA values that are commonly used for most studies:

+
    +
  • NA(a) = ‘not applicable’
  • +
  • NA(b) = ‘missing’
  • +
  • Na(c) = ‘not asked’
  • +
+

Summary of tagged_na values and their +corresponding category values.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
recodeflow tagged_na +category value
NA(a)6
NA(b)7
NA(b)8
NA(b)9
NA(c)question not asked in the survey cycle
+
+
+

Example haven::tagged_na() +

+
+library(haven)
+x <- c(1:5, tagged_na("a"), tagged_na("b"))
+
+# Is used to read the tagged NA in most other functions they are still viewed as NA
+na_tag(x)
+
## [1] NA  NA  NA  NA  NA  "a" "b"
+
+# Is used to print the na as well as their tag
+print_tagged_na(x)
+
## [1]     1     2     3     4     5 NA(a) NA(b)
+
+# Tagged NA's work identically to regular NAs
+x
+
## [1]  1  2  3  4  5 NA NA
+
+is.na(x)
+
## [1] FALSE FALSE FALSE FALSE FALSE  TRUE  TRUE
+
+
+ + + +
+ + + +
+ +
+

+

Site built with pkgdown 2.1.1.

+
+ +
+
+ + + + + + + + diff --git a/docs/articles/missing_data_tagged_na_files/header-attrs-2.29/header-attrs.js b/docs/articles/missing_data_tagged_na_files/header-attrs-2.29/header-attrs.js new file mode 100644 index 00000000..dd57d92e --- /dev/null +++ b/docs/articles/missing_data_tagged_na_files/header-attrs-2.29/header-attrs.js @@ -0,0 +1,12 @@ +// Pandoc 2.9 adds attributes on both header and div. We remove the former (to +// be compatible with the behavior of Pandoc < 2.8). +document.addEventListener('DOMContentLoaded', function(e) { + var hs = document.querySelectorAll("div.section[class*='level'] > :first-child"); + var i, h, a; + for (i = 0; i < hs.length; i++) { + h = hs[i]; + if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6 + a = h.attributes; + while (a.length > 0) h.removeAttribute(a[0].name); + } +}); diff --git a/docs/articles/rec_with_table.html b/docs/articles/rec_with_table.html index d3977aef..5a671fae 100644 --- a/docs/articles/rec_with_table.html +++ b/docs/articles/rec_with_table.html @@ -12,20 +12,20 @@ - + - - + +
@@ -122,119 +113,140 @@

rec_with_table

- Source: vignettes/rec_with_table.Rmd + Source: vignettes/rec_with_table.Rmd
-
-

-What is the function rec_with_table?

-

rec_with_table is the function used to recode variables within your dataset into harmonized variables. rec_with_table reads:

+
+

What is the function rec_with_table? +

+

rec_with_table is the function used to recode variables +within your dataset into harmonized variables. +rec_with_table reads:

  • variable for a list of variables to recode, and
  • -variable_details for instructions on how to recode the variable(s)
  • +variable_details for instructions on how to recode the +variable(s)
-library(recodeflow)
-status <- rec_with_table(data = tester1, 
-                         variables = "status", 
-                         variable_details = variable_details,
-                         log = TRUE,
-                         var_labels = c(status = "Status"))
-#> Using the passed data variable name as database_name
-#> Warning in recode_call(variables = variables, data = data, database_name
-#> = database_name, : is missing from variable details therefore cannot be
-#> recoded
-#> NOTE for status: This is sample survival pbc data
-#> NOTE for status: This is sample survival pbc data
-#> NOTE for status: This is sample survival pbc data
-#> The variable status was recoded into status for the database tester1 the following recodes were made:
-#>   value_to From rows_recoded
-#> 1        0    0           94
-#> 2        1    1            7
-#> 3        2    2          108
-#> 4    NA(b) else            0
+library(recodeflow) +status <- rec_with_table(data = recodeflow::pbc, + variables = "status", + variable_details = recodeflow::pbc_variable_details, + log = TRUE, + var_labels = c(status = "Status")) +#> Using the passed data variable name as database_name
-
-

-Output - Warning messages

-

Warning messages will appear when your dataset is missing variables in your variable worksheet or rec_with_table() call.

+
+

Output - Warning messages +

+

Warning messages will appear when your dataset is missing variables +in your variable worksheet or rec_with_table() +call.

-
-

-Output - Notes

-

By default, rec_with_table() prints notes to the console.

-

Notes can give important details on what and how variables are harmonized. For example, notes can include details on:

+
+

Output - Notes +

+

By default, rec_with_table() prints notes to the +console.

+

Notes can give important details on what and how variables are +harmonized. For example, notes can include details on:

  • which datasets include a variable,
  • how a variable changes across datasets, and
  • -
  • if the recoding rules for a variable are dependent on the source dataset
  • +
  • if the recoding rules for a variable are dependent on the source +dataset
-

You should read and consider notes before deciding whether to harmonize a variable.

-

The notes output is from the column notes in variable_details

+

You should read and consider notes before deciding +whether to harmonize a variable.

+

The notes output is from the column notes in +variable_details

-
-

-Arguments - Required

+
+

Arguments - Required +

    -
  • data A dataframe(s) containing data to be recoded.

  • -
  • variables Either a string of variables to recode or a dataframe containing the variables (e.g., variables)

  • -
  • variable_details A dataframe containing the specifications for recoding.

  • +
  • data A dataframe(s) containing data to be +recoded.

  • +
  • variables Either a string of variables to recode or +a dataframe containing the variables (e.g., +variables)

  • +
  • variable_details A dataframe containing the +specifications for recoding.

-#To recode only a few variables
-age_sex_1 <- rec_with_table(data = tester1, 
-                         variables = c("age","sex"),
-                         variable_details = variable_details)
-
-
-#To recode all variables listed on the variable worksheet
-recoded1 <- rec_with_table(data = tester1,
-                          variables = variables,
-                          variable_details = variable_details)
+#To recode only a few variables +age_sex_1 <- rec_with_table(data = recodeflow::pbc, + variables = c("age","sex"), + variable_details = recodeflow::pbc_variable_details) + + +#To recode all variables listed on the variable worksheet +recoded1 <- rec_with_table(data = recodeflow::pbc, + variables = recodeflow::pbc_variables, + variable_details = recodeflow::pbc_variable_details)
-
-

-Arguments - Default

-

With rec_with_table() the following arguments are only called if you want to modify them.

+
+

Arguments - Default +

+

With rec_with_table() the following arguments are only +called if you want to modify them.

    -
  • database_name defaults to NULL. As a result, rec_with_table() uses the database indicated in the data argument.

  • -
  • else_value defaults to NA. Values out of range set to NA.

  • -
  • append_to_data defaults to FALSE. Recoded variables will not be appended to the original dataset.

  • -
  • log defaults to FALSE. Logs of the variable recoding will not be displayed.

  • -
  • notes defaults to TRUE. Information in the Notes column from variable_details worksheet will be displayed

  • -
  • var_labels is set to NULL. This argument can be used to add labels to a recoded dataset that only contains a subset of variables from variables worksheet. The format to add labels to a subset of variables is c(variable = "Label").

  • -
  • attach_data_name is set to FALSE. This argument can be used to append a column that denotes the name of the dataset each recoded row came from.

  • +
  • database_name defaults to NULL. As a result, +rec_with_table() uses the database indicated in the +data argument.

  • +
  • else_value defaults to NA. Values out of range set +to NA.

  • +
  • append_to_data defaults to FALSE. Recoded variables +will not be appended to the original dataset.

  • +
  • log defaults to FALSE. Logs of the variable recoding +will not be displayed.

  • +
  • notes defaults to TRUE. Information in the +Notes column from variable_details worksheet +will be displayed

  • +
  • var_labels is set to NULL. This argument can be used +to add labels to a recoded dataset that only contains a subset of +variables from variables worksheet. The format to add +labels to a subset of variables is +c(variable = "Label").

  • +
  • attach_data_name is set to FALSE. This argument can +be used to append a column that denotes the name of the dataset each +recoded row came from.

  • +
  • +
+ +
-

Site built with pkgdown 1.6.1.

+

+

Site built with pkgdown 2.1.1.

- + + + diff --git a/docs/articles/rec_with_table_files/header-attrs-2.29/header-attrs.js b/docs/articles/rec_with_table_files/header-attrs-2.29/header-attrs.js new file mode 100644 index 00000000..dd57d92e --- /dev/null +++ b/docs/articles/rec_with_table_files/header-attrs-2.29/header-attrs.js @@ -0,0 +1,12 @@ +// Pandoc 2.9 adds attributes on both header and div. We remove the former (to +// be compatible with the behavior of Pandoc < 2.8). +document.addEventListener('DOMContentLoaded', function(e) { + var hs = document.querySelectorAll("div.section[class*='level'] > :first-child"); + var i, h, a; + for (i = 0; i < hs.length; i++) { + h = hs[i]; + if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6 + a = h.attributes; + while (a.length > 0) h.removeAttribute(a[0].name); + } +}); diff --git a/docs/articles/variable_details.html b/docs/articles/variable_details.html index cd53ffbf..bccf50fa 100644 --- a/docs/articles/variable_details.html +++ b/docs/articles/variable_details.html @@ -12,20 +12,20 @@ - + - - + +
- - - - + + + + + + +
-
-

-Introduction

-

The worksheet variable_details maps variables across datasets. variable_details also contains the instructions for function rec_with_table on how to recode the variables listed in the worksheet variables.

-

Specifically, the function rec_with_table recodes variables listed in column variable_details$variableStart to the variables listed in variable_details$variable.

-
-
#> In the dataframe `variable_details` there are 114 rows and 14 columns
+
+

Introduction +

+

The worksheet variable_details maps variables across +datasets. variable_details also contains the instructions +for function rec_with_table on how to recode the variables +listed in the worksheet variables.

+

Specifically, the function rec_with_table recodes +variables listed in column variable_details$variableStart +to the variables listed in variable_details$variable.

+
+
#> In the dataframe `variable_details` there are 119 rows and 16 columns
-
-

-Structure of the worksheet variable_details +
+

Structure of the worksheet variable_details

-
-

-Naming convention for not applicable and missing values

-

rec_with_table() uses the tagged_na() function from the haven package to tag not applicable responses as NA(a), and missing values (don’t know, refusal, not stated) as NA(b). As you will see later, not applicable values are recoded to NA::a, and missing values are recoded to NA::b. See tagged_na_usage for more information about tagged_na().

+
+

Naming convention for not applicable and missing values +

+

rec_with_table() uses the tagged_na() +function from the haven +package to tag not applicable responses as NA(a), and +missing values (don’t know, refusal, not stated) as NA(b). +As you will see later, not applicable values are recoded to +NA::a, and missing values are recoded to +NA::b. See tagged_na_usage for more information +about tagged_na().

-
-

-Rows

-

Each row in variable_details gives instructions to recode a single category of a final variable. Typically, a single category of a final variable maps to a single category of an original variable. Therefore, in variable_details you’ll have one row per category.

+
+

Rows +

+

Each row in variable_details gives instructions to +recode a single category of a final variable. Typically, a single +category of a final variable maps to a single category of an original +variable. Therefore, in variable_details you’ll have one +row per category.

There are two exceptions to this rule.

    -
  1. Original categories are sometimes combined into a single final variable category. For example,
  2. +
  3. Original categories are sometimes combined into a single final +variable category. For example,
    -
  • Most often survey responses “don’t know,” “refusal,” and “not stated” are combined into a final single “missing” category.
  • -
  • Original age group categories are often combined into larger age groups categories (e.g., original five-year age group categories are combined into final ten-year age group categories).
  • +
  • Most often survey responses “don’t know,” “refusal,” and “not +stated” are combined into a final single “missing” category.
  • +
  • Original age group categories are often combined into larger age +groups categories (e.g., original five-year age group categories are +combined into final ten-year age group categories).
    -
  1. Original datasets with different categories map to separate rows for a final variable. For example,
  2. +
  3. Original datasets with different categories map to separate rows for +a final variable. For example,
    -
  • The final variable, “Sex,” has categories “1” = male and “2” = female.
  • +
  • The final variable, “Sex,” has categories “1” = male and “2” = +female.
  • Dataset A has sex categories “m” = male and “f” = female.
  • Dataset B has categories “1” = male and “2” = female.
  • -
  • Variable_details requires four rows to map the final “Sex” categories = two for dataset A and two for dataset B.
  • +
  • Variable_details requires four rows to map the final “Sex” +categories = two for dataset A and two for dataset B.
-

Note: We recommend not combining variables if the variable has an important change between datasets. variable_detailsdetails$notes is used to identify issues that may be relevant when recoding the variable or category.

+

Note: We recommend not combining variables if the +variable has an important change between datasets. +variable_detailsdetails$notes is used to identify issues +that may be relevant when recoding the variable or category.

-
-

-Columns

-

Here we explain the columns in the worksheet variable_details.

-

Table 1. Summary of the source and level of information used for each column in the worksheet ‘variable_details’.

- +
+

Columns +

+

Here we explain the columns in the worksheet +variable_details.

+

Table 1. Summary of the source and level of +information used for each column in the worksheet +‘variable_details’.

+
- - - @@ -246,9 +260,6 @@

- @@ -258,9 +269,6 @@

- @@ -269,7 +277,7 @@

- - -
@@ -207,7 +227,7 @@

+ recoded @@ -221,9 +241,6 @@

-recoded - typeEnd * @@ -234,9 +251,6 @@

-recoded -
-recoded -
-recoded -
+ original @@ -284,9 +292,6 @@

-original - typeStart * @@ -297,9 +302,6 @@

-original - variableStartlabel @@ -324,3241 +326,1551 @@

-* Columns required for the function rec_with_table. All other columns are recommended but optional. +* Columns required for the function rec_with_table. All other +columns are recommended but optional.
-

The order of the columns within the worksheet variable_details is not important because recodeflow functions use the column names.

+

The order of the columns within the worksheet +variable_details is not important because recodeflow +functions use the column names.

  1. -variable: the name of the final recoded variable.
  2. +variable: the name of the final recoded +variable.
- - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + +
-variable -
variable
-trt -
alk.phos
-trt -
alk.phos
-trt -
ascites
-trt -
ascites
-trt -
ascites
-age -
ascites
-age -
alk.phos
  1. -typeEnd: the data type of the final recoded variable. If the recoded variable is continuous fill in as cont; if the recoded variable that is categorical fill in as cat .
  2. +typeEnd: the data type of the final recoded +variable. If the recoded variable is continuous fill in as +cont; if the recoded variable that is categorical fill in +as cat .
- - - - + + + - - - - + + + - - - - + + + - - - - + + + - - - - + + + - - - - + + + - - - - + + + - - - - + + +
- -variable - -typeEnd -
variabledummyVariable
-7 - -trt - -cat -
alk.phosNA
-8 - -trt - -cat -
alk.phosNA
-9 - -trt - -cat -
ascitesascites_cat3_1
-10 - -trt - -cat -
ascitesascites_cat3_2
-11 - -trt - -cat -
ascitesascites_cat3_NA::b
-12 - -age - -cont -
ascitesascites_cat3_NA::a
-13 - -age - -cont -
alk.phosNA
  1. -typeStart: the variable type as indicated in datasets. As indicated in the typeEnd column, categorical variables are denoted as cat and continuous variables are denoted as cont.
  2. +typeStart: the variable type as indicated in +datasets. As indicated in the typeEnd column, +categorical variables are denoted as cat and continuous +variables are denoted as cont.
- - - - - + + + + - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - + +
- -variable - -typeEnd - -typeStart -
variabledummyVariabletypeEnd
-7 - -trt - -cat - -cat -
alk.phosNAcont
alk.phosNAcont
ascitesascites_cat3_1cat
ascitesascites_cat3_2cat
ascitesascites_cat3_NA::bcat
ascitesascites_cat3_NA::acat
alk.phosNAcont
-8 - -trt - -cat - -cat -
-9 - -trt - -cat - -cat -
-10 - -trt - -cat - -cat -
-11 - -trt - -cat - -cat -
+
    +
  1. +databaseStart: the datasets that contain the +variable and categories of interest, separated by commas.
  2. +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - + +
variabledummyVariabletypeEndtypeStart
alk.phosNAcontcont
alk.phosNAcontcont
ascitesascites_cat3_1catcat
ascitesascites_cat3_2catcat
ascitesascites_cat3_NA::bcatcat
ascitesascites_cat3_NA::acatcat
alk.phosNAcontcont
-12 - -age - -cont - -cont -
+
    +
  1. +variableStart: the original names of the variables +as they are listed in the original datasets, separated by commas.
  2. +
+
    +
  • If the variable name in a particular dataset is different from the +recoded variable name, write out the dataset name, add two colons, and +write out the original variable name for that dataset.
  • +
  • If the variable name in a particular dataset is the same as the +recoded variable name, write the variable name in square brackets. Note: +this only needs to be written out once.
  • +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - + +
variabledummyVariabletypeEndtypeStartdatabaseStart
alk.phosNAcontconttester1; tester2
alk.phosNAcontconttester1; tester2
ascitesascites_cat3_1catcattester1; tester2
ascitesascites_cat3_2catcattester1; tester2
ascitesascites_cat3_NA::bcatcattester1; tester2
ascitesascites_cat3_NA::acatcattester1; tester2
alk.phosNAcontconttester1; tester2
-13 - -age - -cont - -cont -
+
    +
  1. +variableStartLabel: short form label describing the +original variable.
  2. +
+ ++++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
variabledummyVariabletypeEndtypeStartdatabaseStartvariableStart
alk.phosNAcontconttester1; tester2[alk.phos]
alk.phosNAcontconttester1; tester2[alk.phos]
ascitesascites_cat3_1catcattester1; tester2[ascites]
ascitesascites_cat3_2catcattester1; tester2[ascites]
ascitesascites_cat3_NA::bcatcattester1; tester2[ascites]
ascitesascites_cat3_NA::acatcattester1; tester2[ascites]
alk.phosNAcontconttester1; tester2[alk.phos]
-
    +
    1. -databaseStart: the datasets that contain the variable and categories of interest, separated by commas.
    2. +numValidCat: the number of categories for the +recoded variable. This only applies to variables in which the +typeEnd is cat. For continuous variables, +numValidCat = N/A. Note that for categories: not +applicable, missing, and else, are not included in the category count. +This column is not necessary for the function +rec_with_table().
    - - - - - - +++++++++ + + + + + + + + - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - + +
    - -variable - -typeEnd - -typeStart - -databaseStart -
    variabledummyVariabletypeEndtypeStartdatabaseStartvariableStartvariableStartLabel
    -7 - -trt - -cat - -cat - -tester1, tester2 -
    alk.phosNAcontconttester1; tester2[alk.phos]alk.phos
    alk.phosNAcontconttester1; tester2[alk.phos]alk.phos
    ascitesascites_cat3_1catcattester1; tester2[ascites]ascites
    ascitesascites_cat3_2catcattester1; tester2[ascites]ascites
    ascitesascites_cat3_NA::bcatcattester1; tester2[ascites]ascites
    ascitesascites_cat3_NA::acatcattester1; tester2[ascites]ascites
    alk.phosNAcontconttester1; tester2[alk.phos]alk.phos
    -8 - -trt - -cat - -cat - -tester1, tester2 -
    +
      +
    1. +recEnd: the category of the categorical value your +recoding to. For the not applicable category, write NA::a +and for missing and else categories, write NA::b. For +continuous variables that are not recoded in type, you would write in +this column copy so that the function copies the values +without any recoding.
    2. +
    + ++++++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    variabledummyVariabletypeEndtypeStartdatabaseStartvariableStartvariableStartLabelnumValidCat
    alk.phosNAcontconttester1; tester2[alk.phos]alk.phosNA
    alk.phosNAcontconttester1; tester2[alk.phos]alk.phosNA
    ascitesascites_cat3_1catcattester1; tester2[ascites]ascites2
    ascitesascites_cat3_2catcattester1; tester2[ascites]ascites2
    ascitesascites_cat3_NA::bcatcattester1; tester2[ascites]ascites2
    ascitesascites_cat3_NA::acatcattester1; tester2[ascites]ascites2
    alk.phosNAcontconttester1; tester2[alk.phos]alk.phosNA
    -9 - -trt - -cat - -cat - -tester1, tester2 -
    -10 - -trt - -cat - -cat - -tester1, tester2 -
    -11 - -trt - -cat - -cat - -tester1, tester2 -
    -12 - -age - -cont - -cont - -tester1, tester2 -
    -13 - -age - -cont - -cont - -tester1, tester2 -
    -
      -
    1. -variableStart: the original names of the variables as they are listed in the original datasets, separated by commas.
    2. -
    -
      -
    • If the variable name in a particular dataset is different from the recoded variable name, write out the dataset name, add two colons, and write out the original variable name for that dataset.
    • -
    • If the variable name in a particular dataset is the same as the recoded variable name, write the variable name in square brackets. Note: this only needs to be written out once.
    • -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - -variable - -typeEnd - -typeStart - -databaseStart - -variableStart -
    -7 - -trt - -cat - -cat - -tester1, tester2 - -[trt] -
    -8 - -trt - -cat - -cat - -tester1, tester2 - -[trt] -
    -9 - -trt - -cat - -cat - -tester1, tester2 - -[trt] -
    -10 - -trt - -cat - -cat - -tester1, tester2 - -[trt] -
    -11 - -trt - -cat - -cat - -tester1, tester2 - -[trt] -
    -12 - -age - -cont - -cont - -tester1, tester2 - -[age] -
    -13 - -age - -cont - -cont - -tester1, tester2 - -[age] -
    -
      -
    1. -variableStartLabel: short form label describing the original variable.
    2. -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - -variable - -typeEnd - -typeStart - -databaseStart - -variableStart - -variableStartLabel -
    -7 - -trt - -cat - -cat - -tester1, tester2 - -[trt] - -treatment -
    -8 - -trt - -cat - -cat - -tester1, tester2 - -[trt] - -treatment -
    -9 - -trt - -cat - -cat - -tester1, tester2 - -[trt] - -treatment -
    -10 - -trt - -cat - -cat - -tester1, tester2 - -[trt] - -treatment -
    -11 - -trt - -cat - -cat - -tester1, tester2 - -[trt] - -treatment -
    -12 - -age - -cont - -cont - -tester1, tester2 - -[age] - -age -
    -13 - -age - -cont - -cont - -tester1, tester2 - -[age] - -age -
    -
      -
    1. -numValidCat: the number of categories for the recoded variable. This only applies to variables in which the typeEnd is cat. For continuous variables, numValidCat = N/A. Note that for categories: not applicable, missing, and else, are not included in the category count. This column is not necessary for the function rec_with_table().
    2. -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - -variable - -typeEnd - -typeStart - -databaseStart - -variableStart - -variableStartLabel - -numValidCat -
    -7 - -trt - -cat - -cat - -tester1, tester2 - -[trt] - -treatment - -3 -
    -8 - -trt - -cat - -cat - -tester1, tester2 - -[trt] - -treatment - -3 -
    -9 - -trt - -cat - -cat - -tester1, tester2 - -[trt] - -treatment - -3 -
    -10 - -trt - -cat - -cat - -tester1, tester2 - -[trt] - -treatment - -3 -
    -11 - -trt - -cat - -cat - -tester1, tester2 - -[trt] - -treatment - -3 -
    -12 - -age - -cont - -cont - -tester1, tester2 - -[age] - -age - -N/A -
    -13 - -age - -cont - -cont - -tester1, tester2 - -[age] - -age - -N/A -
    -
      -
    1. -recEnd: the category of the categorical value your recoding to. For the not applicable category, write NA::a and for missing and else categories, write NA::b. For continuous variables that are not recoded in type, you would write in this column copy so that the function copies the values without any recoding.
    2. -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - -variable - -typeEnd - -typeStart - -databaseStart - -variableStart - -variableStartLabel - -numValidCat - -recEnd -
    -7 - -trt - -cat - -cat - -tester1, tester2 - -[trt] - -treatment - -3 - -1 -
    -8 - -trt - -cat - -cat - -tester1, tester2 - -[trt] - -treatment - -3 - -2 -
    -9 - -trt - -cat - -cat - -tester1, tester2 - -[trt] - -treatment - -3 - -3 -
    -10 - -trt - -cat - -cat - -tester1, tester2 - -[trt] - -treatment - -3 - -NA::a -
    -11 - -trt - -cat - -cat - -tester1, tester2 - -[trt] - -treatment - -3 - -NA::b -
    -12 - -age - -cont - -cont - -tester1, tester2 - -[age] - -age - -N/A - -copy -
    -13 - -age - -cont - -cont - -tester1, tester2 - -[age] - -age - -N/A - -NA::b -
    -
      -
    • For categorical variables that remain categorical (i.e. from: cat -> to: cat), it is ideal to retain the same values as indicated in the original datasets.
    • -
    • For categorical variables that have changed in type (i.e from: cat -> to: cont), you will have to develop values that make the most sense to your analysis. For example, for variables that change from: cat -> to: cont, you can choose the categories’ lower bound, mid-point, or upper-bound for the continuous value.
    • -
    -
      -
    1. -catLabel: short form label describing the category of a particular variable.
    2. -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - -variable - -typeEnd - -typeStart - -databaseStart - -variableStart - -variableStartLabel - -numValidCat - -recEnd - -catLabel -
    -7 - -trt - -cat - -cat - -tester1, tester2 - -[trt] - -treatment - -3 - -1 - -D-penicillmain -
    -8 - -trt - -cat - -cat - -tester1, tester2 - -[trt] - -treatment - -3 - -2 - -Placebo -
    -9 - -trt - -cat - -cat - -tester1, tester2 - -[trt] - -treatment - -3 - -3 - -none -
    -10 - -trt - -cat - -cat - -tester1, tester2 - -[trt] - -treatment - -3 - -NA::a - -N/A -
    -11 - -trt - -cat - -cat - -tester1, tester2 - -[trt] - -treatment - -3 - -NA::b - -missing -
    -12 - -age - -cont - -cont - -tester1, tester2 - -[age] - -age - -N/A - -copy - -N/A -
    -13 - -age - -cont - -cont - -tester1, tester2 - -[age] - -age - -N/A - -NA::b - -N/A -
    -
      -
    1. -catLabelLong: more detailed label describing the category of a particular variable. This label should be identical to what is recorded in the original data’s documentation (e.g., the exact survey question). For derived variables, you can create your own long label.
    2. -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - -variable - -typeEnd - -typeStart - -databaseStart - -variableStart - -variableStartLabel - -numValidCat - -recEnd - -catLabel - -catLabelLong -
    -7 - -trt - -cat - -cat - -tester1, tester2 - -[trt] - -treatment - -3 - -1 - -D-penicillmain - -D-penicillmain -
    -8 - -trt - -cat - -cat - -tester1, tester2 - -[trt] - -treatment - -3 - -2 - -Placebo - -Placebo -
    -9 - -trt - -cat - -cat - -tester1, tester2 - -[trt] - -treatment - -3 - -3 - -none - -no treatment -
    -10 - -trt - -cat - -cat - -tester1, tester2 - -[trt] - -treatment - -3 - -NA::a - -N/A - -N/A -
    -11 - -trt - -cat - -cat - -tester1, tester2 - -[trt] - -treatment - -3 - -NA::b - -missing - -missing -
    -12 - -age - -cont - -cont - -tester1, tester2 - -[age] - -age - -N/A - -copy - -N/A - -N/A -
    -13 - -age - -cont - -cont - -tester1, tester2 - -[age] - -age - -N/A - -NA::b - -N/A - -N/A -
    -
      -
    1. -units: the units of a particular variable. If there are no units for the variable, write N/A. Note, the function will not work if there different units between the rows of the same variable (e.g. if the concentration of a single molecule has two records one recorded as mg/dl and the other recorded as g/dl).
    2. -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - -variable - -typeEnd - -typeStart - -databaseStart - -variableStart - -variableStartLabel - -numValidCat - -recEnd - -catLabel - -catLabelLong - -units -
    -7 - -trt - -cat - -cat - -tester1, tester2 - -[trt] - -treatment - -3 - -1 - -D-penicillmain - -D-penicillmain - -N/A -
    -8 - -trt - -cat - -cat - -tester1, tester2 - -[trt] - -treatment - -3 - -2 - -Placebo - -Placebo - -N/A -
    -9 - -trt - -cat - -cat - -tester1, tester2 - -[trt] - -treatment - -3 - -3 - -none - -no treatment - -N/A -
    -10 - -trt - -cat - -cat - -tester1, tester2 - -[trt] - -treatment - -3 - -NA::a - -N/A - -N/A - -N/A -
    -11 - -trt - -cat - -cat - -tester1, tester2 - -[trt] - -treatment - -3 - -NA::b - -missing - -missing - -N/A -
    -12 - -age - -cont - -cont - -tester1, tester2 - -[age] - -age - -N/A - -copy - -N/A - -N/A - -years -
    -13 - -age - -cont - -cont - -tester1, tester2 - -[age] - -age - -N/A - -NA::b - -N/A - -N/A - -years -
    -
      -
    1. -recStart: the range of values for a particular category in a variable as indicated in the original data. See data documentation and use the smallest and large values as your range to capture all values across the datasets.
    2. -
    -

    The rules for each category of a new variable are a string in recStart and value in recEnd. These recode pairs are the same syntax as interval notation in which a closed range of values are specified using square brackets. See Notations for intervals for more information on interval notation. Recode pairs are obtained from the recStart and recEnd columns value range is indicated by a comma, e.g. recStart= [1,4]; recEnd = 1 (recodes all values from 1 to 4 into 1} value range for double vectors (with fractional part), all values within the specified range are recoded; e.g. recStart = [1,2.5]; recEnd = 1 recodes 1 to 2.5 into 1, but 2.55 would not be recoded (since it’s not included in the specified range). NA is used for missing values (don’t know, refusal, not stated) else is used all other values, which have not been specified yet, are indicated by else, e.g. recStart = "else"; recEnd = NA (recode all other values (not specified in other rows) to “NA”)} copy the else token can be combined with copy, indicating that all remaining, not yet recoded values should stay the same (are copied from the original value), e.g. recStart = "else"; recEnd = "copy"

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - -variable - -typeEnd - -typeStart - -databaseStart - -variableStart - -variableStartLabel - -numValidCat - -recEnd - -catLabel -
    -7 - -trt - -cat - -cat - -tester1, tester2 - -[trt] - -treatment - -3 - -1 - -D-penicillmain -
    -8 - -trt - -cat - -cat - -tester1, tester2 - -[trt] - -treatment - -3 - -2 - -Placebo -
    -9 - -trt - -cat - -cat - -tester1, tester2 - -[trt] - -treatment - -3 - -3 - -none -
    -10 - -trt - -cat - -cat - -tester1, tester2 - -[trt] - -treatment - -3 - -NA::a - -N/A -
    -11 - -trt - -cat - -cat - -tester1, tester2 - -[trt] - -treatment - -3 - -NA::b - -missing -
    -12 - -age - -cont - -cont - -tester1, tester2 - -[age] - -age - -N/A - -copy - -N/A -
    -13 - -age - -cont - -cont - -tester1, tester2 - -[age] - -age - -N/A - -NA::b - -N/A -
    -
      -
    1. -catStartLabel: label describing each category. This label should be identical to what is shown in the original data documentation. For the missing rows, each missing category is described along with their coded values. You can import labels from a survey’s DDI files using bllflow helper functions. See bllflow documentation.
    2. -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - -variable - -typeEnd - -typeStart - -databaseStart - -variableStart - -variableStartLabel - -numValidCat - -recEnd - -catLabel - -catLabelLong - -units - -recStart - -catStartLabel -
    -7 - -trt - -cat - -cat - -tester1, tester2 - -[trt] - -treatment - -3 - -1 - -D-penicillmain - -D-penicillmain - -N/A - -1 - -D-penicillmain -
    -8 - -trt - -cat - -cat - -tester1, tester2 - -[trt] - -treatment - -3 - -2 - -Placebo - -Placebo - -N/A - -2 - -Placebo -
    -9 - -trt - -cat - -cat - -tester1, tester2 - -[trt] - -treatment - -3 - -3 - -none - -no treatment - -N/A - -3 - -none -
    -10 - -trt - -cat - -cat - -tester1, tester2 - -[trt] - -treatment - -3 - -NA::a - -N/A - -N/A - -N/A - -NA - -N/A -
    -11 - -trt - -cat - -cat - -tester1, tester2 - -[trt] - -treatment - -3 - -NA::b - -missing - -missing - -N/A - -else - -else -
    -12 - -age - -cont - -cont - -tester1, tester2 - -[age] - -age - -N/A - -copy - -N/A - -N/A - -years - -[25,79] - -age -
    -13 - -age - -cont - -cont - -tester1, tester2 - -[age] - -age - -N/A - -NA::b - -N/A - -N/A - -years - -else - -else -
    -
      -
    1. -notes: any relevant notes to inform the user running the recode-with-table function. Things to include here would be changes in wording across datasets, missing/changes in categories, and changes in variable type across datasets.
    2. -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +
    - -variable - -typeEnd - -typeStart - -databaseStart - -variableStart - -variableStartLabel - -numValidCat - -recEnd - -catLabel - -catLabelLong - -units - -recStart - -catStartLabel - -notes -
    -7 - -trt - -cat - -cat - -tester1, tester2 - -[trt] - -treatment - -3 - -1 - -D-penicillmain - -D-penicillmain - -N/A - -1 - -D-penicillmain - -This is sample survival pbc data -
    -8 - -trt - -cat - -cat - -tester1, tester2 - -[trt] - -treatment - -3 - -2 - -Placebo - -Placebo - -N/A - -2 - -Placebo - -This is sample survival pbc data -
    -9 - -trt - -cat - -cat - -tester1, tester2 - -[trt] - -treatment - -3 - -3 - -none - -no treatment - -N/A - -3 - -none - -This is sample survival pbc data -
    +
      +
    • For categorical variables that remain categorical (i.e. from: cat +-> to: cat), it is ideal to retain the same values as indicated in +the original datasets.
    • +
    • For categorical variables that have changed in type (i.e from: cat +-> to: cont), you will have to develop values that make the most +sense to your analysis. For example, for variables that change from: cat +-> to: cont, you can choose the categories’ lower bound, mid-point, +or upper-bound for the continuous value.
    • +
    +
      +
    1. +catLabel: short form label describing the category +of a particular variable.
    2. +
    + +++++++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - + +
    variabledummyVariabletypeEndtypeStartdatabaseStartvariableStartvariableStartLabelnumValidCatrecEnd
    alk.phosNAcontconttester1; tester2[alk.phos]alk.phosNAcopy
    alk.phosNAcontconttester1; tester2[alk.phos]alk.phosNANA::b
    ascitesascites_cat3_1catcattester1; tester2[ascites]ascites20
    ascitesascites_cat3_2catcattester1; tester2[ascites]ascites21
    ascitesascites_cat3_NA::bcatcattester1; tester2[ascites]ascites2NA::b
    ascitesascites_cat3_NA::acatcattester1; tester2[ascites]ascites2NA::a
    alk.phosNAcontconttester1; tester2[alk.phos]alk.phosNANA::a
    -10 - -trt - -cat - -cat - -tester1, tester2 - -[trt] - -treatment - -3 - -NA::a - -N/A - -N/A - -N/A - -NA - -N/A - -This is sample survival pbc data -
    +
      +
    1. +catLabelLong: more detailed label describing the +category of a particular variable. If the category is unchanged from +original data, this label should be identical to what is recorded in the +original data’s documentation (e.g., the exact survey question). For +derived variables, you can create your own long label.
    2. +
    + ++++++++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - + +
    variabledummyVariabletypeEndtypeStartdatabaseStartvariableStartvariableStartLabelnumValidCatrecEndcatLabel
    alk.phosNAcontconttester1; tester2[alk.phos]alk.phosNAcopyNA
    alk.phosNAcontconttester1; tester2[alk.phos]alk.phosNANA::bmissing
    ascitesascites_cat3_1catcattester1; tester2[ascites]ascites20ascites 0
    ascitesascites_cat3_2catcattester1; tester2[ascites]ascites21ascites 1
    ascitesascites_cat3_NA::bcatcattester1; tester2[ascites]ascites2NA::bmissing
    ascitesascites_cat3_NA::acatcattester1; tester2[ascites]ascites2NA::anot applicable
    alk.phosNAcontconttester1; tester2[alk.phos]alk.phosNANA::anot applicable
    -11 - -trt - -cat - -cat - -tester1, tester2 - -[trt] - -treatment - -3 - -NA::b - -missing - -missing - -N/A - -else - -else - -This is sample survival pbc data -
    +
      +
    1. +units: the units of a particular variable. If there +are no units for the variable, write N/A. Note, the +function will not work if there different units between the rows of the +same variable (e.g. if the concentration of a single molecule has two +records one recorded as mg/dl and the other recorded as g/dl).
    2. +
    + +++++++++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - + +
    variabledummyVariabletypeEndtypeStartdatabaseStartvariableStartvariableStartLabelnumValidCatrecEndcatLabelcatLabelLong
    alk.phosNAcontconttester1; tester2[alk.phos]alk.phosNAcopyNANA
    alk.phosNAcontconttester1; tester2[alk.phos]alk.phosNANA::bmissingmissing
    ascitesascites_cat3_1catcattester1; tester2[ascites]ascites20ascites 0ascites 0
    ascitesascites_cat3_2catcattester1; tester2[ascites]ascites21ascites 1ascites 1
    ascitesascites_cat3_NA::bcatcattester1; tester2[ascites]ascites2NA::bmissingmissing
    ascitesascites_cat3_NA::acatcattester1; tester2[ascites]ascites2NA::anot applicablenot applicable
    alk.phosNAcontconttester1; tester2[alk.phos]alk.phosNANA::anot applicablenot applicable
    -12 - -age - -cont - -cont - -tester1, tester2 - -[age] - -age - -N/A - -copy - -N/A - -N/A - -years - -[25,79] - -age - -This is sample survival pbc data -
    +
      +
    1. +recStart: the range of values for a particular +category in a variable as indicated in the original data. See data +documentation and use the smallest and large values as your range to +capture all values across the datasets.
    2. +
    +

    The rules for each category of a new variable are a string in +recStart and value in recEnd. These recode +pairs are the same syntax as interval notation in which a closed range +of values are specified using square brackets. See Notations +for intervals for more information on interval notation. Recode +pairs are obtained from the recStart and recEnd columns value +range is indicated by a comma, +e.g. recStart= [1,4]; recEnd = 1 (recodes all values from 1 +to 4 into 1} value range for double vectors (with fractional +part), all values within the specified range are recoded; +e.g. recStart = [1,2.5]; recEnd = 1 recodes 1 to 2.5 into +1, but 2.55 would not be recoded (since it’s not included in the +specified range). NA is used for missing values (don’t know, +refusal, not stated) else is used all other values, which have +not been specified yet, are indicated by else, +e.g. recStart = "else"; recEnd = NA (recode all other +values (not specified in other rows) to “NA”)} copy the +else token can be combined with copy, +indicating that all remaining, not yet recoded values should stay the +same (are copied from the original value), +e.g. recStart = "else"; recEnd = "copy"

    + +++++++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - + +
    variabledummyVariabletypeEndtypeStartdatabaseStartvariableStartvariableStartLabelnumValidCatrecEnd
    alk.phosNAcontconttester1; tester2[alk.phos]alk.phosNAcopy
    alk.phosNAcontconttester1; tester2[alk.phos]alk.phosNANA::b
    ascitesascites_cat3_1catcattester1; tester2[ascites]ascites20
    ascitesascites_cat3_2catcattester1; tester2[ascites]ascites21
    ascitesascites_cat3_NA::bcatcattester1; tester2[ascites]ascites2NA::b
    ascitesascites_cat3_NA::acatcattester1; tester2[ascites]ascites2NA::a
    alk.phosNAcontconttester1; tester2[alk.phos]alk.phosNANA::a
    -13 - -age - -cont - -cont - -tester1, tester2 - -[age] - -age - -N/A - -NA::b - -N/A - -N/A - -years - -else - -else - -This is sample survival pbc data -
    +
      +
    1. +catStartLabel: label describing each category. This +label should be identical to what is shown in the original data +documentation. For the missing rows, each missing category is described +along with their coded values. You can import labels from a survey’s DDI +files using bllflow helper functions. See bllflow documentation.
    2. +
    + +++++++++++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    variabledummyVariabletypeEndtypeStartdatabaseStartvariableStartvariableStartLabelnumValidCatrecEndcatLabelcatLabelLongunitsrecStart
    alk.phosNAcontconttester1; tester2[alk.phos]alk.phosNAcopyNANANA[200,15000]
    alk.phosNAcontconttester1; tester2[alk.phos]alk.phosNANA::bmissingmissingNAelse
    ascitesascites_cat3_1catcattester1; tester2[ascites]ascites20ascites 0ascites 0NA0
    ascitesascites_cat3_2catcattester1; tester2[ascites]ascites21ascites 1ascites 1NA1
    ascitesascites_cat3_NA::bcatcattester1; tester2[ascites]ascites2NA::bmissingmissingNAelse
    ascitesascites_cat3_NA::acatcattester1; tester2[ascites]ascites2NA::anot applicablenot applicableNA9
    alk.phosNAcontconttester1; tester2[alk.phos]alk.phosNANA::anot applicablenot applicableNA99999
    +
      +
    1. +notes: any relevant notes to inform the user +running the recode-with-table function. Things to include +here would be changes in wording across datasets, missing/changes in +categories, and changes in variable type across datasets.
    2. +
    + ++++++++++++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    variabledummyVariabletypeEndtypeStartdatabaseStartvariableStartvariableStartLabelnumValidCatrecEndcatLabelcatLabelLongunitsrecStartcatStartLabel
    alk.phosNAcontconttester1; tester2[alk.phos]alk.phosNAcopyNANANA[200,15000]NA
    alk.phosNAcontconttester1; tester2[alk.phos]alk.phosNANA::bmissingmissingNAelseNA
    ascitesascites_cat3_1catcattester1; tester2[ascites]ascites20ascites 0ascites 0NA0ascites 0
    ascitesascites_cat3_2catcattester1; tester2[ascites]ascites21ascites 1ascites 1NA1ascites 1
    ascitesascites_cat3_NA::bcatcattester1; tester2[ascites]ascites2NA::bmissingmissingNAelseascites 0
    ascitesascites_cat3_NA::acatcattester1; tester2[ascites]ascites2NA::anot applicablenot applicableNA9not applicable
    alk.phosNAcontconttester1; tester2[alk.phos]alk.phosNANA::anot applicablenot applicableNA99999NA
-
-

-Derived Variables

-

The same naming convention applies to derived variables with the exception of two columns:

+
+

Derived Variables +

+

The same naming convention applies to derived variables with the +exception of two columns:

    -
  1. In variableStart, instead of database names being listed, DerivedVar:: is written followed with the list of original variables used inside square brackets.
  2. +
  3. In variableStart, instead of database names being +listed, DerivedVar:: is written followed with the list +of original variables used inside square brackets.
  • DerivedVar::[var1, var2, var3]
    -
  1. In recEnd, write Func:: followed with the exact name of the custom function used to create the derived variable.
  2. +
  3. In recEnd, write Func:: followed +with the exact name of the custom function used to create the derived +variable.
  • Func::derivedFunction
-

A derived variable looks like this in variable_details.csv

+

A derived variable looks like this in +variable_details.csv

+ ++++++++++++++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
variabledummyVariabletypeEndtypeStartdatabaseStartvariableStartvariableStartLabelnumValidCatrecEndcatLabelcatLabelLongunitsrecStartcatStartLabelvariableStartShortLabelnotes
example_derNAcontconttester1; tester2DerivedVar::[chol, bili]example_derNAFunc::example_der_funN/AN/ANAelseN/Aexample_derA test derived variable
+
+
+

Tables +

+

Certain derived variables may need information from a reference table +to complete their derivation. For example, imagine a derived variable +that has the average sodium consumption for an individual specific to +the individual’s age and sex. It makes sense to put this information in +a table that maps the individual’s age and sex to their sodium +consumption like below,

- - - - - - - - - - - - - - - - + + + + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + +
- -variable - -typeEnd - -typeStart - -databaseStart - -variableStart - -variableStartLabel - -numValidCat - -recEnd - -catLabel - -catLabelLong - -units - -recStart - -catStartLabel - -notes -
agesexsodium_consumption
-64 - -example_der - -cont - -cont - -tester1, tester2 - -DerivedVar::[chol, bili] - -example_der - -N/A - -Func::example_der_fun - -N/A - -N/A - -mg/dl - -else - -N/A - -This is sample survival pbc data -
18male1800
18male1500
19female2100
19female1600
+

with the derivation function shown below,

+
+sodium_consumption <- function(age, sex, reference_table) {
+  return(reference_table[reference_table$age == age & reference_table$sex == sex, ]$sodium_consumption)
+}
+

The reference_table argument in the above function expects a data +frame.

+

Including a table in the start variables for a derived variable can +be done using the syntax, tables::<table_name> where + should be replaced with the name of the +table. For the sodium_consumption derived variable, the +entry in the variables sheet would be,

+ ++++++++++++ + + + + + + + + + + + + + + + + + + + + + + +
variabletypeEnddatabaseStartvariableStarttypeStartrecEndnumValidCategoriesrecStartcatLabelcatLabelLong
sodium_consumptioncontdatabase_oneDerivedVar::[age, sex, +tables::sodium_reference_table]N/AFunc::sodium_consumptionN/AN/A
+

When using the rec_with_table function, the +tables argument can be used to include all the tables +mentioned in the variables sheet.

+ +
-

Site built with pkgdown 1.6.1.

+

+

Site built with pkgdown 2.1.1.

- + + + diff --git a/docs/articles/variable_details_files/crosstalk-1.2.1/css/crosstalk.min.css b/docs/articles/variable_details_files/crosstalk-1.2.1/css/crosstalk.min.css new file mode 100644 index 00000000..6b453828 --- /dev/null +++ b/docs/articles/variable_details_files/crosstalk-1.2.1/css/crosstalk.min.css @@ -0,0 +1 @@ +.container-fluid.crosstalk-bscols{margin-left:-30px;margin-right:-30px;white-space:normal}body>.container-fluid.crosstalk-bscols{margin-left:auto;margin-right:auto}.crosstalk-input-checkboxgroup .crosstalk-options-group .crosstalk-options-column{display:inline-block;padding-right:12px;vertical-align:top}@media only screen and (max-width: 480px){.crosstalk-input-checkboxgroup .crosstalk-options-group .crosstalk-options-column{display:block;padding-right:inherit}}.crosstalk-input{margin-bottom:15px}.crosstalk-input .control-label{margin-bottom:0;vertical-align:middle}.crosstalk-input input[type="checkbox"]{margin:4px 0 0;margin-top:1px;line-height:normal}.crosstalk-input .checkbox{position:relative;display:block;margin-top:10px;margin-bottom:10px}.crosstalk-input .checkbox>label{padding-left:20px;margin-bottom:0;font-weight:400;cursor:pointer}.crosstalk-input .checkbox input[type="checkbox"],.crosstalk-input .checkbox-inline input[type="checkbox"]{position:absolute;margin-top:2px;margin-left:-20px}.crosstalk-input .checkbox+.checkbox{margin-top:-5px}.crosstalk-input .checkbox-inline{position:relative;display:inline-block;padding-left:20px;margin-bottom:0;font-weight:400;vertical-align:middle;cursor:pointer}.crosstalk-input .checkbox-inline+.checkbox-inline{margin-top:0;margin-left:10px} diff --git a/docs/articles/variable_details_files/crosstalk-1.2.1/js/crosstalk.js b/docs/articles/variable_details_files/crosstalk-1.2.1/js/crosstalk.js new file mode 100644 index 00000000..fd9eb53d --- /dev/null +++ b/docs/articles/variable_details_files/crosstalk-1.2.1/js/crosstalk.js @@ -0,0 +1,1474 @@ +(function(){function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o b) { + return 1; + } +} + +/** + * @private + */ + +var FilterSet = function () { + function FilterSet() { + _classCallCheck(this, FilterSet); + + this.reset(); + } + + _createClass(FilterSet, [{ + key: "reset", + value: function reset() { + // Key: handle ID, Value: array of selected keys, or null + this._handles = {}; + // Key: key string, Value: count of handles that include it + this._keys = {}; + this._value = null; + this._activeHandles = 0; + } + }, { + key: "update", + value: function update(handleId, keys) { + if (keys !== null) { + keys = keys.slice(0); // clone before sorting + keys.sort(naturalComparator); + } + + var _diffSortedLists = (0, _util.diffSortedLists)(this._handles[handleId], keys), + added = _diffSortedLists.added, + removed = _diffSortedLists.removed; + + this._handles[handleId] = keys; + + for (var i = 0; i < added.length; i++) { + this._keys[added[i]] = (this._keys[added[i]] || 0) + 1; + } + for (var _i = 0; _i < removed.length; _i++) { + this._keys[removed[_i]]--; + } + + this._updateValue(keys); + } + + /** + * @param {string[]} keys Sorted array of strings that indicate + * a superset of possible keys. + * @private + */ + + }, { + key: "_updateValue", + value: function _updateValue() { + var keys = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this._allKeys; + + var handleCount = Object.keys(this._handles).length; + if (handleCount === 0) { + this._value = null; + } else { + this._value = []; + for (var i = 0; i < keys.length; i++) { + var count = this._keys[keys[i]]; + if (count === handleCount) { + this._value.push(keys[i]); + } + } + } + } + }, { + key: "clear", + value: function clear(handleId) { + if (typeof this._handles[handleId] === "undefined") { + return; + } + + var keys = this._handles[handleId]; + if (!keys) { + keys = []; + } + + for (var i = 0; i < keys.length; i++) { + this._keys[keys[i]]--; + } + delete this._handles[handleId]; + + this._updateValue(); + } + }, { + key: "value", + get: function get() { + return this._value; + } + }, { + key: "_allKeys", + get: function get() { + var allKeys = Object.keys(this._keys); + allKeys.sort(naturalComparator); + return allKeys; + } + }]); + + return FilterSet; +}(); + +exports.default = FilterSet; + +},{"./util":11}],4:[function(require,module,exports){ +(function (global){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; + +exports.default = group; + +var _var2 = require("./var"); + +var _var3 = _interopRequireDefault(_var2); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +// Use a global so that multiple copies of crosstalk.js can be loaded and still +// have groups behave as singletons across all copies. +global.__crosstalk_groups = global.__crosstalk_groups || {}; +var groups = global.__crosstalk_groups; + +function group(groupName) { + if (groupName && typeof groupName === "string") { + if (!groups.hasOwnProperty(groupName)) { + groups[groupName] = new Group(groupName); + } + return groups[groupName]; + } else if ((typeof groupName === "undefined" ? "undefined" : _typeof(groupName)) === "object" && groupName._vars && groupName.var) { + // Appears to already be a group object + return groupName; + } else if (Array.isArray(groupName) && groupName.length == 1 && typeof groupName[0] === "string") { + return group(groupName[0]); + } else { + throw new Error("Invalid groupName argument"); + } +} + +var Group = function () { + function Group(name) { + _classCallCheck(this, Group); + + this.name = name; + this._vars = {}; + } + + _createClass(Group, [{ + key: "var", + value: function _var(name) { + if (!name || typeof name !== "string") { + throw new Error("Invalid var name"); + } + + if (!this._vars.hasOwnProperty(name)) this._vars[name] = new _var3.default(this, name); + return this._vars[name]; + } + }, { + key: "has", + value: function has(name) { + if (!name || typeof name !== "string") { + throw new Error("Invalid var name"); + } + + return this._vars.hasOwnProperty(name); + } + }]); + + return Group; +}(); + +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) + +},{"./var":12}],5:[function(require,module,exports){ +(function (global){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _group = require("./group"); + +var _group2 = _interopRequireDefault(_group); + +var _selection = require("./selection"); + +var _filter = require("./filter"); + +var _input = require("./input"); + +require("./input_selectize"); + +require("./input_checkboxgroup"); + +require("./input_slider"); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +var defaultGroup = (0, _group2.default)("default"); + +function var_(name) { + return defaultGroup.var(name); +} + +function has(name) { + return defaultGroup.has(name); +} + +if (global.Shiny) { + global.Shiny.addCustomMessageHandler("update-client-value", function (message) { + if (typeof message.group === "string") { + (0, _group2.default)(message.group).var(message.name).set(message.value); + } else { + var_(message.name).set(message.value); + } + }); +} + +var crosstalk = { + group: _group2.default, + var: var_, + has: has, + SelectionHandle: _selection.SelectionHandle, + FilterHandle: _filter.FilterHandle, + bind: _input.bind +}; + +/** + * @namespace crosstalk + */ +exports.default = crosstalk; + +global.crosstalk = crosstalk; + +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) + +},{"./filter":2,"./group":4,"./input":6,"./input_checkboxgroup":7,"./input_selectize":8,"./input_slider":9,"./selection":10}],6:[function(require,module,exports){ +(function (global){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.register = register; +exports.bind = bind; +var $ = global.jQuery; + +var bindings = {}; + +function register(reg) { + bindings[reg.className] = reg; + if (global.document && global.document.readyState !== "complete") { + $(function () { + bind(); + }); + } else if (global.document) { + setTimeout(bind, 100); + } +} + +function bind() { + Object.keys(bindings).forEach(function (className) { + var binding = bindings[className]; + $("." + binding.className).not(".crosstalk-input-bound").each(function (i, el) { + bindInstance(binding, el); + }); + }); +} + +// Escape jQuery identifier +function $escape(val) { + return val.replace(/([!"#$%&'()*+,./:;<=>?@[\\\]^`{|}~])/g, "\\$1"); +} + +function bindEl(el) { + var $el = $(el); + Object.keys(bindings).forEach(function (className) { + if ($el.hasClass(className) && !$el.hasClass("crosstalk-input-bound")) { + var binding = bindings[className]; + bindInstance(binding, el); + } + }); +} + +function bindInstance(binding, el) { + var jsonEl = $(el).find("script[type='application/json'][data-for='" + $escape(el.id) + "']"); + var data = JSON.parse(jsonEl[0].innerText); + + var instance = binding.factory(el, data); + $(el).data("crosstalk-instance", instance); + $(el).addClass("crosstalk-input-bound"); +} + +if (global.Shiny) { + var inputBinding = new global.Shiny.InputBinding(); + var _$ = global.jQuery; + _$.extend(inputBinding, { + find: function find(scope) { + return _$(scope).find(".crosstalk-input"); + }, + initialize: function initialize(el) { + if (!_$(el).hasClass("crosstalk-input-bound")) { + bindEl(el); + } + }, + getId: function getId(el) { + return el.id; + }, + getValue: function getValue(el) {}, + setValue: function setValue(el, value) {}, + receiveMessage: function receiveMessage(el, data) {}, + subscribe: function subscribe(el, callback) { + _$(el).data("crosstalk-instance").resume(); + }, + unsubscribe: function unsubscribe(el) { + _$(el).data("crosstalk-instance").suspend(); + } + }); + global.Shiny.inputBindings.register(inputBinding, "crosstalk.inputBinding"); +} + +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) + +},{}],7:[function(require,module,exports){ +(function (global){ +"use strict"; + +var _input = require("./input"); + +var input = _interopRequireWildcard(_input); + +var _filter = require("./filter"); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +var $ = global.jQuery; + +input.register({ + className: "crosstalk-input-checkboxgroup", + + factory: function factory(el, data) { + /* + * map: {"groupA": ["keyA", "keyB", ...], ...} + * group: "ct-groupname" + */ + var ctHandle = new _filter.FilterHandle(data.group); + + var lastKnownKeys = void 0; + var $el = $(el); + $el.on("change", "input[type='checkbox']", function () { + var checked = $el.find("input[type='checkbox']:checked"); + if (checked.length === 0) { + lastKnownKeys = null; + ctHandle.clear(); + } else { + var keys = {}; + checked.each(function () { + data.map[this.value].forEach(function (key) { + keys[key] = true; + }); + }); + var keyArray = Object.keys(keys); + keyArray.sort(); + lastKnownKeys = keyArray; + ctHandle.set(keyArray); + } + }); + + return { + suspend: function suspend() { + ctHandle.clear(); + }, + resume: function resume() { + if (lastKnownKeys) ctHandle.set(lastKnownKeys); + } + }; + } +}); + +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) + +},{"./filter":2,"./input":6}],8:[function(require,module,exports){ +(function (global){ +"use strict"; + +var _input = require("./input"); + +var input = _interopRequireWildcard(_input); + +var _util = require("./util"); + +var util = _interopRequireWildcard(_util); + +var _filter = require("./filter"); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +var $ = global.jQuery; + +input.register({ + className: "crosstalk-input-select", + + factory: function factory(el, data) { + /* + * items: {value: [...], label: [...]} + * map: {"groupA": ["keyA", "keyB", ...], ...} + * group: "ct-groupname" + */ + + var first = [{ value: "", label: "(All)" }]; + var items = util.dataframeToD3(data.items); + var opts = { + options: first.concat(items), + valueField: "value", + labelField: "label", + searchField: "label" + }; + + var select = $(el).find("select")[0]; + + var selectize = $(select).selectize(opts)[0].selectize; + + var ctHandle = new _filter.FilterHandle(data.group); + + var lastKnownKeys = void 0; + selectize.on("change", function () { + if (selectize.items.length === 0) { + lastKnownKeys = null; + ctHandle.clear(); + } else { + var keys = {}; + selectize.items.forEach(function (group) { + data.map[group].forEach(function (key) { + keys[key] = true; + }); + }); + var keyArray = Object.keys(keys); + keyArray.sort(); + lastKnownKeys = keyArray; + ctHandle.set(keyArray); + } + }); + + return { + suspend: function suspend() { + ctHandle.clear(); + }, + resume: function resume() { + if (lastKnownKeys) ctHandle.set(lastKnownKeys); + } + }; + } +}); + +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) + +},{"./filter":2,"./input":6,"./util":11}],9:[function(require,module,exports){ +(function (global){ +"use strict"; + +var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }(); + +var _input = require("./input"); + +var input = _interopRequireWildcard(_input); + +var _filter = require("./filter"); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +var $ = global.jQuery; +var strftime = global.strftime; + +input.register({ + className: "crosstalk-input-slider", + + factory: function factory(el, data) { + /* + * map: {"groupA": ["keyA", "keyB", ...], ...} + * group: "ct-groupname" + */ + var ctHandle = new _filter.FilterHandle(data.group); + + var opts = {}; + var $el = $(el).find("input"); + var dataType = $el.data("data-type"); + var timeFormat = $el.data("time-format"); + var round = $el.data("round"); + var timeFormatter = void 0; + + // Set up formatting functions + if (dataType === "date") { + timeFormatter = strftime.utc(); + opts.prettify = function (num) { + return timeFormatter(timeFormat, new Date(num)); + }; + } else if (dataType === "datetime") { + var timezone = $el.data("timezone"); + if (timezone) timeFormatter = strftime.timezone(timezone);else timeFormatter = strftime; + + opts.prettify = function (num) { + return timeFormatter(timeFormat, new Date(num)); + }; + } else if (dataType === "number") { + if (typeof round !== "undefined") opts.prettify = function (num) { + var factor = Math.pow(10, round); + return Math.round(num * factor) / factor; + }; + } + + $el.ionRangeSlider(opts); + + function getValue() { + var result = $el.data("ionRangeSlider").result; + + // Function for converting numeric value from slider to appropriate type. + var convert = void 0; + var dataType = $el.data("data-type"); + if (dataType === "date") { + convert = function convert(val) { + return formatDateUTC(new Date(+val)); + }; + } else if (dataType === "datetime") { + convert = function convert(val) { + // Convert ms to s + return +val / 1000; + }; + } else { + convert = function convert(val) { + return +val; + }; + } + + if ($el.data("ionRangeSlider").options.type === "double") { + return [convert(result.from), convert(result.to)]; + } else { + return convert(result.from); + } + } + + var lastKnownKeys = null; + + $el.on("change.crosstalkSliderInput", function (event) { + if (!$el.data("updating") && !$el.data("animating")) { + var _getValue = getValue(), + _getValue2 = _slicedToArray(_getValue, 2), + from = _getValue2[0], + to = _getValue2[1]; + + var keys = []; + for (var i = 0; i < data.values.length; i++) { + var val = data.values[i]; + if (val >= from && val <= to) { + keys.push(data.keys[i]); + } + } + keys.sort(); + ctHandle.set(keys); + lastKnownKeys = keys; + } + }); + + // let $el = $(el); + // $el.on("change", "input[type="checkbox"]", function() { + // let checked = $el.find("input[type="checkbox"]:checked"); + // if (checked.length === 0) { + // ctHandle.clear(); + // } else { + // let keys = {}; + // checked.each(function() { + // data.map[this.value].forEach(function(key) { + // keys[key] = true; + // }); + // }); + // let keyArray = Object.keys(keys); + // keyArray.sort(); + // ctHandle.set(keyArray); + // } + // }); + + return { + suspend: function suspend() { + ctHandle.clear(); + }, + resume: function resume() { + if (lastKnownKeys) ctHandle.set(lastKnownKeys); + } + }; + } +}); + +// Convert a number to a string with leading zeros +function padZeros(n, digits) { + var str = n.toString(); + while (str.length < digits) { + str = "0" + str; + }return str; +} + +// Given a Date object, return a string in yyyy-mm-dd format, using the +// UTC date. This may be a day off from the date in the local time zone. +function formatDateUTC(date) { + if (date instanceof Date) { + return date.getUTCFullYear() + "-" + padZeros(date.getUTCMonth() + 1, 2) + "-" + padZeros(date.getUTCDate(), 2); + } else { + return null; + } +} + +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) + +},{"./filter":2,"./input":6}],10:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.SelectionHandle = undefined; + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _events = require("./events"); + +var _events2 = _interopRequireDefault(_events); + +var _group = require("./group"); + +var _group2 = _interopRequireDefault(_group); + +var _util = require("./util"); + +var util = _interopRequireWildcard(_util); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +/** + * Use this class to read and write (and listen for changes to) the selection + * for a Crosstalk group. This is intended to be used for linked brushing. + * + * If two (or more) `SelectionHandle` instances in the same webpage share the + * same group name, they will share the same state. Setting the selection using + * one `SelectionHandle` instance will result in the `value` property instantly + * changing across the others, and `"change"` event listeners on all instances + * (including the one that initiated the sending) will fire. + * + * @param {string} [group] - The name of the Crosstalk group, or if none, + * null or undefined (or any other falsy value). This can be changed later + * via the [SelectionHandle#setGroup](#setGroup) method. + * @param {Object} [extraInfo] - An object whose properties will be copied to + * the event object whenever an event is emitted. + */ +var SelectionHandle = exports.SelectionHandle = function () { + function SelectionHandle() { + var group = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null; + var extraInfo = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; + + _classCallCheck(this, SelectionHandle); + + this._eventRelay = new _events2.default(); + this._emitter = new util.SubscriptionTracker(this._eventRelay); + + // Name of the group we're currently tracking, if any. Can change over time. + this._group = null; + // The Var we're currently tracking, if any. Can change over time. + this._var = null; + // The event handler subscription we currently have on var.on("change"). + this._varOnChangeSub = null; + + this._extraInfo = util.extend({ sender: this }, extraInfo); + + this.setGroup(group); + } + + /** + * Changes the Crosstalk group membership of this SelectionHandle. The group + * being switched away from (if any) will not have its selection value + * modified as a result of calling `setGroup`, even if this handle was the + * most recent handle to set the selection of the group. + * + * The group being switched to (if any) will also not have its selection value + * modified as a result of calling `setGroup`. If you want to set the + * selection value of the new group, call `set` explicitly. + * + * @param {string} group - The name of the Crosstalk group, or null (or + * undefined) to clear the group. + */ + + + _createClass(SelectionHandle, [{ + key: "setGroup", + value: function setGroup(group) { + var _this = this; + + // If group is unchanged, do nothing + if (this._group === group) return; + // Treat null, undefined, and other falsy values the same + if (!this._group && !group) return; + + if (this._var) { + this._var.off("change", this._varOnChangeSub); + this._var = null; + this._varOnChangeSub = null; + } + + this._group = group; + + if (group) { + this._var = (0, _group2.default)(group).var("selection"); + var sub = this._var.on("change", function (e) { + _this._eventRelay.trigger("change", e, _this); + }); + this._varOnChangeSub = sub; + } + } + + /** + * Retrieves the current selection for the group represented by this + * `SelectionHandle`. + * + * - If no selection is active, then this value will be falsy. + * - If a selection is active, but no data points are selected, then this + * value will be an empty array. + * - If a selection is active, and data points are selected, then the keys + * of the selected data points will be present in the array. + */ + + }, { + key: "_mergeExtraInfo", + + + /** + * Combines the given `extraInfo` (if any) with the handle's default + * `_extraInfo` (if any). + * @private + */ + value: function _mergeExtraInfo(extraInfo) { + // Important incidental effect: shallow clone is returned + return util.extend({}, this._extraInfo ? this._extraInfo : null, extraInfo ? extraInfo : null); + } + + /** + * Overwrites the current selection for the group, and raises the `"change"` + * event among all of the group's '`SelectionHandle` instances (including + * this one). + * + * @fires SelectionHandle#change + * @param {string[]} selectedKeys - Falsy, empty array, or array of keys (see + * {@link SelectionHandle#value}). + * @param {Object} [extraInfo] - Extra properties to be included on the event + * object that's passed to listeners (in addition to any options that were + * passed into the `SelectionHandle` constructor). + */ + + }, { + key: "set", + value: function set(selectedKeys, extraInfo) { + if (this._var) this._var.set(selectedKeys, this._mergeExtraInfo(extraInfo)); + } + + /** + * Overwrites the current selection for the group, and raises the `"change"` + * event among all of the group's '`SelectionHandle` instances (including + * this one). + * + * @fires SelectionHandle#change + * @param {Object} [extraInfo] - Extra properties to be included on the event + * object that's passed to listeners (in addition to any that were passed + * into the `SelectionHandle` constructor). + */ + + }, { + key: "clear", + value: function clear(extraInfo) { + if (this._var) this.set(void 0, this._mergeExtraInfo(extraInfo)); + } + + /** + * Subscribes to events on this `SelectionHandle`. + * + * @param {string} eventType - Indicates the type of events to listen to. + * Currently, only `"change"` is supported. + * @param {SelectionHandle~listener} listener - The callback function that + * will be invoked when the event occurs. + * @return {string} - A token to pass to {@link SelectionHandle#off} to cancel + * this subscription. + */ + + }, { + key: "on", + value: function on(eventType, listener) { + return this._emitter.on(eventType, listener); + } + + /** + * Cancels event subscriptions created by {@link SelectionHandle#on}. + * + * @param {string} eventType - The type of event to unsubscribe. + * @param {string|SelectionHandle~listener} listener - Either the callback + * function previously passed into {@link SelectionHandle#on}, or the + * string that was returned from {@link SelectionHandle#on}. + */ + + }, { + key: "off", + value: function off(eventType, listener) { + return this._emitter.off(eventType, listener); + } + + /** + * Shuts down the `SelectionHandle` object. + * + * Removes all event listeners that were added through this handle. + */ + + }, { + key: "close", + value: function close() { + this._emitter.removeAllListeners(); + this.setGroup(null); + } + }, { + key: "value", + get: function get() { + return this._var ? this._var.get() : null; + } + }]); + + return SelectionHandle; +}(); + +/** + * @callback SelectionHandle~listener + * @param {Object} event - An object containing details of the event. For + * `"change"` events, this includes the properties `value` (the new + * value of the selection, or `undefined` if no selection is active), + * `oldValue` (the previous value of the selection), and `sender` (the + * `SelectionHandle` instance that made the change). + */ + +/** + * @event SelectionHandle#change + * @type {object} + * @property {object} value - The new value of the selection, or `undefined` + * if no selection is active. + * @property {object} oldValue - The previous value of the selection. + * @property {SelectionHandle} sender - The `SelectionHandle` instance that + * changed the value. + */ + +},{"./events":1,"./group":4,"./util":11}],11:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; + +exports.extend = extend; +exports.checkSorted = checkSorted; +exports.diffSortedLists = diffSortedLists; +exports.dataframeToD3 = dataframeToD3; + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function extend(target) { + for (var _len = arguments.length, sources = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { + sources[_key - 1] = arguments[_key]; + } + + for (var i = 0; i < sources.length; i++) { + var src = sources[i]; + if (typeof src === "undefined" || src === null) continue; + + for (var key in src) { + if (src.hasOwnProperty(key)) { + target[key] = src[key]; + } + } + } + return target; +} + +function checkSorted(list) { + for (var i = 1; i < list.length; i++) { + if (list[i] <= list[i - 1]) { + throw new Error("List is not sorted or contains duplicate"); + } + } +} + +function diffSortedLists(a, b) { + var i_a = 0; + var i_b = 0; + + if (!a) a = []; + if (!b) b = []; + + var a_only = []; + var b_only = []; + + checkSorted(a); + checkSorted(b); + + while (i_a < a.length && i_b < b.length) { + if (a[i_a] === b[i_b]) { + i_a++; + i_b++; + } else if (a[i_a] < b[i_b]) { + a_only.push(a[i_a++]); + } else { + b_only.push(b[i_b++]); + } + } + + if (i_a < a.length) a_only = a_only.concat(a.slice(i_a)); + if (i_b < b.length) b_only = b_only.concat(b.slice(i_b)); + return { + removed: a_only, + added: b_only + }; +} + +// Convert from wide: { colA: [1,2,3], colB: [4,5,6], ... } +// to long: [ {colA: 1, colB: 4}, {colA: 2, colB: 5}, ... ] +function dataframeToD3(df) { + var names = []; + var length = void 0; + for (var name in df) { + if (df.hasOwnProperty(name)) names.push(name); + if (_typeof(df[name]) !== "object" || typeof df[name].length === "undefined") { + throw new Error("All fields must be arrays"); + } else if (typeof length !== "undefined" && length !== df[name].length) { + throw new Error("All fields must be arrays of the same length"); + } + length = df[name].length; + } + var results = []; + var item = void 0; + for (var row = 0; row < length; row++) { + item = {}; + for (var col = 0; col < names.length; col++) { + item[names[col]] = df[names[col]][row]; + } + results.push(item); + } + return results; +} + +/** + * Keeps track of all event listener additions/removals and lets all active + * listeners be removed with a single operation. + * + * @private + */ + +var SubscriptionTracker = exports.SubscriptionTracker = function () { + function SubscriptionTracker(emitter) { + _classCallCheck(this, SubscriptionTracker); + + this._emitter = emitter; + this._subs = {}; + } + + _createClass(SubscriptionTracker, [{ + key: "on", + value: function on(eventType, listener) { + var sub = this._emitter.on(eventType, listener); + this._subs[sub] = eventType; + return sub; + } + }, { + key: "off", + value: function off(eventType, listener) { + var sub = this._emitter.off(eventType, listener); + if (sub) { + delete this._subs[sub]; + } + return sub; + } + }, { + key: "removeAllListeners", + value: function removeAllListeners() { + var _this = this; + + var current_subs = this._subs; + this._subs = {}; + Object.keys(current_subs).forEach(function (sub) { + _this._emitter.off(current_subs[sub], sub); + }); + } + }]); + + return SubscriptionTracker; +}(); + +},{}],12:[function(require,module,exports){ +(function (global){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _events = require("./events"); + +var _events2 = _interopRequireDefault(_events); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +var Var = function () { + function Var(group, name, /*optional*/value) { + _classCallCheck(this, Var); + + this._group = group; + this._name = name; + this._value = value; + this._events = new _events2.default(); + } + + _createClass(Var, [{ + key: "get", + value: function get() { + return this._value; + } + }, { + key: "set", + value: function set(value, /*optional*/event) { + if (this._value === value) { + // Do nothing; the value hasn't changed + return; + } + var oldValue = this._value; + this._value = value; + // Alert JavaScript listeners that the value has changed + var evt = {}; + if (event && (typeof event === "undefined" ? "undefined" : _typeof(event)) === "object") { + for (var k in event) { + if (event.hasOwnProperty(k)) evt[k] = event[k]; + } + } + evt.oldValue = oldValue; + evt.value = value; + this._events.trigger("change", evt, this); + + // TODO: Make this extensible, to let arbitrary back-ends know that + // something has changed + if (global.Shiny && global.Shiny.onInputChange) { + global.Shiny.onInputChange(".clientValue-" + (this._group.name !== null ? this._group.name + "-" : "") + this._name, typeof value === "undefined" ? null : value); + } + } + }, { + key: "on", + value: function on(eventType, listener) { + return this._events.on(eventType, listener); + } + }, { + key: "off", + value: function off(eventType, listener) { + return this._events.off(eventType, listener); + } + }]); + + return Var; +}(); + +exports.default = Var; + +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) + +},{"./events":1}]},{},[5]) +//# sourceMappingURL=crosstalk.js.map diff --git a/docs/articles/variable_details_files/crosstalk-1.2.1/js/crosstalk.js.map b/docs/articles/variable_details_files/crosstalk-1.2.1/js/crosstalk.js.map new file mode 100644 index 00000000..cff94f08 --- /dev/null +++ b/docs/articles/variable_details_files/crosstalk-1.2.1/js/crosstalk.js.map @@ -0,0 +1,37 @@ +{ + "version": 3, + "sources": [ + "node_modules/browser-pack/_prelude.js", + "javascript/src/events.js", + "javascript/src/filter.js", + "javascript/src/filterset.js", + "javascript/src/group.js", + "javascript/src/index.js", + "javascript/src/input.js", + "javascript/src/input_checkboxgroup.js", + "javascript/src/input_selectize.js", + "javascript/src/input_slider.js", + "javascript/src/selection.js", + "javascript/src/util.js", + "javascript/src/var.js" + ], + "names": [], + "mappings": "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", + "file": "generated.js", + "sourceRoot": "", + "sourcesContent": [ + "(function(){function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require==\"function\"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error(\"Cannot find module '\"+o+\"'\");throw f.code=\"MODULE_NOT_FOUND\",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require==\"function\"&&require;for(var o=0;o {\n this._eventRelay.trigger(\"change\", e, this);\n });\n this._varOnChangeSub = sub;\n }\n }\n\n /**\n * Combine the given `extraInfo` (if any) with the handle's default\n * `_extraInfo` (if any).\n * @private\n */\n _mergeExtraInfo(extraInfo) {\n return util.extend({},\n this._extraInfo ? this._extraInfo : null,\n extraInfo ? extraInfo : null);\n }\n\n /**\n * Close the handle. This clears this handle's contribution to the filter set,\n * and unsubscribes all event listeners.\n */\n close() {\n this._emitter.removeAllListeners();\n this.clear();\n this.setGroup(null);\n }\n\n /**\n * Clear this handle's contribution to the filter set.\n *\n * @param {Object} [extraInfo] - Extra properties to be included on the event\n * object that's passed to listeners (in addition to any options that were\n * passed into the `FilterHandle` constructor).\n * \n * @fires FilterHandle#change\n */\n clear(extraInfo) {\n if (!this._filterSet)\n return;\n this._filterSet.clear(this._id);\n this._onChange(extraInfo);\n }\n\n /**\n * Set this handle's contribution to the filter set. This array should consist\n * of the keys of the rows that _should_ be displayed; any keys that are not\n * present in the array will be considered _filtered out_. Note that multiple\n * `FilterHandle` instances in the group may each contribute an array of keys,\n * and only those keys that appear in _all_ of the arrays make it through the\n * filter.\n *\n * @param {string[]} keys - Empty array, or array of keys. To clear the\n * filter, don't pass an empty array; instead, use the\n * {@link FilterHandle#clear} method.\n * @param {Object} [extraInfo] - Extra properties to be included on the event\n * object that's passed to listeners (in addition to any options that were\n * passed into the `FilterHandle` constructor).\n * \n * @fires FilterHandle#change\n */\n set(keys, extraInfo) {\n if (!this._filterSet)\n return;\n this._filterSet.update(this._id, keys);\n this._onChange(extraInfo);\n }\n\n /**\n * @return {string[]|null} - Either: 1) an array of keys that made it through\n * all of the `FilterHandle` instances, or, 2) `null`, which means no filter\n * is being applied (all data should be displayed).\n */\n get filteredKeys() {\n return this._filterSet ? this._filterSet.value : null;\n }\n\n /**\n * Subscribe to events on this `FilterHandle`.\n *\n * @param {string} eventType - Indicates the type of events to listen to.\n * Currently, only `\"change\"` is supported.\n * @param {FilterHandle~listener} listener - The callback function that\n * will be invoked when the event occurs.\n * @return {string} - A token to pass to {@link FilterHandle#off} to cancel\n * this subscription.\n */\n on(eventType, listener) {\n return this._emitter.on(eventType, listener);\n }\n\n /**\n * Cancel event subscriptions created by {@link FilterHandle#on}.\n *\n * @param {string} eventType - The type of event to unsubscribe.\n * @param {string|FilterHandle~listener} listener - Either the callback\n * function previously passed into {@link FilterHandle#on}, or the\n * string that was returned from {@link FilterHandle#on}.\n */\n off(eventType, listener) {\n return this._emitter.off(eventType, listener);\n }\n\n _onChange(extraInfo) {\n if (!this._filterSet)\n return;\n this._filterVar.set(this._filterSet.value, this._mergeExtraInfo(extraInfo));\n }\n\n /**\n * @callback FilterHandle~listener\n * @param {Object} event - An object containing details of the event. For\n * `\"change\"` events, this includes the properties `value` (the new\n * value of the filter set, or `null` if no filter set is active),\n * `oldValue` (the previous value of the filter set), and `sender` (the\n * `FilterHandle` instance that made the change).\n */\n\n}\n\n/**\n * @event FilterHandle#change\n * @type {object}\n * @property {object} value - The new value of the filter set, or `null`\n * if no filter set is active.\n * @property {object} oldValue - The previous value of the filter set.\n * @property {FilterHandle} sender - The `FilterHandle` instance that\n * changed the value.\n */\n", + "import { diffSortedLists } from \"./util\";\n\nfunction naturalComparator(a, b) {\n if (a === b) {\n return 0;\n } else if (a < b) {\n return -1;\n } else if (a > b) {\n return 1;\n }\n}\n\n/**\n * @private\n */\nexport default class FilterSet {\n constructor() {\n this.reset();\n }\n\n reset() {\n // Key: handle ID, Value: array of selected keys, or null\n this._handles = {};\n // Key: key string, Value: count of handles that include it\n this._keys = {};\n this._value = null;\n this._activeHandles = 0;\n }\n\n get value() {\n return this._value;\n }\n\n update(handleId, keys) {\n if (keys !== null) {\n keys = keys.slice(0); // clone before sorting\n keys.sort(naturalComparator);\n }\n\n let {added, removed} = diffSortedLists(this._handles[handleId], keys);\n this._handles[handleId] = keys;\n\n for (let i = 0; i < added.length; i++) {\n this._keys[added[i]] = (this._keys[added[i]] || 0) + 1;\n }\n for (let i = 0; i < removed.length; i++) {\n this._keys[removed[i]]--;\n }\n\n this._updateValue(keys);\n }\n\n /**\n * @param {string[]} keys Sorted array of strings that indicate\n * a superset of possible keys.\n * @private\n */\n _updateValue(keys = this._allKeys) {\n let handleCount = Object.keys(this._handles).length;\n if (handleCount === 0) {\n this._value = null;\n } else {\n this._value = [];\n for (let i = 0; i < keys.length; i++) {\n let count = this._keys[keys[i]];\n if (count === handleCount) {\n this._value.push(keys[i]);\n }\n }\n }\n }\n\n clear(handleId) {\n if (typeof(this._handles[handleId]) === \"undefined\") {\n return;\n }\n\n let keys = this._handles[handleId];\n if (!keys) {\n keys = [];\n }\n\n for (let i = 0; i < keys.length; i++) {\n this._keys[keys[i]]--;\n }\n delete this._handles[handleId];\n\n this._updateValue();\n }\n\n get _allKeys() {\n let allKeys = Object.keys(this._keys);\n allKeys.sort(naturalComparator);\n return allKeys;\n }\n}\n", + "import Var from \"./var\";\n\n// Use a global so that multiple copies of crosstalk.js can be loaded and still\n// have groups behave as singletons across all copies.\nglobal.__crosstalk_groups = global.__crosstalk_groups || {};\nlet groups = global.__crosstalk_groups;\n\nexport default function group(groupName) {\n if (groupName && typeof(groupName) === \"string\") {\n if (!groups.hasOwnProperty(groupName)) {\n groups[groupName] = new Group(groupName);\n }\n return groups[groupName];\n } else if (typeof(groupName) === \"object\" && groupName._vars && groupName.var) {\n // Appears to already be a group object\n return groupName;\n } else if (Array.isArray(groupName) &&\n groupName.length == 1 &&\n typeof(groupName[0]) === \"string\") {\n return group(groupName[0]);\n } else {\n throw new Error(\"Invalid groupName argument\");\n }\n}\n\nclass Group {\n constructor(name) {\n this.name = name;\n this._vars = {};\n }\n\n var(name) {\n if (!name || typeof(name) !== \"string\") {\n throw new Error(\"Invalid var name\");\n }\n\n if (!this._vars.hasOwnProperty(name))\n this._vars[name] = new Var(this, name);\n return this._vars[name];\n }\n\n has(name) {\n if (!name || typeof(name) !== \"string\") {\n throw new Error(\"Invalid var name\");\n }\n\n return this._vars.hasOwnProperty(name);\n }\n}\n", + "import group from \"./group\";\nimport { SelectionHandle } from \"./selection\";\nimport { FilterHandle } from \"./filter\";\nimport { bind } from \"./input\";\nimport \"./input_selectize\";\nimport \"./input_checkboxgroup\";\nimport \"./input_slider\";\n\nconst defaultGroup = group(\"default\");\n\nfunction var_(name) {\n return defaultGroup.var(name);\n}\n\nfunction has(name) {\n return defaultGroup.has(name);\n}\n\nif (global.Shiny) {\n global.Shiny.addCustomMessageHandler(\"update-client-value\", function(message) {\n if (typeof(message.group) === \"string\") {\n group(message.group).var(message.name).set(message.value);\n } else {\n var_(message.name).set(message.value);\n }\n });\n}\n\nconst crosstalk = {\n group: group,\n var: var_,\n has: has,\n SelectionHandle: SelectionHandle,\n FilterHandle: FilterHandle,\n bind: bind\n};\n\n/**\n * @namespace crosstalk\n */\nexport default crosstalk;\nglobal.crosstalk = crosstalk;\n", + "let $ = global.jQuery;\n\nlet bindings = {};\n\nexport function register(reg) {\n bindings[reg.className] = reg;\n if (global.document && global.document.readyState !== \"complete\") {\n $(() => {\n bind();\n });\n } else if (global.document) {\n setTimeout(bind, 100);\n }\n}\n\nexport function bind() {\n Object.keys(bindings).forEach(function(className) {\n let binding = bindings[className];\n $(\".\" + binding.className).not(\".crosstalk-input-bound\").each(function(i, el) {\n bindInstance(binding, el);\n });\n });\n}\n\n// Escape jQuery identifier\nfunction $escape(val) {\n return val.replace(/([!\"#$%&'()*+,./:;<=>?@[\\\\\\]^`{|}~])/g, \"\\\\$1\");\n}\n\nfunction bindEl(el) {\n let $el = $(el);\n Object.keys(bindings).forEach(function(className) {\n if ($el.hasClass(className) && !$el.hasClass(\"crosstalk-input-bound\")) {\n let binding = bindings[className];\n bindInstance(binding, el);\n }\n });\n}\n\nfunction bindInstance(binding, el) {\n let jsonEl = $(el).find(\"script[type='application/json'][data-for='\" + $escape(el.id) + \"']\");\n let data = JSON.parse(jsonEl[0].innerText);\n\n let instance = binding.factory(el, data);\n $(el).data(\"crosstalk-instance\", instance);\n $(el).addClass(\"crosstalk-input-bound\");\n}\n\nif (global.Shiny) {\n let inputBinding = new global.Shiny.InputBinding();\n let $ = global.jQuery;\n $.extend(inputBinding, {\n find: function(scope) {\n return $(scope).find(\".crosstalk-input\");\n },\n initialize: function(el) {\n if (!$(el).hasClass(\"crosstalk-input-bound\")) {\n bindEl(el);\n }\n },\n getId: function(el) {\n return el.id;\n },\n getValue: function(el) {\n\n },\n setValue: function(el, value) {\n\n },\n receiveMessage: function(el, data) {\n\n },\n subscribe: function(el, callback) {\n $(el).data(\"crosstalk-instance\").resume();\n },\n unsubscribe: function(el) {\n $(el).data(\"crosstalk-instance\").suspend();\n }\n });\n global.Shiny.inputBindings.register(inputBinding, \"crosstalk.inputBinding\");\n}\n", + "import * as input from \"./input\";\nimport { FilterHandle } from \"./filter\";\n\nlet $ = global.jQuery;\n\ninput.register({\n className: \"crosstalk-input-checkboxgroup\",\n\n factory: function(el, data) {\n /*\n * map: {\"groupA\": [\"keyA\", \"keyB\", ...], ...}\n * group: \"ct-groupname\"\n */\n let ctHandle = new FilterHandle(data.group);\n\n let lastKnownKeys;\n let $el = $(el);\n $el.on(\"change\", \"input[type='checkbox']\", function() {\n let checked = $el.find(\"input[type='checkbox']:checked\");\n if (checked.length === 0) {\n lastKnownKeys = null;\n ctHandle.clear();\n } else {\n let keys = {};\n checked.each(function() {\n data.map[this.value].forEach(function(key) {\n keys[key] = true;\n });\n });\n let keyArray = Object.keys(keys);\n keyArray.sort();\n lastKnownKeys = keyArray;\n ctHandle.set(keyArray);\n }\n });\n\n return {\n suspend: function() {\n ctHandle.clear();\n },\n resume: function() {\n if (lastKnownKeys)\n ctHandle.set(lastKnownKeys);\n }\n };\n }\n});\n", + "import * as input from \"./input\";\nimport * as util from \"./util\";\nimport { FilterHandle } from \"./filter\";\n\nlet $ = global.jQuery;\n\ninput.register({\n className: \"crosstalk-input-select\",\n\n factory: function(el, data) {\n /*\n * items: {value: [...], label: [...]}\n * map: {\"groupA\": [\"keyA\", \"keyB\", ...], ...}\n * group: \"ct-groupname\"\n */\n\n let first = [{value: \"\", label: \"(All)\"}];\n let items = util.dataframeToD3(data.items);\n let opts = {\n options: first.concat(items),\n valueField: \"value\",\n labelField: \"label\",\n searchField: \"label\"\n };\n\n let select = $(el).find(\"select\")[0];\n\n let selectize = $(select).selectize(opts)[0].selectize;\n\n let ctHandle = new FilterHandle(data.group);\n\n let lastKnownKeys;\n selectize.on(\"change\", function() {\n if (selectize.items.length === 0) {\n lastKnownKeys = null;\n ctHandle.clear();\n } else {\n let keys = {};\n selectize.items.forEach(function(group) {\n data.map[group].forEach(function(key) {\n keys[key] = true;\n });\n });\n let keyArray = Object.keys(keys);\n keyArray.sort();\n lastKnownKeys = keyArray;\n ctHandle.set(keyArray);\n }\n });\n\n return {\n suspend: function() {\n ctHandle.clear();\n },\n resume: function() {\n if (lastKnownKeys)\n ctHandle.set(lastKnownKeys);\n }\n };\n }\n});\n", + "import * as input from \"./input\";\nimport { FilterHandle } from \"./filter\";\n\nlet $ = global.jQuery;\nlet strftime = global.strftime;\n\ninput.register({\n className: \"crosstalk-input-slider\",\n\n factory: function(el, data) {\n /*\n * map: {\"groupA\": [\"keyA\", \"keyB\", ...], ...}\n * group: \"ct-groupname\"\n */\n let ctHandle = new FilterHandle(data.group);\n\n let opts = {};\n let $el = $(el).find(\"input\");\n let dataType = $el.data(\"data-type\");\n let timeFormat = $el.data(\"time-format\");\n let round = $el.data(\"round\");\n let timeFormatter;\n\n // Set up formatting functions\n if (dataType === \"date\") {\n timeFormatter = strftime.utc();\n opts.prettify = function(num) {\n return timeFormatter(timeFormat, new Date(num));\n };\n\n } else if (dataType === \"datetime\") {\n let timezone = $el.data(\"timezone\");\n if (timezone)\n timeFormatter = strftime.timezone(timezone);\n else\n timeFormatter = strftime;\n\n opts.prettify = function(num) {\n return timeFormatter(timeFormat, new Date(num));\n };\n } else if (dataType === \"number\") {\n if (typeof round !== \"undefined\")\n opts.prettify = function(num) {\n let factor = Math.pow(10, round);\n return Math.round(num * factor) / factor;\n };\n }\n\n $el.ionRangeSlider(opts);\n\n function getValue() {\n let result = $el.data(\"ionRangeSlider\").result;\n\n // Function for converting numeric value from slider to appropriate type.\n let convert;\n let dataType = $el.data(\"data-type\");\n if (dataType === \"date\") {\n convert = function(val) {\n return formatDateUTC(new Date(+val));\n };\n } else if (dataType === \"datetime\") {\n convert = function(val) {\n // Convert ms to s\n return +val / 1000;\n };\n } else {\n convert = function(val) { return +val; };\n }\n\n if ($el.data(\"ionRangeSlider\").options.type === \"double\") {\n return [convert(result.from), convert(result.to)];\n } else {\n return convert(result.from);\n }\n }\n\n let lastKnownKeys = null;\n\n $el.on(\"change.crosstalkSliderInput\", function(event) {\n if (!$el.data(\"updating\") && !$el.data(\"animating\")) {\n let [from, to] = getValue();\n let keys = [];\n for (let i = 0; i < data.values.length; i++) {\n let val = data.values[i];\n if (val >= from && val <= to) {\n keys.push(data.keys[i]);\n }\n }\n keys.sort();\n ctHandle.set(keys);\n lastKnownKeys = keys;\n }\n });\n\n\n // let $el = $(el);\n // $el.on(\"change\", \"input[type=\"checkbox\"]\", function() {\n // let checked = $el.find(\"input[type=\"checkbox\"]:checked\");\n // if (checked.length === 0) {\n // ctHandle.clear();\n // } else {\n // let keys = {};\n // checked.each(function() {\n // data.map[this.value].forEach(function(key) {\n // keys[key] = true;\n // });\n // });\n // let keyArray = Object.keys(keys);\n // keyArray.sort();\n // ctHandle.set(keyArray);\n // }\n // });\n\n return {\n suspend: function() {\n ctHandle.clear();\n },\n resume: function() {\n if (lastKnownKeys)\n ctHandle.set(lastKnownKeys);\n }\n };\n }\n});\n\n\n// Convert a number to a string with leading zeros\nfunction padZeros(n, digits) {\n let str = n.toString();\n while (str.length < digits)\n str = \"0\" + str;\n return str;\n}\n\n// Given a Date object, return a string in yyyy-mm-dd format, using the\n// UTC date. This may be a day off from the date in the local time zone.\nfunction formatDateUTC(date) {\n if (date instanceof Date) {\n return date.getUTCFullYear() + \"-\" +\n padZeros(date.getUTCMonth()+1, 2) + \"-\" +\n padZeros(date.getUTCDate(), 2);\n\n } else {\n return null;\n }\n}\n", + "import Events from \"./events\";\nimport grp from \"./group\";\nimport * as util from \"./util\";\n\n/**\n * Use this class to read and write (and listen for changes to) the selection\n * for a Crosstalk group. This is intended to be used for linked brushing.\n *\n * If two (or more) `SelectionHandle` instances in the same webpage share the\n * same group name, they will share the same state. Setting the selection using\n * one `SelectionHandle` instance will result in the `value` property instantly\n * changing across the others, and `\"change\"` event listeners on all instances\n * (including the one that initiated the sending) will fire.\n *\n * @param {string} [group] - The name of the Crosstalk group, or if none,\n * null or undefined (or any other falsy value). This can be changed later\n * via the [SelectionHandle#setGroup](#setGroup) method.\n * @param {Object} [extraInfo] - An object whose properties will be copied to\n * the event object whenever an event is emitted.\n */\nexport class SelectionHandle {\n\n constructor(group = null, extraInfo = null) {\n this._eventRelay = new Events();\n this._emitter = new util.SubscriptionTracker(this._eventRelay);\n\n // Name of the group we're currently tracking, if any. Can change over time.\n this._group = null;\n // The Var we're currently tracking, if any. Can change over time.\n this._var = null;\n // The event handler subscription we currently have on var.on(\"change\").\n this._varOnChangeSub = null;\n\n this._extraInfo = util.extend({ sender: this }, extraInfo);\n\n this.setGroup(group);\n }\n\n /**\n * Changes the Crosstalk group membership of this SelectionHandle. The group\n * being switched away from (if any) will not have its selection value\n * modified as a result of calling `setGroup`, even if this handle was the\n * most recent handle to set the selection of the group.\n *\n * The group being switched to (if any) will also not have its selection value\n * modified as a result of calling `setGroup`. If you want to set the\n * selection value of the new group, call `set` explicitly.\n *\n * @param {string} group - The name of the Crosstalk group, or null (or\n * undefined) to clear the group.\n */\n setGroup(group) {\n // If group is unchanged, do nothing\n if (this._group === group)\n return;\n // Treat null, undefined, and other falsy values the same\n if (!this._group && !group)\n return;\n\n if (this._var) {\n this._var.off(\"change\", this._varOnChangeSub);\n this._var = null;\n this._varOnChangeSub = null;\n }\n\n this._group = group;\n\n if (group) {\n this._var = grp(group).var(\"selection\");\n let sub = this._var.on(\"change\", (e) => {\n this._eventRelay.trigger(\"change\", e, this);\n });\n this._varOnChangeSub = sub;\n }\n }\n\n /**\n * Retrieves the current selection for the group represented by this\n * `SelectionHandle`.\n *\n * - If no selection is active, then this value will be falsy.\n * - If a selection is active, but no data points are selected, then this\n * value will be an empty array.\n * - If a selection is active, and data points are selected, then the keys\n * of the selected data points will be present in the array.\n */\n get value() {\n return this._var ? this._var.get() : null;\n }\n\n /**\n * Combines the given `extraInfo` (if any) with the handle's default\n * `_extraInfo` (if any).\n * @private\n */\n _mergeExtraInfo(extraInfo) {\n // Important incidental effect: shallow clone is returned\n return util.extend({},\n this._extraInfo ? this._extraInfo : null,\n extraInfo ? extraInfo : null);\n }\n\n /**\n * Overwrites the current selection for the group, and raises the `\"change\"`\n * event among all of the group's '`SelectionHandle` instances (including\n * this one).\n *\n * @fires SelectionHandle#change\n * @param {string[]} selectedKeys - Falsy, empty array, or array of keys (see\n * {@link SelectionHandle#value}).\n * @param {Object} [extraInfo] - Extra properties to be included on the event\n * object that's passed to listeners (in addition to any options that were\n * passed into the `SelectionHandle` constructor).\n */\n set(selectedKeys, extraInfo) {\n if (this._var)\n this._var.set(selectedKeys, this._mergeExtraInfo(extraInfo));\n }\n\n /**\n * Overwrites the current selection for the group, and raises the `\"change\"`\n * event among all of the group's '`SelectionHandle` instances (including\n * this one).\n *\n * @fires SelectionHandle#change\n * @param {Object} [extraInfo] - Extra properties to be included on the event\n * object that's passed to listeners (in addition to any that were passed\n * into the `SelectionHandle` constructor).\n */\n clear(extraInfo) {\n if (this._var)\n this.set(void 0, this._mergeExtraInfo(extraInfo));\n }\n\n /**\n * Subscribes to events on this `SelectionHandle`.\n *\n * @param {string} eventType - Indicates the type of events to listen to.\n * Currently, only `\"change\"` is supported.\n * @param {SelectionHandle~listener} listener - The callback function that\n * will be invoked when the event occurs.\n * @return {string} - A token to pass to {@link SelectionHandle#off} to cancel\n * this subscription.\n */\n on(eventType, listener) {\n return this._emitter.on(eventType, listener);\n }\n\n /**\n * Cancels event subscriptions created by {@link SelectionHandle#on}.\n *\n * @param {string} eventType - The type of event to unsubscribe.\n * @param {string|SelectionHandle~listener} listener - Either the callback\n * function previously passed into {@link SelectionHandle#on}, or the\n * string that was returned from {@link SelectionHandle#on}.\n */\n off(eventType, listener) {\n return this._emitter.off(eventType, listener);\n }\n\n /**\n * Shuts down the `SelectionHandle` object.\n *\n * Removes all event listeners that were added through this handle.\n */\n close() {\n this._emitter.removeAllListeners();\n this.setGroup(null);\n }\n}\n\n/**\n * @callback SelectionHandle~listener\n * @param {Object} event - An object containing details of the event. For\n * `\"change\"` events, this includes the properties `value` (the new\n * value of the selection, or `undefined` if no selection is active),\n * `oldValue` (the previous value of the selection), and `sender` (the\n * `SelectionHandle` instance that made the change).\n */\n\n/**\n * @event SelectionHandle#change\n * @type {object}\n * @property {object} value - The new value of the selection, or `undefined`\n * if no selection is active.\n * @property {object} oldValue - The previous value of the selection.\n * @property {SelectionHandle} sender - The `SelectionHandle` instance that\n * changed the value.\n */\n", + "export function extend(target, ...sources) {\n for (let i = 0; i < sources.length; i++) {\n let src = sources[i];\n if (typeof(src) === \"undefined\" || src === null)\n continue;\n\n for (let key in src) {\n if (src.hasOwnProperty(key)) {\n target[key] = src[key];\n }\n }\n }\n return target;\n}\n\nexport function checkSorted(list) {\n for (let i = 1; i < list.length; i++) {\n if (list[i] <= list[i-1]) {\n throw new Error(\"List is not sorted or contains duplicate\");\n }\n }\n}\n\nexport function diffSortedLists(a, b) {\n let i_a = 0;\n let i_b = 0;\n\n if (!a) a = [];\n if (!b) b = [];\n\n let a_only = [];\n let b_only = [];\n\n checkSorted(a);\n checkSorted(b);\n\n while (i_a < a.length && i_b < b.length) {\n if (a[i_a] === b[i_b]) {\n i_a++;\n i_b++;\n } else if (a[i_a] < b[i_b]) {\n a_only.push(a[i_a++]);\n } else {\n b_only.push(b[i_b++]);\n }\n }\n\n if (i_a < a.length)\n a_only = a_only.concat(a.slice(i_a));\n if (i_b < b.length)\n b_only = b_only.concat(b.slice(i_b));\n return {\n removed: a_only,\n added: b_only\n };\n}\n\n// Convert from wide: { colA: [1,2,3], colB: [4,5,6], ... }\n// to long: [ {colA: 1, colB: 4}, {colA: 2, colB: 5}, ... ]\nexport function dataframeToD3(df) {\n let names = [];\n let length;\n for (let name in df) {\n if (df.hasOwnProperty(name))\n names.push(name);\n if (typeof(df[name]) !== \"object\" || typeof(df[name].length) === \"undefined\") {\n throw new Error(\"All fields must be arrays\");\n } else if (typeof(length) !== \"undefined\" && length !== df[name].length) {\n throw new Error(\"All fields must be arrays of the same length\");\n }\n length = df[name].length;\n }\n let results = [];\n let item;\n for (let row = 0; row < length; row++) {\n item = {};\n for (let col = 0; col < names.length; col++) {\n item[names[col]] = df[names[col]][row];\n }\n results.push(item);\n }\n return results;\n}\n\n/**\n * Keeps track of all event listener additions/removals and lets all active\n * listeners be removed with a single operation.\n *\n * @private\n */\nexport class SubscriptionTracker {\n constructor(emitter) {\n this._emitter = emitter;\n this._subs = {};\n }\n\n on(eventType, listener) {\n let sub = this._emitter.on(eventType, listener);\n this._subs[sub] = eventType;\n return sub;\n }\n\n off(eventType, listener) {\n let sub = this._emitter.off(eventType, listener);\n if (sub) {\n delete this._subs[sub];\n }\n return sub;\n }\n\n removeAllListeners() {\n let current_subs = this._subs;\n this._subs = {};\n Object.keys(current_subs).forEach((sub) => {\n this._emitter.off(current_subs[sub], sub);\n });\n }\n}\n", + "import Events from \"./events\";\n\nexport default class Var {\n constructor(group, name, /*optional*/ value) {\n this._group = group;\n this._name = name;\n this._value = value;\n this._events = new Events();\n }\n\n get() {\n return this._value;\n }\n\n set(value, /*optional*/ event) {\n if (this._value === value) {\n // Do nothing; the value hasn't changed\n return;\n }\n let oldValue = this._value;\n this._value = value;\n // Alert JavaScript listeners that the value has changed\n let evt = {};\n if (event && typeof(event) === \"object\") {\n for (let k in event) {\n if (event.hasOwnProperty(k))\n evt[k] = event[k];\n }\n }\n evt.oldValue = oldValue;\n evt.value = value;\n this._events.trigger(\"change\", evt, this);\n\n // TODO: Make this extensible, to let arbitrary back-ends know that\n // something has changed\n if (global.Shiny && global.Shiny.onInputChange) {\n global.Shiny.onInputChange(\n \".clientValue-\" +\n (this._group.name !== null ? this._group.name + \"-\" : \"\") +\n this._name,\n typeof(value) === \"undefined\" ? null : value\n );\n }\n }\n\n on(eventType, listener) {\n return this._events.on(eventType, listener);\n }\n\n off(eventType, listener) {\n return this._events.off(eventType, listener);\n }\n}\n" + ] +} \ No newline at end of file diff --git a/docs/articles/variable_details_files/crosstalk-1.2.1/js/crosstalk.min.js b/docs/articles/variable_details_files/crosstalk-1.2.1/js/crosstalk.min.js new file mode 100644 index 00000000..b7ec0ac9 --- /dev/null +++ b/docs/articles/variable_details_files/crosstalk-1.2.1/js/crosstalk.min.js @@ -0,0 +1,2 @@ +!function o(u,a,l){function s(n,e){if(!a[n]){if(!u[n]){var t="function"==typeof require&&require;if(!e&&t)return t(n,!0);if(f)return f(n,!0);var r=new Error("Cannot find module '"+n+"'");throw r.code="MODULE_NOT_FOUND",r}var i=a[n]={exports:{}};u[n][0].call(i.exports,function(e){var t=u[n][1][e];return s(t||e)},i,i.exports,o,u,a,l)}return a[n].exports}for(var f="function"==typeof require&&require,e=0;e?@[\\\]^`{|}~])/g,"\\$1")+"']"),r=JSON.parse(n[0].innerText),i=e.factory(t,r);o(t).data("crosstalk-instance",i),o(t).addClass("crosstalk-input-bound")}if(t.Shiny){var e=new t.Shiny.InputBinding,u=t.jQuery;u.extend(e,{find:function(e){return u(e).find(".crosstalk-input")},initialize:function(e){var t,n;u(e).hasClass("crosstalk-input-bound")||(n=o(t=e),Object.keys(r).forEach(function(e){n.hasClass(e)&&!n.hasClass("crosstalk-input-bound")&&i(r[e],t)}))},getId:function(e){return e.id},getValue:function(e){},setValue:function(e,t){},receiveMessage:function(e,t){},subscribe:function(e,t){u(e).data("crosstalk-instance").resume()},unsubscribe:function(e){u(e).data("crosstalk-instance").suspend()}}),t.Shiny.inputBindings.register(e,"crosstalk.inputBinding")}}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{}],7:[function(r,e,t){(function(e){"use strict";var t=function(e){{if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[n]=e[n]);return t.default=e,t}}(r("./input")),n=r("./filter");var a=e.jQuery;t.register({className:"crosstalk-input-checkboxgroup",factory:function(e,r){var i=new n.FilterHandle(r.group),o=void 0,u=a(e);return u.on("change","input[type='checkbox']",function(){var e=u.find("input[type='checkbox']:checked");if(0===e.length)o=null,i.clear();else{var t={};e.each(function(){r.map[this.value].forEach(function(e){t[e]=!0})});var n=Object.keys(t);n.sort(),o=n,i.set(n)}}),{suspend:function(){i.clear()},resume:function(){o&&i.set(o)}}}})}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{"./filter":2,"./input":6}],8:[function(r,e,t){(function(e){"use strict";var t=n(r("./input")),l=n(r("./util")),s=r("./filter");function n(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[n]=e[n]);return t.default=e,t}var f=e.jQuery;t.register({className:"crosstalk-input-select",factory:function(e,n){var t=l.dataframeToD3(n.items),r={options:[{value:"",label:"(All)"}].concat(t),valueField:"value",labelField:"label",searchField:"label"},i=f(e).find("select")[0],o=f(i).selectize(r)[0].selectize,u=new s.FilterHandle(n.group),a=void 0;return o.on("change",function(){if(0===o.items.length)a=null,u.clear();else{var t={};o.items.forEach(function(e){n.map[e].forEach(function(e){t[e]=!0})});var e=Object.keys(t);e.sort(),a=e,u.set(e)}}),{suspend:function(){u.clear()},resume:function(){a&&u.set(a)}}}})}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{"./filter":2,"./input":6,"./util":11}],9:[function(n,e,t){(function(e){"use strict";var d=function(e,t){if(Array.isArray(e))return e;if(Symbol.iterator in Object(e))return function(e,t){var n=[],r=!0,i=!1,o=void 0;try{for(var u,a=e[Symbol.iterator]();!(r=(u=a.next()).done)&&(n.push(u.value),!t||n.length!==t);r=!0);}catch(e){i=!0,o=e}finally{try{!r&&a.return&&a.return()}finally{if(i)throw o}}return n}(e,t);throw new TypeError("Invalid attempt to destructure non-iterable instance")},t=function(e){{if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[n]=e[n]);return t.default=e,t}}(n("./input")),a=n("./filter");var v=e.jQuery,p=e.strftime;function y(e,t){for(var n=e.toString();n.length {\n this._eventRelay.trigger(\"change\", e, this);\n });\n this._varOnChangeSub = sub;\n }\n }\n\n /**\n * Combine the given `extraInfo` (if any) with the handle's default\n * `_extraInfo` (if any).\n * @private\n */\n _mergeExtraInfo(extraInfo) {\n return util.extend({},\n this._extraInfo ? this._extraInfo : null,\n extraInfo ? extraInfo : null);\n }\n\n /**\n * Close the handle. This clears this handle's contribution to the filter set,\n * and unsubscribes all event listeners.\n */\n close() {\n this._emitter.removeAllListeners();\n this.clear();\n this.setGroup(null);\n }\n\n /**\n * Clear this handle's contribution to the filter set.\n *\n * @param {Object} [extraInfo] - Extra properties to be included on the event\n * object that's passed to listeners (in addition to any options that were\n * passed into the `FilterHandle` constructor).\n * \n * @fires FilterHandle#change\n */\n clear(extraInfo) {\n if (!this._filterSet)\n return;\n this._filterSet.clear(this._id);\n this._onChange(extraInfo);\n }\n\n /**\n * Set this handle's contribution to the filter set. This array should consist\n * of the keys of the rows that _should_ be displayed; any keys that are not\n * present in the array will be considered _filtered out_. Note that multiple\n * `FilterHandle` instances in the group may each contribute an array of keys,\n * and only those keys that appear in _all_ of the arrays make it through the\n * filter.\n *\n * @param {string[]} keys - Empty array, or array of keys. To clear the\n * filter, don't pass an empty array; instead, use the\n * {@link FilterHandle#clear} method.\n * @param {Object} [extraInfo] - Extra properties to be included on the event\n * object that's passed to listeners (in addition to any options that were\n * passed into the `FilterHandle` constructor).\n * \n * @fires FilterHandle#change\n */\n set(keys, extraInfo) {\n if (!this._filterSet)\n return;\n this._filterSet.update(this._id, keys);\n this._onChange(extraInfo);\n }\n\n /**\n * @return {string[]|null} - Either: 1) an array of keys that made it through\n * all of the `FilterHandle` instances, or, 2) `null`, which means no filter\n * is being applied (all data should be displayed).\n */\n get filteredKeys() {\n return this._filterSet ? this._filterSet.value : null;\n }\n\n /**\n * Subscribe to events on this `FilterHandle`.\n *\n * @param {string} eventType - Indicates the type of events to listen to.\n * Currently, only `\"change\"` is supported.\n * @param {FilterHandle~listener} listener - The callback function that\n * will be invoked when the event occurs.\n * @return {string} - A token to pass to {@link FilterHandle#off} to cancel\n * this subscription.\n */\n on(eventType, listener) {\n return this._emitter.on(eventType, listener);\n }\n\n /**\n * Cancel event subscriptions created by {@link FilterHandle#on}.\n *\n * @param {string} eventType - The type of event to unsubscribe.\n * @param {string|FilterHandle~listener} listener - Either the callback\n * function previously passed into {@link FilterHandle#on}, or the\n * string that was returned from {@link FilterHandle#on}.\n */\n off(eventType, listener) {\n return this._emitter.off(eventType, listener);\n }\n\n _onChange(extraInfo) {\n if (!this._filterSet)\n return;\n this._filterVar.set(this._filterSet.value, this._mergeExtraInfo(extraInfo));\n }\n\n /**\n * @callback FilterHandle~listener\n * @param {Object} event - An object containing details of the event. For\n * `\"change\"` events, this includes the properties `value` (the new\n * value of the filter set, or `null` if no filter set is active),\n * `oldValue` (the previous value of the filter set), and `sender` (the\n * `FilterHandle` instance that made the change).\n */\n\n}\n\n/**\n * @event FilterHandle#change\n * @type {object}\n * @property {object} value - The new value of the filter set, or `null`\n * if no filter set is active.\n * @property {object} oldValue - The previous value of the filter set.\n * @property {FilterHandle} sender - The `FilterHandle` instance that\n * changed the value.\n */\n","import { diffSortedLists } from \"./util\";\n\nfunction naturalComparator(a, b) {\n if (a === b) {\n return 0;\n } else if (a < b) {\n return -1;\n } else if (a > b) {\n return 1;\n }\n}\n\n/**\n * @private\n */\nexport default class FilterSet {\n constructor() {\n this.reset();\n }\n\n reset() {\n // Key: handle ID, Value: array of selected keys, or null\n this._handles = {};\n // Key: key string, Value: count of handles that include it\n this._keys = {};\n this._value = null;\n this._activeHandles = 0;\n }\n\n get value() {\n return this._value;\n }\n\n update(handleId, keys) {\n if (keys !== null) {\n keys = keys.slice(0); // clone before sorting\n keys.sort(naturalComparator);\n }\n\n let {added, removed} = diffSortedLists(this._handles[handleId], keys);\n this._handles[handleId] = keys;\n\n for (let i = 0; i < added.length; i++) {\n this._keys[added[i]] = (this._keys[added[i]] || 0) + 1;\n }\n for (let i = 0; i < removed.length; i++) {\n this._keys[removed[i]]--;\n }\n\n this._updateValue(keys);\n }\n\n /**\n * @param {string[]} keys Sorted array of strings that indicate\n * a superset of possible keys.\n * @private\n */\n _updateValue(keys = this._allKeys) {\n let handleCount = Object.keys(this._handles).length;\n if (handleCount === 0) {\n this._value = null;\n } else {\n this._value = [];\n for (let i = 0; i < keys.length; i++) {\n let count = this._keys[keys[i]];\n if (count === handleCount) {\n this._value.push(keys[i]);\n }\n }\n }\n }\n\n clear(handleId) {\n if (typeof(this._handles[handleId]) === \"undefined\") {\n return;\n }\n\n let keys = this._handles[handleId];\n if (!keys) {\n keys = [];\n }\n\n for (let i = 0; i < keys.length; i++) {\n this._keys[keys[i]]--;\n }\n delete this._handles[handleId];\n\n this._updateValue();\n }\n\n get _allKeys() {\n let allKeys = Object.keys(this._keys);\n allKeys.sort(naturalComparator);\n return allKeys;\n }\n}\n","import Var from \"./var\";\n\n// Use a global so that multiple copies of crosstalk.js can be loaded and still\n// have groups behave as singletons across all copies.\nglobal.__crosstalk_groups = global.__crosstalk_groups || {};\nlet groups = global.__crosstalk_groups;\n\nexport default function group(groupName) {\n if (groupName && typeof(groupName) === \"string\") {\n if (!groups.hasOwnProperty(groupName)) {\n groups[groupName] = new Group(groupName);\n }\n return groups[groupName];\n } else if (typeof(groupName) === \"object\" && groupName._vars && groupName.var) {\n // Appears to already be a group object\n return groupName;\n } else if (Array.isArray(groupName) &&\n groupName.length == 1 &&\n typeof(groupName[0]) === \"string\") {\n return group(groupName[0]);\n } else {\n throw new Error(\"Invalid groupName argument\");\n }\n}\n\nclass Group {\n constructor(name) {\n this.name = name;\n this._vars = {};\n }\n\n var(name) {\n if (!name || typeof(name) !== \"string\") {\n throw new Error(\"Invalid var name\");\n }\n\n if (!this._vars.hasOwnProperty(name))\n this._vars[name] = new Var(this, name);\n return this._vars[name];\n }\n\n has(name) {\n if (!name || typeof(name) !== \"string\") {\n throw new Error(\"Invalid var name\");\n }\n\n return this._vars.hasOwnProperty(name);\n }\n}\n","import group from \"./group\";\nimport { SelectionHandle } from \"./selection\";\nimport { FilterHandle } from \"./filter\";\nimport { bind } from \"./input\";\nimport \"./input_selectize\";\nimport \"./input_checkboxgroup\";\nimport \"./input_slider\";\n\nconst defaultGroup = group(\"default\");\n\nfunction var_(name) {\n return defaultGroup.var(name);\n}\n\nfunction has(name) {\n return defaultGroup.has(name);\n}\n\nif (global.Shiny) {\n global.Shiny.addCustomMessageHandler(\"update-client-value\", function(message) {\n if (typeof(message.group) === \"string\") {\n group(message.group).var(message.name).set(message.value);\n } else {\n var_(message.name).set(message.value);\n }\n });\n}\n\nconst crosstalk = {\n group: group,\n var: var_,\n has: has,\n SelectionHandle: SelectionHandle,\n FilterHandle: FilterHandle,\n bind: bind\n};\n\n/**\n * @namespace crosstalk\n */\nexport default crosstalk;\nglobal.crosstalk = crosstalk;\n","let $ = global.jQuery;\n\nlet bindings = {};\n\nexport function register(reg) {\n bindings[reg.className] = reg;\n if (global.document && global.document.readyState !== \"complete\") {\n $(() => {\n bind();\n });\n } else if (global.document) {\n setTimeout(bind, 100);\n }\n}\n\nexport function bind() {\n Object.keys(bindings).forEach(function(className) {\n let binding = bindings[className];\n $(\".\" + binding.className).not(\".crosstalk-input-bound\").each(function(i, el) {\n bindInstance(binding, el);\n });\n });\n}\n\n// Escape jQuery identifier\nfunction $escape(val) {\n return val.replace(/([!\"#$%&'()*+,./:;<=>?@[\\\\\\]^`{|}~])/g, \"\\\\$1\");\n}\n\nfunction bindEl(el) {\n let $el = $(el);\n Object.keys(bindings).forEach(function(className) {\n if ($el.hasClass(className) && !$el.hasClass(\"crosstalk-input-bound\")) {\n let binding = bindings[className];\n bindInstance(binding, el);\n }\n });\n}\n\nfunction bindInstance(binding, el) {\n let jsonEl = $(el).find(\"script[type='application/json'][data-for='\" + $escape(el.id) + \"']\");\n let data = JSON.parse(jsonEl[0].innerText);\n\n let instance = binding.factory(el, data);\n $(el).data(\"crosstalk-instance\", instance);\n $(el).addClass(\"crosstalk-input-bound\");\n}\n\nif (global.Shiny) {\n let inputBinding = new global.Shiny.InputBinding();\n let $ = global.jQuery;\n $.extend(inputBinding, {\n find: function(scope) {\n return $(scope).find(\".crosstalk-input\");\n },\n initialize: function(el) {\n if (!$(el).hasClass(\"crosstalk-input-bound\")) {\n bindEl(el);\n }\n },\n getId: function(el) {\n return el.id;\n },\n getValue: function(el) {\n\n },\n setValue: function(el, value) {\n\n },\n receiveMessage: function(el, data) {\n\n },\n subscribe: function(el, callback) {\n $(el).data(\"crosstalk-instance\").resume();\n },\n unsubscribe: function(el) {\n $(el).data(\"crosstalk-instance\").suspend();\n }\n });\n global.Shiny.inputBindings.register(inputBinding, \"crosstalk.inputBinding\");\n}\n","import * as input from \"./input\";\nimport { FilterHandle } from \"./filter\";\n\nlet $ = global.jQuery;\n\ninput.register({\n className: \"crosstalk-input-checkboxgroup\",\n\n factory: function(el, data) {\n /*\n * map: {\"groupA\": [\"keyA\", \"keyB\", ...], ...}\n * group: \"ct-groupname\"\n */\n let ctHandle = new FilterHandle(data.group);\n\n let lastKnownKeys;\n let $el = $(el);\n $el.on(\"change\", \"input[type='checkbox']\", function() {\n let checked = $el.find(\"input[type='checkbox']:checked\");\n if (checked.length === 0) {\n lastKnownKeys = null;\n ctHandle.clear();\n } else {\n let keys = {};\n checked.each(function() {\n data.map[this.value].forEach(function(key) {\n keys[key] = true;\n });\n });\n let keyArray = Object.keys(keys);\n keyArray.sort();\n lastKnownKeys = keyArray;\n ctHandle.set(keyArray);\n }\n });\n\n return {\n suspend: function() {\n ctHandle.clear();\n },\n resume: function() {\n if (lastKnownKeys)\n ctHandle.set(lastKnownKeys);\n }\n };\n }\n});\n","import * as input from \"./input\";\nimport * as util from \"./util\";\nimport { FilterHandle } from \"./filter\";\n\nlet $ = global.jQuery;\n\ninput.register({\n className: \"crosstalk-input-select\",\n\n factory: function(el, data) {\n /*\n * items: {value: [...], label: [...]}\n * map: {\"groupA\": [\"keyA\", \"keyB\", ...], ...}\n * group: \"ct-groupname\"\n */\n\n let first = [{value: \"\", label: \"(All)\"}];\n let items = util.dataframeToD3(data.items);\n let opts = {\n options: first.concat(items),\n valueField: \"value\",\n labelField: \"label\",\n searchField: \"label\"\n };\n\n let select = $(el).find(\"select\")[0];\n\n let selectize = $(select).selectize(opts)[0].selectize;\n\n let ctHandle = new FilterHandle(data.group);\n\n let lastKnownKeys;\n selectize.on(\"change\", function() {\n if (selectize.items.length === 0) {\n lastKnownKeys = null;\n ctHandle.clear();\n } else {\n let keys = {};\n selectize.items.forEach(function(group) {\n data.map[group].forEach(function(key) {\n keys[key] = true;\n });\n });\n let keyArray = Object.keys(keys);\n keyArray.sort();\n lastKnownKeys = keyArray;\n ctHandle.set(keyArray);\n }\n });\n\n return {\n suspend: function() {\n ctHandle.clear();\n },\n resume: function() {\n if (lastKnownKeys)\n ctHandle.set(lastKnownKeys);\n }\n };\n }\n});\n","import * as input from \"./input\";\nimport { FilterHandle } from \"./filter\";\n\nlet $ = global.jQuery;\nlet strftime = global.strftime;\n\ninput.register({\n className: \"crosstalk-input-slider\",\n\n factory: function(el, data) {\n /*\n * map: {\"groupA\": [\"keyA\", \"keyB\", ...], ...}\n * group: \"ct-groupname\"\n */\n let ctHandle = new FilterHandle(data.group);\n\n let opts = {};\n let $el = $(el).find(\"input\");\n let dataType = $el.data(\"data-type\");\n let timeFormat = $el.data(\"time-format\");\n let round = $el.data(\"round\");\n let timeFormatter;\n\n // Set up formatting functions\n if (dataType === \"date\") {\n timeFormatter = strftime.utc();\n opts.prettify = function(num) {\n return timeFormatter(timeFormat, new Date(num));\n };\n\n } else if (dataType === \"datetime\") {\n let timezone = $el.data(\"timezone\");\n if (timezone)\n timeFormatter = strftime.timezone(timezone);\n else\n timeFormatter = strftime;\n\n opts.prettify = function(num) {\n return timeFormatter(timeFormat, new Date(num));\n };\n } else if (dataType === \"number\") {\n if (typeof round !== \"undefined\")\n opts.prettify = function(num) {\n let factor = Math.pow(10, round);\n return Math.round(num * factor) / factor;\n };\n }\n\n $el.ionRangeSlider(opts);\n\n function getValue() {\n let result = $el.data(\"ionRangeSlider\").result;\n\n // Function for converting numeric value from slider to appropriate type.\n let convert;\n let dataType = $el.data(\"data-type\");\n if (dataType === \"date\") {\n convert = function(val) {\n return formatDateUTC(new Date(+val));\n };\n } else if (dataType === \"datetime\") {\n convert = function(val) {\n // Convert ms to s\n return +val / 1000;\n };\n } else {\n convert = function(val) { return +val; };\n }\n\n if ($el.data(\"ionRangeSlider\").options.type === \"double\") {\n return [convert(result.from), convert(result.to)];\n } else {\n return convert(result.from);\n }\n }\n\n let lastKnownKeys = null;\n\n $el.on(\"change.crosstalkSliderInput\", function(event) {\n if (!$el.data(\"updating\") && !$el.data(\"animating\")) {\n let [from, to] = getValue();\n let keys = [];\n for (let i = 0; i < data.values.length; i++) {\n let val = data.values[i];\n if (val >= from && val <= to) {\n keys.push(data.keys[i]);\n }\n }\n keys.sort();\n ctHandle.set(keys);\n lastKnownKeys = keys;\n }\n });\n\n\n // let $el = $(el);\n // $el.on(\"change\", \"input[type=\"checkbox\"]\", function() {\n // let checked = $el.find(\"input[type=\"checkbox\"]:checked\");\n // if (checked.length === 0) {\n // ctHandle.clear();\n // } else {\n // let keys = {};\n // checked.each(function() {\n // data.map[this.value].forEach(function(key) {\n // keys[key] = true;\n // });\n // });\n // let keyArray = Object.keys(keys);\n // keyArray.sort();\n // ctHandle.set(keyArray);\n // }\n // });\n\n return {\n suspend: function() {\n ctHandle.clear();\n },\n resume: function() {\n if (lastKnownKeys)\n ctHandle.set(lastKnownKeys);\n }\n };\n }\n});\n\n\n// Convert a number to a string with leading zeros\nfunction padZeros(n, digits) {\n let str = n.toString();\n while (str.length < digits)\n str = \"0\" + str;\n return str;\n}\n\n// Given a Date object, return a string in yyyy-mm-dd format, using the\n// UTC date. This may be a day off from the date in the local time zone.\nfunction formatDateUTC(date) {\n if (date instanceof Date) {\n return date.getUTCFullYear() + \"-\" +\n padZeros(date.getUTCMonth()+1, 2) + \"-\" +\n padZeros(date.getUTCDate(), 2);\n\n } else {\n return null;\n }\n}\n","import Events from \"./events\";\nimport grp from \"./group\";\nimport * as util from \"./util\";\n\n/**\n * Use this class to read and write (and listen for changes to) the selection\n * for a Crosstalk group. This is intended to be used for linked brushing.\n *\n * If two (or more) `SelectionHandle` instances in the same webpage share the\n * same group name, they will share the same state. Setting the selection using\n * one `SelectionHandle` instance will result in the `value` property instantly\n * changing across the others, and `\"change\"` event listeners on all instances\n * (including the one that initiated the sending) will fire.\n *\n * @param {string} [group] - The name of the Crosstalk group, or if none,\n * null or undefined (or any other falsy value). This can be changed later\n * via the [SelectionHandle#setGroup](#setGroup) method.\n * @param {Object} [extraInfo] - An object whose properties will be copied to\n * the event object whenever an event is emitted.\n */\nexport class SelectionHandle {\n\n constructor(group = null, extraInfo = null) {\n this._eventRelay = new Events();\n this._emitter = new util.SubscriptionTracker(this._eventRelay);\n\n // Name of the group we're currently tracking, if any. Can change over time.\n this._group = null;\n // The Var we're currently tracking, if any. Can change over time.\n this._var = null;\n // The event handler subscription we currently have on var.on(\"change\").\n this._varOnChangeSub = null;\n\n this._extraInfo = util.extend({ sender: this }, extraInfo);\n\n this.setGroup(group);\n }\n\n /**\n * Changes the Crosstalk group membership of this SelectionHandle. The group\n * being switched away from (if any) will not have its selection value\n * modified as a result of calling `setGroup`, even if this handle was the\n * most recent handle to set the selection of the group.\n *\n * The group being switched to (if any) will also not have its selection value\n * modified as a result of calling `setGroup`. If you want to set the\n * selection value of the new group, call `set` explicitly.\n *\n * @param {string} group - The name of the Crosstalk group, or null (or\n * undefined) to clear the group.\n */\n setGroup(group) {\n // If group is unchanged, do nothing\n if (this._group === group)\n return;\n // Treat null, undefined, and other falsy values the same\n if (!this._group && !group)\n return;\n\n if (this._var) {\n this._var.off(\"change\", this._varOnChangeSub);\n this._var = null;\n this._varOnChangeSub = null;\n }\n\n this._group = group;\n\n if (group) {\n this._var = grp(group).var(\"selection\");\n let sub = this._var.on(\"change\", (e) => {\n this._eventRelay.trigger(\"change\", e, this);\n });\n this._varOnChangeSub = sub;\n }\n }\n\n /**\n * Retrieves the current selection for the group represented by this\n * `SelectionHandle`.\n *\n * - If no selection is active, then this value will be falsy.\n * - If a selection is active, but no data points are selected, then this\n * value will be an empty array.\n * - If a selection is active, and data points are selected, then the keys\n * of the selected data points will be present in the array.\n */\n get value() {\n return this._var ? this._var.get() : null;\n }\n\n /**\n * Combines the given `extraInfo` (if any) with the handle's default\n * `_extraInfo` (if any).\n * @private\n */\n _mergeExtraInfo(extraInfo) {\n // Important incidental effect: shallow clone is returned\n return util.extend({},\n this._extraInfo ? this._extraInfo : null,\n extraInfo ? extraInfo : null);\n }\n\n /**\n * Overwrites the current selection for the group, and raises the `\"change\"`\n * event among all of the group's '`SelectionHandle` instances (including\n * this one).\n *\n * @fires SelectionHandle#change\n * @param {string[]} selectedKeys - Falsy, empty array, or array of keys (see\n * {@link SelectionHandle#value}).\n * @param {Object} [extraInfo] - Extra properties to be included on the event\n * object that's passed to listeners (in addition to any options that were\n * passed into the `SelectionHandle` constructor).\n */\n set(selectedKeys, extraInfo) {\n if (this._var)\n this._var.set(selectedKeys, this._mergeExtraInfo(extraInfo));\n }\n\n /**\n * Overwrites the current selection for the group, and raises the `\"change\"`\n * event among all of the group's '`SelectionHandle` instances (including\n * this one).\n *\n * @fires SelectionHandle#change\n * @param {Object} [extraInfo] - Extra properties to be included on the event\n * object that's passed to listeners (in addition to any that were passed\n * into the `SelectionHandle` constructor).\n */\n clear(extraInfo) {\n if (this._var)\n this.set(void 0, this._mergeExtraInfo(extraInfo));\n }\n\n /**\n * Subscribes to events on this `SelectionHandle`.\n *\n * @param {string} eventType - Indicates the type of events to listen to.\n * Currently, only `\"change\"` is supported.\n * @param {SelectionHandle~listener} listener - The callback function that\n * will be invoked when the event occurs.\n * @return {string} - A token to pass to {@link SelectionHandle#off} to cancel\n * this subscription.\n */\n on(eventType, listener) {\n return this._emitter.on(eventType, listener);\n }\n\n /**\n * Cancels event subscriptions created by {@link SelectionHandle#on}.\n *\n * @param {string} eventType - The type of event to unsubscribe.\n * @param {string|SelectionHandle~listener} listener - Either the callback\n * function previously passed into {@link SelectionHandle#on}, or the\n * string that was returned from {@link SelectionHandle#on}.\n */\n off(eventType, listener) {\n return this._emitter.off(eventType, listener);\n }\n\n /**\n * Shuts down the `SelectionHandle` object.\n *\n * Removes all event listeners that were added through this handle.\n */\n close() {\n this._emitter.removeAllListeners();\n this.setGroup(null);\n }\n}\n\n/**\n * @callback SelectionHandle~listener\n * @param {Object} event - An object containing details of the event. For\n * `\"change\"` events, this includes the properties `value` (the new\n * value of the selection, or `undefined` if no selection is active),\n * `oldValue` (the previous value of the selection), and `sender` (the\n * `SelectionHandle` instance that made the change).\n */\n\n/**\n * @event SelectionHandle#change\n * @type {object}\n * @property {object} value - The new value of the selection, or `undefined`\n * if no selection is active.\n * @property {object} oldValue - The previous value of the selection.\n * @property {SelectionHandle} sender - The `SelectionHandle` instance that\n * changed the value.\n */\n","export function extend(target, ...sources) {\n for (let i = 0; i < sources.length; i++) {\n let src = sources[i];\n if (typeof(src) === \"undefined\" || src === null)\n continue;\n\n for (let key in src) {\n if (src.hasOwnProperty(key)) {\n target[key] = src[key];\n }\n }\n }\n return target;\n}\n\nexport function checkSorted(list) {\n for (let i = 1; i < list.length; i++) {\n if (list[i] <= list[i-1]) {\n throw new Error(\"List is not sorted or contains duplicate\");\n }\n }\n}\n\nexport function diffSortedLists(a, b) {\n let i_a = 0;\n let i_b = 0;\n\n if (!a) a = [];\n if (!b) b = [];\n\n let a_only = [];\n let b_only = [];\n\n checkSorted(a);\n checkSorted(b);\n\n while (i_a < a.length && i_b < b.length) {\n if (a[i_a] === b[i_b]) {\n i_a++;\n i_b++;\n } else if (a[i_a] < b[i_b]) {\n a_only.push(a[i_a++]);\n } else {\n b_only.push(b[i_b++]);\n }\n }\n\n if (i_a < a.length)\n a_only = a_only.concat(a.slice(i_a));\n if (i_b < b.length)\n b_only = b_only.concat(b.slice(i_b));\n return {\n removed: a_only,\n added: b_only\n };\n}\n\n// Convert from wide: { colA: [1,2,3], colB: [4,5,6], ... }\n// to long: [ {colA: 1, colB: 4}, {colA: 2, colB: 5}, ... ]\nexport function dataframeToD3(df) {\n let names = [];\n let length;\n for (let name in df) {\n if (df.hasOwnProperty(name))\n names.push(name);\n if (typeof(df[name]) !== \"object\" || typeof(df[name].length) === \"undefined\") {\n throw new Error(\"All fields must be arrays\");\n } else if (typeof(length) !== \"undefined\" && length !== df[name].length) {\n throw new Error(\"All fields must be arrays of the same length\");\n }\n length = df[name].length;\n }\n let results = [];\n let item;\n for (let row = 0; row < length; row++) {\n item = {};\n for (let col = 0; col < names.length; col++) {\n item[names[col]] = df[names[col]][row];\n }\n results.push(item);\n }\n return results;\n}\n\n/**\n * Keeps track of all event listener additions/removals and lets all active\n * listeners be removed with a single operation.\n *\n * @private\n */\nexport class SubscriptionTracker {\n constructor(emitter) {\n this._emitter = emitter;\n this._subs = {};\n }\n\n on(eventType, listener) {\n let sub = this._emitter.on(eventType, listener);\n this._subs[sub] = eventType;\n return sub;\n }\n\n off(eventType, listener) {\n let sub = this._emitter.off(eventType, listener);\n if (sub) {\n delete this._subs[sub];\n }\n return sub;\n }\n\n removeAllListeners() {\n let current_subs = this._subs;\n this._subs = {};\n Object.keys(current_subs).forEach((sub) => {\n this._emitter.off(current_subs[sub], sub);\n });\n }\n}\n","import Events from \"./events\";\n\nexport default class Var {\n constructor(group, name, /*optional*/ value) {\n this._group = group;\n this._name = name;\n this._value = value;\n this._events = new Events();\n }\n\n get() {\n return this._value;\n }\n\n set(value, /*optional*/ event) {\n if (this._value === value) {\n // Do nothing; the value hasn't changed\n return;\n }\n let oldValue = this._value;\n this._value = value;\n // Alert JavaScript listeners that the value has changed\n let evt = {};\n if (event && typeof(event) === \"object\") {\n for (let k in event) {\n if (event.hasOwnProperty(k))\n evt[k] = event[k];\n }\n }\n evt.oldValue = oldValue;\n evt.value = value;\n this._events.trigger(\"change\", evt, this);\n\n // TODO: Make this extensible, to let arbitrary back-ends know that\n // something has changed\n if (global.Shiny && global.Shiny.onInputChange) {\n global.Shiny.onInputChange(\n \".clientValue-\" +\n (this._group.name !== null ? this._group.name + \"-\" : \"\") +\n this._name,\n typeof(value) === \"undefined\" ? null : value\n );\n }\n }\n\n on(eventType, listener) {\n return this._events.on(eventType, listener);\n }\n\n off(eventType, listener) {\n return this._events.off(eventType, listener);\n }\n}\n"]} \ No newline at end of file diff --git a/docs/articles/variable_details_files/crosstalk-1.2.1/scss/crosstalk.scss b/docs/articles/variable_details_files/crosstalk-1.2.1/scss/crosstalk.scss new file mode 100644 index 00000000..35665616 --- /dev/null +++ b/docs/articles/variable_details_files/crosstalk-1.2.1/scss/crosstalk.scss @@ -0,0 +1,75 @@ +/* Adjust margins outwards, so column contents line up with the edges of the + parent of container-fluid. */ +.container-fluid.crosstalk-bscols { + margin-left: -30px; + margin-right: -30px; + white-space: normal; +} + +/* But don't adjust the margins outwards if we're directly under the body, + i.e. we were the top-level of something at the console. */ +body > .container-fluid.crosstalk-bscols { + margin-left: auto; + margin-right: auto; +} + +.crosstalk-input-checkboxgroup .crosstalk-options-group .crosstalk-options-column { + display: inline-block; + padding-right: 12px; + vertical-align: top; +} + +@media only screen and (max-width:480px) { + .crosstalk-input-checkboxgroup .crosstalk-options-group .crosstalk-options-column { + display: block; + padding-right: inherit; + } +} + +/* Relevant BS3 styles to make filter_checkbox() look reasonable without Bootstrap */ +.crosstalk-input { + margin-bottom: 15px; /* a la .form-group */ + .control-label { + margin-bottom: 0; + vertical-align: middle; + } + input[type="checkbox"] { + margin: 4px 0 0; + margin-top: 1px; + line-height: normal; + } + .checkbox { + position: relative; + display: block; + margin-top: 10px; + margin-bottom: 10px; + } + .checkbox > label{ + padding-left: 20px; + margin-bottom: 0; + font-weight: 400; + cursor: pointer; + } + .checkbox input[type="checkbox"], + .checkbox-inline input[type="checkbox"] { + position: absolute; + margin-top: 2px; + margin-left: -20px; + } + .checkbox + .checkbox { + margin-top: -5px; + } + .checkbox-inline { + position: relative; + display: inline-block; + padding-left: 20px; + margin-bottom: 0; + font-weight: 400; + vertical-align: middle; + cursor: pointer; + } + .checkbox-inline + .checkbox-inline { + margin-top: 0; + margin-left: 10px; + } +} diff --git a/docs/articles/variable_details_files/datatables-binding-0.33/datatables.js b/docs/articles/variable_details_files/datatables-binding-0.33/datatables.js new file mode 100644 index 00000000..765b53cb --- /dev/null +++ b/docs/articles/variable_details_files/datatables-binding-0.33/datatables.js @@ -0,0 +1,1539 @@ +(function() { + +// some helper functions: using a global object DTWidget so that it can be used +// in JS() code, e.g. datatable(options = list(foo = JS('code'))); unlike R's +// dynamic scoping, when 'code' is eval'ed, JavaScript does not know objects +// from the "parent frame", e.g. JS('DTWidget') will not work unless it was made +// a global object +var DTWidget = {}; + +// 123456666.7890 -> 123,456,666.7890 +var markInterval = function(d, digits, interval, mark, decMark, precision) { + x = precision ? d.toPrecision(digits) : d.toFixed(digits); + if (!/^-?[\d.]+$/.test(x)) return x; + var xv = x.split('.'); + if (xv.length > 2) return x; // should have at most one decimal point + xv[0] = xv[0].replace(new RegExp('\\B(?=(\\d{' + interval + '})+(?!\\d))', 'g'), mark); + return xv.join(decMark); +}; + +DTWidget.formatCurrency = function(data, currency, digits, interval, mark, decMark, before, zeroPrint) { + var d = parseFloat(data); + if (isNaN(d)) return ''; + if (zeroPrint !== null && d === 0.0) return zeroPrint; + var res = markInterval(d, digits, interval, mark, decMark); + res = before ? (/^-/.test(res) ? '-' + currency + res.replace(/^-/, '') : currency + res) : + res + currency; + return res; +}; + +DTWidget.formatString = function(data, prefix, suffix) { + var d = data; + if (d === null) return ''; + return prefix + d + suffix; +}; + +DTWidget.formatPercentage = function(data, digits, interval, mark, decMark, zeroPrint) { + var d = parseFloat(data); + if (isNaN(d)) return ''; + if (zeroPrint !== null && d === 0.0) return zeroPrint; + return markInterval(d * 100, digits, interval, mark, decMark) + '%'; +}; + +DTWidget.formatRound = function(data, digits, interval, mark, decMark, zeroPrint) { + var d = parseFloat(data); + if (isNaN(d)) return ''; + if (zeroPrint !== null && d === 0.0) return zeroPrint; + return markInterval(d, digits, interval, mark, decMark); +}; + +DTWidget.formatSignif = function(data, digits, interval, mark, decMark, zeroPrint) { + var d = parseFloat(data); + if (isNaN(d)) return ''; + if (zeroPrint !== null && d === 0.0) return zeroPrint; + return markInterval(d, digits, interval, mark, decMark, true); +}; + +DTWidget.formatDate = function(data, method, params) { + var d = data; + if (d === null) return ''; + // (new Date('2015-10-28')).toDateString() may return 2015-10-27 because the + // actual time created could be like 'Tue Oct 27 2015 19:00:00 GMT-0500 (CDT)', + // i.e. the date-only string is treated as UTC time instead of local time + if ((method === 'toDateString' || method === 'toLocaleDateString') && /^\d{4,}\D\d{2}\D\d{2}$/.test(d)) { + d = d.split(/\D/); + d = new Date(d[0], d[1] - 1, d[2]); + } else { + d = new Date(d); + } + return d[method].apply(d, params); +}; + +window.DTWidget = DTWidget; + +// A helper function to update the properties of existing filters +var setFilterProps = function(td, props) { + // Update enabled/disabled state + var $input = $(td).find('input').first(); + var searchable = $input.data('searchable'); + $input.prop('disabled', !searchable || props.disabled); + + // Based on the filter type, set its new values + var type = td.getAttribute('data-type'); + if (['factor', 'logical'].includes(type)) { + // Reformat the new dropdown options for use with selectize + var new_vals = props.params.options.map(function(item) { + return { text: item, value: item }; + }); + + // Find the selectize object + var dropdown = $(td).find('.selectized').eq(0)[0].selectize; + + // Note the current values + var old_vals = dropdown.getValue(); + + // Remove the existing values + dropdown.clearOptions(); + + // Add the new options + dropdown.addOption(new_vals); + + // Preserve the existing values + dropdown.setValue(old_vals); + + } else if (['number', 'integer', 'date', 'time'].includes(type)) { + // Apply internal scaling to new limits. Updating scale not yet implemented. + var slider = $(td).find('.noUi-target').eq(0); + var scale = Math.pow(10, Math.max(0, +slider.data('scale') || 0)); + var new_vals = [props.params.min * scale, props.params.max * scale]; + + // Note what the new limits will be just for this filter + var new_lims = new_vals.slice(); + + // Determine the current values and limits + var old_vals = slider.val().map(Number); + var old_lims = slider.noUiSlider('options').range; + old_lims = [old_lims.min, old_lims.max]; + + // Preserve the current values if filters have been applied; otherwise, apply no filtering + if (old_vals[0] != old_lims[0]) { + new_vals[0] = Math.max(old_vals[0], new_vals[0]); + } + + if (old_vals[1] != old_lims[1]) { + new_vals[1] = Math.min(old_vals[1], new_vals[1]); + } + + // Update the endpoints of the slider + slider.noUiSlider({ + start: new_vals, + range: {'min': new_lims[0], 'max': new_lims[1]} + }, true); + } +}; + +var transposeArray2D = function(a) { + return a.length === 0 ? a : HTMLWidgets.transposeArray2D(a); +}; + +var crosstalkPluginsInstalled = false; + +function maybeInstallCrosstalkPlugins() { + if (crosstalkPluginsInstalled) + return; + crosstalkPluginsInstalled = true; + + $.fn.dataTable.ext.afnFiltering.push( + function(oSettings, aData, iDataIndex) { + var ctfilter = oSettings.nTable.ctfilter; + if (ctfilter && !ctfilter[iDataIndex]) + return false; + + var ctselect = oSettings.nTable.ctselect; + if (ctselect && !ctselect[iDataIndex]) + return false; + + return true; + } + ); +} + +HTMLWidgets.widget({ + name: "datatables", + type: "output", + renderOnNullValue: true, + initialize: function(el, width, height) { + // in order that the type=number inputs return a number + $.valHooks.number = { + get: function(el) { + var value = parseFloat(el.value); + return isNaN(value) ? "" : value; + } + }; + $(el).html(' '); + return { + data: null, + ctfilterHandle: new crosstalk.FilterHandle(), + ctfilterSubscription: null, + ctselectHandle: new crosstalk.SelectionHandle(), + ctselectSubscription: null + }; + }, + renderValue: function(el, data, instance) { + if (el.offsetWidth === 0 || el.offsetHeight === 0) { + instance.data = data; + return; + } + instance.data = null; + var $el = $(el); + $el.empty(); + + if (data === null) { + $el.append(' '); + // clear previous Shiny inputs (if any) + for (var i in instance.clearInputs) instance.clearInputs[i](); + instance.clearInputs = {}; + return; + } + + var crosstalkOptions = data.crosstalkOptions; + if (!crosstalkOptions) crosstalkOptions = { + 'key': null, 'group': null + }; + if (crosstalkOptions.group) { + maybeInstallCrosstalkPlugins(); + instance.ctfilterHandle.setGroup(crosstalkOptions.group); + instance.ctselectHandle.setGroup(crosstalkOptions.group); + } + + // if we are in the viewer then we always want to fillContainer and + // and autoHideNavigation (unless the user has explicitly set these) + if (window.HTMLWidgets.viewerMode) { + if (!data.hasOwnProperty("fillContainer")) + data.fillContainer = true; + if (!data.hasOwnProperty("autoHideNavigation")) + data.autoHideNavigation = true; + } + + // propagate fillContainer to instance (so we have it in resize) + instance.fillContainer = data.fillContainer; + + var cells = data.data; + + if (cells instanceof Array) cells = transposeArray2D(cells); + + $el.append(data.container); + var $table = $el.find('table'); + if (data.class) $table.addClass(data.class); + if (data.caption) $table.prepend(data.caption); + + if (!data.selection) data.selection = { + mode: 'none', selected: null, target: 'row', selectable: null + }; + if (HTMLWidgets.shinyMode && data.selection.mode !== 'none' && + data.selection.target === 'row+column') { + if ($table.children('tfoot').length === 0) { + $table.append($('')); + $table.find('thead tr').clone().appendTo($table.find('tfoot')); + } + } + + // column filters + var filterRow; + switch (data.filter) { + case 'top': + $table.children('thead').append(data.filterHTML); + filterRow = $table.find('thead tr:last td'); + break; + case 'bottom': + if ($table.children('tfoot').length === 0) { + $table.append($('')); + } + $table.children('tfoot').prepend(data.filterHTML); + filterRow = $table.find('tfoot tr:first td'); + break; + } + + var options = { searchDelay: 1000 }; + if (cells !== null) $.extend(options, { + data: cells + }); + + // options for fillContainer + var bootstrapActive = typeof($.fn.popover) != 'undefined'; + if (instance.fillContainer) { + + // force scrollX/scrollY and turn off autoWidth + options.scrollX = true; + options.scrollY = "100px"; // can be any value, we'll adjust below + + // if we aren't paginating then move around the info/filter controls + // to save space at the bottom and rephrase the info callback + if (data.options.paging === false) { + + // we know how to do this cleanly for bootstrap, not so much + // for other themes/layouts + if (bootstrapActive) { + options.dom = "<'row'<'col-sm-4'i><'col-sm-8'f>>" + + "<'row'<'col-sm-12'tr>>"; + } + + options.fnInfoCallback = function(oSettings, iStart, iEnd, + iMax, iTotal, sPre) { + return Number(iTotal).toLocaleString() + " records"; + }; + } + } + + // auto hide navigation if requested + // Note, this only works on client-side processing mode as on server-side, + // cells (data.data) is null; In addition, we require the pageLength option + // being provided explicitly to enable this. Despite we may be able to deduce + // the default value of pageLength, it may complicate things so we'd rather + // put this responsiblity to users and warn them on the R side. + if (data.autoHideNavigation === true && data.options.paging !== false) { + // strip all nav if length >= cells + if ((cells instanceof Array) && data.options.pageLength >= cells.length) + options.dom = bootstrapActive ? "<'row'<'col-sm-12'tr>>" : "t"; + // alternatively lean things out for flexdashboard mobile portrait + else if (bootstrapActive && window.FlexDashboard && window.FlexDashboard.isMobilePhone()) + options.dom = "<'row'<'col-sm-12'f>>" + + "<'row'<'col-sm-12'tr>>" + + "<'row'<'col-sm-12'p>>"; + } + + $.extend(true, options, data.options || {}); + + var searchCols = options.searchCols; + if (searchCols) { + searchCols = searchCols.map(function(x) { + return x === null ? '' : x.search; + }); + // FIXME: this means I don't respect the escapeRegex setting + delete options.searchCols; + } + + // server-side processing? + var server = options.serverSide === true; + + // use the dataSrc function to pre-process JSON data returned from R + var DT_rows_all = [], DT_rows_current = []; + if (server && HTMLWidgets.shinyMode && typeof options.ajax === 'object' && + /^session\/[\da-z]+\/dataobj/.test(options.ajax.url) && !options.ajax.dataSrc) { + options.ajax.dataSrc = function(json) { + DT_rows_all = $.makeArray(json.DT_rows_all); + DT_rows_current = $.makeArray(json.DT_rows_current); + var data = json.data; + if (!colReorderEnabled()) return data; + var table = $table.DataTable(), order = table.colReorder.order(), flag = true, i, j, row; + for (i = 0; i < order.length; ++i) if (order[i] !== i) flag = false; + if (flag) return data; + for (i = 0; i < data.length; ++i) { + row = data[i].slice(); + for (j = 0; j < order.length; ++j) data[i][j] = row[order[j]]; + } + return data; + }; + } + + var thiz = this; + if (instance.fillContainer) $table.on('init.dt', function(e) { + thiz.fillAvailableHeight(el, $(el).innerHeight()); + }); + // If the page contains serveral datatables and one of which enables colReorder, + // the table.colReorder.order() function will exist but throws error when called. + // So it seems like the only way to know if colReorder is enabled or not is to + // check the options. + var colReorderEnabled = function() { return "colReorder" in options; }; + var table = $table.DataTable(options); + $el.data('datatable', table); + + if ('rowGroup' in options) { + // Maintain RowGroup dataSrc when columns are reordered (#1109) + table.on('column-reorder', function(e, settings, details) { + var oldDataSrc = table.rowGroup().dataSrc(); + var newDataSrc = details.mapping[oldDataSrc]; + table.rowGroup().dataSrc(newDataSrc); + }); + } + + // Unregister previous Crosstalk event subscriptions, if they exist + if (instance.ctfilterSubscription) { + instance.ctfilterHandle.off("change", instance.ctfilterSubscription); + instance.ctfilterSubscription = null; + } + if (instance.ctselectSubscription) { + instance.ctselectHandle.off("change", instance.ctselectSubscription); + instance.ctselectSubscription = null; + } + + if (!crosstalkOptions.group) { + $table[0].ctfilter = null; + $table[0].ctselect = null; + } else { + var key = crosstalkOptions.key; + function keysToMatches(keys) { + if (!keys) { + return null; + } else { + var selectedKeys = {}; + for (var i = 0; i < keys.length; i++) { + selectedKeys[keys[i]] = true; + } + var matches = {}; + for (var j = 0; j < key.length; j++) { + if (selectedKeys[key[j]]) + matches[j] = true; + } + return matches; + } + } + + function applyCrosstalkFilter(e) { + $table[0].ctfilter = keysToMatches(e.value); + table.draw(); + } + instance.ctfilterSubscription = instance.ctfilterHandle.on("change", applyCrosstalkFilter); + applyCrosstalkFilter({value: instance.ctfilterHandle.filteredKeys}); + + function applyCrosstalkSelection(e) { + if (e.sender !== instance.ctselectHandle) { + table + .rows('.' + selClass, {search: 'applied'}) + .nodes() + .to$() + .removeClass(selClass); + if (selectedRows) + changeInput('rows_selected', selectedRows(), void 0, true); + } + + if (e.sender !== instance.ctselectHandle && e.value && e.value.length) { + var matches = keysToMatches(e.value); + + // persistent selection with plotly (& leaflet) + var ctOpts = crosstalk.var("plotlyCrosstalkOpts").get() || {}; + if (ctOpts.persistent === true) { + var matches = $.extend(matches, $table[0].ctselect); + } + + $table[0].ctselect = matches; + table.draw(); + } else { + if ($table[0].ctselect) { + $table[0].ctselect = null; + table.draw(); + } + } + } + instance.ctselectSubscription = instance.ctselectHandle.on("change", applyCrosstalkSelection); + // TODO: This next line doesn't seem to work when renderDataTable is used + applyCrosstalkSelection({value: instance.ctselectHandle.value}); + } + + var inArray = function(val, array) { + return $.inArray(val, $.makeArray(array)) > -1; + }; + + // search the i-th column + var searchColumn = function(i, value) { + var regex = false, ci = true; + if (options.search) { + regex = options.search.regex, + ci = options.search.caseInsensitive !== false; + } + // need to transpose the column index when colReorder is enabled + if (table.colReorder) i = table.colReorder.transpose(i); + return table.column(i).search(value, regex, !regex, ci); + }; + + if (data.filter !== 'none') { + if (!data.hasOwnProperty('filterSettings')) data.filterSettings = {}; + + filterRow.each(function(i, td) { + + var $td = $(td), type = $td.data('type'), filter; + var $input = $td.children('div').first().children('input'); + var disabled = $input.prop('disabled'); + var searchable = table.settings()[0].aoColumns[i].bSearchable; + $input.prop('disabled', !searchable || disabled); + $input.data('searchable', searchable); // for updating later + $input.on('input blur', function() { + $input.next('span').toggle(Boolean($input.val())); + }); + // Bootstrap sets pointer-events to none and we won't be able to click + // the clear button + $input.next('span').css('pointer-events', 'auto').hide().click(function() { + $(this).hide().prev('input').val('').trigger('input').focus(); + }); + var searchCol; // search string for this column + if (searchCols && searchCols[i]) { + searchCol = searchCols[i]; + $input.val(searchCol).trigger('input'); + } + var $x = $td.children('div').last(); + + // remove the overflow: hidden attribute of the scrollHead + // (otherwise the scrolling table body obscures the filters) + // The workaround and the discussion from + // https://github.com/rstudio/DT/issues/554#issuecomment-518007347 + // Otherwise the filter selection will not be anchored to the values + // when the columns number is many and scrollX is enabled. + var scrollHead = $(el).find('.dataTables_scrollHead,.dataTables_scrollFoot'); + var cssOverflowHead = scrollHead.css('overflow'); + var scrollBody = $(el).find('.dataTables_scrollBody'); + var cssOverflowBody = scrollBody.css('overflow'); + var scrollTable = $(el).find('.dataTables_scroll'); + var cssOverflowTable = scrollTable.css('overflow'); + if (cssOverflowHead === 'hidden') { + $x.on('show hide', function(e) { + if (e.type === 'show') { + scrollHead.css('overflow', 'visible'); + scrollBody.css('overflow', 'visible'); + scrollTable.css('overflow-x', 'scroll'); + } else { + scrollHead.css('overflow', cssOverflowHead); + scrollBody.css('overflow', cssOverflowBody); + scrollTable.css('overflow-x', cssOverflowTable); + } + }); + $x.css('z-index', 25); + } + + if (inArray(type, ['factor', 'logical'])) { + $input.on({ + click: function() { + $input.parent().hide(); $x.show().trigger('show'); filter[0].selectize.focus(); + }, + input: function() { + var v1 = JSON.stringify(filter[0].selectize.getValue()), v2 = $input.val(); + if (v1 === '[]') v1 = ''; + if (v1 !== v2) filter[0].selectize.setValue(v2 === '' ? [] : JSON.parse(v2)); + } + }); + var $input2 = $x.children('select'); + filter = $input2.selectize($.extend({ + options: $input2.data('options').map(function(v, i) { + return ({text: v, value: v}); + }), + plugins: ['remove_button'], + hideSelected: true, + onChange: function(value) { + if (value === null) value = []; // compatibility with jQuery 3.0 + $input.val(value.length ? JSON.stringify(value) : ''); + if (value.length) $input.trigger('input'); + $input.attr('title', $input.val()); + if (server) { + searchColumn(i, value.length ? JSON.stringify(value) : '').draw(); + return; + } + // turn off filter if nothing selected + $td.data('filter', value.length > 0); + table.draw(); // redraw table, and filters will be applied + } + }, data.filterSettings.select)); + filter[0].selectize.on('blur', function() { + $x.hide().trigger('hide'); $input.parent().show(); $input.trigger('blur'); + }); + filter.next('div').css('margin-bottom', 'auto'); + } else if (type === 'character') { + var fun = function() { + searchColumn(i, $input.val()).draw(); + }; + // throttle searching for server-side processing + var throttledFun = $.fn.dataTable.util.throttle(fun, options.searchDelay); + $input.on('input', function(e, immediate) { + // always bypass throttling when immediate = true (via the updateSearch method) + (immediate || !server) ? fun() : throttledFun(); + }); + } else if (inArray(type, ['number', 'integer', 'date', 'time'])) { + var $x0 = $x; + $x = $x0.children('div').first(); + $x0.css({ + 'background-color': '#fff', + 'border': '1px #ddd solid', + 'border-radius': '4px', + 'padding': data.vertical ? '35px 20px': '20px 20px 10px 20px' + }); + var $spans = $x0.children('span').css({ + 'margin-top': data.vertical ? '0' : '10px', + 'white-space': 'nowrap' + }); + var $span1 = $spans.first(), $span2 = $spans.last(); + var r1 = +$x.data('min'), r2 = +$x.data('max'); + // when the numbers are too small or have many decimal places, the + // slider may have numeric precision problems (#150) + var scale = Math.pow(10, Math.max(0, +$x.data('scale') || 0)); + r1 = Math.round(r1 * scale); r2 = Math.round(r2 * scale); + var scaleBack = function(x, scale) { + if (scale === 1) return x; + var d = Math.round(Math.log(scale) / Math.log(10)); + // to avoid problems like 3.423/100 -> 0.034230000000000003 + return (x / scale).toFixed(d); + }; + var slider_min = function() { + return filter.noUiSlider('options').range.min; + }; + var slider_max = function() { + return filter.noUiSlider('options').range.max; + }; + $input.on({ + focus: function() { + $x0.show().trigger('show'); + // first, make sure the slider div leaves at least 20px between + // the two (slider value) span's + $x0.width(Math.max(160, $span1.outerWidth() + $span2.outerWidth() + 20)); + // then, if the input is really wide or slider is vertical, + // make the slider the same width as the input + if ($x0.outerWidth() < $input.outerWidth() || data.vertical) { + $x0.outerWidth($input.outerWidth()); + } + // make sure the slider div does not reach beyond the right margin + if ($(window).width() < $x0.offset().left + $x0.width()) { + $x0.offset({ + 'left': $input.offset().left + $input.outerWidth() - $x0.outerWidth() + }); + } + }, + blur: function() { + $x0.hide().trigger('hide'); + }, + input: function() { + if ($input.val() === '') filter.val([slider_min(), slider_max()]); + }, + change: function() { + var v = $input.val().replace(/\s/g, ''); + if (v === '') return; + v = v.split('...'); + if (v.length !== 2) { + $input.parent().addClass('has-error'); + return; + } + if (v[0] === '') v[0] = slider_min(); + if (v[1] === '') v[1] = slider_max(); + $input.parent().removeClass('has-error'); + // treat date as UTC time at midnight + var strTime = function(x) { + var s = type === 'date' ? 'T00:00:00Z' : ''; + var t = new Date(x + s).getTime(); + // add 10 minutes to date since it does not hurt the date, and + // it helps avoid the tricky floating point arithmetic problems, + // e.g. sometimes the date may be a few milliseconds earlier + // than the midnight due to precision problems in noUiSlider + return type === 'date' ? t + 3600000 : t; + }; + if (inArray(type, ['date', 'time'])) { + v[0] = strTime(v[0]); + v[1] = strTime(v[1]); + } + if (v[0] != slider_min()) v[0] *= scale; + if (v[1] != slider_max()) v[1] *= scale; + filter.val(v); + } + }); + var formatDate = function(d) { + d = scaleBack(d, scale); + if (type === 'number') return d; + if (type === 'integer') return parseInt(d); + var x = new Date(+d); + if (type === 'date') { + var pad0 = function(x) { + return ('0' + x).substr(-2, 2); + }; + return x.getUTCFullYear() + '-' + pad0(1 + x.getUTCMonth()) + + '-' + pad0(x.getUTCDate()); + } else { + return x.toISOString(); + } + }; + var opts = type === 'date' ? { step: 60 * 60 * 1000 } : + type === 'integer' ? { step: 1 } : {}; + + opts.orientation = data.vertical ? 'vertical': 'horizontal'; + opts.direction = data.vertical ? 'rtl': 'ltr'; + + filter = $x.noUiSlider($.extend({ + start: [r1, r2], + range: {min: r1, max: r2}, + connect: true + }, opts, data.filterSettings.slider)); + if (scale > 1) (function() { + var t1 = r1, t2 = r2; + var val = filter.val(); + while (val[0] > r1 || val[1] < r2) { + if (val[0] > r1) { + t1 -= val[0] - r1; + } + if (val[1] < r2) { + t2 += r2 - val[1]; + } + filter = $x.noUiSlider($.extend({ + start: [t1, t2], + range: {min: t1, max: t2}, + connect: true + }, opts, data.filterSettings.slider), true); + val = filter.val(); + } + r1 = t1; r2 = t2; + })(); + // format with active column renderer, if defined + var colDef = data.options.columnDefs.find(function(def) { + return (def.targets === i || inArray(i, def.targets)) && 'render' in def; + }); + var updateSliderText = function(v1, v2) { + // we only know how to use function renderers + if (colDef && typeof colDef.render === 'function') { + var restore = function(v) { + v = scaleBack(v, scale); + return inArray(type, ['date', 'time']) ? new Date(+v) : v; + } + $span1.text(colDef.render(restore(v1), 'display')); + $span2.text(colDef.render(restore(v2), 'display')); + } else { + $span1.text(formatDate(v1)); + $span2.text(formatDate(v2)); + } + }; + updateSliderText(r1, r2); + var updateSlider = function(e) { + var val = filter.val(); + // turn off filter if in full range + $td.data('filter', val[0] > slider_min() || val[1] < slider_max()); + var v1 = formatDate(val[0]), v2 = formatDate(val[1]), ival; + if ($td.data('filter')) { + ival = v1 + ' ... ' + v2; + $input.attr('title', ival).val(ival).trigger('input'); + } else { + $input.attr('title', '').val(''); + } + updateSliderText(val[0], val[1]); + if (e.type === 'slide') return; // no searching when sliding only + if (server) { + searchColumn(i, $td.data('filter') ? ival : '').draw(); + return; + } + table.draw(); + }; + filter.on({ + set: updateSlider, + slide: updateSlider + }); + } + + // server-side processing will be handled by R (or whatever server + // language you use); the following code is only needed for client-side + // processing + if (server) { + // if a search string has been pre-set, search now + if (searchCol) $input.trigger('input').trigger('change'); + return; + } + + var customFilter = function(settings, data, dataIndex) { + // there is no way to attach a search function to a specific table, + // and we need to make sure a global search function is not applied to + // all tables (i.e. a range filter in a previous table should not be + // applied to the current table); we use the settings object to + // determine if we want to perform searching on the current table, + // since settings.sTableId will be different to different tables + if (table.settings()[0] !== settings) return true; + // no filter on this column or no need to filter this column + if (typeof filter === 'undefined' || !$td.data('filter')) return true; + + var r = filter.val(), v, r0, r1; + var i_data = function(i) { + if (!colReorderEnabled()) return i; + var order = table.colReorder.order(), k; + for (k = 0; k < order.length; ++k) if (order[k] === i) return k; + return i; // in theory it will never be here... + } + v = data[i_data(i)]; + if (type === 'number' || type === 'integer') { + v = parseFloat(v); + // how to handle NaN? currently exclude these rows + if (isNaN(v)) return(false); + r0 = parseFloat(scaleBack(r[0], scale)) + r1 = parseFloat(scaleBack(r[1], scale)); + if (v >= r0 && v <= r1) return true; + } else if (type === 'date' || type === 'time') { + v = new Date(v); + r0 = new Date(r[0] / scale); r1 = new Date(r[1] / scale); + if (v >= r0 && v <= r1) return true; + } else if (type === 'factor') { + if (r.length === 0 || inArray(v, r)) return true; + } else if (type === 'logical') { + if (r.length === 0) return true; + if (inArray(v === '' ? 'na' : v, r)) return true; + } + return false; + }; + + $.fn.dataTable.ext.search.push(customFilter); + + // search for the preset search strings if it is non-empty + if (searchCol) $input.trigger('input').trigger('change'); + + }); + + } + + // highlight search keywords + var highlight = function() { + var body = $(table.table().body()); + // removing the old highlighting first + body.unhighlight(); + + // don't highlight the "not found" row, so we get the rows using the api + if (table.rows({ filter: 'applied' }).data().length === 0) return; + // highlight global search keywords + body.highlight($.trim(table.search()).split(/\s+/)); + // then highlight keywords from individual column filters + if (filterRow) filterRow.each(function(i, td) { + var $td = $(td), type = $td.data('type'); + if (type !== 'character') return; + var $input = $td.children('div').first().children('input'); + var column = table.column(i).nodes().to$(), + val = $.trim($input.val()); + if (type !== 'character' || val === '') return; + column.highlight(val.split(/\s+/)); + }); + }; + + if (options.searchHighlight) { + table + .on('draw.dt.dth column-visibility.dt.dth column-reorder.dt.dth', highlight) + .on('destroy', function() { + // remove event handler + table.off('draw.dt.dth column-visibility.dt.dth column-reorder.dt.dth'); + }); + + // Set the option for escaping regex characters in our search string. This will be used + // for all future matching. + jQuery.fn.highlight.options.escapeRegex = (!options.search || !options.search.regex); + + // initial highlight for state saved conditions and initial states + highlight(); + } + + // run the callback function on the table instance + if (typeof data.callback === 'function') data.callback(table); + + // double click to edit the cell, row, column, or all cells + if (data.editable) table.on('dblclick.dt', 'tbody td', function(e) { + // only bring up the editor when the cell itself is dbclicked, and ignore + // other dbclick events bubbled up (e.g. from the ) + if (e.target !== this) return; + var target = [], immediate = false; + switch (data.editable.target) { + case 'cell': + target = [this]; + immediate = true; // edit will take effect immediately + break; + case 'row': + target = table.cells(table.cell(this).index().row, '*').nodes(); + break; + case 'column': + target = table.cells('*', table.cell(this).index().column).nodes(); + break; + case 'all': + target = table.cells().nodes(); + break; + default: + throw 'The editable parameter must be "cell", "row", "column", or "all"'; + } + var disableCols = data.editable.disable ? data.editable.disable.columns : null; + var numericCols = data.editable.numeric; + var areaCols = data.editable.area; + var dateCols = data.editable.date; + for (var i = 0; i < target.length; i++) { + (function(cell, current) { + var $cell = $(cell), html = $cell.html(); + var _cell = table.cell(cell), value = _cell.data(), index = _cell.index().column; + var $input; + if (inArray(index, numericCols)) { + $input = $(''); + } else if (inArray(index, areaCols)) { + $input = $(''); + } else if (inArray(index, dateCols)) { + $input = $(''); + } else { + $input = $(''); + } + if (!immediate) { + $cell.data('input', $input).data('html', html); + $input.attr('title', 'Hit Ctrl+Enter to finish editing, or Esc to cancel'); + } + $input.val(value); + if (inArray(index, disableCols)) { + $input.attr('readonly', '').css('filter', 'invert(25%)'); + } + $cell.empty().append($input); + if (cell === current) $input.focus(); + $input.css('width', '100%'); + + if (immediate) $input.on('blur', function(e) { + var valueNew = $input.val(); + if (valueNew !== value) { + _cell.data(valueNew); + if (HTMLWidgets.shinyMode) { + changeInput('cell_edit', [cellInfo(cell)], 'DT.cellInfo', null, {priority: 'event'}); + } + // for server-side processing, users have to call replaceData() to update the table + if (!server) table.draw(false); + } else { + $cell.html(html); + } + }).on('keyup', function(e) { + // hit Escape to cancel editing + if (e.keyCode === 27) $input.trigger('blur'); + }); + + // bulk edit (row, column, or all) + if (!immediate) $input.on('keyup', function(e) { + var removeInput = function($cell, restore) { + $cell.data('input').remove(); + if (restore) $cell.html($cell.data('html')); + } + if (e.keyCode === 27) { + for (var i = 0; i < target.length; i++) { + removeInput($(target[i]), true); + } + } else if (e.keyCode === 13 && e.ctrlKey) { + // Ctrl + Enter + var cell, $cell, _cell, cellData = []; + for (var i = 0; i < target.length; i++) { + cell = target[i]; $cell = $(cell); _cell = table.cell(cell); + _cell.data($cell.data('input').val()); + HTMLWidgets.shinyMode && cellData.push(cellInfo(cell)); + removeInput($cell, false); + } + if (HTMLWidgets.shinyMode) { + changeInput('cell_edit', cellData, 'DT.cellInfo', null, {priority: "event"}); + } + if (!server) table.draw(false); + } + }); + })(target[i], this); + } + }); + + // interaction with shiny + if (!HTMLWidgets.shinyMode && !crosstalkOptions.group) return; + + var methods = {}; + var shinyData = {}; + + methods.updateCaption = function(caption) { + if (!caption) return; + $table.children('caption').replaceWith(caption); + } + + // register clear functions to remove input values when the table is removed + instance.clearInputs = {}; + + var changeInput = function(id, value, type, noCrosstalk, opts) { + var event = id; + id = el.id + '_' + id; + if (type) id = id + ':' + type; + // do not update if the new value is the same as old value + if (event !== 'cell_edit' && !/_clicked$/.test(event) && shinyData.hasOwnProperty(id) && shinyData[id] === JSON.stringify(value)) + return; + shinyData[id] = JSON.stringify(value); + if (HTMLWidgets.shinyMode && Shiny.setInputValue) { + Shiny.setInputValue(id, value, opts); + if (!instance.clearInputs[id]) instance.clearInputs[id] = function() { + Shiny.setInputValue(id, null); + } + } + + // HACK + if (event === "rows_selected" && !noCrosstalk) { + if (crosstalkOptions.group) { + var keys = crosstalkOptions.key; + var selectedKeys = null; + if (value) { + selectedKeys = []; + for (var i = 0; i < value.length; i++) { + // The value array's contents use 1-based row numbers, so we must + // convert to 0-based before indexing into the keys array. + selectedKeys.push(keys[value[i] - 1]); + } + } + instance.ctselectHandle.set(selectedKeys); + } + } + }; + + var addOne = function(x) { + return x.map(function(i) { return 1 + i; }); + }; + + var unique = function(x) { + var ux = []; + $.each(x, function(i, el){ + if ($.inArray(el, ux) === -1) ux.push(el); + }); + return ux; + } + + // change the row index of a cell + var tweakCellIndex = function(cell) { + var info = cell.index(); + // some cell may not be valid. e.g, #759 + // when using the RowGroup extension, datatables will + // generate the row label and the cells are not part of + // the data thus contain no row/col info + if (info === undefined) + return {row: null, col: null}; + if (server) { + info.row = DT_rows_current[info.row]; + } else { + info.row += 1; + } + return {row: info.row, col: info.column}; + } + + var cleanSelectedValues = function() { + changeInput('rows_selected', []); + changeInput('columns_selected', []); + changeInput('cells_selected', transposeArray2D([]), 'shiny.matrix'); + } + // #828 we should clean the selection on the server-side when the table reloads + cleanSelectedValues(); + + // a flag to indicates if select extension is initialized or not + var flagSelectExt = table.settings()[0]._select !== undefined; + // the Select extension should only be used in the client mode and + // when the selection.mode is set to none + if (data.selection.mode === 'none' && !server && flagSelectExt) { + var updateRowsSelected = function() { + var rows = table.rows({selected: true}); + var selected = []; + $.each(rows.indexes().toArray(), function(i, v) { + selected.push(v + 1); + }); + changeInput('rows_selected', selected); + } + var updateColsSelected = function() { + var columns = table.columns({selected: true}); + changeInput('columns_selected', columns.indexes().toArray()); + } + var updateCellsSelected = function() { + var cells = table.cells({selected: true}); + var selected = []; + cells.every(function() { + var row = this.index().row; + var col = this.index().column; + selected = selected.concat([[row + 1, col]]); + }); + changeInput('cells_selected', transposeArray2D(selected), 'shiny.matrix'); + } + table.on('select deselect', function(e, dt, type, indexes) { + updateRowsSelected(); + updateColsSelected(); + updateCellsSelected(); + }) + updateRowsSelected(); + updateColsSelected(); + updateCellsSelected(); + } + + var selMode = data.selection.mode, selTarget = data.selection.target; + var selDisable = data.selection.selectable === false; + if (inArray(selMode, ['single', 'multiple'])) { + var selClass = inArray(data.style, ['bootstrap', 'bootstrap4']) ? 'active' : 'selected'; + // selected1: row indices; selected2: column indices + var initSel = function(x) { + if (x === null || typeof x === 'boolean' || selTarget === 'cell') { + return {rows: [], cols: []}; + } else if (selTarget === 'row') { + return {rows: $.makeArray(x), cols: []}; + } else if (selTarget === 'column') { + return {rows: [], cols: $.makeArray(x)}; + } else if (selTarget === 'row+column') { + return {rows: $.makeArray(x.rows), cols: $.makeArray(x.cols)}; + } + } + var selected = data.selection.selected; + var selected1 = initSel(selected).rows, selected2 = initSel(selected).cols; + // selectable should contain either all positive or all non-positive values, not both + // positive values indicate "selectable" while non-positive values means "nonselectable" + // the assertion is performed on R side. (only column indicides could be zero which indicates + // the row name) + var selectable = data.selection.selectable; + var selectable1 = initSel(selectable).rows, selectable2 = initSel(selectable).cols; + + // After users reorder the rows or filter the table, we cannot use the table index + // directly. Instead, we need this function to find out the rows between the two clicks. + // If user filter the table again between the start click and the end click, the behavior + // would be undefined, but it should not be a problem. + var shiftSelRowsIndex = function(start, end) { + var indexes = server ? DT_rows_all : table.rows({ search: 'applied' }).indexes().toArray(); + start = indexes.indexOf(start); end = indexes.indexOf(end); + // if start is larger than end, we need to swap + if (start > end) { + var tmp = end; end = start; start = tmp; + } + return indexes.slice(start, end + 1); + } + + var serverRowIndex = function(clientRowIndex) { + return server ? DT_rows_current[clientRowIndex] : clientRowIndex + 1; + } + + // row, column, or cell selection + var lastClickedRow; + if (inArray(selTarget, ['row', 'row+column'])) { + // Get the current selected rows. It will also + // update the selected1's value based on the current row selection state + // Note we can't put this function inside selectRows() directly, + // the reason is method.selectRows() will override selected1's value but this + // function will add rows to selected1 (keep the existing selection), which is + // inconsistent with column and cell selection. + var selectedRows = function() { + var rows = table.rows('.' + selClass); + var idx = rows.indexes().toArray(); + if (!server) { + selected1 = addOne(idx); + return selected1; + } + idx = idx.map(function(i) { + return DT_rows_current[i]; + }); + selected1 = selMode === 'multiple' ? unique(selected1.concat(idx)) : idx; + return selected1; + } + // Change selected1's value based on selectable1, then refresh the row state + var onlyKeepSelectableRows = function() { + if (selDisable) { // users can't select; useful when only want backend select + selected1 = []; + return; + } + if (selectable1.length === 0) return; + var nonselectable = selectable1[0] <= 0; + if (nonselectable) { + // should make selectable1 positive + selected1 = $(selected1).not(selectable1.map(function(i) { return -i; })).get(); + } else { + selected1 = $(selected1).filter(selectable1).get(); + } + } + // Change selected1's value based on selectable1, then + // refresh the row selection state according to values in selected1 + var selectRows = function(ignoreSelectable) { + if (!ignoreSelectable) onlyKeepSelectableRows(); + table.$('tr.' + selClass).removeClass(selClass); + if (selected1.length === 0) return; + if (server) { + table.rows({page: 'current'}).every(function() { + if (inArray(DT_rows_current[this.index()], selected1)) { + $(this.node()).addClass(selClass); + } + }); + } else { + var selected0 = selected1.map(function(i) { return i - 1; }); + $(table.rows(selected0).nodes()).addClass(selClass); + } + } + table.on('mousedown.dt', 'tbody tr', function(e) { + var $this = $(this), thisRow = table.row(this); + if (selMode === 'multiple') { + if (e.shiftKey && lastClickedRow !== undefined) { + // select or de-select depends on the last clicked row's status + var flagSel = !$this.hasClass(selClass); + var crtClickedRow = serverRowIndex(thisRow.index()); + if (server) { + var rowsIndex = shiftSelRowsIndex(lastClickedRow, crtClickedRow); + // update current page's selClass + rowsIndex.map(function(i) { + var rowIndex = DT_rows_current.indexOf(i); + if (rowIndex >= 0) { + var row = table.row(rowIndex).nodes().to$(); + var flagRowSel = !row.hasClass(selClass); + if (flagSel === flagRowSel) row.toggleClass(selClass); + } + }); + // update selected1 + if (flagSel) { + selected1 = unique(selected1.concat(rowsIndex)); + } else { + selected1 = selected1.filter(function(index) { + return !inArray(index, rowsIndex); + }); + } + } else { + // js starts from 0 + shiftSelRowsIndex(lastClickedRow - 1, crtClickedRow - 1).map(function(value) { + var row = table.row(value).nodes().to$(); + var flagRowSel = !row.hasClass(selClass); + if (flagSel === flagRowSel) row.toggleClass(selClass); + }); + } + e.preventDefault(); + } else { + $this.toggleClass(selClass); + } + } else { + if ($this.hasClass(selClass)) { + $this.removeClass(selClass); + } else { + table.$('tr.' + selClass).removeClass(selClass); + $this.addClass(selClass); + } + } + if (server && !$this.hasClass(selClass)) { + var id = DT_rows_current[thisRow.index()]; + // remove id from selected1 since its class .selected has been removed + if (inArray(id, selected1)) selected1.splice($.inArray(id, selected1), 1); + } + selectedRows(); // update selected1's value based on selClass + selectRows(false); // only keep the selectable rows + changeInput('rows_selected', selected1); + changeInput('row_last_clicked', serverRowIndex(thisRow.index()), null, null, {priority: 'event'}); + lastClickedRow = serverRowIndex(thisRow.index()); + }); + selectRows(false); // in case users have specified pre-selected rows + // restore selected rows after the table is redrawn (e.g. sort/search/page); + // client-side tables will preserve the selections automatically; for + // server-side tables, we have to *real* row indices are in `selected1` + changeInput('rows_selected', selected1); + if (server) table.on('draw.dt', function(e) { selectRows(false); }); + methods.selectRows = function(selected, ignoreSelectable) { + selected1 = $.makeArray(selected); + selectRows(ignoreSelectable); + changeInput('rows_selected', selected1); + } + } + + if (inArray(selTarget, ['column', 'row+column'])) { + if (selTarget === 'row+column') { + $(table.columns().footer()).css('cursor', 'pointer'); + } + // update selected2's value based on selectable2 + var onlyKeepSelectableCols = function() { + if (selDisable) { // users can't select; useful when only want backend select + selected2 = []; + return; + } + if (selectable2.length === 0) return; + var nonselectable = selectable2[0] <= 0; + if (nonselectable) { + // need to make selectable2 positive + selected2 = $(selected2).not(selectable2.map(function(i) { return -i; })).get(); + } else { + selected2 = $(selected2).filter(selectable2).get(); + } + } + // update selected2 and then + // refresh the col selection state according to values in selected2 + var selectCols = function(ignoreSelectable) { + if (!ignoreSelectable) onlyKeepSelectableCols(); + // if selected2 is not a valide index (e.g., larger than the column number) + // table.columns(selected2) will fail and result in a blank table + // this is different from the table.rows(), where the out-of-range indexes + // doesn't affect at all + selected2 = $(selected2).filter(table.columns().indexes()).get(); + table.columns().nodes().flatten().to$().removeClass(selClass); + if (selected2.length > 0) + table.columns(selected2).nodes().flatten().to$().addClass(selClass); + } + var callback = function() { + var colIdx = selTarget === 'column' ? table.cell(this).index().column : + $.inArray(this, table.columns().footer()), + thisCol = $(table.column(colIdx).nodes()); + if (colIdx === -1) return; + if (thisCol.hasClass(selClass)) { + thisCol.removeClass(selClass); + selected2.splice($.inArray(colIdx, selected2), 1); + } else { + if (selMode === 'single') $(table.cells().nodes()).removeClass(selClass); + thisCol.addClass(selClass); + selected2 = selMode === 'single' ? [colIdx] : unique(selected2.concat([colIdx])); + } + selectCols(false); // update selected2 based on selectable + changeInput('columns_selected', selected2); + } + if (selTarget === 'column') { + $(table.table().body()).on('click.dt', 'td', callback); + } else { + $(table.table().footer()).on('click.dt', 'tr th', callback); + } + selectCols(false); // in case users have specified pre-selected columns + changeInput('columns_selected', selected2); + if (server) table.on('draw.dt', function(e) { selectCols(false); }); + methods.selectColumns = function(selected, ignoreSelectable) { + selected2 = $.makeArray(selected); + selectCols(ignoreSelectable); + changeInput('columns_selected', selected2); + } + } + + if (selTarget === 'cell') { + var selected3 = [], selectable3 = []; + if (selected !== null) selected3 = selected; + if (selectable !== null && typeof selectable !== 'boolean') selectable3 = selectable; + var findIndex = function(ij, sel) { + for (var i = 0; i < sel.length; i++) { + if (ij[0] === sel[i][0] && ij[1] === sel[i][1]) return i; + } + return -1; + } + // Change selected3's value based on selectable3, then refresh the cell state + var onlyKeepSelectableCells = function() { + if (selDisable) { // users can't select; useful when only want backend select + selected3 = []; + return; + } + if (selectable3.length === 0) return; + var nonselectable = selectable3[0][0] <= 0; + var out = []; + if (nonselectable) { + selected3.map(function(ij) { + // should make selectable3 positive + if (findIndex([-ij[0], -ij[1]], selectable3) === -1) { out.push(ij); } + }); + } else { + selected3.map(function(ij) { + if (findIndex(ij, selectable3) > -1) { out.push(ij); } + }); + } + selected3 = out; + } + // Change selected3's value based on selectable3, then + // refresh the cell selection state according to values in selected3 + var selectCells = function(ignoreSelectable) { + if (!ignoreSelectable) onlyKeepSelectableCells(); + table.$('td.' + selClass).removeClass(selClass); + if (selected3.length === 0) return; + if (server) { + table.cells({page: 'current'}).every(function() { + var info = tweakCellIndex(this); + if (findIndex([info.row, info.col], selected3) > -1) + $(this.node()).addClass(selClass); + }); + } else { + selected3.map(function(ij) { + $(table.cell(ij[0] - 1, ij[1]).node()).addClass(selClass); + }); + } + }; + table.on('click.dt', 'tbody td', function() { + var $this = $(this), info = tweakCellIndex(table.cell(this)); + if ($this.hasClass(selClass)) { + $this.removeClass(selClass); + selected3.splice(findIndex([info.row, info.col], selected3), 1); + } else { + if (selMode === 'single') $(table.cells().nodes()).removeClass(selClass); + $this.addClass(selClass); + selected3 = selMode === 'single' ? [[info.row, info.col]] : + unique(selected3.concat([[info.row, info.col]])); + } + selectCells(false); // must call this to update selected3 based on selectable3 + changeInput('cells_selected', transposeArray2D(selected3), 'shiny.matrix'); + }); + selectCells(false); // in case users have specified pre-selected columns + changeInput('cells_selected', transposeArray2D(selected3), 'shiny.matrix'); + + if (server) table.on('draw.dt', function(e) { selectCells(false); }); + methods.selectCells = function(selected, ignoreSelectable) { + selected3 = selected ? selected : []; + selectCells(ignoreSelectable); + changeInput('cells_selected', transposeArray2D(selected3), 'shiny.matrix'); + } + } + } + + // expose some table info to Shiny + var updateTableInfo = function(e, settings) { + // TODO: is anyone interested in the page info? + // changeInput('page_info', table.page.info()); + var updateRowInfo = function(id, modifier) { + var idx; + if (server) { + idx = modifier.page === 'current' ? DT_rows_current : DT_rows_all; + } else { + var rows = table.rows($.extend({ + search: 'applied', + page: 'all' + }, modifier)); + idx = addOne(rows.indexes().toArray()); + } + changeInput('rows' + '_' + id, idx); + }; + updateRowInfo('current', {page: 'current'}); + updateRowInfo('all', {}); + } + table.on('draw.dt', updateTableInfo); + updateTableInfo(); + + // state info + table.on('draw.dt column-visibility.dt', function() { + changeInput('state', table.state()); + }); + changeInput('state', table.state()); + + // search info + var updateSearchInfo = function() { + changeInput('search', table.search()); + if (filterRow) changeInput('search_columns', filterRow.toArray().map(function(td) { + return $(td).find('input').first().val(); + })); + } + table.on('draw.dt', updateSearchInfo); + updateSearchInfo(); + + var cellInfo = function(thiz) { + var info = tweakCellIndex(table.cell(thiz)); + info.value = table.cell(thiz).data(); + return info; + } + // the current cell clicked on + table.on('click.dt', 'tbody td', function() { + changeInput('cell_clicked', cellInfo(this), null, null, {priority: 'event'}); + }) + changeInput('cell_clicked', {}); + + // do not trigger table selection when clicking on links unless they have classes + table.on('mousedown.dt', 'tbody td a', function(e) { + if (this.className === '') e.stopPropagation(); + }); + + methods.addRow = function(data, rowname, resetPaging) { + var n = table.columns().indexes().length, d = n - data.length; + if (d === 1) { + data = rowname.concat(data) + } else if (d !== 0) { + console.log(data); + console.log(table.columns().indexes()); + throw 'New data must be of the same length as current data (' + n + ')'; + }; + table.row.add(data).draw(resetPaging); + } + + methods.updateSearch = function(keywords) { + if (keywords.global !== null) + $(table.table().container()).find('input[type=search]').first() + .val(keywords.global).trigger('input'); + var columns = keywords.columns; + if (!filterRow || columns === null) return; + filterRow.toArray().map(function(td, i) { + var v = typeof columns === 'string' ? columns : columns[i]; + if (typeof v === 'undefined') { + console.log('The search keyword for column ' + i + ' is undefined') + return; + } + // Update column search string and values on linked filter widgets. + // 'input' for factor and char filters, 'change' for numeric filters. + $(td).find('input').first().val(v).trigger('input', [true]).trigger('change'); + }); + table.draw(); + } + + methods.hideCols = function(hide, reset) { + if (reset) table.columns().visible(true, false); + table.columns(hide).visible(false); + } + + methods.showCols = function(show, reset) { + if (reset) table.columns().visible(false, false); + table.columns(show).visible(true); + } + + methods.colReorder = function(order, origOrder) { + table.colReorder.order(order, origOrder); + } + + methods.selectPage = function(page) { + if (table.page.info().pages < page || page < 1) { + throw 'Selected page is out of range'; + }; + table.page(page - 1).draw(false); + } + + methods.reloadData = function(resetPaging, clearSelection) { + // empty selections first if necessary + if (methods.selectRows && inArray('row', clearSelection)) methods.selectRows([]); + if (methods.selectColumns && inArray('column', clearSelection)) methods.selectColumns([]); + if (methods.selectCells && inArray('cell', clearSelection)) methods.selectCells([]); + table.ajax.reload(null, resetPaging); + } + + // update table filters (set new limits of sliders) + methods.updateFilters = function(newProps) { + // loop through each filter in the filter row + filterRow.each(function(i, td) { + var k = i; + if (filterRow.length > newProps.length) { + if (i === 0) return; // first column is row names + k = i - 1; + } + // Update the filters to reflect the updated data. + // Allow "falsy" (e.g. NULL) to signify a no-op. + if (newProps[k]) { + setFilterProps(td, newProps[k]); + } + }); + }; + + table.shinyMethods = methods; + }, + resize: function(el, width, height, instance) { + if (instance.data) this.renderValue(el, instance.data, instance); + + // dynamically adjust height if fillContainer = TRUE + if (instance.fillContainer) + this.fillAvailableHeight(el, height); + + this.adjustWidth(el); + }, + + // dynamically set the scroll body to fill available height + // (used with fillContainer = TRUE) + fillAvailableHeight: function(el, availableHeight) { + + // see how much of the table is occupied by header/footer elements + // and use that to compute a target scroll body height + var dtWrapper = $(el).find('div.dataTables_wrapper'); + var dtScrollBody = $(el).find($('div.dataTables_scrollBody')); + var framingHeight = dtWrapper.innerHeight() - dtScrollBody.innerHeight(); + var scrollBodyHeight = availableHeight - framingHeight; + + // we need to set `max-height` to none as datatables library now sets this + // to a fixed height, disabling the ability to resize to fill the window, + // as it will be set to a fixed 100px under such circumstances, e.g., RStudio IDE, + // or FlexDashboard + // see https://github.com/rstudio/DT/issues/951#issuecomment-1026464509 + dtScrollBody.css('max-height', 'none'); + // set the height + dtScrollBody.height(scrollBodyHeight + 'px'); + }, + + // adjust the width of columns; remove the hard-coded widths on table and the + // scroll header when scrollX/Y are enabled + adjustWidth: function(el) { + var $el = $(el), table = $el.data('datatable'); + if (table) table.columns.adjust(); + $el.find('.dataTables_scrollHeadInner').css('width', '') + .children('table').css('margin-left', ''); + } +}); + + if (!HTMLWidgets.shinyMode) return; + + Shiny.addCustomMessageHandler('datatable-calls', function(data) { + var id = data.id; + var el = document.getElementById(id); + var table = el ? $(el).data('datatable') : null; + if (!table) { + console.log("Couldn't find table with id " + id); + return; + } + + var methods = table.shinyMethods, call = data.call; + if (methods[call.method]) { + methods[call.method].apply(table, call.args); + } else { + console.log("Unknown method " + call.method); + } + }); + +})(); diff --git a/docs/articles/variable_details_files/datatables-css-0.0.0/datatables-crosstalk.css b/docs/articles/variable_details_files/datatables-css-0.0.0/datatables-crosstalk.css index 43422d25..bd1159c8 100644 --- a/docs/articles/variable_details_files/datatables-css-0.0.0/datatables-crosstalk.css +++ b/docs/articles/variable_details_files/datatables-css-0.0.0/datatables-crosstalk.css @@ -5,3 +5,28 @@ html body div.DTS div.dataTables_scrollBody { background: none; } + + +/* +Fix https://github.com/rstudio/DT/issues/563 +If the `table.display` is set to "block" (e.g., pkgdown), the browser will display +datatable objects strangely. The search panel and the page buttons will still be +in full-width but the table body will be "compact" and shorter. +In therory, having this attributes will affect `dom="t"` +with `display: block` users. But in reality, there should be no one. +We may remove the below lines in the future if the upstream agree to have this there. +See https://github.com/DataTables/DataTablesSrc/issues/160 +*/ + +table.dataTable { + display: table; +} + + +/* +When DTOutput(fill = TRUE), it receives a .html-fill-item class (via htmltools::bindFillRole()), which effectively amounts to `flex: 1 1 auto`. That's mostly fine, but the case where `fillContainer=TRUE`+`height:auto`+`flex-basis:auto` and the container (e.g., a bslib::card()) doesn't have a defined height is a bit problematic since the table wants to fit the parent but the parent wants to fit the table, which results pretty small table height (maybe because there is a minimum height somewhere?). It seems better in this case to impose a 400px height default for the table, which we can do by setting `flex-basis` to 400px (the table is still allowed to grow/shrink when the container has an opinionated height). +*/ + +.html-fill-container > .html-fill-item.datatables { + flex-basis: 400px; +} diff --git a/docs/articles/variable_details_files/dt-core-1.13.6/css/jquery.dataTables.extra.css b/docs/articles/variable_details_files/dt-core-1.13.6/css/jquery.dataTables.extra.css new file mode 100644 index 00000000..b2dd141f --- /dev/null +++ b/docs/articles/variable_details_files/dt-core-1.13.6/css/jquery.dataTables.extra.css @@ -0,0 +1,28 @@ +/* Selected rows/cells */ +table.dataTable tr.selected td, table.dataTable td.selected { + background-color: #b0bed9 !important; +} +/* In case of scrollX/Y or FixedHeader */ +.dataTables_scrollBody .dataTables_sizing { + visibility: hidden; +} + +/* The datatables' theme CSS file doesn't define +the color but with white background. It leads to an issue that +when the HTML's body color is set to 'white', the user can't +see the text since the background is white. One case happens in the +RStudio's IDE when inline viewing the DT table inside an Rmd file, +if the IDE theme is set to "Cobalt". + +See https://github.com/rstudio/DT/issues/447 for more info + +This fixes should have little side-effects because all the other elements +of the default theme use the #333 font color. + +TODO: The upstream may use relative colors for both the table background +and the color. It means the table can display well without this patch +then. At that time, we need to remove the below CSS attributes. +*/ +div.datatables { + color: #333; +} diff --git a/docs/articles/variable_details_files/dt-core-1.13.6/css/jquery.dataTables.min.css b/docs/articles/variable_details_files/dt-core-1.13.6/css/jquery.dataTables.min.css new file mode 100644 index 00000000..ad59f843 --- /dev/null +++ b/docs/articles/variable_details_files/dt-core-1.13.6/css/jquery.dataTables.min.css @@ -0,0 +1 @@ +:root{--dt-row-selected: 13, 110, 253;--dt-row-selected-text: 255, 255, 255;--dt-row-selected-link: 9, 10, 11;--dt-row-stripe: 0, 0, 0;--dt-row-hover: 0, 0, 0;--dt-column-ordering: 0, 0, 0;--dt-html-background: white}:root.dark{--dt-html-background: rgb(33, 37, 41)}table.dataTable td.dt-control{text-align:center;cursor:pointer}table.dataTable td.dt-control:before{display:inline-block;color:rgba(0, 0, 0, 0.5);content:"►"}table.dataTable tr.dt-hasChild td.dt-control:before{content:"▼"}html.dark table.dataTable td.dt-control:before{color:rgba(255, 255, 255, 0.5)}html.dark table.dataTable tr.dt-hasChild td.dt-control:before{color:rgba(255, 255, 255, 0.5)}table.dataTable thead>tr>th.sorting,table.dataTable thead>tr>th.sorting_asc,table.dataTable thead>tr>th.sorting_desc,table.dataTable thead>tr>th.sorting_asc_disabled,table.dataTable thead>tr>th.sorting_desc_disabled,table.dataTable thead>tr>td.sorting,table.dataTable thead>tr>td.sorting_asc,table.dataTable thead>tr>td.sorting_desc,table.dataTable thead>tr>td.sorting_asc_disabled,table.dataTable thead>tr>td.sorting_desc_disabled{cursor:pointer;position:relative;padding-right:26px}table.dataTable thead>tr>th.sorting:before,table.dataTable thead>tr>th.sorting:after,table.dataTable thead>tr>th.sorting_asc:before,table.dataTable thead>tr>th.sorting_asc:after,table.dataTable thead>tr>th.sorting_desc:before,table.dataTable thead>tr>th.sorting_desc:after,table.dataTable thead>tr>th.sorting_asc_disabled:before,table.dataTable thead>tr>th.sorting_asc_disabled:after,table.dataTable thead>tr>th.sorting_desc_disabled:before,table.dataTable thead>tr>th.sorting_desc_disabled:after,table.dataTable thead>tr>td.sorting:before,table.dataTable thead>tr>td.sorting:after,table.dataTable thead>tr>td.sorting_asc:before,table.dataTable thead>tr>td.sorting_asc:after,table.dataTable thead>tr>td.sorting_desc:before,table.dataTable thead>tr>td.sorting_desc:after,table.dataTable thead>tr>td.sorting_asc_disabled:before,table.dataTable thead>tr>td.sorting_asc_disabled:after,table.dataTable thead>tr>td.sorting_desc_disabled:before,table.dataTable thead>tr>td.sorting_desc_disabled:after{position:absolute;display:block;opacity:.125;right:10px;line-height:9px;font-size:.8em}table.dataTable thead>tr>th.sorting:before,table.dataTable thead>tr>th.sorting_asc:before,table.dataTable thead>tr>th.sorting_desc:before,table.dataTable thead>tr>th.sorting_asc_disabled:before,table.dataTable thead>tr>th.sorting_desc_disabled:before,table.dataTable thead>tr>td.sorting:before,table.dataTable thead>tr>td.sorting_asc:before,table.dataTable thead>tr>td.sorting_desc:before,table.dataTable thead>tr>td.sorting_asc_disabled:before,table.dataTable thead>tr>td.sorting_desc_disabled:before{bottom:50%;content:"▲";content:"▲"/""}table.dataTable thead>tr>th.sorting:after,table.dataTable thead>tr>th.sorting_asc:after,table.dataTable thead>tr>th.sorting_desc:after,table.dataTable thead>tr>th.sorting_asc_disabled:after,table.dataTable thead>tr>th.sorting_desc_disabled:after,table.dataTable thead>tr>td.sorting:after,table.dataTable thead>tr>td.sorting_asc:after,table.dataTable thead>tr>td.sorting_desc:after,table.dataTable thead>tr>td.sorting_asc_disabled:after,table.dataTable thead>tr>td.sorting_desc_disabled:after{top:50%;content:"▼";content:"▼"/""}table.dataTable thead>tr>th.sorting_asc:before,table.dataTable thead>tr>th.sorting_desc:after,table.dataTable thead>tr>td.sorting_asc:before,table.dataTable thead>tr>td.sorting_desc:after{opacity:.6}table.dataTable thead>tr>th.sorting_desc_disabled:after,table.dataTable thead>tr>th.sorting_asc_disabled:before,table.dataTable thead>tr>td.sorting_desc_disabled:after,table.dataTable thead>tr>td.sorting_asc_disabled:before{display:none}table.dataTable thead>tr>th:active,table.dataTable thead>tr>td:active{outline:none}div.dataTables_scrollBody>table.dataTable>thead>tr>th:before,div.dataTables_scrollBody>table.dataTable>thead>tr>th:after,div.dataTables_scrollBody>table.dataTable>thead>tr>td:before,div.dataTables_scrollBody>table.dataTable>thead>tr>td:after{display:none}div.dataTables_processing{position:absolute;top:50%;left:50%;width:200px;margin-left:-100px;margin-top:-26px;text-align:center;padding:2px}div.dataTables_processing>div:last-child{position:relative;width:80px;height:15px;margin:1em auto}div.dataTables_processing>div:last-child>div{position:absolute;top:0;width:13px;height:13px;border-radius:50%;background:rgb(13, 110, 253);background:rgb(var(--dt-row-selected));animation-timing-function:cubic-bezier(0, 1, 1, 0)}div.dataTables_processing>div:last-child>div:nth-child(1){left:8px;animation:datatables-loader-1 .6s infinite}div.dataTables_processing>div:last-child>div:nth-child(2){left:8px;animation:datatables-loader-2 .6s infinite}div.dataTables_processing>div:last-child>div:nth-child(3){left:32px;animation:datatables-loader-2 .6s infinite}div.dataTables_processing>div:last-child>div:nth-child(4){left:56px;animation:datatables-loader-3 .6s infinite}@keyframes datatables-loader-1{0%{transform:scale(0)}100%{transform:scale(1)}}@keyframes datatables-loader-3{0%{transform:scale(1)}100%{transform:scale(0)}}@keyframes datatables-loader-2{0%{transform:translate(0, 0)}100%{transform:translate(24px, 0)}}table.dataTable.nowrap th,table.dataTable.nowrap td{white-space:nowrap}table.dataTable th.dt-left,table.dataTable td.dt-left{text-align:left}table.dataTable th.dt-center,table.dataTable td.dt-center,table.dataTable td.dataTables_empty{text-align:center}table.dataTable th.dt-right,table.dataTable td.dt-right{text-align:right}table.dataTable th.dt-justify,table.dataTable td.dt-justify{text-align:justify}table.dataTable th.dt-nowrap,table.dataTable td.dt-nowrap{white-space:nowrap}table.dataTable thead th,table.dataTable thead td,table.dataTable tfoot th,table.dataTable tfoot td{text-align:left}table.dataTable thead th.dt-head-left,table.dataTable thead td.dt-head-left,table.dataTable tfoot th.dt-head-left,table.dataTable tfoot td.dt-head-left{text-align:left}table.dataTable thead th.dt-head-center,table.dataTable thead td.dt-head-center,table.dataTable tfoot th.dt-head-center,table.dataTable tfoot td.dt-head-center{text-align:center}table.dataTable thead th.dt-head-right,table.dataTable thead td.dt-head-right,table.dataTable tfoot th.dt-head-right,table.dataTable tfoot td.dt-head-right{text-align:right}table.dataTable thead th.dt-head-justify,table.dataTable thead td.dt-head-justify,table.dataTable tfoot th.dt-head-justify,table.dataTable tfoot td.dt-head-justify{text-align:justify}table.dataTable thead th.dt-head-nowrap,table.dataTable thead td.dt-head-nowrap,table.dataTable tfoot th.dt-head-nowrap,table.dataTable tfoot td.dt-head-nowrap{white-space:nowrap}table.dataTable tbody th.dt-body-left,table.dataTable tbody td.dt-body-left{text-align:left}table.dataTable tbody th.dt-body-center,table.dataTable tbody td.dt-body-center{text-align:center}table.dataTable tbody th.dt-body-right,table.dataTable tbody td.dt-body-right{text-align:right}table.dataTable tbody th.dt-body-justify,table.dataTable tbody td.dt-body-justify{text-align:justify}table.dataTable tbody th.dt-body-nowrap,table.dataTable tbody td.dt-body-nowrap{white-space:nowrap}table.dataTable{width:100%;margin:0 auto;clear:both;border-collapse:separate;border-spacing:0}table.dataTable thead th,table.dataTable tfoot th{font-weight:bold}table.dataTable>thead>tr>th,table.dataTable>thead>tr>td{padding:10px;border-bottom:1px solid rgba(0, 0, 0, 0.3)}table.dataTable>thead>tr>th:active,table.dataTable>thead>tr>td:active{outline:none}table.dataTable>tfoot>tr>th,table.dataTable>tfoot>tr>td{padding:10px 10px 6px 10px;border-top:1px solid rgba(0, 0, 0, 0.3)}table.dataTable tbody tr{background-color:transparent}table.dataTable tbody tr.selected>*{box-shadow:inset 0 0 0 9999px rgba(13, 110, 253, 0.9);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.9);color:rgb(255, 255, 255);color:rgb(var(--dt-row-selected-text))}table.dataTable tbody tr.selected a{color:rgb(9, 10, 11);color:rgb(var(--dt-row-selected-link))}table.dataTable tbody th,table.dataTable tbody td{padding:8px 10px}table.dataTable.row-border>tbody>tr>th,table.dataTable.row-border>tbody>tr>td,table.dataTable.display>tbody>tr>th,table.dataTable.display>tbody>tr>td{border-top:1px solid rgba(0, 0, 0, 0.15)}table.dataTable.row-border>tbody>tr:first-child>th,table.dataTable.row-border>tbody>tr:first-child>td,table.dataTable.display>tbody>tr:first-child>th,table.dataTable.display>tbody>tr:first-child>td{border-top:none}table.dataTable.row-border>tbody>tr.selected+tr.selected>td,table.dataTable.display>tbody>tr.selected+tr.selected>td{border-top-color:#0262ef}table.dataTable.cell-border>tbody>tr>th,table.dataTable.cell-border>tbody>tr>td{border-top:1px solid rgba(0, 0, 0, 0.15);border-right:1px solid rgba(0, 0, 0, 0.15)}table.dataTable.cell-border>tbody>tr>th:first-child,table.dataTable.cell-border>tbody>tr>td:first-child{border-left:1px solid rgba(0, 0, 0, 0.15)}table.dataTable.cell-border>tbody>tr:first-child>th,table.dataTable.cell-border>tbody>tr:first-child>td{border-top:none}table.dataTable.stripe>tbody>tr.odd>*,table.dataTable.display>tbody>tr.odd>*{box-shadow:inset 0 0 0 9999px rgba(0, 0, 0, 0.023);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-stripe), 0.023)}table.dataTable.stripe>tbody>tr.odd.selected>*,table.dataTable.display>tbody>tr.odd.selected>*{box-shadow:inset 0 0 0 9999px rgba(13, 110, 253, 0.923);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.923)}table.dataTable.hover>tbody>tr:hover>*,table.dataTable.display>tbody>tr:hover>*{box-shadow:inset 0 0 0 9999px rgba(0, 0, 0, 0.035);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-hover), 0.035)}table.dataTable.hover>tbody>tr.selected:hover>*,table.dataTable.display>tbody>tr.selected:hover>*{box-shadow:inset 0 0 0 9999px #0d6efd !important;box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 1) !important}table.dataTable.order-column>tbody tr>.sorting_1,table.dataTable.order-column>tbody tr>.sorting_2,table.dataTable.order-column>tbody tr>.sorting_3,table.dataTable.display>tbody tr>.sorting_1,table.dataTable.display>tbody tr>.sorting_2,table.dataTable.display>tbody tr>.sorting_3{box-shadow:inset 0 0 0 9999px rgba(0, 0, 0, 0.019);box-shadow:inset 0 0 0 9999px rgba(var(--dt-column-ordering), 0.019)}table.dataTable.order-column>tbody tr.selected>.sorting_1,table.dataTable.order-column>tbody tr.selected>.sorting_2,table.dataTable.order-column>tbody tr.selected>.sorting_3,table.dataTable.display>tbody tr.selected>.sorting_1,table.dataTable.display>tbody tr.selected>.sorting_2,table.dataTable.display>tbody tr.selected>.sorting_3{box-shadow:inset 0 0 0 9999px rgba(13, 110, 253, 0.919);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.919)}table.dataTable.display>tbody>tr.odd>.sorting_1,table.dataTable.order-column.stripe>tbody>tr.odd>.sorting_1{box-shadow:inset 0 0 0 9999px rgba(0, 0, 0, 0.054);box-shadow:inset 0 0 0 9999px rgba(var(--dt-column-ordering), 0.054)}table.dataTable.display>tbody>tr.odd>.sorting_2,table.dataTable.order-column.stripe>tbody>tr.odd>.sorting_2{box-shadow:inset 0 0 0 9999px rgba(0, 0, 0, 0.047);box-shadow:inset 0 0 0 9999px rgba(var(--dt-column-ordering), 0.047)}table.dataTable.display>tbody>tr.odd>.sorting_3,table.dataTable.order-column.stripe>tbody>tr.odd>.sorting_3{box-shadow:inset 0 0 0 9999px rgba(0, 0, 0, 0.039);box-shadow:inset 0 0 0 9999px rgba(var(--dt-column-ordering), 0.039)}table.dataTable.display>tbody>tr.odd.selected>.sorting_1,table.dataTable.order-column.stripe>tbody>tr.odd.selected>.sorting_1{box-shadow:inset 0 0 0 9999px rgba(13, 110, 253, 0.954);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.954)}table.dataTable.display>tbody>tr.odd.selected>.sorting_2,table.dataTable.order-column.stripe>tbody>tr.odd.selected>.sorting_2{box-shadow:inset 0 0 0 9999px rgba(13, 110, 253, 0.947);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.947)}table.dataTable.display>tbody>tr.odd.selected>.sorting_3,table.dataTable.order-column.stripe>tbody>tr.odd.selected>.sorting_3{box-shadow:inset 0 0 0 9999px rgba(13, 110, 253, 0.939);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.939)}table.dataTable.display>tbody>tr.even>.sorting_1,table.dataTable.order-column.stripe>tbody>tr.even>.sorting_1{box-shadow:inset 0 0 0 9999px rgba(0, 0, 0, 0.019);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.019)}table.dataTable.display>tbody>tr.even>.sorting_2,table.dataTable.order-column.stripe>tbody>tr.even>.sorting_2{box-shadow:inset 0 0 0 9999px rgba(0, 0, 0, 0.011);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.011)}table.dataTable.display>tbody>tr.even>.sorting_3,table.dataTable.order-column.stripe>tbody>tr.even>.sorting_3{box-shadow:inset 0 0 0 9999px rgba(0, 0, 0, 0.003);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.003)}table.dataTable.display>tbody>tr.even.selected>.sorting_1,table.dataTable.order-column.stripe>tbody>tr.even.selected>.sorting_1{box-shadow:inset 0 0 0 9999px rgba(13, 110, 253, 0.919);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.919)}table.dataTable.display>tbody>tr.even.selected>.sorting_2,table.dataTable.order-column.stripe>tbody>tr.even.selected>.sorting_2{box-shadow:inset 0 0 0 9999px rgba(13, 110, 253, 0.911);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.911)}table.dataTable.display>tbody>tr.even.selected>.sorting_3,table.dataTable.order-column.stripe>tbody>tr.even.selected>.sorting_3{box-shadow:inset 0 0 0 9999px rgba(13, 110, 253, 0.903);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.903)}table.dataTable.display tbody tr:hover>.sorting_1,table.dataTable.order-column.hover tbody tr:hover>.sorting_1{box-shadow:inset 0 0 0 9999px rgba(0, 0, 0, 0.082);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-hover), 0.082)}table.dataTable.display tbody tr:hover>.sorting_2,table.dataTable.order-column.hover tbody tr:hover>.sorting_2{box-shadow:inset 0 0 0 9999px rgba(0, 0, 0, 0.074);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-hover), 0.074)}table.dataTable.display tbody tr:hover>.sorting_3,table.dataTable.order-column.hover tbody tr:hover>.sorting_3{box-shadow:inset 0 0 0 9999px rgba(0, 0, 0, 0.062);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-hover), 0.062)}table.dataTable.display tbody tr:hover.selected>.sorting_1,table.dataTable.order-column.hover tbody tr:hover.selected>.sorting_1{box-shadow:inset 0 0 0 9999px rgba(13, 110, 253, 0.982);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.982)}table.dataTable.display tbody tr:hover.selected>.sorting_2,table.dataTable.order-column.hover tbody tr:hover.selected>.sorting_2{box-shadow:inset 0 0 0 9999px rgba(13, 110, 253, 0.974);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.974)}table.dataTable.display tbody tr:hover.selected>.sorting_3,table.dataTable.order-column.hover tbody tr:hover.selected>.sorting_3{box-shadow:inset 0 0 0 9999px rgba(13, 110, 253, 0.962);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.962)}table.dataTable.no-footer{border-bottom:1px solid rgba(0, 0, 0, 0.3)}table.dataTable.compact thead th,table.dataTable.compact thead td,table.dataTable.compact tfoot th,table.dataTable.compact tfoot td,table.dataTable.compact tbody th,table.dataTable.compact tbody td{padding:4px}table.dataTable th,table.dataTable td{box-sizing:content-box}.dataTables_wrapper{position:relative;clear:both}.dataTables_wrapper .dataTables_length{float:left}.dataTables_wrapper .dataTables_length select{border:1px solid #aaa;border-radius:3px;padding:5px;background-color:transparent;color:inherit;padding:4px}.dataTables_wrapper .dataTables_filter{float:right;text-align:right}.dataTables_wrapper .dataTables_filter input{border:1px solid #aaa;border-radius:3px;padding:5px;background-color:transparent;color:inherit;margin-left:3px}.dataTables_wrapper .dataTables_info{clear:both;float:left;padding-top:.755em}.dataTables_wrapper .dataTables_paginate{float:right;text-align:right;padding-top:.25em}.dataTables_wrapper .dataTables_paginate .paginate_button{box-sizing:border-box;display:inline-block;min-width:1.5em;padding:.5em 1em;margin-left:2px;text-align:center;text-decoration:none !important;cursor:pointer;color:inherit !important;border:1px solid transparent;border-radius:2px;background:transparent}.dataTables_wrapper .dataTables_paginate .paginate_button.current,.dataTables_wrapper .dataTables_paginate .paginate_button.current:hover{color:inherit !important;border:1px solid rgba(0, 0, 0, 0.3);background-color:rgba(0, 0, 0, 0.05);background:-webkit-gradient(linear, left top, left bottom, color-stop(0%, rgba(230, 230, 230, 0.05)), color-stop(100%, rgba(0, 0, 0, 0.05)));background:-webkit-linear-gradient(top, rgba(230, 230, 230, 0.05) 0%, rgba(0, 0, 0, 0.05) 100%);background:-moz-linear-gradient(top, rgba(230, 230, 230, 0.05) 0%, rgba(0, 0, 0, 0.05) 100%);background:-ms-linear-gradient(top, rgba(230, 230, 230, 0.05) 0%, rgba(0, 0, 0, 0.05) 100%);background:-o-linear-gradient(top, rgba(230, 230, 230, 0.05) 0%, rgba(0, 0, 0, 0.05) 100%);background:linear-gradient(to bottom, rgba(230, 230, 230, 0.05) 0%, rgba(0, 0, 0, 0.05) 100%)}.dataTables_wrapper .dataTables_paginate .paginate_button.disabled,.dataTables_wrapper .dataTables_paginate .paginate_button.disabled:hover,.dataTables_wrapper .dataTables_paginate .paginate_button.disabled:active{cursor:default;color:#666 !important;border:1px solid transparent;background:transparent;box-shadow:none}.dataTables_wrapper .dataTables_paginate .paginate_button:hover{color:white !important;border:1px solid #111;background-color:#111;background:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #585858), color-stop(100%, #111));background:-webkit-linear-gradient(top, #585858 0%, #111 100%);background:-moz-linear-gradient(top, #585858 0%, #111 100%);background:-ms-linear-gradient(top, #585858 0%, #111 100%);background:-o-linear-gradient(top, #585858 0%, #111 100%);background:linear-gradient(to bottom, #585858 0%, #111 100%)}.dataTables_wrapper .dataTables_paginate .paginate_button:active{outline:none;background-color:#0c0c0c;background:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #2b2b2b), color-stop(100%, #0c0c0c));background:-webkit-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);background:-moz-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);background:-ms-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);background:-o-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);background:linear-gradient(to bottom, #2b2b2b 0%, #0c0c0c 100%);box-shadow:inset 0 0 3px #111}.dataTables_wrapper .dataTables_paginate .ellipsis{padding:0 1em}.dataTables_wrapper .dataTables_length,.dataTables_wrapper .dataTables_filter,.dataTables_wrapper .dataTables_info,.dataTables_wrapper .dataTables_processing,.dataTables_wrapper .dataTables_paginate{color:inherit}.dataTables_wrapper .dataTables_scroll{clear:both}.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody{-webkit-overflow-scrolling:touch}.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>thead>tr>th,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>thead>tr>td,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>tbody>tr>th,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>tbody>tr>td{vertical-align:middle}.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>thead>tr>th>div.dataTables_sizing,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>thead>tr>td>div.dataTables_sizing,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>tbody>tr>th>div.dataTables_sizing,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>tbody>tr>td>div.dataTables_sizing{height:0;overflow:hidden;margin:0 !important;padding:0 !important}.dataTables_wrapper.no-footer .dataTables_scrollBody{border-bottom:1px solid rgba(0, 0, 0, 0.3)}.dataTables_wrapper.no-footer div.dataTables_scrollHead table.dataTable,.dataTables_wrapper.no-footer div.dataTables_scrollBody>table{border-bottom:none}.dataTables_wrapper:after{visibility:hidden;display:block;content:"";clear:both;height:0}@media screen and (max-width: 767px){.dataTables_wrapper .dataTables_info,.dataTables_wrapper .dataTables_paginate{float:none;text-align:center}.dataTables_wrapper .dataTables_paginate{margin-top:.5em}}@media screen and (max-width: 640px){.dataTables_wrapper .dataTables_length,.dataTables_wrapper .dataTables_filter{float:none;text-align:center}.dataTables_wrapper .dataTables_filter{margin-top:.5em}}html.dark{--dt-row-hover: 255, 255, 255;--dt-row-stripe: 255, 255, 255;--dt-column-ordering: 255, 255, 255}html.dark table.dataTable>thead>tr>th,html.dark table.dataTable>thead>tr>td{border-bottom:1px solid rgb(89, 91, 94)}html.dark table.dataTable>thead>tr>th:active,html.dark table.dataTable>thead>tr>td:active{outline:none}html.dark table.dataTable>tfoot>tr>th,html.dark table.dataTable>tfoot>tr>td{border-top:1px solid rgb(89, 91, 94)}html.dark table.dataTable.row-border>tbody>tr>th,html.dark table.dataTable.row-border>tbody>tr>td,html.dark table.dataTable.display>tbody>tr>th,html.dark table.dataTable.display>tbody>tr>td{border-top:1px solid rgb(64, 67, 70)}html.dark table.dataTable.row-border>tbody>tr.selected+tr.selected>td,html.dark table.dataTable.display>tbody>tr.selected+tr.selected>td{border-top-color:#0257d5}html.dark table.dataTable.cell-border>tbody>tr>th,html.dark table.dataTable.cell-border>tbody>tr>td{border-top:1px solid rgb(64, 67, 70);border-right:1px solid rgb(64, 67, 70)}html.dark table.dataTable.cell-border>tbody>tr>th:first-child,html.dark table.dataTable.cell-border>tbody>tr>td:first-child{border-left:1px solid rgb(64, 67, 70)}html.dark .dataTables_wrapper .dataTables_filter input,html.dark .dataTables_wrapper .dataTables_length select{border:1px solid rgba(255, 255, 255, 0.2);background-color:var(--dt-html-background)}html.dark .dataTables_wrapper .dataTables_paginate .paginate_button.current,html.dark .dataTables_wrapper .dataTables_paginate .paginate_button.current:hover{border:1px solid rgb(89, 91, 94);background:rgba(255, 255, 255, 0.15)}html.dark .dataTables_wrapper .dataTables_paginate .paginate_button.disabled,html.dark .dataTables_wrapper .dataTables_paginate .paginate_button.disabled:hover,html.dark .dataTables_wrapper .dataTables_paginate .paginate_button.disabled:active{color:#666 !important}html.dark .dataTables_wrapper .dataTables_paginate .paginate_button:hover{border:1px solid rgb(53, 53, 53);background:rgb(53, 53, 53)}html.dark .dataTables_wrapper .dataTables_paginate .paginate_button:active{background:#3a3a3a} diff --git a/docs/articles/variable_details_files/dt-core-1.13.6/js/jquery.dataTables.min.js b/docs/articles/variable_details_files/dt-core-1.13.6/js/jquery.dataTables.min.js new file mode 100644 index 00000000..f786b0da --- /dev/null +++ b/docs/articles/variable_details_files/dt-core-1.13.6/js/jquery.dataTables.min.js @@ -0,0 +1,4 @@ +/*! DataTables 1.13.6 + * ©2008-2023 SpryMedia Ltd - datatables.net/license + */ +!function(n){"use strict";var a;"function"==typeof define&&define.amd?define(["jquery"],function(t){return n(t,window,document)}):"object"==typeof exports?(a=require("jquery"),"undefined"==typeof window?module.exports=function(t,e){return t=t||window,e=e||a(t),n(e,t,t.document)}:n(a,window,window.document)):window.DataTable=n(jQuery,window,document)}(function(P,j,v,H){"use strict";function d(t){var e=parseInt(t,10);return!isNaN(e)&&isFinite(t)?e:null}function l(t,e,n){var a=typeof t,r="string"==a;return"number"==a||"bigint"==a||!!h(t)||(e&&r&&(t=$(t,e)),n&&r&&(t=t.replace(q,"")),!isNaN(parseFloat(t))&&isFinite(t))}function a(t,e,n){var a;return!!h(t)||(h(a=t)||"string"==typeof a)&&!!l(t.replace(V,"").replace(/ + - - + +
- - - + + + + + + - -
+ +
-
-

-Introduction

-

The variables worksheet acts as a reference sheet your project(s), by listing the variables you are using.

-

This vignette describes how the variables worksheet is organized and how to find variables that you can transform. The How to guides provides examples of how to use the this.

+
+

Introduction +

+

The variables worksheet acts as a reference sheet your +project(s), by listing the variables you are using.

+

This vignette describes how the variables worksheet is +organized and how to find variables that you can transform. The How to guides provides +examples of how to use the this.

Read the variables worksheet

-
#> There are 23 variables, grouped in 20 sections and 6 subjects that are available for transformation.
-
#> You can search for variables in the table below. Try searching for the lab tests. There are 10 variables are in the lab test subject. 
-#>     
-#>     Try sorting the subject column by clicking the up beside the `subject` heading: the top 10 rows of the table should show the lab tests variables:
-#>  [1] "bili"     "chol"     "albumin"  "copper"   "alk.phos" "ast"     
-#>  [7] "trig"     "platelet" "protime"  "stage"
-
- +
#> There are 24 variables, grouped in 21 sections and 8 subjects that are available for transformation.
+
#> You can search for variables in the table below. Try searching for the lab tests. There are 10 variables are in the lab test subject. 
+#>     
+#>     Try sorting the subject column by clicking the up beside the `subject` heading: the top 10 rows of the table should show the lab tests variables:
+#> [1] "c(\"albumin\", \"alk.phos\", \"ast\", \"bili\", \"chol\", \"copper\", \"platelet\", \"protime\", \"stage\", \"trig\")"
+
+
-
-

-How the variables.csv sheet is organized

+
+

How the variables.csv sheet is organized +

There are 8 columns in this worksheet as follows:

    -
  1. variable: the name of the final transformed variable.

  2. -
  3. label: the shorthand label for the variable.

  4. -
  5. labelLong: a more detailed label for the variable.

  6. -
  7. section: the section where this variable could be found (i.e. demographic, lab test).

  8. -
  9. subject: what the variable pertains to (i.e. age, sex, cholestral concentration).

  10. -
  11. variableType: whether the final variable is categorical or continuous.

  12. -
  13. units: any units for the final variable.

  14. -
  15. databaseStart: the list of databases that contain the variable of interest

  16. -
  17. variableStart: the original names of the variables as they are listed in each respective database

  18. +
  19. variable: the name of the final transformed +variable.

  20. +
  21. label: the shorthand label for the +variable.

  22. +
  23. labelLong: a more detailed label for the +variable.

  24. +
  25. section: the section where this variable could +be found (i.e. demographic, lab test).

  26. +
  27. subject: what the variable pertains to +(i.e. age, sex, cholestral concentration).

  28. +
  29. variableType: whether the final variable is +categorical or continuous.

  30. +
  31. units: any units for the final +variable.

  32. +
  33. databaseStart: the list of databases that +contain the variable of interest

  34. +
  35. variableStart: the original names of the +variables as they are listed in each respective database

-
-

-Derived Variables

-

Derived variables follow the same naming conventions as recoded variables when listed in variables worksheet.

+
+

Derived Variables +

+

Derived variables follow the same naming conventions as recoded +variables when listed in variables worksheet.

+ +
-

Site built with pkgdown 1.6.1.

+

+

Site built with pkgdown 2.1.1.

- + + + diff --git a/docs/articles/variables_sheet_files/crosstalk-1.2.1/css/crosstalk.min.css b/docs/articles/variables_sheet_files/crosstalk-1.2.1/css/crosstalk.min.css new file mode 100644 index 00000000..6b453828 --- /dev/null +++ b/docs/articles/variables_sheet_files/crosstalk-1.2.1/css/crosstalk.min.css @@ -0,0 +1 @@ +.container-fluid.crosstalk-bscols{margin-left:-30px;margin-right:-30px;white-space:normal}body>.container-fluid.crosstalk-bscols{margin-left:auto;margin-right:auto}.crosstalk-input-checkboxgroup .crosstalk-options-group .crosstalk-options-column{display:inline-block;padding-right:12px;vertical-align:top}@media only screen and (max-width: 480px){.crosstalk-input-checkboxgroup .crosstalk-options-group .crosstalk-options-column{display:block;padding-right:inherit}}.crosstalk-input{margin-bottom:15px}.crosstalk-input .control-label{margin-bottom:0;vertical-align:middle}.crosstalk-input input[type="checkbox"]{margin:4px 0 0;margin-top:1px;line-height:normal}.crosstalk-input .checkbox{position:relative;display:block;margin-top:10px;margin-bottom:10px}.crosstalk-input .checkbox>label{padding-left:20px;margin-bottom:0;font-weight:400;cursor:pointer}.crosstalk-input .checkbox input[type="checkbox"],.crosstalk-input .checkbox-inline input[type="checkbox"]{position:absolute;margin-top:2px;margin-left:-20px}.crosstalk-input .checkbox+.checkbox{margin-top:-5px}.crosstalk-input .checkbox-inline{position:relative;display:inline-block;padding-left:20px;margin-bottom:0;font-weight:400;vertical-align:middle;cursor:pointer}.crosstalk-input .checkbox-inline+.checkbox-inline{margin-top:0;margin-left:10px} diff --git a/docs/articles/variables_sheet_files/crosstalk-1.2.1/js/crosstalk.js b/docs/articles/variables_sheet_files/crosstalk-1.2.1/js/crosstalk.js new file mode 100644 index 00000000..fd9eb53d --- /dev/null +++ b/docs/articles/variables_sheet_files/crosstalk-1.2.1/js/crosstalk.js @@ -0,0 +1,1474 @@ +(function(){function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o b) { + return 1; + } +} + +/** + * @private + */ + +var FilterSet = function () { + function FilterSet() { + _classCallCheck(this, FilterSet); + + this.reset(); + } + + _createClass(FilterSet, [{ + key: "reset", + value: function reset() { + // Key: handle ID, Value: array of selected keys, or null + this._handles = {}; + // Key: key string, Value: count of handles that include it + this._keys = {}; + this._value = null; + this._activeHandles = 0; + } + }, { + key: "update", + value: function update(handleId, keys) { + if (keys !== null) { + keys = keys.slice(0); // clone before sorting + keys.sort(naturalComparator); + } + + var _diffSortedLists = (0, _util.diffSortedLists)(this._handles[handleId], keys), + added = _diffSortedLists.added, + removed = _diffSortedLists.removed; + + this._handles[handleId] = keys; + + for (var i = 0; i < added.length; i++) { + this._keys[added[i]] = (this._keys[added[i]] || 0) + 1; + } + for (var _i = 0; _i < removed.length; _i++) { + this._keys[removed[_i]]--; + } + + this._updateValue(keys); + } + + /** + * @param {string[]} keys Sorted array of strings that indicate + * a superset of possible keys. + * @private + */ + + }, { + key: "_updateValue", + value: function _updateValue() { + var keys = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this._allKeys; + + var handleCount = Object.keys(this._handles).length; + if (handleCount === 0) { + this._value = null; + } else { + this._value = []; + for (var i = 0; i < keys.length; i++) { + var count = this._keys[keys[i]]; + if (count === handleCount) { + this._value.push(keys[i]); + } + } + } + } + }, { + key: "clear", + value: function clear(handleId) { + if (typeof this._handles[handleId] === "undefined") { + return; + } + + var keys = this._handles[handleId]; + if (!keys) { + keys = []; + } + + for (var i = 0; i < keys.length; i++) { + this._keys[keys[i]]--; + } + delete this._handles[handleId]; + + this._updateValue(); + } + }, { + key: "value", + get: function get() { + return this._value; + } + }, { + key: "_allKeys", + get: function get() { + var allKeys = Object.keys(this._keys); + allKeys.sort(naturalComparator); + return allKeys; + } + }]); + + return FilterSet; +}(); + +exports.default = FilterSet; + +},{"./util":11}],4:[function(require,module,exports){ +(function (global){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; + +exports.default = group; + +var _var2 = require("./var"); + +var _var3 = _interopRequireDefault(_var2); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +// Use a global so that multiple copies of crosstalk.js can be loaded and still +// have groups behave as singletons across all copies. +global.__crosstalk_groups = global.__crosstalk_groups || {}; +var groups = global.__crosstalk_groups; + +function group(groupName) { + if (groupName && typeof groupName === "string") { + if (!groups.hasOwnProperty(groupName)) { + groups[groupName] = new Group(groupName); + } + return groups[groupName]; + } else if ((typeof groupName === "undefined" ? "undefined" : _typeof(groupName)) === "object" && groupName._vars && groupName.var) { + // Appears to already be a group object + return groupName; + } else if (Array.isArray(groupName) && groupName.length == 1 && typeof groupName[0] === "string") { + return group(groupName[0]); + } else { + throw new Error("Invalid groupName argument"); + } +} + +var Group = function () { + function Group(name) { + _classCallCheck(this, Group); + + this.name = name; + this._vars = {}; + } + + _createClass(Group, [{ + key: "var", + value: function _var(name) { + if (!name || typeof name !== "string") { + throw new Error("Invalid var name"); + } + + if (!this._vars.hasOwnProperty(name)) this._vars[name] = new _var3.default(this, name); + return this._vars[name]; + } + }, { + key: "has", + value: function has(name) { + if (!name || typeof name !== "string") { + throw new Error("Invalid var name"); + } + + return this._vars.hasOwnProperty(name); + } + }]); + + return Group; +}(); + +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) + +},{"./var":12}],5:[function(require,module,exports){ +(function (global){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _group = require("./group"); + +var _group2 = _interopRequireDefault(_group); + +var _selection = require("./selection"); + +var _filter = require("./filter"); + +var _input = require("./input"); + +require("./input_selectize"); + +require("./input_checkboxgroup"); + +require("./input_slider"); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +var defaultGroup = (0, _group2.default)("default"); + +function var_(name) { + return defaultGroup.var(name); +} + +function has(name) { + return defaultGroup.has(name); +} + +if (global.Shiny) { + global.Shiny.addCustomMessageHandler("update-client-value", function (message) { + if (typeof message.group === "string") { + (0, _group2.default)(message.group).var(message.name).set(message.value); + } else { + var_(message.name).set(message.value); + } + }); +} + +var crosstalk = { + group: _group2.default, + var: var_, + has: has, + SelectionHandle: _selection.SelectionHandle, + FilterHandle: _filter.FilterHandle, + bind: _input.bind +}; + +/** + * @namespace crosstalk + */ +exports.default = crosstalk; + +global.crosstalk = crosstalk; + +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) + +},{"./filter":2,"./group":4,"./input":6,"./input_checkboxgroup":7,"./input_selectize":8,"./input_slider":9,"./selection":10}],6:[function(require,module,exports){ +(function (global){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.register = register; +exports.bind = bind; +var $ = global.jQuery; + +var bindings = {}; + +function register(reg) { + bindings[reg.className] = reg; + if (global.document && global.document.readyState !== "complete") { + $(function () { + bind(); + }); + } else if (global.document) { + setTimeout(bind, 100); + } +} + +function bind() { + Object.keys(bindings).forEach(function (className) { + var binding = bindings[className]; + $("." + binding.className).not(".crosstalk-input-bound").each(function (i, el) { + bindInstance(binding, el); + }); + }); +} + +// Escape jQuery identifier +function $escape(val) { + return val.replace(/([!"#$%&'()*+,./:;<=>?@[\\\]^`{|}~])/g, "\\$1"); +} + +function bindEl(el) { + var $el = $(el); + Object.keys(bindings).forEach(function (className) { + if ($el.hasClass(className) && !$el.hasClass("crosstalk-input-bound")) { + var binding = bindings[className]; + bindInstance(binding, el); + } + }); +} + +function bindInstance(binding, el) { + var jsonEl = $(el).find("script[type='application/json'][data-for='" + $escape(el.id) + "']"); + var data = JSON.parse(jsonEl[0].innerText); + + var instance = binding.factory(el, data); + $(el).data("crosstalk-instance", instance); + $(el).addClass("crosstalk-input-bound"); +} + +if (global.Shiny) { + var inputBinding = new global.Shiny.InputBinding(); + var _$ = global.jQuery; + _$.extend(inputBinding, { + find: function find(scope) { + return _$(scope).find(".crosstalk-input"); + }, + initialize: function initialize(el) { + if (!_$(el).hasClass("crosstalk-input-bound")) { + bindEl(el); + } + }, + getId: function getId(el) { + return el.id; + }, + getValue: function getValue(el) {}, + setValue: function setValue(el, value) {}, + receiveMessage: function receiveMessage(el, data) {}, + subscribe: function subscribe(el, callback) { + _$(el).data("crosstalk-instance").resume(); + }, + unsubscribe: function unsubscribe(el) { + _$(el).data("crosstalk-instance").suspend(); + } + }); + global.Shiny.inputBindings.register(inputBinding, "crosstalk.inputBinding"); +} + +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) + +},{}],7:[function(require,module,exports){ +(function (global){ +"use strict"; + +var _input = require("./input"); + +var input = _interopRequireWildcard(_input); + +var _filter = require("./filter"); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +var $ = global.jQuery; + +input.register({ + className: "crosstalk-input-checkboxgroup", + + factory: function factory(el, data) { + /* + * map: {"groupA": ["keyA", "keyB", ...], ...} + * group: "ct-groupname" + */ + var ctHandle = new _filter.FilterHandle(data.group); + + var lastKnownKeys = void 0; + var $el = $(el); + $el.on("change", "input[type='checkbox']", function () { + var checked = $el.find("input[type='checkbox']:checked"); + if (checked.length === 0) { + lastKnownKeys = null; + ctHandle.clear(); + } else { + var keys = {}; + checked.each(function () { + data.map[this.value].forEach(function (key) { + keys[key] = true; + }); + }); + var keyArray = Object.keys(keys); + keyArray.sort(); + lastKnownKeys = keyArray; + ctHandle.set(keyArray); + } + }); + + return { + suspend: function suspend() { + ctHandle.clear(); + }, + resume: function resume() { + if (lastKnownKeys) ctHandle.set(lastKnownKeys); + } + }; + } +}); + +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) + +},{"./filter":2,"./input":6}],8:[function(require,module,exports){ +(function (global){ +"use strict"; + +var _input = require("./input"); + +var input = _interopRequireWildcard(_input); + +var _util = require("./util"); + +var util = _interopRequireWildcard(_util); + +var _filter = require("./filter"); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +var $ = global.jQuery; + +input.register({ + className: "crosstalk-input-select", + + factory: function factory(el, data) { + /* + * items: {value: [...], label: [...]} + * map: {"groupA": ["keyA", "keyB", ...], ...} + * group: "ct-groupname" + */ + + var first = [{ value: "", label: "(All)" }]; + var items = util.dataframeToD3(data.items); + var opts = { + options: first.concat(items), + valueField: "value", + labelField: "label", + searchField: "label" + }; + + var select = $(el).find("select")[0]; + + var selectize = $(select).selectize(opts)[0].selectize; + + var ctHandle = new _filter.FilterHandle(data.group); + + var lastKnownKeys = void 0; + selectize.on("change", function () { + if (selectize.items.length === 0) { + lastKnownKeys = null; + ctHandle.clear(); + } else { + var keys = {}; + selectize.items.forEach(function (group) { + data.map[group].forEach(function (key) { + keys[key] = true; + }); + }); + var keyArray = Object.keys(keys); + keyArray.sort(); + lastKnownKeys = keyArray; + ctHandle.set(keyArray); + } + }); + + return { + suspend: function suspend() { + ctHandle.clear(); + }, + resume: function resume() { + if (lastKnownKeys) ctHandle.set(lastKnownKeys); + } + }; + } +}); + +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) + +},{"./filter":2,"./input":6,"./util":11}],9:[function(require,module,exports){ +(function (global){ +"use strict"; + +var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }(); + +var _input = require("./input"); + +var input = _interopRequireWildcard(_input); + +var _filter = require("./filter"); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +var $ = global.jQuery; +var strftime = global.strftime; + +input.register({ + className: "crosstalk-input-slider", + + factory: function factory(el, data) { + /* + * map: {"groupA": ["keyA", "keyB", ...], ...} + * group: "ct-groupname" + */ + var ctHandle = new _filter.FilterHandle(data.group); + + var opts = {}; + var $el = $(el).find("input"); + var dataType = $el.data("data-type"); + var timeFormat = $el.data("time-format"); + var round = $el.data("round"); + var timeFormatter = void 0; + + // Set up formatting functions + if (dataType === "date") { + timeFormatter = strftime.utc(); + opts.prettify = function (num) { + return timeFormatter(timeFormat, new Date(num)); + }; + } else if (dataType === "datetime") { + var timezone = $el.data("timezone"); + if (timezone) timeFormatter = strftime.timezone(timezone);else timeFormatter = strftime; + + opts.prettify = function (num) { + return timeFormatter(timeFormat, new Date(num)); + }; + } else if (dataType === "number") { + if (typeof round !== "undefined") opts.prettify = function (num) { + var factor = Math.pow(10, round); + return Math.round(num * factor) / factor; + }; + } + + $el.ionRangeSlider(opts); + + function getValue() { + var result = $el.data("ionRangeSlider").result; + + // Function for converting numeric value from slider to appropriate type. + var convert = void 0; + var dataType = $el.data("data-type"); + if (dataType === "date") { + convert = function convert(val) { + return formatDateUTC(new Date(+val)); + }; + } else if (dataType === "datetime") { + convert = function convert(val) { + // Convert ms to s + return +val / 1000; + }; + } else { + convert = function convert(val) { + return +val; + }; + } + + if ($el.data("ionRangeSlider").options.type === "double") { + return [convert(result.from), convert(result.to)]; + } else { + return convert(result.from); + } + } + + var lastKnownKeys = null; + + $el.on("change.crosstalkSliderInput", function (event) { + if (!$el.data("updating") && !$el.data("animating")) { + var _getValue = getValue(), + _getValue2 = _slicedToArray(_getValue, 2), + from = _getValue2[0], + to = _getValue2[1]; + + var keys = []; + for (var i = 0; i < data.values.length; i++) { + var val = data.values[i]; + if (val >= from && val <= to) { + keys.push(data.keys[i]); + } + } + keys.sort(); + ctHandle.set(keys); + lastKnownKeys = keys; + } + }); + + // let $el = $(el); + // $el.on("change", "input[type="checkbox"]", function() { + // let checked = $el.find("input[type="checkbox"]:checked"); + // if (checked.length === 0) { + // ctHandle.clear(); + // } else { + // let keys = {}; + // checked.each(function() { + // data.map[this.value].forEach(function(key) { + // keys[key] = true; + // }); + // }); + // let keyArray = Object.keys(keys); + // keyArray.sort(); + // ctHandle.set(keyArray); + // } + // }); + + return { + suspend: function suspend() { + ctHandle.clear(); + }, + resume: function resume() { + if (lastKnownKeys) ctHandle.set(lastKnownKeys); + } + }; + } +}); + +// Convert a number to a string with leading zeros +function padZeros(n, digits) { + var str = n.toString(); + while (str.length < digits) { + str = "0" + str; + }return str; +} + +// Given a Date object, return a string in yyyy-mm-dd format, using the +// UTC date. This may be a day off from the date in the local time zone. +function formatDateUTC(date) { + if (date instanceof Date) { + return date.getUTCFullYear() + "-" + padZeros(date.getUTCMonth() + 1, 2) + "-" + padZeros(date.getUTCDate(), 2); + } else { + return null; + } +} + +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) + +},{"./filter":2,"./input":6}],10:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.SelectionHandle = undefined; + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _events = require("./events"); + +var _events2 = _interopRequireDefault(_events); + +var _group = require("./group"); + +var _group2 = _interopRequireDefault(_group); + +var _util = require("./util"); + +var util = _interopRequireWildcard(_util); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +/** + * Use this class to read and write (and listen for changes to) the selection + * for a Crosstalk group. This is intended to be used for linked brushing. + * + * If two (or more) `SelectionHandle` instances in the same webpage share the + * same group name, they will share the same state. Setting the selection using + * one `SelectionHandle` instance will result in the `value` property instantly + * changing across the others, and `"change"` event listeners on all instances + * (including the one that initiated the sending) will fire. + * + * @param {string} [group] - The name of the Crosstalk group, or if none, + * null or undefined (or any other falsy value). This can be changed later + * via the [SelectionHandle#setGroup](#setGroup) method. + * @param {Object} [extraInfo] - An object whose properties will be copied to + * the event object whenever an event is emitted. + */ +var SelectionHandle = exports.SelectionHandle = function () { + function SelectionHandle() { + var group = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null; + var extraInfo = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; + + _classCallCheck(this, SelectionHandle); + + this._eventRelay = new _events2.default(); + this._emitter = new util.SubscriptionTracker(this._eventRelay); + + // Name of the group we're currently tracking, if any. Can change over time. + this._group = null; + // The Var we're currently tracking, if any. Can change over time. + this._var = null; + // The event handler subscription we currently have on var.on("change"). + this._varOnChangeSub = null; + + this._extraInfo = util.extend({ sender: this }, extraInfo); + + this.setGroup(group); + } + + /** + * Changes the Crosstalk group membership of this SelectionHandle. The group + * being switched away from (if any) will not have its selection value + * modified as a result of calling `setGroup`, even if this handle was the + * most recent handle to set the selection of the group. + * + * The group being switched to (if any) will also not have its selection value + * modified as a result of calling `setGroup`. If you want to set the + * selection value of the new group, call `set` explicitly. + * + * @param {string} group - The name of the Crosstalk group, or null (or + * undefined) to clear the group. + */ + + + _createClass(SelectionHandle, [{ + key: "setGroup", + value: function setGroup(group) { + var _this = this; + + // If group is unchanged, do nothing + if (this._group === group) return; + // Treat null, undefined, and other falsy values the same + if (!this._group && !group) return; + + if (this._var) { + this._var.off("change", this._varOnChangeSub); + this._var = null; + this._varOnChangeSub = null; + } + + this._group = group; + + if (group) { + this._var = (0, _group2.default)(group).var("selection"); + var sub = this._var.on("change", function (e) { + _this._eventRelay.trigger("change", e, _this); + }); + this._varOnChangeSub = sub; + } + } + + /** + * Retrieves the current selection for the group represented by this + * `SelectionHandle`. + * + * - If no selection is active, then this value will be falsy. + * - If a selection is active, but no data points are selected, then this + * value will be an empty array. + * - If a selection is active, and data points are selected, then the keys + * of the selected data points will be present in the array. + */ + + }, { + key: "_mergeExtraInfo", + + + /** + * Combines the given `extraInfo` (if any) with the handle's default + * `_extraInfo` (if any). + * @private + */ + value: function _mergeExtraInfo(extraInfo) { + // Important incidental effect: shallow clone is returned + return util.extend({}, this._extraInfo ? this._extraInfo : null, extraInfo ? extraInfo : null); + } + + /** + * Overwrites the current selection for the group, and raises the `"change"` + * event among all of the group's '`SelectionHandle` instances (including + * this one). + * + * @fires SelectionHandle#change + * @param {string[]} selectedKeys - Falsy, empty array, or array of keys (see + * {@link SelectionHandle#value}). + * @param {Object} [extraInfo] - Extra properties to be included on the event + * object that's passed to listeners (in addition to any options that were + * passed into the `SelectionHandle` constructor). + */ + + }, { + key: "set", + value: function set(selectedKeys, extraInfo) { + if (this._var) this._var.set(selectedKeys, this._mergeExtraInfo(extraInfo)); + } + + /** + * Overwrites the current selection for the group, and raises the `"change"` + * event among all of the group's '`SelectionHandle` instances (including + * this one). + * + * @fires SelectionHandle#change + * @param {Object} [extraInfo] - Extra properties to be included on the event + * object that's passed to listeners (in addition to any that were passed + * into the `SelectionHandle` constructor). + */ + + }, { + key: "clear", + value: function clear(extraInfo) { + if (this._var) this.set(void 0, this._mergeExtraInfo(extraInfo)); + } + + /** + * Subscribes to events on this `SelectionHandle`. + * + * @param {string} eventType - Indicates the type of events to listen to. + * Currently, only `"change"` is supported. + * @param {SelectionHandle~listener} listener - The callback function that + * will be invoked when the event occurs. + * @return {string} - A token to pass to {@link SelectionHandle#off} to cancel + * this subscription. + */ + + }, { + key: "on", + value: function on(eventType, listener) { + return this._emitter.on(eventType, listener); + } + + /** + * Cancels event subscriptions created by {@link SelectionHandle#on}. + * + * @param {string} eventType - The type of event to unsubscribe. + * @param {string|SelectionHandle~listener} listener - Either the callback + * function previously passed into {@link SelectionHandle#on}, or the + * string that was returned from {@link SelectionHandle#on}. + */ + + }, { + key: "off", + value: function off(eventType, listener) { + return this._emitter.off(eventType, listener); + } + + /** + * Shuts down the `SelectionHandle` object. + * + * Removes all event listeners that were added through this handle. + */ + + }, { + key: "close", + value: function close() { + this._emitter.removeAllListeners(); + this.setGroup(null); + } + }, { + key: "value", + get: function get() { + return this._var ? this._var.get() : null; + } + }]); + + return SelectionHandle; +}(); + +/** + * @callback SelectionHandle~listener + * @param {Object} event - An object containing details of the event. For + * `"change"` events, this includes the properties `value` (the new + * value of the selection, or `undefined` if no selection is active), + * `oldValue` (the previous value of the selection), and `sender` (the + * `SelectionHandle` instance that made the change). + */ + +/** + * @event SelectionHandle#change + * @type {object} + * @property {object} value - The new value of the selection, or `undefined` + * if no selection is active. + * @property {object} oldValue - The previous value of the selection. + * @property {SelectionHandle} sender - The `SelectionHandle` instance that + * changed the value. + */ + +},{"./events":1,"./group":4,"./util":11}],11:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; + +exports.extend = extend; +exports.checkSorted = checkSorted; +exports.diffSortedLists = diffSortedLists; +exports.dataframeToD3 = dataframeToD3; + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function extend(target) { + for (var _len = arguments.length, sources = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { + sources[_key - 1] = arguments[_key]; + } + + for (var i = 0; i < sources.length; i++) { + var src = sources[i]; + if (typeof src === "undefined" || src === null) continue; + + for (var key in src) { + if (src.hasOwnProperty(key)) { + target[key] = src[key]; + } + } + } + return target; +} + +function checkSorted(list) { + for (var i = 1; i < list.length; i++) { + if (list[i] <= list[i - 1]) { + throw new Error("List is not sorted or contains duplicate"); + } + } +} + +function diffSortedLists(a, b) { + var i_a = 0; + var i_b = 0; + + if (!a) a = []; + if (!b) b = []; + + var a_only = []; + var b_only = []; + + checkSorted(a); + checkSorted(b); + + while (i_a < a.length && i_b < b.length) { + if (a[i_a] === b[i_b]) { + i_a++; + i_b++; + } else if (a[i_a] < b[i_b]) { + a_only.push(a[i_a++]); + } else { + b_only.push(b[i_b++]); + } + } + + if (i_a < a.length) a_only = a_only.concat(a.slice(i_a)); + if (i_b < b.length) b_only = b_only.concat(b.slice(i_b)); + return { + removed: a_only, + added: b_only + }; +} + +// Convert from wide: { colA: [1,2,3], colB: [4,5,6], ... } +// to long: [ {colA: 1, colB: 4}, {colA: 2, colB: 5}, ... ] +function dataframeToD3(df) { + var names = []; + var length = void 0; + for (var name in df) { + if (df.hasOwnProperty(name)) names.push(name); + if (_typeof(df[name]) !== "object" || typeof df[name].length === "undefined") { + throw new Error("All fields must be arrays"); + } else if (typeof length !== "undefined" && length !== df[name].length) { + throw new Error("All fields must be arrays of the same length"); + } + length = df[name].length; + } + var results = []; + var item = void 0; + for (var row = 0; row < length; row++) { + item = {}; + for (var col = 0; col < names.length; col++) { + item[names[col]] = df[names[col]][row]; + } + results.push(item); + } + return results; +} + +/** + * Keeps track of all event listener additions/removals and lets all active + * listeners be removed with a single operation. + * + * @private + */ + +var SubscriptionTracker = exports.SubscriptionTracker = function () { + function SubscriptionTracker(emitter) { + _classCallCheck(this, SubscriptionTracker); + + this._emitter = emitter; + this._subs = {}; + } + + _createClass(SubscriptionTracker, [{ + key: "on", + value: function on(eventType, listener) { + var sub = this._emitter.on(eventType, listener); + this._subs[sub] = eventType; + return sub; + } + }, { + key: "off", + value: function off(eventType, listener) { + var sub = this._emitter.off(eventType, listener); + if (sub) { + delete this._subs[sub]; + } + return sub; + } + }, { + key: "removeAllListeners", + value: function removeAllListeners() { + var _this = this; + + var current_subs = this._subs; + this._subs = {}; + Object.keys(current_subs).forEach(function (sub) { + _this._emitter.off(current_subs[sub], sub); + }); + } + }]); + + return SubscriptionTracker; +}(); + +},{}],12:[function(require,module,exports){ +(function (global){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _events = require("./events"); + +var _events2 = _interopRequireDefault(_events); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +var Var = function () { + function Var(group, name, /*optional*/value) { + _classCallCheck(this, Var); + + this._group = group; + this._name = name; + this._value = value; + this._events = new _events2.default(); + } + + _createClass(Var, [{ + key: "get", + value: function get() { + return this._value; + } + }, { + key: "set", + value: function set(value, /*optional*/event) { + if (this._value === value) { + // Do nothing; the value hasn't changed + return; + } + var oldValue = this._value; + this._value = value; + // Alert JavaScript listeners that the value has changed + var evt = {}; + if (event && (typeof event === "undefined" ? "undefined" : _typeof(event)) === "object") { + for (var k in event) { + if (event.hasOwnProperty(k)) evt[k] = event[k]; + } + } + evt.oldValue = oldValue; + evt.value = value; + this._events.trigger("change", evt, this); + + // TODO: Make this extensible, to let arbitrary back-ends know that + // something has changed + if (global.Shiny && global.Shiny.onInputChange) { + global.Shiny.onInputChange(".clientValue-" + (this._group.name !== null ? this._group.name + "-" : "") + this._name, typeof value === "undefined" ? null : value); + } + } + }, { + key: "on", + value: function on(eventType, listener) { + return this._events.on(eventType, listener); + } + }, { + key: "off", + value: function off(eventType, listener) { + return this._events.off(eventType, listener); + } + }]); + + return Var; +}(); + +exports.default = Var; + +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) + +},{"./events":1}]},{},[5]) +//# sourceMappingURL=crosstalk.js.map diff --git a/docs/articles/variables_sheet_files/crosstalk-1.2.1/js/crosstalk.js.map b/docs/articles/variables_sheet_files/crosstalk-1.2.1/js/crosstalk.js.map new file mode 100644 index 00000000..cff94f08 --- /dev/null +++ b/docs/articles/variables_sheet_files/crosstalk-1.2.1/js/crosstalk.js.map @@ -0,0 +1,37 @@ +{ + "version": 3, + "sources": [ + "node_modules/browser-pack/_prelude.js", + "javascript/src/events.js", + "javascript/src/filter.js", + "javascript/src/filterset.js", + "javascript/src/group.js", + "javascript/src/index.js", + "javascript/src/input.js", + "javascript/src/input_checkboxgroup.js", + "javascript/src/input_selectize.js", + "javascript/src/input_slider.js", + "javascript/src/selection.js", + "javascript/src/util.js", + "javascript/src/var.js" + ], + "names": [], + "mappings": "AAAA;;;;;;;;;;;ICAqB,M;AACnB,oBAAc;AAAA;;AACZ,SAAK,MAAL,GAAc,EAAd;AACA,SAAK,IAAL,GAAY,CAAZ;AACD;;;;uBAEE,S,EAAW,Q,EAAU;AACtB,UAAI,OAAO,KAAK,MAAL,CAAY,SAAZ,CAAX;AACA,UAAI,CAAC,IAAL,EAAW;AACT,eAAO,KAAK,MAAL,CAAY,SAAZ,IAAyB,EAAhC;AACD;AACD,UAAI,MAAM,QAAS,KAAK,IAAL,EAAnB;AACA,WAAK,GAAL,IAAY,QAAZ;AACA,aAAO,GAAP;AACD;;AAED;;;;wBACI,S,EAAW,Q,EAAU;AACvB,UAAI,OAAO,KAAK,MAAL,CAAY,SAAZ,CAAX;AACA,UAAI,OAAO,QAAP,KAAqB,UAAzB,EAAqC;AACnC,aAAK,IAAI,GAAT,IAAgB,IAAhB,EAAsB;AACpB,cAAI,KAAK,cAAL,CAAoB,GAApB,CAAJ,EAA8B;AAC5B,gBAAI,KAAK,GAAL,MAAc,QAAlB,EAA4B;AAC1B,qBAAO,KAAK,GAAL,CAAP;AACA,qBAAO,GAAP;AACD;AACF;AACF;AACD,eAAO,KAAP;AACD,OAVD,MAUO,IAAI,OAAO,QAAP,KAAqB,QAAzB,EAAmC;AACxC,YAAI,QAAQ,KAAK,QAAL,CAAZ,EAA4B;AAC1B,iBAAO,KAAK,QAAL,CAAP;AACA,iBAAO,QAAP;AACD;AACD,eAAO,KAAP;AACD,OANM,MAMA;AACL,cAAM,IAAI,KAAJ,CAAU,8BAAV,CAAN;AACD;AACF;;;4BAEO,S,EAAW,G,EAAK,O,EAAS;AAC/B,UAAI,OAAO,KAAK,MAAL,CAAY,SAAZ,CAAX;AACA,WAAK,IAAI,GAAT,IAAgB,IAAhB,EAAsB;AACpB,YAAI,KAAK,cAAL,CAAoB,GAApB,CAAJ,EAA8B;AAC5B,eAAK,GAAL,EAAU,IAAV,CAAe,OAAf,EAAwB,GAAxB;AACD;AACF;AACF;;;;;;kBA/CkB,M;;;;;;;;;;;;ACArB;;;;AACA;;;;AACA;;;;AACA;;IAAY,I;;;;;;;;AAEZ,SAAS,YAAT,CAAsB,KAAtB,EAA6B;AAC3B,MAAI,QAAQ,MAAM,GAAN,CAAU,WAAV,CAAZ;AACA,MAAI,SAAS,MAAM,GAAN,EAAb;AACA,MAAI,CAAC,MAAL,EAAa;AACX,aAAS,yBAAT;AACA,UAAM,GAAN,CAAU,MAAV;AACD;AACD,SAAO,MAAP;AACD;;AAED,IAAI,KAAK,CAAT;AACA,SAAS,MAAT,GAAkB;AAChB,SAAO,IAAP;AACD;;AAED;;;;;;;;;;;;;;;;;;;;;;;;;IAwBa,Y,WAAA,Y;AACX,wBAAY,KAAZ,EAAmB,SAAnB,EAA8B;AAAA;;AAC5B,SAAK,WAAL,GAAmB,sBAAnB;AACA,SAAK,QAAL,GAAgB,IAAI,KAAK,mBAAT,CAA6B,KAAK,WAAlC,CAAhB;;AAEA;AACA,SAAK,MAAL,GAAc,IAAd;AACA;AACA,SAAK,UAAL,GAAkB,IAAlB;AACA;AACA,SAAK,UAAL,GAAkB,IAAlB;AACA;AACA,SAAK,eAAL,GAAuB,IAAvB;;AAEA,SAAK,UAAL,GAAkB,KAAK,MAAL,CAAY,EAAE,QAAQ,IAAV,EAAZ,EAA8B,SAA9B,CAAlB;;AAEA,SAAK,GAAL,GAAW,WAAW,QAAtB;;AAEA,SAAK,QAAL,CAAc,KAAd;AACD;;AAED;;;;;;;;;;;;;;6BAUS,K,EAAO;AAAA;;AACd;AACA,UAAI,KAAK,MAAL,KAAgB,KAApB,EACE;AACF;AACA,UAAI,CAAC,KAAK,MAAN,IAAgB,CAAC,KAArB,EACE;;AAEF,UAAI,KAAK,UAAT,EAAqB;AACnB,aAAK,UAAL,CAAgB,GAAhB,CAAoB,QAApB,EAA8B,KAAK,eAAnC;AACA,aAAK,KAAL;AACA,aAAK,eAAL,GAAuB,IAAvB;AACA,aAAK,UAAL,GAAkB,IAAlB;AACA,aAAK,UAAL,GAAkB,IAAlB;AACD;;AAED,WAAK,MAAL,GAAc,KAAd;;AAEA,UAAI,KAAJ,EAAW;AACT,gBAAQ,qBAAI,KAAJ,CAAR;AACA,aAAK,UAAL,GAAkB,aAAa,KAAb,CAAlB;AACA,aAAK,UAAL,GAAkB,qBAAI,KAAJ,EAAW,GAAX,CAAe,QAAf,CAAlB;AACA,YAAI,MAAM,KAAK,UAAL,CAAgB,EAAhB,CAAmB,QAAnB,EAA6B,UAAC,CAAD,EAAO;AAC5C,gBAAK,WAAL,CAAiB,OAAjB,CAAyB,QAAzB,EAAmC,CAAnC;AACD,SAFS,CAAV;AAGA,aAAK,eAAL,GAAuB,GAAvB;AACD;AACF;;AAED;;;;;;;;oCAKgB,S,EAAW;AACzB,aAAO,KAAK,MAAL,CAAY,EAAZ,EACL,KAAK,UAAL,GAAkB,KAAK,UAAvB,GAAoC,IAD/B,EAEL,YAAY,SAAZ,GAAwB,IAFnB,CAAP;AAGD;;AAED;;;;;;;4BAIQ;AACN,WAAK,QAAL,CAAc,kBAAd;AACA,WAAK,KAAL;AACA,WAAK,QAAL,CAAc,IAAd;AACD;;AAED;;;;;;;;;;;;0BASM,S,EAAW;AACf,UAAI,CAAC,KAAK,UAAV,EACE;AACF,WAAK,UAAL,CAAgB,KAAhB,CAAsB,KAAK,GAA3B;AACA,WAAK,SAAL,CAAe,SAAf;AACD;;AAED;;;;;;;;;;;;;;;;;;;;wBAiBI,I,EAAM,S,EAAW;AACnB,UAAI,CAAC,KAAK,UAAV,EACE;AACF,WAAK,UAAL,CAAgB,MAAhB,CAAuB,KAAK,GAA5B,EAAiC,IAAjC;AACA,WAAK,SAAL,CAAe,SAAf;AACD;;AAED;;;;;;;;;;AASA;;;;;;;;;;uBAUG,S,EAAW,Q,EAAU;AACtB,aAAO,KAAK,QAAL,CAAc,EAAd,CAAiB,SAAjB,EAA4B,QAA5B,CAAP;AACD;;AAED;;;;;;;;;;;wBAQI,S,EAAW,Q,EAAU;AACvB,aAAO,KAAK,QAAL,CAAc,GAAd,CAAkB,SAAlB,EAA6B,QAA7B,CAAP;AACD;;;8BAES,S,EAAW;AACnB,UAAI,CAAC,KAAK,UAAV,EACE;AACF,WAAK,UAAL,CAAgB,GAAhB,CAAoB,KAAK,UAAL,CAAgB,KAApC,EAA2C,KAAK,eAAL,CAAqB,SAArB,CAA3C;AACD;;AAED;;;;;;;;;;;wBApCmB;AACjB,aAAO,KAAK,UAAL,GAAkB,KAAK,UAAL,CAAgB,KAAlC,GAA0C,IAAjD;AACD;;;;;;AA6CH;;;;;;;;;;;;;;;;;;;ACzNA;;;;AAEA,SAAS,iBAAT,CAA2B,CAA3B,EAA8B,CAA9B,EAAiC;AAC/B,MAAI,MAAM,CAAV,EAAa;AACX,WAAO,CAAP;AACD,GAFD,MAEO,IAAI,IAAI,CAAR,EAAW;AAChB,WAAO,CAAC,CAAR;AACD,GAFM,MAEA,IAAI,IAAI,CAAR,EAAW;AAChB,WAAO,CAAP;AACD;AACF;;AAED;;;;IAGqB,S;AACnB,uBAAc;AAAA;;AACZ,SAAK,KAAL;AACD;;;;4BAEO;AACN;AACA,WAAK,QAAL,GAAgB,EAAhB;AACA;AACA,WAAK,KAAL,GAAa,EAAb;AACA,WAAK,MAAL,GAAc,IAAd;AACA,WAAK,cAAL,GAAsB,CAAtB;AACD;;;2BAMM,Q,EAAU,I,EAAM;AACrB,UAAI,SAAS,IAAb,EAAmB;AACjB,eAAO,KAAK,KAAL,CAAW,CAAX,CAAP,CADiB,CACK;AACtB,aAAK,IAAL,CAAU,iBAAV;AACD;;AAJoB,6BAME,2BAAgB,KAAK,QAAL,CAAc,QAAd,CAAhB,EAAyC,IAAzC,CANF;AAAA,UAMhB,KANgB,oBAMhB,KANgB;AAAA,UAMT,OANS,oBAMT,OANS;;AAOrB,WAAK,QAAL,CAAc,QAAd,IAA0B,IAA1B;;AAEA,WAAK,IAAI,IAAI,CAAb,EAAgB,IAAI,MAAM,MAA1B,EAAkC,GAAlC,EAAuC;AACrC,aAAK,KAAL,CAAW,MAAM,CAAN,CAAX,IAAuB,CAAC,KAAK,KAAL,CAAW,MAAM,CAAN,CAAX,KAAwB,CAAzB,IAA8B,CAArD;AACD;AACD,WAAK,IAAI,KAAI,CAAb,EAAgB,KAAI,QAAQ,MAA5B,EAAoC,IAApC,EAAyC;AACvC,aAAK,KAAL,CAAW,QAAQ,EAAR,CAAX;AACD;;AAED,WAAK,YAAL,CAAkB,IAAlB;AACD;;AAED;;;;;;;;mCAKmC;AAAA,UAAtB,IAAsB,uEAAf,KAAK,QAAU;;AACjC,UAAI,cAAc,OAAO,IAAP,CAAY,KAAK,QAAjB,EAA2B,MAA7C;AACA,UAAI,gBAAgB,CAApB,EAAuB;AACrB,aAAK,MAAL,GAAc,IAAd;AACD,OAFD,MAEO;AACL,aAAK,MAAL,GAAc,EAAd;AACA,aAAK,IAAI,IAAI,CAAb,EAAgB,IAAI,KAAK,MAAzB,EAAiC,GAAjC,EAAsC;AACpC,cAAI,QAAQ,KAAK,KAAL,CAAW,KAAK,CAAL,CAAX,CAAZ;AACA,cAAI,UAAU,WAAd,EAA2B;AACzB,iBAAK,MAAL,CAAY,IAAZ,CAAiB,KAAK,CAAL,CAAjB;AACD;AACF;AACF;AACF;;;0BAEK,Q,EAAU;AACd,UAAI,OAAO,KAAK,QAAL,CAAc,QAAd,CAAP,KAAoC,WAAxC,EAAqD;AACnD;AACD;;AAED,UAAI,OAAO,KAAK,QAAL,CAAc,QAAd,CAAX;AACA,UAAI,CAAC,IAAL,EAAW;AACT,eAAO,EAAP;AACD;;AAED,WAAK,IAAI,IAAI,CAAb,EAAgB,IAAI,KAAK,MAAzB,EAAiC,GAAjC,EAAsC;AACpC,aAAK,KAAL,CAAW,KAAK,CAAL,CAAX;AACD;AACD,aAAO,KAAK,QAAL,CAAc,QAAd,CAAP;;AAEA,WAAK,YAAL;AACD;;;wBA3DW;AACV,aAAO,KAAK,MAAZ;AACD;;;wBA2Dc;AACb,UAAI,UAAU,OAAO,IAAP,CAAY,KAAK,KAAjB,CAAd;AACA,cAAQ,IAAR,CAAa,iBAAb;AACA,aAAO,OAAP;AACD;;;;;;kBA/EkB,S;;;;;;;;;;;;;;kBCRG,K;;AAPxB;;;;;;;;AAEA;AACA;AACA,OAAO,kBAAP,GAA4B,OAAO,kBAAP,IAA6B,EAAzD;AACA,IAAI,SAAS,OAAO,kBAApB;;AAEe,SAAS,KAAT,CAAe,SAAf,EAA0B;AACvC,MAAI,aAAa,OAAO,SAAP,KAAsB,QAAvC,EAAiD;AAC/C,QAAI,CAAC,OAAO,cAAP,CAAsB,SAAtB,CAAL,EAAuC;AACrC,aAAO,SAAP,IAAoB,IAAI,KAAJ,CAAU,SAAV,CAApB;AACD;AACD,WAAO,OAAO,SAAP,CAAP;AACD,GALD,MAKO,IAAI,QAAO,SAAP,yCAAO,SAAP,OAAsB,QAAtB,IAAkC,UAAU,KAA5C,IAAqD,UAAU,GAAnE,EAAwE;AAC7E;AACA,WAAO,SAAP;AACD,GAHM,MAGA,IAAI,MAAM,OAAN,CAAc,SAAd,KACP,UAAU,MAAV,IAAoB,CADb,IAEP,OAAO,UAAU,CAAV,CAAP,KAAyB,QAFtB,EAEgC;AACrC,WAAO,MAAM,UAAU,CAAV,CAAN,CAAP;AACD,GAJM,MAIA;AACL,UAAM,IAAI,KAAJ,CAAU,4BAAV,CAAN;AACD;AACF;;IAEK,K;AACJ,iBAAY,IAAZ,EAAkB;AAAA;;AAChB,SAAK,IAAL,GAAY,IAAZ;AACA,SAAK,KAAL,GAAa,EAAb;AACD;;;;yBAEG,I,EAAM;AACR,UAAI,CAAC,IAAD,IAAS,OAAO,IAAP,KAAiB,QAA9B,EAAwC;AACtC,cAAM,IAAI,KAAJ,CAAU,kBAAV,CAAN;AACD;;AAED,UAAI,CAAC,KAAK,KAAL,CAAW,cAAX,CAA0B,IAA1B,CAAL,EACE,KAAK,KAAL,CAAW,IAAX,IAAmB,kBAAQ,IAAR,EAAc,IAAd,CAAnB;AACF,aAAO,KAAK,KAAL,CAAW,IAAX,CAAP;AACD;;;wBAEG,I,EAAM;AACR,UAAI,CAAC,IAAD,IAAS,OAAO,IAAP,KAAiB,QAA9B,EAAwC;AACtC,cAAM,IAAI,KAAJ,CAAU,kBAAV,CAAN;AACD;;AAED,aAAO,KAAK,KAAL,CAAW,cAAX,CAA0B,IAA1B,CAAP;AACD;;;;;;;;;;;;;;;;AC/CH;;;;AACA;;AACA;;AACA;;AACA;;AACA;;AACA;;;;AAEA,IAAM,eAAe,qBAAM,SAAN,CAArB;;AAEA,SAAS,IAAT,CAAc,IAAd,EAAoB;AAClB,SAAO,aAAa,GAAb,CAAiB,IAAjB,CAAP;AACD;;AAED,SAAS,GAAT,CAAa,IAAb,EAAmB;AACjB,SAAO,aAAa,GAAb,CAAiB,IAAjB,CAAP;AACD;;AAED,IAAI,OAAO,KAAX,EAAkB;AAChB,SAAO,KAAP,CAAa,uBAAb,CAAqC,qBAArC,EAA4D,UAAS,OAAT,EAAkB;AAC5E,QAAI,OAAO,QAAQ,KAAf,KAA0B,QAA9B,EAAwC;AACtC,2BAAM,QAAQ,KAAd,EAAqB,GAArB,CAAyB,QAAQ,IAAjC,EAAuC,GAAvC,CAA2C,QAAQ,KAAnD;AACD,KAFD,MAEO;AACL,WAAK,QAAQ,IAAb,EAAmB,GAAnB,CAAuB,QAAQ,KAA/B;AACD;AACF,GAND;AAOD;;AAED,IAAM,YAAY;AAChB,wBADgB;AAEhB,OAAK,IAFW;AAGhB,OAAK,GAHW;AAIhB,6CAJgB;AAKhB,oCALgB;AAMhB;AANgB,CAAlB;;AASA;;;kBAGe,S;;AACf,OAAO,SAAP,GAAmB,SAAnB;;;;;;;;;;;QCrCgB,Q,GAAA,Q;QAWA,I,GAAA,I;AAfhB,IAAI,IAAI,OAAO,MAAf;;AAEA,IAAI,WAAW,EAAf;;AAEO,SAAS,QAAT,CAAkB,GAAlB,EAAuB;AAC5B,WAAS,IAAI,SAAb,IAA0B,GAA1B;AACA,MAAI,OAAO,QAAP,IAAmB,OAAO,QAAP,CAAgB,UAAhB,KAA+B,UAAtD,EAAkE;AAChE,MAAE,YAAM;AACN;AACD,KAFD;AAGD,GAJD,MAIO,IAAI,OAAO,QAAX,EAAqB;AAC1B,eAAW,IAAX,EAAiB,GAAjB;AACD;AACF;;AAEM,SAAS,IAAT,GAAgB;AACrB,SAAO,IAAP,CAAY,QAAZ,EAAsB,OAAtB,CAA8B,UAAS,SAAT,EAAoB;AAChD,QAAI,UAAU,SAAS,SAAT,CAAd;AACA,MAAE,MAAM,QAAQ,SAAhB,EAA2B,GAA3B,CAA+B,wBAA/B,EAAyD,IAAzD,CAA8D,UAAS,CAAT,EAAY,EAAZ,EAAgB;AAC5E,mBAAa,OAAb,EAAsB,EAAtB;AACD,KAFD;AAGD,GALD;AAMD;;AAED;AACA,SAAS,OAAT,CAAiB,GAAjB,EAAsB;AACpB,SAAO,IAAI,OAAJ,CAAY,uCAAZ,EAAqD,MAArD,CAAP;AACD;;AAED,SAAS,MAAT,CAAgB,EAAhB,EAAoB;AAClB,MAAI,MAAM,EAAE,EAAF,CAAV;AACA,SAAO,IAAP,CAAY,QAAZ,EAAsB,OAAtB,CAA8B,UAAS,SAAT,EAAoB;AAChD,QAAI,IAAI,QAAJ,CAAa,SAAb,KAA2B,CAAC,IAAI,QAAJ,CAAa,uBAAb,CAAhC,EAAuE;AACrE,UAAI,UAAU,SAAS,SAAT,CAAd;AACA,mBAAa,OAAb,EAAsB,EAAtB;AACD;AACF,GALD;AAMD;;AAED,SAAS,YAAT,CAAsB,OAAtB,EAA+B,EAA/B,EAAmC;AACjC,MAAI,SAAS,EAAE,EAAF,EAAM,IAAN,CAAW,+CAA+C,QAAQ,GAAG,EAAX,CAA/C,GAAgE,IAA3E,CAAb;AACA,MAAI,OAAO,KAAK,KAAL,CAAW,OAAO,CAAP,EAAU,SAArB,CAAX;;AAEA,MAAI,WAAW,QAAQ,OAAR,CAAgB,EAAhB,EAAoB,IAApB,CAAf;AACA,IAAE,EAAF,EAAM,IAAN,CAAW,oBAAX,EAAiC,QAAjC;AACA,IAAE,EAAF,EAAM,QAAN,CAAe,uBAAf;AACD;;AAED,IAAI,OAAO,KAAX,EAAkB;AAChB,MAAI,eAAe,IAAI,OAAO,KAAP,CAAa,YAAjB,EAAnB;AACA,MAAI,KAAI,OAAO,MAAf;AACA,KAAE,MAAF,CAAS,YAAT,EAAuB;AACrB,UAAM,cAAS,KAAT,EAAgB;AACpB,aAAO,GAAE,KAAF,EAAS,IAAT,CAAc,kBAAd,CAAP;AACD,KAHoB;AAIrB,gBAAY,oBAAS,EAAT,EAAa;AACvB,UAAI,CAAC,GAAE,EAAF,EAAM,QAAN,CAAe,uBAAf,CAAL,EAA8C;AAC5C,eAAO,EAAP;AACD;AACF,KARoB;AASrB,WAAO,eAAS,EAAT,EAAa;AAClB,aAAO,GAAG,EAAV;AACD,KAXoB;AAYrB,cAAU,kBAAS,EAAT,EAAa,CAEtB,CAdoB;AAerB,cAAU,kBAAS,EAAT,EAAa,KAAb,EAAoB,CAE7B,CAjBoB;AAkBrB,oBAAgB,wBAAS,EAAT,EAAa,IAAb,EAAmB,CAElC,CApBoB;AAqBrB,eAAW,mBAAS,EAAT,EAAa,QAAb,EAAuB;AAChC,SAAE,EAAF,EAAM,IAAN,CAAW,oBAAX,EAAiC,MAAjC;AACD,KAvBoB;AAwBrB,iBAAa,qBAAS,EAAT,EAAa;AACxB,SAAE,EAAF,EAAM,IAAN,CAAW,oBAAX,EAAiC,OAAjC;AACD;AA1BoB,GAAvB;AA4BA,SAAO,KAAP,CAAa,aAAb,CAA2B,QAA3B,CAAoC,YAApC,EAAkD,wBAAlD;AACD;;;;;;;;AChFD;;IAAY,K;;AACZ;;;;AAEA,IAAI,IAAI,OAAO,MAAf;;AAEA,MAAM,QAAN,CAAe;AACb,aAAW,+BADE;;AAGb,WAAS,iBAAS,EAAT,EAAa,IAAb,EAAmB;AAC1B;;;;AAIA,QAAI,WAAW,yBAAiB,KAAK,KAAtB,CAAf;;AAEA,QAAI,sBAAJ;AACA,QAAI,MAAM,EAAE,EAAF,CAAV;AACA,QAAI,EAAJ,CAAO,QAAP,EAAiB,wBAAjB,EAA2C,YAAW;AACpD,UAAI,UAAU,IAAI,IAAJ,CAAS,gCAAT,CAAd;AACA,UAAI,QAAQ,MAAR,KAAmB,CAAvB,EAA0B;AACxB,wBAAgB,IAAhB;AACA,iBAAS,KAAT;AACD,OAHD,MAGO;AACL,YAAI,OAAO,EAAX;AACA,gBAAQ,IAAR,CAAa,YAAW;AACtB,eAAK,GAAL,CAAS,KAAK,KAAd,EAAqB,OAArB,CAA6B,UAAS,GAAT,EAAc;AACzC,iBAAK,GAAL,IAAY,IAAZ;AACD,WAFD;AAGD,SAJD;AAKA,YAAI,WAAW,OAAO,IAAP,CAAY,IAAZ,CAAf;AACA,iBAAS,IAAT;AACA,wBAAgB,QAAhB;AACA,iBAAS,GAAT,CAAa,QAAb;AACD;AACF,KAjBD;;AAmBA,WAAO;AACL,eAAS,mBAAW;AAClB,iBAAS,KAAT;AACD,OAHI;AAIL,cAAQ,kBAAW;AACjB,YAAI,aAAJ,EACE,SAAS,GAAT,CAAa,aAAb;AACH;AAPI,KAAP;AASD;AAxCY,CAAf;;;;;;;;ACLA;;IAAY,K;;AACZ;;IAAY,I;;AACZ;;;;AAEA,IAAI,IAAI,OAAO,MAAf;;AAEA,MAAM,QAAN,CAAe;AACb,aAAW,wBADE;;AAGb,WAAS,iBAAS,EAAT,EAAa,IAAb,EAAmB;AAC1B;;;;;;AAMA,QAAI,QAAQ,CAAC,EAAC,OAAO,EAAR,EAAY,OAAO,OAAnB,EAAD,CAAZ;AACA,QAAI,QAAQ,KAAK,aAAL,CAAmB,KAAK,KAAxB,CAAZ;AACA,QAAI,OAAO;AACT,eAAS,MAAM,MAAN,CAAa,KAAb,CADA;AAET,kBAAY,OAFH;AAGT,kBAAY,OAHH;AAIT,mBAAa;AAJJ,KAAX;;AAOA,QAAI,SAAS,EAAE,EAAF,EAAM,IAAN,CAAW,QAAX,EAAqB,CAArB,CAAb;;AAEA,QAAI,YAAY,EAAE,MAAF,EAAU,SAAV,CAAoB,IAApB,EAA0B,CAA1B,EAA6B,SAA7C;;AAEA,QAAI,WAAW,yBAAiB,KAAK,KAAtB,CAAf;;AAEA,QAAI,sBAAJ;AACA,cAAU,EAAV,CAAa,QAAb,EAAuB,YAAW;AAChC,UAAI,UAAU,KAAV,CAAgB,MAAhB,KAA2B,CAA/B,EAAkC;AAChC,wBAAgB,IAAhB;AACA,iBAAS,KAAT;AACD,OAHD,MAGO;AACL,YAAI,OAAO,EAAX;AACA,kBAAU,KAAV,CAAgB,OAAhB,CAAwB,UAAS,KAAT,EAAgB;AACtC,eAAK,GAAL,CAAS,KAAT,EAAgB,OAAhB,CAAwB,UAAS,GAAT,EAAc;AACpC,iBAAK,GAAL,IAAY,IAAZ;AACD,WAFD;AAGD,SAJD;AAKA,YAAI,WAAW,OAAO,IAAP,CAAY,IAAZ,CAAf;AACA,iBAAS,IAAT;AACA,wBAAgB,QAAhB;AACA,iBAAS,GAAT,CAAa,QAAb;AACD;AACF,KAhBD;;AAkBA,WAAO;AACL,eAAS,mBAAW;AAClB,iBAAS,KAAT;AACD,OAHI;AAIL,cAAQ,kBAAW;AACjB,YAAI,aAAJ,EACE,SAAS,GAAT,CAAa,aAAb;AACH;AAPI,KAAP;AASD;AArDY,CAAf;;;;;;;;;;ACNA;;IAAY,K;;AACZ;;;;AAEA,IAAI,IAAI,OAAO,MAAf;AACA,IAAI,WAAW,OAAO,QAAtB;;AAEA,MAAM,QAAN,CAAe;AACb,aAAW,wBADE;;AAGb,WAAS,iBAAS,EAAT,EAAa,IAAb,EAAmB;AAC1B;;;;AAIA,QAAI,WAAW,yBAAiB,KAAK,KAAtB,CAAf;;AAEA,QAAI,OAAO,EAAX;AACA,QAAI,MAAM,EAAE,EAAF,EAAM,IAAN,CAAW,OAAX,CAAV;AACA,QAAI,WAAW,IAAI,IAAJ,CAAS,WAAT,CAAf;AACA,QAAI,aAAa,IAAI,IAAJ,CAAS,aAAT,CAAjB;AACA,QAAI,QAAQ,IAAI,IAAJ,CAAS,OAAT,CAAZ;AACA,QAAI,sBAAJ;;AAEA;AACA,QAAI,aAAa,MAAjB,EAAyB;AACvB,sBAAgB,SAAS,GAAT,EAAhB;AACA,WAAK,QAAL,GAAgB,UAAS,GAAT,EAAc;AAC5B,eAAO,cAAc,UAAd,EAA0B,IAAI,IAAJ,CAAS,GAAT,CAA1B,CAAP;AACD,OAFD;AAID,KAND,MAMO,IAAI,aAAa,UAAjB,EAA6B;AAClC,UAAI,WAAW,IAAI,IAAJ,CAAS,UAAT,CAAf;AACA,UAAI,QAAJ,EACE,gBAAgB,SAAS,QAAT,CAAkB,QAAlB,CAAhB,CADF,KAGE,gBAAgB,QAAhB;;AAEF,WAAK,QAAL,GAAgB,UAAS,GAAT,EAAc;AAC5B,eAAO,cAAc,UAAd,EAA0B,IAAI,IAAJ,CAAS,GAAT,CAA1B,CAAP;AACD,OAFD;AAGD,KAVM,MAUA,IAAI,aAAa,QAAjB,EAA2B;AAChC,UAAI,OAAO,KAAP,KAAiB,WAArB,EACE,KAAK,QAAL,GAAgB,UAAS,GAAT,EAAc;AAC5B,YAAI,SAAS,KAAK,GAAL,CAAS,EAAT,EAAa,KAAb,CAAb;AACA,eAAO,KAAK,KAAL,CAAW,MAAM,MAAjB,IAA2B,MAAlC;AACD,OAHD;AAIH;;AAED,QAAI,cAAJ,CAAmB,IAAnB;;AAEA,aAAS,QAAT,GAAoB;AAClB,UAAI,SAAS,IAAI,IAAJ,CAAS,gBAAT,EAA2B,MAAxC;;AAEA;AACA,UAAI,gBAAJ;AACA,UAAI,WAAW,IAAI,IAAJ,CAAS,WAAT,CAAf;AACA,UAAI,aAAa,MAAjB,EAAyB;AACvB,kBAAU,iBAAS,GAAT,EAAc;AACtB,iBAAO,cAAc,IAAI,IAAJ,CAAS,CAAC,GAAV,CAAd,CAAP;AACD,SAFD;AAGD,OAJD,MAIO,IAAI,aAAa,UAAjB,EAA6B;AAClC,kBAAU,iBAAS,GAAT,EAAc;AACtB;AACA,iBAAO,CAAC,GAAD,GAAO,IAAd;AACD,SAHD;AAID,OALM,MAKA;AACL,kBAAU,iBAAS,GAAT,EAAc;AAAE,iBAAO,CAAC,GAAR;AAAc,SAAxC;AACD;;AAED,UAAI,IAAI,IAAJ,CAAS,gBAAT,EAA2B,OAA3B,CAAmC,IAAnC,KAA4C,QAAhD,EAA0D;AACxD,eAAO,CAAC,QAAQ,OAAO,IAAf,CAAD,EAAuB,QAAQ,OAAO,EAAf,CAAvB,CAAP;AACD,OAFD,MAEO;AACL,eAAO,QAAQ,OAAO,IAAf,CAAP;AACD;AACF;;AAED,QAAI,gBAAgB,IAApB;;AAEA,QAAI,EAAJ,CAAO,6BAAP,EAAsC,UAAS,KAAT,EAAgB;AACpD,UAAI,CAAC,IAAI,IAAJ,CAAS,UAAT,CAAD,IAAyB,CAAC,IAAI,IAAJ,CAAS,WAAT,CAA9B,EAAqD;AAAA,wBAClC,UADkC;AAAA;AAAA,YAC9C,IAD8C;AAAA,YACxC,EADwC;;AAEnD,YAAI,OAAO,EAAX;AACA,aAAK,IAAI,IAAI,CAAb,EAAgB,IAAI,KAAK,MAAL,CAAY,MAAhC,EAAwC,GAAxC,EAA6C;AAC3C,cAAI,MAAM,KAAK,MAAL,CAAY,CAAZ,CAAV;AACA,cAAI,OAAO,IAAP,IAAe,OAAO,EAA1B,EAA8B;AAC5B,iBAAK,IAAL,CAAU,KAAK,IAAL,CAAU,CAAV,CAAV;AACD;AACF;AACD,aAAK,IAAL;AACA,iBAAS,GAAT,CAAa,IAAb;AACA,wBAAgB,IAAhB;AACD;AACF,KAdD;;AAiBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,WAAO;AACL,eAAS,mBAAW;AAClB,iBAAS,KAAT;AACD,OAHI;AAIL,cAAQ,kBAAW;AACjB,YAAI,aAAJ,EACE,SAAS,GAAT,CAAa,aAAb;AACH;AAPI,KAAP;AASD;AApHY,CAAf;;AAwHA;AACA,SAAS,QAAT,CAAkB,CAAlB,EAAqB,MAArB,EAA6B;AAC3B,MAAI,MAAM,EAAE,QAAF,EAAV;AACA,SAAO,IAAI,MAAJ,GAAa,MAApB;AACE,UAAM,MAAM,GAAZ;AADF,GAEA,OAAO,GAAP;AACD;;AAED;AACA;AACA,SAAS,aAAT,CAAuB,IAAvB,EAA6B;AAC3B,MAAI,gBAAgB,IAApB,EAA0B;AACxB,WAAO,KAAK,cAAL,KAAwB,GAAxB,GACA,SAAS,KAAK,WAAL,KAAmB,CAA5B,EAA+B,CAA/B,CADA,GACoC,GADpC,GAEA,SAAS,KAAK,UAAL,EAAT,EAA4B,CAA5B,CAFP;AAID,GALD,MAKO;AACL,WAAO,IAAP;AACD;AACF;;;;;;;;;;;;;;ACjJD;;;;AACA;;;;AACA;;IAAY,I;;;;;;;;AAEZ;;;;;;;;;;;;;;;;IAgBa,e,WAAA,e;AAEX,6BAA4C;AAAA,QAAhC,KAAgC,uEAAxB,IAAwB;AAAA,QAAlB,SAAkB,uEAAN,IAAM;;AAAA;;AAC1C,SAAK,WAAL,GAAmB,sBAAnB;AACA,SAAK,QAAL,GAAgB,IAAI,KAAK,mBAAT,CAA6B,KAAK,WAAlC,CAAhB;;AAEA;AACA,SAAK,MAAL,GAAc,IAAd;AACA;AACA,SAAK,IAAL,GAAY,IAAZ;AACA;AACA,SAAK,eAAL,GAAuB,IAAvB;;AAEA,SAAK,UAAL,GAAkB,KAAK,MAAL,CAAY,EAAE,QAAQ,IAAV,EAAZ,EAA8B,SAA9B,CAAlB;;AAEA,SAAK,QAAL,CAAc,KAAd;AACD;;AAED;;;;;;;;;;;;;;;;;6BAaS,K,EAAO;AAAA;;AACd;AACA,UAAI,KAAK,MAAL,KAAgB,KAApB,EACE;AACF;AACA,UAAI,CAAC,KAAK,MAAN,IAAgB,CAAC,KAArB,EACE;;AAEF,UAAI,KAAK,IAAT,EAAe;AACb,aAAK,IAAL,CAAU,GAAV,CAAc,QAAd,EAAwB,KAAK,eAA7B;AACA,aAAK,IAAL,GAAY,IAAZ;AACA,aAAK,eAAL,GAAuB,IAAvB;AACD;;AAED,WAAK,MAAL,GAAc,KAAd;;AAEA,UAAI,KAAJ,EAAW;AACT,aAAK,IAAL,GAAY,qBAAI,KAAJ,EAAW,GAAX,CAAe,WAAf,CAAZ;AACA,YAAI,MAAM,KAAK,IAAL,CAAU,EAAV,CAAa,QAAb,EAAuB,UAAC,CAAD,EAAO;AACtC,gBAAK,WAAL,CAAiB,OAAjB,CAAyB,QAAzB,EAAmC,CAAnC;AACD,SAFS,CAAV;AAGA,aAAK,eAAL,GAAuB,GAAvB;AACD;AACF;;AAED;;;;;;;;;;;;;;;AAcA;;;;;oCAKgB,S,EAAW;AACzB;AACA,aAAO,KAAK,MAAL,CAAY,EAAZ,EACL,KAAK,UAAL,GAAkB,KAAK,UAAvB,GAAoC,IAD/B,EAEL,YAAY,SAAZ,GAAwB,IAFnB,CAAP;AAGD;;AAED;;;;;;;;;;;;;;;wBAYI,Y,EAAc,S,EAAW;AAC3B,UAAI,KAAK,IAAT,EACE,KAAK,IAAL,CAAU,GAAV,CAAc,YAAd,EAA4B,KAAK,eAAL,CAAqB,SAArB,CAA5B;AACH;;AAED;;;;;;;;;;;;;0BAUM,S,EAAW;AACf,UAAI,KAAK,IAAT,EACE,KAAK,GAAL,CAAS,KAAK,CAAd,EAAiB,KAAK,eAAL,CAAqB,SAArB,CAAjB;AACH;;AAED;;;;;;;;;;;;;uBAUG,S,EAAW,Q,EAAU;AACtB,aAAO,KAAK,QAAL,CAAc,EAAd,CAAiB,SAAjB,EAA4B,QAA5B,CAAP;AACD;;AAED;;;;;;;;;;;wBAQI,S,EAAW,Q,EAAU;AACvB,aAAO,KAAK,QAAL,CAAc,GAAd,CAAkB,SAAlB,EAA6B,QAA7B,CAAP;AACD;;AAED;;;;;;;;4BAKQ;AACN,WAAK,QAAL,CAAc,kBAAd;AACA,WAAK,QAAL,CAAc,IAAd;AACD;;;wBAlFW;AACV,aAAO,KAAK,IAAL,GAAY,KAAK,IAAL,CAAU,GAAV,EAAZ,GAA8B,IAArC;AACD;;;;;;AAmFH;;;;;;;;;AASA;;;;;;;;;;;;;;;;;;;;;QCpLgB,M,GAAA,M;QAeA,W,GAAA,W;QAQA,e,GAAA,e;QAoCA,a,GAAA,a;;;;AA3DT,SAAS,MAAT,CAAgB,MAAhB,EAAoC;AAAA,oCAAT,OAAS;AAAT,WAAS;AAAA;;AACzC,OAAK,IAAI,IAAI,CAAb,EAAgB,IAAI,QAAQ,MAA5B,EAAoC,GAApC,EAAyC;AACvC,QAAI,MAAM,QAAQ,CAAR,CAAV;AACA,QAAI,OAAO,GAAP,KAAgB,WAAhB,IAA+B,QAAQ,IAA3C,EACE;;AAEF,SAAK,IAAI,GAAT,IAAgB,GAAhB,EAAqB;AACnB,UAAI,IAAI,cAAJ,CAAmB,GAAnB,CAAJ,EAA6B;AAC3B,eAAO,GAAP,IAAc,IAAI,GAAJ,CAAd;AACD;AACF;AACF;AACD,SAAO,MAAP;AACD;;AAEM,SAAS,WAAT,CAAqB,IAArB,EAA2B;AAChC,OAAK,IAAI,IAAI,CAAb,EAAgB,IAAI,KAAK,MAAzB,EAAiC,GAAjC,EAAsC;AACpC,QAAI,KAAK,CAAL,KAAW,KAAK,IAAE,CAAP,CAAf,EAA0B;AACxB,YAAM,IAAI,KAAJ,CAAU,0CAAV,CAAN;AACD;AACF;AACF;;AAEM,SAAS,eAAT,CAAyB,CAAzB,EAA4B,CAA5B,EAA+B;AACpC,MAAI,MAAM,CAAV;AACA,MAAI,MAAM,CAAV;;AAEA,MAAI,CAAC,CAAL,EAAQ,IAAI,EAAJ;AACR,MAAI,CAAC,CAAL,EAAQ,IAAI,EAAJ;;AAER,MAAI,SAAS,EAAb;AACA,MAAI,SAAS,EAAb;;AAEA,cAAY,CAAZ;AACA,cAAY,CAAZ;;AAEA,SAAO,MAAM,EAAE,MAAR,IAAkB,MAAM,EAAE,MAAjC,EAAyC;AACvC,QAAI,EAAE,GAAF,MAAW,EAAE,GAAF,CAAf,EAAuB;AACrB;AACA;AACD,KAHD,MAGO,IAAI,EAAE,GAAF,IAAS,EAAE,GAAF,CAAb,EAAqB;AAC1B,aAAO,IAAP,CAAY,EAAE,KAAF,CAAZ;AACD,KAFM,MAEA;AACL,aAAO,IAAP,CAAY,EAAE,KAAF,CAAZ;AACD;AACF;;AAED,MAAI,MAAM,EAAE,MAAZ,EACE,SAAS,OAAO,MAAP,CAAc,EAAE,KAAF,CAAQ,GAAR,CAAd,CAAT;AACF,MAAI,MAAM,EAAE,MAAZ,EACE,SAAS,OAAO,MAAP,CAAc,EAAE,KAAF,CAAQ,GAAR,CAAd,CAAT;AACF,SAAO;AACL,aAAS,MADJ;AAEL,WAAO;AAFF,GAAP;AAID;;AAED;AACA;AACO,SAAS,aAAT,CAAuB,EAAvB,EAA2B;AAChC,MAAI,QAAQ,EAAZ;AACA,MAAI,eAAJ;AACA,OAAK,IAAI,IAAT,IAAiB,EAAjB,EAAqB;AACnB,QAAI,GAAG,cAAH,CAAkB,IAAlB,CAAJ,EACE,MAAM,IAAN,CAAW,IAAX;AACF,QAAI,QAAO,GAAG,IAAH,CAAP,MAAqB,QAArB,IAAiC,OAAO,GAAG,IAAH,EAAS,MAAhB,KAA4B,WAAjE,EAA8E;AAC5E,YAAM,IAAI,KAAJ,CAAU,2BAAV,CAAN;AACD,KAFD,MAEO,IAAI,OAAO,MAAP,KAAmB,WAAnB,IAAkC,WAAW,GAAG,IAAH,EAAS,MAA1D,EAAkE;AACvE,YAAM,IAAI,KAAJ,CAAU,8CAAV,CAAN;AACD;AACD,aAAS,GAAG,IAAH,EAAS,MAAlB;AACD;AACD,MAAI,UAAU,EAAd;AACA,MAAI,aAAJ;AACA,OAAK,IAAI,MAAM,CAAf,EAAkB,MAAM,MAAxB,EAAgC,KAAhC,EAAuC;AACrC,WAAO,EAAP;AACA,SAAK,IAAI,MAAM,CAAf,EAAkB,MAAM,MAAM,MAA9B,EAAsC,KAAtC,EAA6C;AAC3C,WAAK,MAAM,GAAN,CAAL,IAAmB,GAAG,MAAM,GAAN,CAAH,EAAe,GAAf,CAAnB;AACD;AACD,YAAQ,IAAR,CAAa,IAAb;AACD;AACD,SAAO,OAAP;AACD;;AAED;;;;;;;IAMa,mB,WAAA,mB;AACX,+BAAY,OAAZ,EAAqB;AAAA;;AACnB,SAAK,QAAL,GAAgB,OAAhB;AACA,SAAK,KAAL,GAAa,EAAb;AACD;;;;uBAEE,S,EAAW,Q,EAAU;AACtB,UAAI,MAAM,KAAK,QAAL,CAAc,EAAd,CAAiB,SAAjB,EAA4B,QAA5B,CAAV;AACA,WAAK,KAAL,CAAW,GAAX,IAAkB,SAAlB;AACA,aAAO,GAAP;AACD;;;wBAEG,S,EAAW,Q,EAAU;AACvB,UAAI,MAAM,KAAK,QAAL,CAAc,GAAd,CAAkB,SAAlB,EAA6B,QAA7B,CAAV;AACA,UAAI,GAAJ,EAAS;AACP,eAAO,KAAK,KAAL,CAAW,GAAX,CAAP;AACD;AACD,aAAO,GAAP;AACD;;;yCAEoB;AAAA;;AACnB,UAAI,eAAe,KAAK,KAAxB;AACA,WAAK,KAAL,GAAa,EAAb;AACA,aAAO,IAAP,CAAY,YAAZ,EAA0B,OAA1B,CAAkC,UAAC,GAAD,EAAS;AACzC,cAAK,QAAL,CAAc,GAAd,CAAkB,aAAa,GAAb,CAAlB,EAAqC,GAArC;AACD,OAFD;AAGD;;;;;;;;;;;;;;;;;;ACpHH;;;;;;;;IAEqB,G;AACnB,eAAY,KAAZ,EAAmB,IAAnB,EAAyB,YAAa,KAAtC,EAA6C;AAAA;;AAC3C,SAAK,MAAL,GAAc,KAAd;AACA,SAAK,KAAL,GAAa,IAAb;AACA,SAAK,MAAL,GAAc,KAAd;AACA,SAAK,OAAL,GAAe,sBAAf;AACD;;;;0BAEK;AACJ,aAAO,KAAK,MAAZ;AACD;;;wBAEG,K,EAAO,YAAa,K,EAAO;AAC7B,UAAI,KAAK,MAAL,KAAgB,KAApB,EAA2B;AACzB;AACA;AACD;AACD,UAAI,WAAW,KAAK,MAApB;AACA,WAAK,MAAL,GAAc,KAAd;AACA;AACA,UAAI,MAAM,EAAV;AACA,UAAI,SAAS,QAAO,KAAP,yCAAO,KAAP,OAAkB,QAA/B,EAAyC;AACvC,aAAK,IAAI,CAAT,IAAc,KAAd,EAAqB;AACnB,cAAI,MAAM,cAAN,CAAqB,CAArB,CAAJ,EACE,IAAI,CAAJ,IAAS,MAAM,CAAN,CAAT;AACH;AACF;AACD,UAAI,QAAJ,GAAe,QAAf;AACA,UAAI,KAAJ,GAAY,KAAZ;AACA,WAAK,OAAL,CAAa,OAAb,CAAqB,QAArB,EAA+B,GAA/B,EAAoC,IAApC;;AAEA;AACA;AACA,UAAI,OAAO,KAAP,IAAgB,OAAO,KAAP,CAAa,aAAjC,EAAgD;AAC9C,eAAO,KAAP,CAAa,aAAb,CACE,mBACG,KAAK,MAAL,CAAY,IAAZ,KAAqB,IAArB,GAA4B,KAAK,MAAL,CAAY,IAAZ,GAAmB,GAA/C,GAAqD,EADxD,IAEE,KAAK,KAHT,EAIE,OAAO,KAAP,KAAkB,WAAlB,GAAgC,IAAhC,GAAuC,KAJzC;AAMD;AACF;;;uBAEE,S,EAAW,Q,EAAU;AACtB,aAAO,KAAK,OAAL,CAAa,EAAb,CAAgB,SAAhB,EAA2B,QAA3B,CAAP;AACD;;;wBAEG,S,EAAW,Q,EAAU;AACvB,aAAO,KAAK,OAAL,CAAa,GAAb,CAAiB,SAAjB,EAA4B,QAA5B,CAAP;AACD;;;;;;kBAjDkB,G", + "file": "generated.js", + "sourceRoot": "", + "sourcesContent": [ + "(function(){function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require==\"function\"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error(\"Cannot find module '\"+o+\"'\");throw f.code=\"MODULE_NOT_FOUND\",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require==\"function\"&&require;for(var o=0;o {\n this._eventRelay.trigger(\"change\", e, this);\n });\n this._varOnChangeSub = sub;\n }\n }\n\n /**\n * Combine the given `extraInfo` (if any) with the handle's default\n * `_extraInfo` (if any).\n * @private\n */\n _mergeExtraInfo(extraInfo) {\n return util.extend({},\n this._extraInfo ? this._extraInfo : null,\n extraInfo ? extraInfo : null);\n }\n\n /**\n * Close the handle. This clears this handle's contribution to the filter set,\n * and unsubscribes all event listeners.\n */\n close() {\n this._emitter.removeAllListeners();\n this.clear();\n this.setGroup(null);\n }\n\n /**\n * Clear this handle's contribution to the filter set.\n *\n * @param {Object} [extraInfo] - Extra properties to be included on the event\n * object that's passed to listeners (in addition to any options that were\n * passed into the `FilterHandle` constructor).\n * \n * @fires FilterHandle#change\n */\n clear(extraInfo) {\n if (!this._filterSet)\n return;\n this._filterSet.clear(this._id);\n this._onChange(extraInfo);\n }\n\n /**\n * Set this handle's contribution to the filter set. This array should consist\n * of the keys of the rows that _should_ be displayed; any keys that are not\n * present in the array will be considered _filtered out_. Note that multiple\n * `FilterHandle` instances in the group may each contribute an array of keys,\n * and only those keys that appear in _all_ of the arrays make it through the\n * filter.\n *\n * @param {string[]} keys - Empty array, or array of keys. To clear the\n * filter, don't pass an empty array; instead, use the\n * {@link FilterHandle#clear} method.\n * @param {Object} [extraInfo] - Extra properties to be included on the event\n * object that's passed to listeners (in addition to any options that were\n * passed into the `FilterHandle` constructor).\n * \n * @fires FilterHandle#change\n */\n set(keys, extraInfo) {\n if (!this._filterSet)\n return;\n this._filterSet.update(this._id, keys);\n this._onChange(extraInfo);\n }\n\n /**\n * @return {string[]|null} - Either: 1) an array of keys that made it through\n * all of the `FilterHandle` instances, or, 2) `null`, which means no filter\n * is being applied (all data should be displayed).\n */\n get filteredKeys() {\n return this._filterSet ? this._filterSet.value : null;\n }\n\n /**\n * Subscribe to events on this `FilterHandle`.\n *\n * @param {string} eventType - Indicates the type of events to listen to.\n * Currently, only `\"change\"` is supported.\n * @param {FilterHandle~listener} listener - The callback function that\n * will be invoked when the event occurs.\n * @return {string} - A token to pass to {@link FilterHandle#off} to cancel\n * this subscription.\n */\n on(eventType, listener) {\n return this._emitter.on(eventType, listener);\n }\n\n /**\n * Cancel event subscriptions created by {@link FilterHandle#on}.\n *\n * @param {string} eventType - The type of event to unsubscribe.\n * @param {string|FilterHandle~listener} listener - Either the callback\n * function previously passed into {@link FilterHandle#on}, or the\n * string that was returned from {@link FilterHandle#on}.\n */\n off(eventType, listener) {\n return this._emitter.off(eventType, listener);\n }\n\n _onChange(extraInfo) {\n if (!this._filterSet)\n return;\n this._filterVar.set(this._filterSet.value, this._mergeExtraInfo(extraInfo));\n }\n\n /**\n * @callback FilterHandle~listener\n * @param {Object} event - An object containing details of the event. For\n * `\"change\"` events, this includes the properties `value` (the new\n * value of the filter set, or `null` if no filter set is active),\n * `oldValue` (the previous value of the filter set), and `sender` (the\n * `FilterHandle` instance that made the change).\n */\n\n}\n\n/**\n * @event FilterHandle#change\n * @type {object}\n * @property {object} value - The new value of the filter set, or `null`\n * if no filter set is active.\n * @property {object} oldValue - The previous value of the filter set.\n * @property {FilterHandle} sender - The `FilterHandle` instance that\n * changed the value.\n */\n", + "import { diffSortedLists } from \"./util\";\n\nfunction naturalComparator(a, b) {\n if (a === b) {\n return 0;\n } else if (a < b) {\n return -1;\n } else if (a > b) {\n return 1;\n }\n}\n\n/**\n * @private\n */\nexport default class FilterSet {\n constructor() {\n this.reset();\n }\n\n reset() {\n // Key: handle ID, Value: array of selected keys, or null\n this._handles = {};\n // Key: key string, Value: count of handles that include it\n this._keys = {};\n this._value = null;\n this._activeHandles = 0;\n }\n\n get value() {\n return this._value;\n }\n\n update(handleId, keys) {\n if (keys !== null) {\n keys = keys.slice(0); // clone before sorting\n keys.sort(naturalComparator);\n }\n\n let {added, removed} = diffSortedLists(this._handles[handleId], keys);\n this._handles[handleId] = keys;\n\n for (let i = 0; i < added.length; i++) {\n this._keys[added[i]] = (this._keys[added[i]] || 0) + 1;\n }\n for (let i = 0; i < removed.length; i++) {\n this._keys[removed[i]]--;\n }\n\n this._updateValue(keys);\n }\n\n /**\n * @param {string[]} keys Sorted array of strings that indicate\n * a superset of possible keys.\n * @private\n */\n _updateValue(keys = this._allKeys) {\n let handleCount = Object.keys(this._handles).length;\n if (handleCount === 0) {\n this._value = null;\n } else {\n this._value = [];\n for (let i = 0; i < keys.length; i++) {\n let count = this._keys[keys[i]];\n if (count === handleCount) {\n this._value.push(keys[i]);\n }\n }\n }\n }\n\n clear(handleId) {\n if (typeof(this._handles[handleId]) === \"undefined\") {\n return;\n }\n\n let keys = this._handles[handleId];\n if (!keys) {\n keys = [];\n }\n\n for (let i = 0; i < keys.length; i++) {\n this._keys[keys[i]]--;\n }\n delete this._handles[handleId];\n\n this._updateValue();\n }\n\n get _allKeys() {\n let allKeys = Object.keys(this._keys);\n allKeys.sort(naturalComparator);\n return allKeys;\n }\n}\n", + "import Var from \"./var\";\n\n// Use a global so that multiple copies of crosstalk.js can be loaded and still\n// have groups behave as singletons across all copies.\nglobal.__crosstalk_groups = global.__crosstalk_groups || {};\nlet groups = global.__crosstalk_groups;\n\nexport default function group(groupName) {\n if (groupName && typeof(groupName) === \"string\") {\n if (!groups.hasOwnProperty(groupName)) {\n groups[groupName] = new Group(groupName);\n }\n return groups[groupName];\n } else if (typeof(groupName) === \"object\" && groupName._vars && groupName.var) {\n // Appears to already be a group object\n return groupName;\n } else if (Array.isArray(groupName) &&\n groupName.length == 1 &&\n typeof(groupName[0]) === \"string\") {\n return group(groupName[0]);\n } else {\n throw new Error(\"Invalid groupName argument\");\n }\n}\n\nclass Group {\n constructor(name) {\n this.name = name;\n this._vars = {};\n }\n\n var(name) {\n if (!name || typeof(name) !== \"string\") {\n throw new Error(\"Invalid var name\");\n }\n\n if (!this._vars.hasOwnProperty(name))\n this._vars[name] = new Var(this, name);\n return this._vars[name];\n }\n\n has(name) {\n if (!name || typeof(name) !== \"string\") {\n throw new Error(\"Invalid var name\");\n }\n\n return this._vars.hasOwnProperty(name);\n }\n}\n", + "import group from \"./group\";\nimport { SelectionHandle } from \"./selection\";\nimport { FilterHandle } from \"./filter\";\nimport { bind } from \"./input\";\nimport \"./input_selectize\";\nimport \"./input_checkboxgroup\";\nimport \"./input_slider\";\n\nconst defaultGroup = group(\"default\");\n\nfunction var_(name) {\n return defaultGroup.var(name);\n}\n\nfunction has(name) {\n return defaultGroup.has(name);\n}\n\nif (global.Shiny) {\n global.Shiny.addCustomMessageHandler(\"update-client-value\", function(message) {\n if (typeof(message.group) === \"string\") {\n group(message.group).var(message.name).set(message.value);\n } else {\n var_(message.name).set(message.value);\n }\n });\n}\n\nconst crosstalk = {\n group: group,\n var: var_,\n has: has,\n SelectionHandle: SelectionHandle,\n FilterHandle: FilterHandle,\n bind: bind\n};\n\n/**\n * @namespace crosstalk\n */\nexport default crosstalk;\nglobal.crosstalk = crosstalk;\n", + "let $ = global.jQuery;\n\nlet bindings = {};\n\nexport function register(reg) {\n bindings[reg.className] = reg;\n if (global.document && global.document.readyState !== \"complete\") {\n $(() => {\n bind();\n });\n } else if (global.document) {\n setTimeout(bind, 100);\n }\n}\n\nexport function bind() {\n Object.keys(bindings).forEach(function(className) {\n let binding = bindings[className];\n $(\".\" + binding.className).not(\".crosstalk-input-bound\").each(function(i, el) {\n bindInstance(binding, el);\n });\n });\n}\n\n// Escape jQuery identifier\nfunction $escape(val) {\n return val.replace(/([!\"#$%&'()*+,./:;<=>?@[\\\\\\]^`{|}~])/g, \"\\\\$1\");\n}\n\nfunction bindEl(el) {\n let $el = $(el);\n Object.keys(bindings).forEach(function(className) {\n if ($el.hasClass(className) && !$el.hasClass(\"crosstalk-input-bound\")) {\n let binding = bindings[className];\n bindInstance(binding, el);\n }\n });\n}\n\nfunction bindInstance(binding, el) {\n let jsonEl = $(el).find(\"script[type='application/json'][data-for='\" + $escape(el.id) + \"']\");\n let data = JSON.parse(jsonEl[0].innerText);\n\n let instance = binding.factory(el, data);\n $(el).data(\"crosstalk-instance\", instance);\n $(el).addClass(\"crosstalk-input-bound\");\n}\n\nif (global.Shiny) {\n let inputBinding = new global.Shiny.InputBinding();\n let $ = global.jQuery;\n $.extend(inputBinding, {\n find: function(scope) {\n return $(scope).find(\".crosstalk-input\");\n },\n initialize: function(el) {\n if (!$(el).hasClass(\"crosstalk-input-bound\")) {\n bindEl(el);\n }\n },\n getId: function(el) {\n return el.id;\n },\n getValue: function(el) {\n\n },\n setValue: function(el, value) {\n\n },\n receiveMessage: function(el, data) {\n\n },\n subscribe: function(el, callback) {\n $(el).data(\"crosstalk-instance\").resume();\n },\n unsubscribe: function(el) {\n $(el).data(\"crosstalk-instance\").suspend();\n }\n });\n global.Shiny.inputBindings.register(inputBinding, \"crosstalk.inputBinding\");\n}\n", + "import * as input from \"./input\";\nimport { FilterHandle } from \"./filter\";\n\nlet $ = global.jQuery;\n\ninput.register({\n className: \"crosstalk-input-checkboxgroup\",\n\n factory: function(el, data) {\n /*\n * map: {\"groupA\": [\"keyA\", \"keyB\", ...], ...}\n * group: \"ct-groupname\"\n */\n let ctHandle = new FilterHandle(data.group);\n\n let lastKnownKeys;\n let $el = $(el);\n $el.on(\"change\", \"input[type='checkbox']\", function() {\n let checked = $el.find(\"input[type='checkbox']:checked\");\n if (checked.length === 0) {\n lastKnownKeys = null;\n ctHandle.clear();\n } else {\n let keys = {};\n checked.each(function() {\n data.map[this.value].forEach(function(key) {\n keys[key] = true;\n });\n });\n let keyArray = Object.keys(keys);\n keyArray.sort();\n lastKnownKeys = keyArray;\n ctHandle.set(keyArray);\n }\n });\n\n return {\n suspend: function() {\n ctHandle.clear();\n },\n resume: function() {\n if (lastKnownKeys)\n ctHandle.set(lastKnownKeys);\n }\n };\n }\n});\n", + "import * as input from \"./input\";\nimport * as util from \"./util\";\nimport { FilterHandle } from \"./filter\";\n\nlet $ = global.jQuery;\n\ninput.register({\n className: \"crosstalk-input-select\",\n\n factory: function(el, data) {\n /*\n * items: {value: [...], label: [...]}\n * map: {\"groupA\": [\"keyA\", \"keyB\", ...], ...}\n * group: \"ct-groupname\"\n */\n\n let first = [{value: \"\", label: \"(All)\"}];\n let items = util.dataframeToD3(data.items);\n let opts = {\n options: first.concat(items),\n valueField: \"value\",\n labelField: \"label\",\n searchField: \"label\"\n };\n\n let select = $(el).find(\"select\")[0];\n\n let selectize = $(select).selectize(opts)[0].selectize;\n\n let ctHandle = new FilterHandle(data.group);\n\n let lastKnownKeys;\n selectize.on(\"change\", function() {\n if (selectize.items.length === 0) {\n lastKnownKeys = null;\n ctHandle.clear();\n } else {\n let keys = {};\n selectize.items.forEach(function(group) {\n data.map[group].forEach(function(key) {\n keys[key] = true;\n });\n });\n let keyArray = Object.keys(keys);\n keyArray.sort();\n lastKnownKeys = keyArray;\n ctHandle.set(keyArray);\n }\n });\n\n return {\n suspend: function() {\n ctHandle.clear();\n },\n resume: function() {\n if (lastKnownKeys)\n ctHandle.set(lastKnownKeys);\n }\n };\n }\n});\n", + "import * as input from \"./input\";\nimport { FilterHandle } from \"./filter\";\n\nlet $ = global.jQuery;\nlet strftime = global.strftime;\n\ninput.register({\n className: \"crosstalk-input-slider\",\n\n factory: function(el, data) {\n /*\n * map: {\"groupA\": [\"keyA\", \"keyB\", ...], ...}\n * group: \"ct-groupname\"\n */\n let ctHandle = new FilterHandle(data.group);\n\n let opts = {};\n let $el = $(el).find(\"input\");\n let dataType = $el.data(\"data-type\");\n let timeFormat = $el.data(\"time-format\");\n let round = $el.data(\"round\");\n let timeFormatter;\n\n // Set up formatting functions\n if (dataType === \"date\") {\n timeFormatter = strftime.utc();\n opts.prettify = function(num) {\n return timeFormatter(timeFormat, new Date(num));\n };\n\n } else if (dataType === \"datetime\") {\n let timezone = $el.data(\"timezone\");\n if (timezone)\n timeFormatter = strftime.timezone(timezone);\n else\n timeFormatter = strftime;\n\n opts.prettify = function(num) {\n return timeFormatter(timeFormat, new Date(num));\n };\n } else if (dataType === \"number\") {\n if (typeof round !== \"undefined\")\n opts.prettify = function(num) {\n let factor = Math.pow(10, round);\n return Math.round(num * factor) / factor;\n };\n }\n\n $el.ionRangeSlider(opts);\n\n function getValue() {\n let result = $el.data(\"ionRangeSlider\").result;\n\n // Function for converting numeric value from slider to appropriate type.\n let convert;\n let dataType = $el.data(\"data-type\");\n if (dataType === \"date\") {\n convert = function(val) {\n return formatDateUTC(new Date(+val));\n };\n } else if (dataType === \"datetime\") {\n convert = function(val) {\n // Convert ms to s\n return +val / 1000;\n };\n } else {\n convert = function(val) { return +val; };\n }\n\n if ($el.data(\"ionRangeSlider\").options.type === \"double\") {\n return [convert(result.from), convert(result.to)];\n } else {\n return convert(result.from);\n }\n }\n\n let lastKnownKeys = null;\n\n $el.on(\"change.crosstalkSliderInput\", function(event) {\n if (!$el.data(\"updating\") && !$el.data(\"animating\")) {\n let [from, to] = getValue();\n let keys = [];\n for (let i = 0; i < data.values.length; i++) {\n let val = data.values[i];\n if (val >= from && val <= to) {\n keys.push(data.keys[i]);\n }\n }\n keys.sort();\n ctHandle.set(keys);\n lastKnownKeys = keys;\n }\n });\n\n\n // let $el = $(el);\n // $el.on(\"change\", \"input[type=\"checkbox\"]\", function() {\n // let checked = $el.find(\"input[type=\"checkbox\"]:checked\");\n // if (checked.length === 0) {\n // ctHandle.clear();\n // } else {\n // let keys = {};\n // checked.each(function() {\n // data.map[this.value].forEach(function(key) {\n // keys[key] = true;\n // });\n // });\n // let keyArray = Object.keys(keys);\n // keyArray.sort();\n // ctHandle.set(keyArray);\n // }\n // });\n\n return {\n suspend: function() {\n ctHandle.clear();\n },\n resume: function() {\n if (lastKnownKeys)\n ctHandle.set(lastKnownKeys);\n }\n };\n }\n});\n\n\n// Convert a number to a string with leading zeros\nfunction padZeros(n, digits) {\n let str = n.toString();\n while (str.length < digits)\n str = \"0\" + str;\n return str;\n}\n\n// Given a Date object, return a string in yyyy-mm-dd format, using the\n// UTC date. This may be a day off from the date in the local time zone.\nfunction formatDateUTC(date) {\n if (date instanceof Date) {\n return date.getUTCFullYear() + \"-\" +\n padZeros(date.getUTCMonth()+1, 2) + \"-\" +\n padZeros(date.getUTCDate(), 2);\n\n } else {\n return null;\n }\n}\n", + "import Events from \"./events\";\nimport grp from \"./group\";\nimport * as util from \"./util\";\n\n/**\n * Use this class to read and write (and listen for changes to) the selection\n * for a Crosstalk group. This is intended to be used for linked brushing.\n *\n * If two (or more) `SelectionHandle` instances in the same webpage share the\n * same group name, they will share the same state. Setting the selection using\n * one `SelectionHandle` instance will result in the `value` property instantly\n * changing across the others, and `\"change\"` event listeners on all instances\n * (including the one that initiated the sending) will fire.\n *\n * @param {string} [group] - The name of the Crosstalk group, or if none,\n * null or undefined (or any other falsy value). This can be changed later\n * via the [SelectionHandle#setGroup](#setGroup) method.\n * @param {Object} [extraInfo] - An object whose properties will be copied to\n * the event object whenever an event is emitted.\n */\nexport class SelectionHandle {\n\n constructor(group = null, extraInfo = null) {\n this._eventRelay = new Events();\n this._emitter = new util.SubscriptionTracker(this._eventRelay);\n\n // Name of the group we're currently tracking, if any. Can change over time.\n this._group = null;\n // The Var we're currently tracking, if any. Can change over time.\n this._var = null;\n // The event handler subscription we currently have on var.on(\"change\").\n this._varOnChangeSub = null;\n\n this._extraInfo = util.extend({ sender: this }, extraInfo);\n\n this.setGroup(group);\n }\n\n /**\n * Changes the Crosstalk group membership of this SelectionHandle. The group\n * being switched away from (if any) will not have its selection value\n * modified as a result of calling `setGroup`, even if this handle was the\n * most recent handle to set the selection of the group.\n *\n * The group being switched to (if any) will also not have its selection value\n * modified as a result of calling `setGroup`. If you want to set the\n * selection value of the new group, call `set` explicitly.\n *\n * @param {string} group - The name of the Crosstalk group, or null (or\n * undefined) to clear the group.\n */\n setGroup(group) {\n // If group is unchanged, do nothing\n if (this._group === group)\n return;\n // Treat null, undefined, and other falsy values the same\n if (!this._group && !group)\n return;\n\n if (this._var) {\n this._var.off(\"change\", this._varOnChangeSub);\n this._var = null;\n this._varOnChangeSub = null;\n }\n\n this._group = group;\n\n if (group) {\n this._var = grp(group).var(\"selection\");\n let sub = this._var.on(\"change\", (e) => {\n this._eventRelay.trigger(\"change\", e, this);\n });\n this._varOnChangeSub = sub;\n }\n }\n\n /**\n * Retrieves the current selection for the group represented by this\n * `SelectionHandle`.\n *\n * - If no selection is active, then this value will be falsy.\n * - If a selection is active, but no data points are selected, then this\n * value will be an empty array.\n * - If a selection is active, and data points are selected, then the keys\n * of the selected data points will be present in the array.\n */\n get value() {\n return this._var ? this._var.get() : null;\n }\n\n /**\n * Combines the given `extraInfo` (if any) with the handle's default\n * `_extraInfo` (if any).\n * @private\n */\n _mergeExtraInfo(extraInfo) {\n // Important incidental effect: shallow clone is returned\n return util.extend({},\n this._extraInfo ? this._extraInfo : null,\n extraInfo ? extraInfo : null);\n }\n\n /**\n * Overwrites the current selection for the group, and raises the `\"change\"`\n * event among all of the group's '`SelectionHandle` instances (including\n * this one).\n *\n * @fires SelectionHandle#change\n * @param {string[]} selectedKeys - Falsy, empty array, or array of keys (see\n * {@link SelectionHandle#value}).\n * @param {Object} [extraInfo] - Extra properties to be included on the event\n * object that's passed to listeners (in addition to any options that were\n * passed into the `SelectionHandle` constructor).\n */\n set(selectedKeys, extraInfo) {\n if (this._var)\n this._var.set(selectedKeys, this._mergeExtraInfo(extraInfo));\n }\n\n /**\n * Overwrites the current selection for the group, and raises the `\"change\"`\n * event among all of the group's '`SelectionHandle` instances (including\n * this one).\n *\n * @fires SelectionHandle#change\n * @param {Object} [extraInfo] - Extra properties to be included on the event\n * object that's passed to listeners (in addition to any that were passed\n * into the `SelectionHandle` constructor).\n */\n clear(extraInfo) {\n if (this._var)\n this.set(void 0, this._mergeExtraInfo(extraInfo));\n }\n\n /**\n * Subscribes to events on this `SelectionHandle`.\n *\n * @param {string} eventType - Indicates the type of events to listen to.\n * Currently, only `\"change\"` is supported.\n * @param {SelectionHandle~listener} listener - The callback function that\n * will be invoked when the event occurs.\n * @return {string} - A token to pass to {@link SelectionHandle#off} to cancel\n * this subscription.\n */\n on(eventType, listener) {\n return this._emitter.on(eventType, listener);\n }\n\n /**\n * Cancels event subscriptions created by {@link SelectionHandle#on}.\n *\n * @param {string} eventType - The type of event to unsubscribe.\n * @param {string|SelectionHandle~listener} listener - Either the callback\n * function previously passed into {@link SelectionHandle#on}, or the\n * string that was returned from {@link SelectionHandle#on}.\n */\n off(eventType, listener) {\n return this._emitter.off(eventType, listener);\n }\n\n /**\n * Shuts down the `SelectionHandle` object.\n *\n * Removes all event listeners that were added through this handle.\n */\n close() {\n this._emitter.removeAllListeners();\n this.setGroup(null);\n }\n}\n\n/**\n * @callback SelectionHandle~listener\n * @param {Object} event - An object containing details of the event. For\n * `\"change\"` events, this includes the properties `value` (the new\n * value of the selection, or `undefined` if no selection is active),\n * `oldValue` (the previous value of the selection), and `sender` (the\n * `SelectionHandle` instance that made the change).\n */\n\n/**\n * @event SelectionHandle#change\n * @type {object}\n * @property {object} value - The new value of the selection, or `undefined`\n * if no selection is active.\n * @property {object} oldValue - The previous value of the selection.\n * @property {SelectionHandle} sender - The `SelectionHandle` instance that\n * changed the value.\n */\n", + "export function extend(target, ...sources) {\n for (let i = 0; i < sources.length; i++) {\n let src = sources[i];\n if (typeof(src) === \"undefined\" || src === null)\n continue;\n\n for (let key in src) {\n if (src.hasOwnProperty(key)) {\n target[key] = src[key];\n }\n }\n }\n return target;\n}\n\nexport function checkSorted(list) {\n for (let i = 1; i < list.length; i++) {\n if (list[i] <= list[i-1]) {\n throw new Error(\"List is not sorted or contains duplicate\");\n }\n }\n}\n\nexport function diffSortedLists(a, b) {\n let i_a = 0;\n let i_b = 0;\n\n if (!a) a = [];\n if (!b) b = [];\n\n let a_only = [];\n let b_only = [];\n\n checkSorted(a);\n checkSorted(b);\n\n while (i_a < a.length && i_b < b.length) {\n if (a[i_a] === b[i_b]) {\n i_a++;\n i_b++;\n } else if (a[i_a] < b[i_b]) {\n a_only.push(a[i_a++]);\n } else {\n b_only.push(b[i_b++]);\n }\n }\n\n if (i_a < a.length)\n a_only = a_only.concat(a.slice(i_a));\n if (i_b < b.length)\n b_only = b_only.concat(b.slice(i_b));\n return {\n removed: a_only,\n added: b_only\n };\n}\n\n// Convert from wide: { colA: [1,2,3], colB: [4,5,6], ... }\n// to long: [ {colA: 1, colB: 4}, {colA: 2, colB: 5}, ... ]\nexport function dataframeToD3(df) {\n let names = [];\n let length;\n for (let name in df) {\n if (df.hasOwnProperty(name))\n names.push(name);\n if (typeof(df[name]) !== \"object\" || typeof(df[name].length) === \"undefined\") {\n throw new Error(\"All fields must be arrays\");\n } else if (typeof(length) !== \"undefined\" && length !== df[name].length) {\n throw new Error(\"All fields must be arrays of the same length\");\n }\n length = df[name].length;\n }\n let results = [];\n let item;\n for (let row = 0; row < length; row++) {\n item = {};\n for (let col = 0; col < names.length; col++) {\n item[names[col]] = df[names[col]][row];\n }\n results.push(item);\n }\n return results;\n}\n\n/**\n * Keeps track of all event listener additions/removals and lets all active\n * listeners be removed with a single operation.\n *\n * @private\n */\nexport class SubscriptionTracker {\n constructor(emitter) {\n this._emitter = emitter;\n this._subs = {};\n }\n\n on(eventType, listener) {\n let sub = this._emitter.on(eventType, listener);\n this._subs[sub] = eventType;\n return sub;\n }\n\n off(eventType, listener) {\n let sub = this._emitter.off(eventType, listener);\n if (sub) {\n delete this._subs[sub];\n }\n return sub;\n }\n\n removeAllListeners() {\n let current_subs = this._subs;\n this._subs = {};\n Object.keys(current_subs).forEach((sub) => {\n this._emitter.off(current_subs[sub], sub);\n });\n }\n}\n", + "import Events from \"./events\";\n\nexport default class Var {\n constructor(group, name, /*optional*/ value) {\n this._group = group;\n this._name = name;\n this._value = value;\n this._events = new Events();\n }\n\n get() {\n return this._value;\n }\n\n set(value, /*optional*/ event) {\n if (this._value === value) {\n // Do nothing; the value hasn't changed\n return;\n }\n let oldValue = this._value;\n this._value = value;\n // Alert JavaScript listeners that the value has changed\n let evt = {};\n if (event && typeof(event) === \"object\") {\n for (let k in event) {\n if (event.hasOwnProperty(k))\n evt[k] = event[k];\n }\n }\n evt.oldValue = oldValue;\n evt.value = value;\n this._events.trigger(\"change\", evt, this);\n\n // TODO: Make this extensible, to let arbitrary back-ends know that\n // something has changed\n if (global.Shiny && global.Shiny.onInputChange) {\n global.Shiny.onInputChange(\n \".clientValue-\" +\n (this._group.name !== null ? this._group.name + \"-\" : \"\") +\n this._name,\n typeof(value) === \"undefined\" ? null : value\n );\n }\n }\n\n on(eventType, listener) {\n return this._events.on(eventType, listener);\n }\n\n off(eventType, listener) {\n return this._events.off(eventType, listener);\n }\n}\n" + ] +} \ No newline at end of file diff --git a/docs/articles/variables_sheet_files/crosstalk-1.2.1/js/crosstalk.min.js b/docs/articles/variables_sheet_files/crosstalk-1.2.1/js/crosstalk.min.js new file mode 100644 index 00000000..b7ec0ac9 --- /dev/null +++ b/docs/articles/variables_sheet_files/crosstalk-1.2.1/js/crosstalk.min.js @@ -0,0 +1,2 @@ +!function o(u,a,l){function s(n,e){if(!a[n]){if(!u[n]){var t="function"==typeof require&&require;if(!e&&t)return t(n,!0);if(f)return f(n,!0);var r=new Error("Cannot find module '"+n+"'");throw r.code="MODULE_NOT_FOUND",r}var i=a[n]={exports:{}};u[n][0].call(i.exports,function(e){var t=u[n][1][e];return s(t||e)},i,i.exports,o,u,a,l)}return a[n].exports}for(var f="function"==typeof require&&require,e=0;e?@[\\\]^`{|}~])/g,"\\$1")+"']"),r=JSON.parse(n[0].innerText),i=e.factory(t,r);o(t).data("crosstalk-instance",i),o(t).addClass("crosstalk-input-bound")}if(t.Shiny){var e=new t.Shiny.InputBinding,u=t.jQuery;u.extend(e,{find:function(e){return u(e).find(".crosstalk-input")},initialize:function(e){var t,n;u(e).hasClass("crosstalk-input-bound")||(n=o(t=e),Object.keys(r).forEach(function(e){n.hasClass(e)&&!n.hasClass("crosstalk-input-bound")&&i(r[e],t)}))},getId:function(e){return e.id},getValue:function(e){},setValue:function(e,t){},receiveMessage:function(e,t){},subscribe:function(e,t){u(e).data("crosstalk-instance").resume()},unsubscribe:function(e){u(e).data("crosstalk-instance").suspend()}}),t.Shiny.inputBindings.register(e,"crosstalk.inputBinding")}}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{}],7:[function(r,e,t){(function(e){"use strict";var t=function(e){{if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[n]=e[n]);return t.default=e,t}}(r("./input")),n=r("./filter");var a=e.jQuery;t.register({className:"crosstalk-input-checkboxgroup",factory:function(e,r){var i=new n.FilterHandle(r.group),o=void 0,u=a(e);return u.on("change","input[type='checkbox']",function(){var e=u.find("input[type='checkbox']:checked");if(0===e.length)o=null,i.clear();else{var t={};e.each(function(){r.map[this.value].forEach(function(e){t[e]=!0})});var n=Object.keys(t);n.sort(),o=n,i.set(n)}}),{suspend:function(){i.clear()},resume:function(){o&&i.set(o)}}}})}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{"./filter":2,"./input":6}],8:[function(r,e,t){(function(e){"use strict";var t=n(r("./input")),l=n(r("./util")),s=r("./filter");function n(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[n]=e[n]);return t.default=e,t}var f=e.jQuery;t.register({className:"crosstalk-input-select",factory:function(e,n){var t=l.dataframeToD3(n.items),r={options:[{value:"",label:"(All)"}].concat(t),valueField:"value",labelField:"label",searchField:"label"},i=f(e).find("select")[0],o=f(i).selectize(r)[0].selectize,u=new s.FilterHandle(n.group),a=void 0;return o.on("change",function(){if(0===o.items.length)a=null,u.clear();else{var t={};o.items.forEach(function(e){n.map[e].forEach(function(e){t[e]=!0})});var e=Object.keys(t);e.sort(),a=e,u.set(e)}}),{suspend:function(){u.clear()},resume:function(){a&&u.set(a)}}}})}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{"./filter":2,"./input":6,"./util":11}],9:[function(n,e,t){(function(e){"use strict";var d=function(e,t){if(Array.isArray(e))return e;if(Symbol.iterator in Object(e))return function(e,t){var n=[],r=!0,i=!1,o=void 0;try{for(var u,a=e[Symbol.iterator]();!(r=(u=a.next()).done)&&(n.push(u.value),!t||n.length!==t);r=!0);}catch(e){i=!0,o=e}finally{try{!r&&a.return&&a.return()}finally{if(i)throw o}}return n}(e,t);throw new TypeError("Invalid attempt to destructure non-iterable instance")},t=function(e){{if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[n]=e[n]);return t.default=e,t}}(n("./input")),a=n("./filter");var v=e.jQuery,p=e.strftime;function y(e,t){for(var n=e.toString();n.length {\n this._eventRelay.trigger(\"change\", e, this);\n });\n this._varOnChangeSub = sub;\n }\n }\n\n /**\n * Combine the given `extraInfo` (if any) with the handle's default\n * `_extraInfo` (if any).\n * @private\n */\n _mergeExtraInfo(extraInfo) {\n return util.extend({},\n this._extraInfo ? this._extraInfo : null,\n extraInfo ? extraInfo : null);\n }\n\n /**\n * Close the handle. This clears this handle's contribution to the filter set,\n * and unsubscribes all event listeners.\n */\n close() {\n this._emitter.removeAllListeners();\n this.clear();\n this.setGroup(null);\n }\n\n /**\n * Clear this handle's contribution to the filter set.\n *\n * @param {Object} [extraInfo] - Extra properties to be included on the event\n * object that's passed to listeners (in addition to any options that were\n * passed into the `FilterHandle` constructor).\n * \n * @fires FilterHandle#change\n */\n clear(extraInfo) {\n if (!this._filterSet)\n return;\n this._filterSet.clear(this._id);\n this._onChange(extraInfo);\n }\n\n /**\n * Set this handle's contribution to the filter set. This array should consist\n * of the keys of the rows that _should_ be displayed; any keys that are not\n * present in the array will be considered _filtered out_. Note that multiple\n * `FilterHandle` instances in the group may each contribute an array of keys,\n * and only those keys that appear in _all_ of the arrays make it through the\n * filter.\n *\n * @param {string[]} keys - Empty array, or array of keys. To clear the\n * filter, don't pass an empty array; instead, use the\n * {@link FilterHandle#clear} method.\n * @param {Object} [extraInfo] - Extra properties to be included on the event\n * object that's passed to listeners (in addition to any options that were\n * passed into the `FilterHandle` constructor).\n * \n * @fires FilterHandle#change\n */\n set(keys, extraInfo) {\n if (!this._filterSet)\n return;\n this._filterSet.update(this._id, keys);\n this._onChange(extraInfo);\n }\n\n /**\n * @return {string[]|null} - Either: 1) an array of keys that made it through\n * all of the `FilterHandle` instances, or, 2) `null`, which means no filter\n * is being applied (all data should be displayed).\n */\n get filteredKeys() {\n return this._filterSet ? this._filterSet.value : null;\n }\n\n /**\n * Subscribe to events on this `FilterHandle`.\n *\n * @param {string} eventType - Indicates the type of events to listen to.\n * Currently, only `\"change\"` is supported.\n * @param {FilterHandle~listener} listener - The callback function that\n * will be invoked when the event occurs.\n * @return {string} - A token to pass to {@link FilterHandle#off} to cancel\n * this subscription.\n */\n on(eventType, listener) {\n return this._emitter.on(eventType, listener);\n }\n\n /**\n * Cancel event subscriptions created by {@link FilterHandle#on}.\n *\n * @param {string} eventType - The type of event to unsubscribe.\n * @param {string|FilterHandle~listener} listener - Either the callback\n * function previously passed into {@link FilterHandle#on}, or the\n * string that was returned from {@link FilterHandle#on}.\n */\n off(eventType, listener) {\n return this._emitter.off(eventType, listener);\n }\n\n _onChange(extraInfo) {\n if (!this._filterSet)\n return;\n this._filterVar.set(this._filterSet.value, this._mergeExtraInfo(extraInfo));\n }\n\n /**\n * @callback FilterHandle~listener\n * @param {Object} event - An object containing details of the event. For\n * `\"change\"` events, this includes the properties `value` (the new\n * value of the filter set, or `null` if no filter set is active),\n * `oldValue` (the previous value of the filter set), and `sender` (the\n * `FilterHandle` instance that made the change).\n */\n\n}\n\n/**\n * @event FilterHandle#change\n * @type {object}\n * @property {object} value - The new value of the filter set, or `null`\n * if no filter set is active.\n * @property {object} oldValue - The previous value of the filter set.\n * @property {FilterHandle} sender - The `FilterHandle` instance that\n * changed the value.\n */\n","import { diffSortedLists } from \"./util\";\n\nfunction naturalComparator(a, b) {\n if (a === b) {\n return 0;\n } else if (a < b) {\n return -1;\n } else if (a > b) {\n return 1;\n }\n}\n\n/**\n * @private\n */\nexport default class FilterSet {\n constructor() {\n this.reset();\n }\n\n reset() {\n // Key: handle ID, Value: array of selected keys, or null\n this._handles = {};\n // Key: key string, Value: count of handles that include it\n this._keys = {};\n this._value = null;\n this._activeHandles = 0;\n }\n\n get value() {\n return this._value;\n }\n\n update(handleId, keys) {\n if (keys !== null) {\n keys = keys.slice(0); // clone before sorting\n keys.sort(naturalComparator);\n }\n\n let {added, removed} = diffSortedLists(this._handles[handleId], keys);\n this._handles[handleId] = keys;\n\n for (let i = 0; i < added.length; i++) {\n this._keys[added[i]] = (this._keys[added[i]] || 0) + 1;\n }\n for (let i = 0; i < removed.length; i++) {\n this._keys[removed[i]]--;\n }\n\n this._updateValue(keys);\n }\n\n /**\n * @param {string[]} keys Sorted array of strings that indicate\n * a superset of possible keys.\n * @private\n */\n _updateValue(keys = this._allKeys) {\n let handleCount = Object.keys(this._handles).length;\n if (handleCount === 0) {\n this._value = null;\n } else {\n this._value = [];\n for (let i = 0; i < keys.length; i++) {\n let count = this._keys[keys[i]];\n if (count === handleCount) {\n this._value.push(keys[i]);\n }\n }\n }\n }\n\n clear(handleId) {\n if (typeof(this._handles[handleId]) === \"undefined\") {\n return;\n }\n\n let keys = this._handles[handleId];\n if (!keys) {\n keys = [];\n }\n\n for (let i = 0; i < keys.length; i++) {\n this._keys[keys[i]]--;\n }\n delete this._handles[handleId];\n\n this._updateValue();\n }\n\n get _allKeys() {\n let allKeys = Object.keys(this._keys);\n allKeys.sort(naturalComparator);\n return allKeys;\n }\n}\n","import Var from \"./var\";\n\n// Use a global so that multiple copies of crosstalk.js can be loaded and still\n// have groups behave as singletons across all copies.\nglobal.__crosstalk_groups = global.__crosstalk_groups || {};\nlet groups = global.__crosstalk_groups;\n\nexport default function group(groupName) {\n if (groupName && typeof(groupName) === \"string\") {\n if (!groups.hasOwnProperty(groupName)) {\n groups[groupName] = new Group(groupName);\n }\n return groups[groupName];\n } else if (typeof(groupName) === \"object\" && groupName._vars && groupName.var) {\n // Appears to already be a group object\n return groupName;\n } else if (Array.isArray(groupName) &&\n groupName.length == 1 &&\n typeof(groupName[0]) === \"string\") {\n return group(groupName[0]);\n } else {\n throw new Error(\"Invalid groupName argument\");\n }\n}\n\nclass Group {\n constructor(name) {\n this.name = name;\n this._vars = {};\n }\n\n var(name) {\n if (!name || typeof(name) !== \"string\") {\n throw new Error(\"Invalid var name\");\n }\n\n if (!this._vars.hasOwnProperty(name))\n this._vars[name] = new Var(this, name);\n return this._vars[name];\n }\n\n has(name) {\n if (!name || typeof(name) !== \"string\") {\n throw new Error(\"Invalid var name\");\n }\n\n return this._vars.hasOwnProperty(name);\n }\n}\n","import group from \"./group\";\nimport { SelectionHandle } from \"./selection\";\nimport { FilterHandle } from \"./filter\";\nimport { bind } from \"./input\";\nimport \"./input_selectize\";\nimport \"./input_checkboxgroup\";\nimport \"./input_slider\";\n\nconst defaultGroup = group(\"default\");\n\nfunction var_(name) {\n return defaultGroup.var(name);\n}\n\nfunction has(name) {\n return defaultGroup.has(name);\n}\n\nif (global.Shiny) {\n global.Shiny.addCustomMessageHandler(\"update-client-value\", function(message) {\n if (typeof(message.group) === \"string\") {\n group(message.group).var(message.name).set(message.value);\n } else {\n var_(message.name).set(message.value);\n }\n });\n}\n\nconst crosstalk = {\n group: group,\n var: var_,\n has: has,\n SelectionHandle: SelectionHandle,\n FilterHandle: FilterHandle,\n bind: bind\n};\n\n/**\n * @namespace crosstalk\n */\nexport default crosstalk;\nglobal.crosstalk = crosstalk;\n","let $ = global.jQuery;\n\nlet bindings = {};\n\nexport function register(reg) {\n bindings[reg.className] = reg;\n if (global.document && global.document.readyState !== \"complete\") {\n $(() => {\n bind();\n });\n } else if (global.document) {\n setTimeout(bind, 100);\n }\n}\n\nexport function bind() {\n Object.keys(bindings).forEach(function(className) {\n let binding = bindings[className];\n $(\".\" + binding.className).not(\".crosstalk-input-bound\").each(function(i, el) {\n bindInstance(binding, el);\n });\n });\n}\n\n// Escape jQuery identifier\nfunction $escape(val) {\n return val.replace(/([!\"#$%&'()*+,./:;<=>?@[\\\\\\]^`{|}~])/g, \"\\\\$1\");\n}\n\nfunction bindEl(el) {\n let $el = $(el);\n Object.keys(bindings).forEach(function(className) {\n if ($el.hasClass(className) && !$el.hasClass(\"crosstalk-input-bound\")) {\n let binding = bindings[className];\n bindInstance(binding, el);\n }\n });\n}\n\nfunction bindInstance(binding, el) {\n let jsonEl = $(el).find(\"script[type='application/json'][data-for='\" + $escape(el.id) + \"']\");\n let data = JSON.parse(jsonEl[0].innerText);\n\n let instance = binding.factory(el, data);\n $(el).data(\"crosstalk-instance\", instance);\n $(el).addClass(\"crosstalk-input-bound\");\n}\n\nif (global.Shiny) {\n let inputBinding = new global.Shiny.InputBinding();\n let $ = global.jQuery;\n $.extend(inputBinding, {\n find: function(scope) {\n return $(scope).find(\".crosstalk-input\");\n },\n initialize: function(el) {\n if (!$(el).hasClass(\"crosstalk-input-bound\")) {\n bindEl(el);\n }\n },\n getId: function(el) {\n return el.id;\n },\n getValue: function(el) {\n\n },\n setValue: function(el, value) {\n\n },\n receiveMessage: function(el, data) {\n\n },\n subscribe: function(el, callback) {\n $(el).data(\"crosstalk-instance\").resume();\n },\n unsubscribe: function(el) {\n $(el).data(\"crosstalk-instance\").suspend();\n }\n });\n global.Shiny.inputBindings.register(inputBinding, \"crosstalk.inputBinding\");\n}\n","import * as input from \"./input\";\nimport { FilterHandle } from \"./filter\";\n\nlet $ = global.jQuery;\n\ninput.register({\n className: \"crosstalk-input-checkboxgroup\",\n\n factory: function(el, data) {\n /*\n * map: {\"groupA\": [\"keyA\", \"keyB\", ...], ...}\n * group: \"ct-groupname\"\n */\n let ctHandle = new FilterHandle(data.group);\n\n let lastKnownKeys;\n let $el = $(el);\n $el.on(\"change\", \"input[type='checkbox']\", function() {\n let checked = $el.find(\"input[type='checkbox']:checked\");\n if (checked.length === 0) {\n lastKnownKeys = null;\n ctHandle.clear();\n } else {\n let keys = {};\n checked.each(function() {\n data.map[this.value].forEach(function(key) {\n keys[key] = true;\n });\n });\n let keyArray = Object.keys(keys);\n keyArray.sort();\n lastKnownKeys = keyArray;\n ctHandle.set(keyArray);\n }\n });\n\n return {\n suspend: function() {\n ctHandle.clear();\n },\n resume: function() {\n if (lastKnownKeys)\n ctHandle.set(lastKnownKeys);\n }\n };\n }\n});\n","import * as input from \"./input\";\nimport * as util from \"./util\";\nimport { FilterHandle } from \"./filter\";\n\nlet $ = global.jQuery;\n\ninput.register({\n className: \"crosstalk-input-select\",\n\n factory: function(el, data) {\n /*\n * items: {value: [...], label: [...]}\n * map: {\"groupA\": [\"keyA\", \"keyB\", ...], ...}\n * group: \"ct-groupname\"\n */\n\n let first = [{value: \"\", label: \"(All)\"}];\n let items = util.dataframeToD3(data.items);\n let opts = {\n options: first.concat(items),\n valueField: \"value\",\n labelField: \"label\",\n searchField: \"label\"\n };\n\n let select = $(el).find(\"select\")[0];\n\n let selectize = $(select).selectize(opts)[0].selectize;\n\n let ctHandle = new FilterHandle(data.group);\n\n let lastKnownKeys;\n selectize.on(\"change\", function() {\n if (selectize.items.length === 0) {\n lastKnownKeys = null;\n ctHandle.clear();\n } else {\n let keys = {};\n selectize.items.forEach(function(group) {\n data.map[group].forEach(function(key) {\n keys[key] = true;\n });\n });\n let keyArray = Object.keys(keys);\n keyArray.sort();\n lastKnownKeys = keyArray;\n ctHandle.set(keyArray);\n }\n });\n\n return {\n suspend: function() {\n ctHandle.clear();\n },\n resume: function() {\n if (lastKnownKeys)\n ctHandle.set(lastKnownKeys);\n }\n };\n }\n});\n","import * as input from \"./input\";\nimport { FilterHandle } from \"./filter\";\n\nlet $ = global.jQuery;\nlet strftime = global.strftime;\n\ninput.register({\n className: \"crosstalk-input-slider\",\n\n factory: function(el, data) {\n /*\n * map: {\"groupA\": [\"keyA\", \"keyB\", ...], ...}\n * group: \"ct-groupname\"\n */\n let ctHandle = new FilterHandle(data.group);\n\n let opts = {};\n let $el = $(el).find(\"input\");\n let dataType = $el.data(\"data-type\");\n let timeFormat = $el.data(\"time-format\");\n let round = $el.data(\"round\");\n let timeFormatter;\n\n // Set up formatting functions\n if (dataType === \"date\") {\n timeFormatter = strftime.utc();\n opts.prettify = function(num) {\n return timeFormatter(timeFormat, new Date(num));\n };\n\n } else if (dataType === \"datetime\") {\n let timezone = $el.data(\"timezone\");\n if (timezone)\n timeFormatter = strftime.timezone(timezone);\n else\n timeFormatter = strftime;\n\n opts.prettify = function(num) {\n return timeFormatter(timeFormat, new Date(num));\n };\n } else if (dataType === \"number\") {\n if (typeof round !== \"undefined\")\n opts.prettify = function(num) {\n let factor = Math.pow(10, round);\n return Math.round(num * factor) / factor;\n };\n }\n\n $el.ionRangeSlider(opts);\n\n function getValue() {\n let result = $el.data(\"ionRangeSlider\").result;\n\n // Function for converting numeric value from slider to appropriate type.\n let convert;\n let dataType = $el.data(\"data-type\");\n if (dataType === \"date\") {\n convert = function(val) {\n return formatDateUTC(new Date(+val));\n };\n } else if (dataType === \"datetime\") {\n convert = function(val) {\n // Convert ms to s\n return +val / 1000;\n };\n } else {\n convert = function(val) { return +val; };\n }\n\n if ($el.data(\"ionRangeSlider\").options.type === \"double\") {\n return [convert(result.from), convert(result.to)];\n } else {\n return convert(result.from);\n }\n }\n\n let lastKnownKeys = null;\n\n $el.on(\"change.crosstalkSliderInput\", function(event) {\n if (!$el.data(\"updating\") && !$el.data(\"animating\")) {\n let [from, to] = getValue();\n let keys = [];\n for (let i = 0; i < data.values.length; i++) {\n let val = data.values[i];\n if (val >= from && val <= to) {\n keys.push(data.keys[i]);\n }\n }\n keys.sort();\n ctHandle.set(keys);\n lastKnownKeys = keys;\n }\n });\n\n\n // let $el = $(el);\n // $el.on(\"change\", \"input[type=\"checkbox\"]\", function() {\n // let checked = $el.find(\"input[type=\"checkbox\"]:checked\");\n // if (checked.length === 0) {\n // ctHandle.clear();\n // } else {\n // let keys = {};\n // checked.each(function() {\n // data.map[this.value].forEach(function(key) {\n // keys[key] = true;\n // });\n // });\n // let keyArray = Object.keys(keys);\n // keyArray.sort();\n // ctHandle.set(keyArray);\n // }\n // });\n\n return {\n suspend: function() {\n ctHandle.clear();\n },\n resume: function() {\n if (lastKnownKeys)\n ctHandle.set(lastKnownKeys);\n }\n };\n }\n});\n\n\n// Convert a number to a string with leading zeros\nfunction padZeros(n, digits) {\n let str = n.toString();\n while (str.length < digits)\n str = \"0\" + str;\n return str;\n}\n\n// Given a Date object, return a string in yyyy-mm-dd format, using the\n// UTC date. This may be a day off from the date in the local time zone.\nfunction formatDateUTC(date) {\n if (date instanceof Date) {\n return date.getUTCFullYear() + \"-\" +\n padZeros(date.getUTCMonth()+1, 2) + \"-\" +\n padZeros(date.getUTCDate(), 2);\n\n } else {\n return null;\n }\n}\n","import Events from \"./events\";\nimport grp from \"./group\";\nimport * as util from \"./util\";\n\n/**\n * Use this class to read and write (and listen for changes to) the selection\n * for a Crosstalk group. This is intended to be used for linked brushing.\n *\n * If two (or more) `SelectionHandle` instances in the same webpage share the\n * same group name, they will share the same state. Setting the selection using\n * one `SelectionHandle` instance will result in the `value` property instantly\n * changing across the others, and `\"change\"` event listeners on all instances\n * (including the one that initiated the sending) will fire.\n *\n * @param {string} [group] - The name of the Crosstalk group, or if none,\n * null or undefined (or any other falsy value). This can be changed later\n * via the [SelectionHandle#setGroup](#setGroup) method.\n * @param {Object} [extraInfo] - An object whose properties will be copied to\n * the event object whenever an event is emitted.\n */\nexport class SelectionHandle {\n\n constructor(group = null, extraInfo = null) {\n this._eventRelay = new Events();\n this._emitter = new util.SubscriptionTracker(this._eventRelay);\n\n // Name of the group we're currently tracking, if any. Can change over time.\n this._group = null;\n // The Var we're currently tracking, if any. Can change over time.\n this._var = null;\n // The event handler subscription we currently have on var.on(\"change\").\n this._varOnChangeSub = null;\n\n this._extraInfo = util.extend({ sender: this }, extraInfo);\n\n this.setGroup(group);\n }\n\n /**\n * Changes the Crosstalk group membership of this SelectionHandle. The group\n * being switched away from (if any) will not have its selection value\n * modified as a result of calling `setGroup`, even if this handle was the\n * most recent handle to set the selection of the group.\n *\n * The group being switched to (if any) will also not have its selection value\n * modified as a result of calling `setGroup`. If you want to set the\n * selection value of the new group, call `set` explicitly.\n *\n * @param {string} group - The name of the Crosstalk group, or null (or\n * undefined) to clear the group.\n */\n setGroup(group) {\n // If group is unchanged, do nothing\n if (this._group === group)\n return;\n // Treat null, undefined, and other falsy values the same\n if (!this._group && !group)\n return;\n\n if (this._var) {\n this._var.off(\"change\", this._varOnChangeSub);\n this._var = null;\n this._varOnChangeSub = null;\n }\n\n this._group = group;\n\n if (group) {\n this._var = grp(group).var(\"selection\");\n let sub = this._var.on(\"change\", (e) => {\n this._eventRelay.trigger(\"change\", e, this);\n });\n this._varOnChangeSub = sub;\n }\n }\n\n /**\n * Retrieves the current selection for the group represented by this\n * `SelectionHandle`.\n *\n * - If no selection is active, then this value will be falsy.\n * - If a selection is active, but no data points are selected, then this\n * value will be an empty array.\n * - If a selection is active, and data points are selected, then the keys\n * of the selected data points will be present in the array.\n */\n get value() {\n return this._var ? this._var.get() : null;\n }\n\n /**\n * Combines the given `extraInfo` (if any) with the handle's default\n * `_extraInfo` (if any).\n * @private\n */\n _mergeExtraInfo(extraInfo) {\n // Important incidental effect: shallow clone is returned\n return util.extend({},\n this._extraInfo ? this._extraInfo : null,\n extraInfo ? extraInfo : null);\n }\n\n /**\n * Overwrites the current selection for the group, and raises the `\"change\"`\n * event among all of the group's '`SelectionHandle` instances (including\n * this one).\n *\n * @fires SelectionHandle#change\n * @param {string[]} selectedKeys - Falsy, empty array, or array of keys (see\n * {@link SelectionHandle#value}).\n * @param {Object} [extraInfo] - Extra properties to be included on the event\n * object that's passed to listeners (in addition to any options that were\n * passed into the `SelectionHandle` constructor).\n */\n set(selectedKeys, extraInfo) {\n if (this._var)\n this._var.set(selectedKeys, this._mergeExtraInfo(extraInfo));\n }\n\n /**\n * Overwrites the current selection for the group, and raises the `\"change\"`\n * event among all of the group's '`SelectionHandle` instances (including\n * this one).\n *\n * @fires SelectionHandle#change\n * @param {Object} [extraInfo] - Extra properties to be included on the event\n * object that's passed to listeners (in addition to any that were passed\n * into the `SelectionHandle` constructor).\n */\n clear(extraInfo) {\n if (this._var)\n this.set(void 0, this._mergeExtraInfo(extraInfo));\n }\n\n /**\n * Subscribes to events on this `SelectionHandle`.\n *\n * @param {string} eventType - Indicates the type of events to listen to.\n * Currently, only `\"change\"` is supported.\n * @param {SelectionHandle~listener} listener - The callback function that\n * will be invoked when the event occurs.\n * @return {string} - A token to pass to {@link SelectionHandle#off} to cancel\n * this subscription.\n */\n on(eventType, listener) {\n return this._emitter.on(eventType, listener);\n }\n\n /**\n * Cancels event subscriptions created by {@link SelectionHandle#on}.\n *\n * @param {string} eventType - The type of event to unsubscribe.\n * @param {string|SelectionHandle~listener} listener - Either the callback\n * function previously passed into {@link SelectionHandle#on}, or the\n * string that was returned from {@link SelectionHandle#on}.\n */\n off(eventType, listener) {\n return this._emitter.off(eventType, listener);\n }\n\n /**\n * Shuts down the `SelectionHandle` object.\n *\n * Removes all event listeners that were added through this handle.\n */\n close() {\n this._emitter.removeAllListeners();\n this.setGroup(null);\n }\n}\n\n/**\n * @callback SelectionHandle~listener\n * @param {Object} event - An object containing details of the event. For\n * `\"change\"` events, this includes the properties `value` (the new\n * value of the selection, or `undefined` if no selection is active),\n * `oldValue` (the previous value of the selection), and `sender` (the\n * `SelectionHandle` instance that made the change).\n */\n\n/**\n * @event SelectionHandle#change\n * @type {object}\n * @property {object} value - The new value of the selection, or `undefined`\n * if no selection is active.\n * @property {object} oldValue - The previous value of the selection.\n * @property {SelectionHandle} sender - The `SelectionHandle` instance that\n * changed the value.\n */\n","export function extend(target, ...sources) {\n for (let i = 0; i < sources.length; i++) {\n let src = sources[i];\n if (typeof(src) === \"undefined\" || src === null)\n continue;\n\n for (let key in src) {\n if (src.hasOwnProperty(key)) {\n target[key] = src[key];\n }\n }\n }\n return target;\n}\n\nexport function checkSorted(list) {\n for (let i = 1; i < list.length; i++) {\n if (list[i] <= list[i-1]) {\n throw new Error(\"List is not sorted or contains duplicate\");\n }\n }\n}\n\nexport function diffSortedLists(a, b) {\n let i_a = 0;\n let i_b = 0;\n\n if (!a) a = [];\n if (!b) b = [];\n\n let a_only = [];\n let b_only = [];\n\n checkSorted(a);\n checkSorted(b);\n\n while (i_a < a.length && i_b < b.length) {\n if (a[i_a] === b[i_b]) {\n i_a++;\n i_b++;\n } else if (a[i_a] < b[i_b]) {\n a_only.push(a[i_a++]);\n } else {\n b_only.push(b[i_b++]);\n }\n }\n\n if (i_a < a.length)\n a_only = a_only.concat(a.slice(i_a));\n if (i_b < b.length)\n b_only = b_only.concat(b.slice(i_b));\n return {\n removed: a_only,\n added: b_only\n };\n}\n\n// Convert from wide: { colA: [1,2,3], colB: [4,5,6], ... }\n// to long: [ {colA: 1, colB: 4}, {colA: 2, colB: 5}, ... ]\nexport function dataframeToD3(df) {\n let names = [];\n let length;\n for (let name in df) {\n if (df.hasOwnProperty(name))\n names.push(name);\n if (typeof(df[name]) !== \"object\" || typeof(df[name].length) === \"undefined\") {\n throw new Error(\"All fields must be arrays\");\n } else if (typeof(length) !== \"undefined\" && length !== df[name].length) {\n throw new Error(\"All fields must be arrays of the same length\");\n }\n length = df[name].length;\n }\n let results = [];\n let item;\n for (let row = 0; row < length; row++) {\n item = {};\n for (let col = 0; col < names.length; col++) {\n item[names[col]] = df[names[col]][row];\n }\n results.push(item);\n }\n return results;\n}\n\n/**\n * Keeps track of all event listener additions/removals and lets all active\n * listeners be removed with a single operation.\n *\n * @private\n */\nexport class SubscriptionTracker {\n constructor(emitter) {\n this._emitter = emitter;\n this._subs = {};\n }\n\n on(eventType, listener) {\n let sub = this._emitter.on(eventType, listener);\n this._subs[sub] = eventType;\n return sub;\n }\n\n off(eventType, listener) {\n let sub = this._emitter.off(eventType, listener);\n if (sub) {\n delete this._subs[sub];\n }\n return sub;\n }\n\n removeAllListeners() {\n let current_subs = this._subs;\n this._subs = {};\n Object.keys(current_subs).forEach((sub) => {\n this._emitter.off(current_subs[sub], sub);\n });\n }\n}\n","import Events from \"./events\";\n\nexport default class Var {\n constructor(group, name, /*optional*/ value) {\n this._group = group;\n this._name = name;\n this._value = value;\n this._events = new Events();\n }\n\n get() {\n return this._value;\n }\n\n set(value, /*optional*/ event) {\n if (this._value === value) {\n // Do nothing; the value hasn't changed\n return;\n }\n let oldValue = this._value;\n this._value = value;\n // Alert JavaScript listeners that the value has changed\n let evt = {};\n if (event && typeof(event) === \"object\") {\n for (let k in event) {\n if (event.hasOwnProperty(k))\n evt[k] = event[k];\n }\n }\n evt.oldValue = oldValue;\n evt.value = value;\n this._events.trigger(\"change\", evt, this);\n\n // TODO: Make this extensible, to let arbitrary back-ends know that\n // something has changed\n if (global.Shiny && global.Shiny.onInputChange) {\n global.Shiny.onInputChange(\n \".clientValue-\" +\n (this._group.name !== null ? this._group.name + \"-\" : \"\") +\n this._name,\n typeof(value) === \"undefined\" ? null : value\n );\n }\n }\n\n on(eventType, listener) {\n return this._events.on(eventType, listener);\n }\n\n off(eventType, listener) {\n return this._events.off(eventType, listener);\n }\n}\n"]} \ No newline at end of file diff --git a/docs/articles/variables_sheet_files/crosstalk-1.2.1/scss/crosstalk.scss b/docs/articles/variables_sheet_files/crosstalk-1.2.1/scss/crosstalk.scss new file mode 100644 index 00000000..35665616 --- /dev/null +++ b/docs/articles/variables_sheet_files/crosstalk-1.2.1/scss/crosstalk.scss @@ -0,0 +1,75 @@ +/* Adjust margins outwards, so column contents line up with the edges of the + parent of container-fluid. */ +.container-fluid.crosstalk-bscols { + margin-left: -30px; + margin-right: -30px; + white-space: normal; +} + +/* But don't adjust the margins outwards if we're directly under the body, + i.e. we were the top-level of something at the console. */ +body > .container-fluid.crosstalk-bscols { + margin-left: auto; + margin-right: auto; +} + +.crosstalk-input-checkboxgroup .crosstalk-options-group .crosstalk-options-column { + display: inline-block; + padding-right: 12px; + vertical-align: top; +} + +@media only screen and (max-width:480px) { + .crosstalk-input-checkboxgroup .crosstalk-options-group .crosstalk-options-column { + display: block; + padding-right: inherit; + } +} + +/* Relevant BS3 styles to make filter_checkbox() look reasonable without Bootstrap */ +.crosstalk-input { + margin-bottom: 15px; /* a la .form-group */ + .control-label { + margin-bottom: 0; + vertical-align: middle; + } + input[type="checkbox"] { + margin: 4px 0 0; + margin-top: 1px; + line-height: normal; + } + .checkbox { + position: relative; + display: block; + margin-top: 10px; + margin-bottom: 10px; + } + .checkbox > label{ + padding-left: 20px; + margin-bottom: 0; + font-weight: 400; + cursor: pointer; + } + .checkbox input[type="checkbox"], + .checkbox-inline input[type="checkbox"] { + position: absolute; + margin-top: 2px; + margin-left: -20px; + } + .checkbox + .checkbox { + margin-top: -5px; + } + .checkbox-inline { + position: relative; + display: inline-block; + padding-left: 20px; + margin-bottom: 0; + font-weight: 400; + vertical-align: middle; + cursor: pointer; + } + .checkbox-inline + .checkbox-inline { + margin-top: 0; + margin-left: 10px; + } +} diff --git a/docs/articles/variables_sheet_files/datatables-binding-0.33/datatables.js b/docs/articles/variables_sheet_files/datatables-binding-0.33/datatables.js new file mode 100644 index 00000000..765b53cb --- /dev/null +++ b/docs/articles/variables_sheet_files/datatables-binding-0.33/datatables.js @@ -0,0 +1,1539 @@ +(function() { + +// some helper functions: using a global object DTWidget so that it can be used +// in JS() code, e.g. datatable(options = list(foo = JS('code'))); unlike R's +// dynamic scoping, when 'code' is eval'ed, JavaScript does not know objects +// from the "parent frame", e.g. JS('DTWidget') will not work unless it was made +// a global object +var DTWidget = {}; + +// 123456666.7890 -> 123,456,666.7890 +var markInterval = function(d, digits, interval, mark, decMark, precision) { + x = precision ? d.toPrecision(digits) : d.toFixed(digits); + if (!/^-?[\d.]+$/.test(x)) return x; + var xv = x.split('.'); + if (xv.length > 2) return x; // should have at most one decimal point + xv[0] = xv[0].replace(new RegExp('\\B(?=(\\d{' + interval + '})+(?!\\d))', 'g'), mark); + return xv.join(decMark); +}; + +DTWidget.formatCurrency = function(data, currency, digits, interval, mark, decMark, before, zeroPrint) { + var d = parseFloat(data); + if (isNaN(d)) return ''; + if (zeroPrint !== null && d === 0.0) return zeroPrint; + var res = markInterval(d, digits, interval, mark, decMark); + res = before ? (/^-/.test(res) ? '-' + currency + res.replace(/^-/, '') : currency + res) : + res + currency; + return res; +}; + +DTWidget.formatString = function(data, prefix, suffix) { + var d = data; + if (d === null) return ''; + return prefix + d + suffix; +}; + +DTWidget.formatPercentage = function(data, digits, interval, mark, decMark, zeroPrint) { + var d = parseFloat(data); + if (isNaN(d)) return ''; + if (zeroPrint !== null && d === 0.0) return zeroPrint; + return markInterval(d * 100, digits, interval, mark, decMark) + '%'; +}; + +DTWidget.formatRound = function(data, digits, interval, mark, decMark, zeroPrint) { + var d = parseFloat(data); + if (isNaN(d)) return ''; + if (zeroPrint !== null && d === 0.0) return zeroPrint; + return markInterval(d, digits, interval, mark, decMark); +}; + +DTWidget.formatSignif = function(data, digits, interval, mark, decMark, zeroPrint) { + var d = parseFloat(data); + if (isNaN(d)) return ''; + if (zeroPrint !== null && d === 0.0) return zeroPrint; + return markInterval(d, digits, interval, mark, decMark, true); +}; + +DTWidget.formatDate = function(data, method, params) { + var d = data; + if (d === null) return ''; + // (new Date('2015-10-28')).toDateString() may return 2015-10-27 because the + // actual time created could be like 'Tue Oct 27 2015 19:00:00 GMT-0500 (CDT)', + // i.e. the date-only string is treated as UTC time instead of local time + if ((method === 'toDateString' || method === 'toLocaleDateString') && /^\d{4,}\D\d{2}\D\d{2}$/.test(d)) { + d = d.split(/\D/); + d = new Date(d[0], d[1] - 1, d[2]); + } else { + d = new Date(d); + } + return d[method].apply(d, params); +}; + +window.DTWidget = DTWidget; + +// A helper function to update the properties of existing filters +var setFilterProps = function(td, props) { + // Update enabled/disabled state + var $input = $(td).find('input').first(); + var searchable = $input.data('searchable'); + $input.prop('disabled', !searchable || props.disabled); + + // Based on the filter type, set its new values + var type = td.getAttribute('data-type'); + if (['factor', 'logical'].includes(type)) { + // Reformat the new dropdown options for use with selectize + var new_vals = props.params.options.map(function(item) { + return { text: item, value: item }; + }); + + // Find the selectize object + var dropdown = $(td).find('.selectized').eq(0)[0].selectize; + + // Note the current values + var old_vals = dropdown.getValue(); + + // Remove the existing values + dropdown.clearOptions(); + + // Add the new options + dropdown.addOption(new_vals); + + // Preserve the existing values + dropdown.setValue(old_vals); + + } else if (['number', 'integer', 'date', 'time'].includes(type)) { + // Apply internal scaling to new limits. Updating scale not yet implemented. + var slider = $(td).find('.noUi-target').eq(0); + var scale = Math.pow(10, Math.max(0, +slider.data('scale') || 0)); + var new_vals = [props.params.min * scale, props.params.max * scale]; + + // Note what the new limits will be just for this filter + var new_lims = new_vals.slice(); + + // Determine the current values and limits + var old_vals = slider.val().map(Number); + var old_lims = slider.noUiSlider('options').range; + old_lims = [old_lims.min, old_lims.max]; + + // Preserve the current values if filters have been applied; otherwise, apply no filtering + if (old_vals[0] != old_lims[0]) { + new_vals[0] = Math.max(old_vals[0], new_vals[0]); + } + + if (old_vals[1] != old_lims[1]) { + new_vals[1] = Math.min(old_vals[1], new_vals[1]); + } + + // Update the endpoints of the slider + slider.noUiSlider({ + start: new_vals, + range: {'min': new_lims[0], 'max': new_lims[1]} + }, true); + } +}; + +var transposeArray2D = function(a) { + return a.length === 0 ? a : HTMLWidgets.transposeArray2D(a); +}; + +var crosstalkPluginsInstalled = false; + +function maybeInstallCrosstalkPlugins() { + if (crosstalkPluginsInstalled) + return; + crosstalkPluginsInstalled = true; + + $.fn.dataTable.ext.afnFiltering.push( + function(oSettings, aData, iDataIndex) { + var ctfilter = oSettings.nTable.ctfilter; + if (ctfilter && !ctfilter[iDataIndex]) + return false; + + var ctselect = oSettings.nTable.ctselect; + if (ctselect && !ctselect[iDataIndex]) + return false; + + return true; + } + ); +} + +HTMLWidgets.widget({ + name: "datatables", + type: "output", + renderOnNullValue: true, + initialize: function(el, width, height) { + // in order that the type=number inputs return a number + $.valHooks.number = { + get: function(el) { + var value = parseFloat(el.value); + return isNaN(value) ? "" : value; + } + }; + $(el).html(' '); + return { + data: null, + ctfilterHandle: new crosstalk.FilterHandle(), + ctfilterSubscription: null, + ctselectHandle: new crosstalk.SelectionHandle(), + ctselectSubscription: null + }; + }, + renderValue: function(el, data, instance) { + if (el.offsetWidth === 0 || el.offsetHeight === 0) { + instance.data = data; + return; + } + instance.data = null; + var $el = $(el); + $el.empty(); + + if (data === null) { + $el.append(' '); + // clear previous Shiny inputs (if any) + for (var i in instance.clearInputs) instance.clearInputs[i](); + instance.clearInputs = {}; + return; + } + + var crosstalkOptions = data.crosstalkOptions; + if (!crosstalkOptions) crosstalkOptions = { + 'key': null, 'group': null + }; + if (crosstalkOptions.group) { + maybeInstallCrosstalkPlugins(); + instance.ctfilterHandle.setGroup(crosstalkOptions.group); + instance.ctselectHandle.setGroup(crosstalkOptions.group); + } + + // if we are in the viewer then we always want to fillContainer and + // and autoHideNavigation (unless the user has explicitly set these) + if (window.HTMLWidgets.viewerMode) { + if (!data.hasOwnProperty("fillContainer")) + data.fillContainer = true; + if (!data.hasOwnProperty("autoHideNavigation")) + data.autoHideNavigation = true; + } + + // propagate fillContainer to instance (so we have it in resize) + instance.fillContainer = data.fillContainer; + + var cells = data.data; + + if (cells instanceof Array) cells = transposeArray2D(cells); + + $el.append(data.container); + var $table = $el.find('table'); + if (data.class) $table.addClass(data.class); + if (data.caption) $table.prepend(data.caption); + + if (!data.selection) data.selection = { + mode: 'none', selected: null, target: 'row', selectable: null + }; + if (HTMLWidgets.shinyMode && data.selection.mode !== 'none' && + data.selection.target === 'row+column') { + if ($table.children('tfoot').length === 0) { + $table.append($('')); + $table.find('thead tr').clone().appendTo($table.find('tfoot')); + } + } + + // column filters + var filterRow; + switch (data.filter) { + case 'top': + $table.children('thead').append(data.filterHTML); + filterRow = $table.find('thead tr:last td'); + break; + case 'bottom': + if ($table.children('tfoot').length === 0) { + $table.append($('')); + } + $table.children('tfoot').prepend(data.filterHTML); + filterRow = $table.find('tfoot tr:first td'); + break; + } + + var options = { searchDelay: 1000 }; + if (cells !== null) $.extend(options, { + data: cells + }); + + // options for fillContainer + var bootstrapActive = typeof($.fn.popover) != 'undefined'; + if (instance.fillContainer) { + + // force scrollX/scrollY and turn off autoWidth + options.scrollX = true; + options.scrollY = "100px"; // can be any value, we'll adjust below + + // if we aren't paginating then move around the info/filter controls + // to save space at the bottom and rephrase the info callback + if (data.options.paging === false) { + + // we know how to do this cleanly for bootstrap, not so much + // for other themes/layouts + if (bootstrapActive) { + options.dom = "<'row'<'col-sm-4'i><'col-sm-8'f>>" + + "<'row'<'col-sm-12'tr>>"; + } + + options.fnInfoCallback = function(oSettings, iStart, iEnd, + iMax, iTotal, sPre) { + return Number(iTotal).toLocaleString() + " records"; + }; + } + } + + // auto hide navigation if requested + // Note, this only works on client-side processing mode as on server-side, + // cells (data.data) is null; In addition, we require the pageLength option + // being provided explicitly to enable this. Despite we may be able to deduce + // the default value of pageLength, it may complicate things so we'd rather + // put this responsiblity to users and warn them on the R side. + if (data.autoHideNavigation === true && data.options.paging !== false) { + // strip all nav if length >= cells + if ((cells instanceof Array) && data.options.pageLength >= cells.length) + options.dom = bootstrapActive ? "<'row'<'col-sm-12'tr>>" : "t"; + // alternatively lean things out for flexdashboard mobile portrait + else if (bootstrapActive && window.FlexDashboard && window.FlexDashboard.isMobilePhone()) + options.dom = "<'row'<'col-sm-12'f>>" + + "<'row'<'col-sm-12'tr>>" + + "<'row'<'col-sm-12'p>>"; + } + + $.extend(true, options, data.options || {}); + + var searchCols = options.searchCols; + if (searchCols) { + searchCols = searchCols.map(function(x) { + return x === null ? '' : x.search; + }); + // FIXME: this means I don't respect the escapeRegex setting + delete options.searchCols; + } + + // server-side processing? + var server = options.serverSide === true; + + // use the dataSrc function to pre-process JSON data returned from R + var DT_rows_all = [], DT_rows_current = []; + if (server && HTMLWidgets.shinyMode && typeof options.ajax === 'object' && + /^session\/[\da-z]+\/dataobj/.test(options.ajax.url) && !options.ajax.dataSrc) { + options.ajax.dataSrc = function(json) { + DT_rows_all = $.makeArray(json.DT_rows_all); + DT_rows_current = $.makeArray(json.DT_rows_current); + var data = json.data; + if (!colReorderEnabled()) return data; + var table = $table.DataTable(), order = table.colReorder.order(), flag = true, i, j, row; + for (i = 0; i < order.length; ++i) if (order[i] !== i) flag = false; + if (flag) return data; + for (i = 0; i < data.length; ++i) { + row = data[i].slice(); + for (j = 0; j < order.length; ++j) data[i][j] = row[order[j]]; + } + return data; + }; + } + + var thiz = this; + if (instance.fillContainer) $table.on('init.dt', function(e) { + thiz.fillAvailableHeight(el, $(el).innerHeight()); + }); + // If the page contains serveral datatables and one of which enables colReorder, + // the table.colReorder.order() function will exist but throws error when called. + // So it seems like the only way to know if colReorder is enabled or not is to + // check the options. + var colReorderEnabled = function() { return "colReorder" in options; }; + var table = $table.DataTable(options); + $el.data('datatable', table); + + if ('rowGroup' in options) { + // Maintain RowGroup dataSrc when columns are reordered (#1109) + table.on('column-reorder', function(e, settings, details) { + var oldDataSrc = table.rowGroup().dataSrc(); + var newDataSrc = details.mapping[oldDataSrc]; + table.rowGroup().dataSrc(newDataSrc); + }); + } + + // Unregister previous Crosstalk event subscriptions, if they exist + if (instance.ctfilterSubscription) { + instance.ctfilterHandle.off("change", instance.ctfilterSubscription); + instance.ctfilterSubscription = null; + } + if (instance.ctselectSubscription) { + instance.ctselectHandle.off("change", instance.ctselectSubscription); + instance.ctselectSubscription = null; + } + + if (!crosstalkOptions.group) { + $table[0].ctfilter = null; + $table[0].ctselect = null; + } else { + var key = crosstalkOptions.key; + function keysToMatches(keys) { + if (!keys) { + return null; + } else { + var selectedKeys = {}; + for (var i = 0; i < keys.length; i++) { + selectedKeys[keys[i]] = true; + } + var matches = {}; + for (var j = 0; j < key.length; j++) { + if (selectedKeys[key[j]]) + matches[j] = true; + } + return matches; + } + } + + function applyCrosstalkFilter(e) { + $table[0].ctfilter = keysToMatches(e.value); + table.draw(); + } + instance.ctfilterSubscription = instance.ctfilterHandle.on("change", applyCrosstalkFilter); + applyCrosstalkFilter({value: instance.ctfilterHandle.filteredKeys}); + + function applyCrosstalkSelection(e) { + if (e.sender !== instance.ctselectHandle) { + table + .rows('.' + selClass, {search: 'applied'}) + .nodes() + .to$() + .removeClass(selClass); + if (selectedRows) + changeInput('rows_selected', selectedRows(), void 0, true); + } + + if (e.sender !== instance.ctselectHandle && e.value && e.value.length) { + var matches = keysToMatches(e.value); + + // persistent selection with plotly (& leaflet) + var ctOpts = crosstalk.var("plotlyCrosstalkOpts").get() || {}; + if (ctOpts.persistent === true) { + var matches = $.extend(matches, $table[0].ctselect); + } + + $table[0].ctselect = matches; + table.draw(); + } else { + if ($table[0].ctselect) { + $table[0].ctselect = null; + table.draw(); + } + } + } + instance.ctselectSubscription = instance.ctselectHandle.on("change", applyCrosstalkSelection); + // TODO: This next line doesn't seem to work when renderDataTable is used + applyCrosstalkSelection({value: instance.ctselectHandle.value}); + } + + var inArray = function(val, array) { + return $.inArray(val, $.makeArray(array)) > -1; + }; + + // search the i-th column + var searchColumn = function(i, value) { + var regex = false, ci = true; + if (options.search) { + regex = options.search.regex, + ci = options.search.caseInsensitive !== false; + } + // need to transpose the column index when colReorder is enabled + if (table.colReorder) i = table.colReorder.transpose(i); + return table.column(i).search(value, regex, !regex, ci); + }; + + if (data.filter !== 'none') { + if (!data.hasOwnProperty('filterSettings')) data.filterSettings = {}; + + filterRow.each(function(i, td) { + + var $td = $(td), type = $td.data('type'), filter; + var $input = $td.children('div').first().children('input'); + var disabled = $input.prop('disabled'); + var searchable = table.settings()[0].aoColumns[i].bSearchable; + $input.prop('disabled', !searchable || disabled); + $input.data('searchable', searchable); // for updating later + $input.on('input blur', function() { + $input.next('span').toggle(Boolean($input.val())); + }); + // Bootstrap sets pointer-events to none and we won't be able to click + // the clear button + $input.next('span').css('pointer-events', 'auto').hide().click(function() { + $(this).hide().prev('input').val('').trigger('input').focus(); + }); + var searchCol; // search string for this column + if (searchCols && searchCols[i]) { + searchCol = searchCols[i]; + $input.val(searchCol).trigger('input'); + } + var $x = $td.children('div').last(); + + // remove the overflow: hidden attribute of the scrollHead + // (otherwise the scrolling table body obscures the filters) + // The workaround and the discussion from + // https://github.com/rstudio/DT/issues/554#issuecomment-518007347 + // Otherwise the filter selection will not be anchored to the values + // when the columns number is many and scrollX is enabled. + var scrollHead = $(el).find('.dataTables_scrollHead,.dataTables_scrollFoot'); + var cssOverflowHead = scrollHead.css('overflow'); + var scrollBody = $(el).find('.dataTables_scrollBody'); + var cssOverflowBody = scrollBody.css('overflow'); + var scrollTable = $(el).find('.dataTables_scroll'); + var cssOverflowTable = scrollTable.css('overflow'); + if (cssOverflowHead === 'hidden') { + $x.on('show hide', function(e) { + if (e.type === 'show') { + scrollHead.css('overflow', 'visible'); + scrollBody.css('overflow', 'visible'); + scrollTable.css('overflow-x', 'scroll'); + } else { + scrollHead.css('overflow', cssOverflowHead); + scrollBody.css('overflow', cssOverflowBody); + scrollTable.css('overflow-x', cssOverflowTable); + } + }); + $x.css('z-index', 25); + } + + if (inArray(type, ['factor', 'logical'])) { + $input.on({ + click: function() { + $input.parent().hide(); $x.show().trigger('show'); filter[0].selectize.focus(); + }, + input: function() { + var v1 = JSON.stringify(filter[0].selectize.getValue()), v2 = $input.val(); + if (v1 === '[]') v1 = ''; + if (v1 !== v2) filter[0].selectize.setValue(v2 === '' ? [] : JSON.parse(v2)); + } + }); + var $input2 = $x.children('select'); + filter = $input2.selectize($.extend({ + options: $input2.data('options').map(function(v, i) { + return ({text: v, value: v}); + }), + plugins: ['remove_button'], + hideSelected: true, + onChange: function(value) { + if (value === null) value = []; // compatibility with jQuery 3.0 + $input.val(value.length ? JSON.stringify(value) : ''); + if (value.length) $input.trigger('input'); + $input.attr('title', $input.val()); + if (server) { + searchColumn(i, value.length ? JSON.stringify(value) : '').draw(); + return; + } + // turn off filter if nothing selected + $td.data('filter', value.length > 0); + table.draw(); // redraw table, and filters will be applied + } + }, data.filterSettings.select)); + filter[0].selectize.on('blur', function() { + $x.hide().trigger('hide'); $input.parent().show(); $input.trigger('blur'); + }); + filter.next('div').css('margin-bottom', 'auto'); + } else if (type === 'character') { + var fun = function() { + searchColumn(i, $input.val()).draw(); + }; + // throttle searching for server-side processing + var throttledFun = $.fn.dataTable.util.throttle(fun, options.searchDelay); + $input.on('input', function(e, immediate) { + // always bypass throttling when immediate = true (via the updateSearch method) + (immediate || !server) ? fun() : throttledFun(); + }); + } else if (inArray(type, ['number', 'integer', 'date', 'time'])) { + var $x0 = $x; + $x = $x0.children('div').first(); + $x0.css({ + 'background-color': '#fff', + 'border': '1px #ddd solid', + 'border-radius': '4px', + 'padding': data.vertical ? '35px 20px': '20px 20px 10px 20px' + }); + var $spans = $x0.children('span').css({ + 'margin-top': data.vertical ? '0' : '10px', + 'white-space': 'nowrap' + }); + var $span1 = $spans.first(), $span2 = $spans.last(); + var r1 = +$x.data('min'), r2 = +$x.data('max'); + // when the numbers are too small or have many decimal places, the + // slider may have numeric precision problems (#150) + var scale = Math.pow(10, Math.max(0, +$x.data('scale') || 0)); + r1 = Math.round(r1 * scale); r2 = Math.round(r2 * scale); + var scaleBack = function(x, scale) { + if (scale === 1) return x; + var d = Math.round(Math.log(scale) / Math.log(10)); + // to avoid problems like 3.423/100 -> 0.034230000000000003 + return (x / scale).toFixed(d); + }; + var slider_min = function() { + return filter.noUiSlider('options').range.min; + }; + var slider_max = function() { + return filter.noUiSlider('options').range.max; + }; + $input.on({ + focus: function() { + $x0.show().trigger('show'); + // first, make sure the slider div leaves at least 20px between + // the two (slider value) span's + $x0.width(Math.max(160, $span1.outerWidth() + $span2.outerWidth() + 20)); + // then, if the input is really wide or slider is vertical, + // make the slider the same width as the input + if ($x0.outerWidth() < $input.outerWidth() || data.vertical) { + $x0.outerWidth($input.outerWidth()); + } + // make sure the slider div does not reach beyond the right margin + if ($(window).width() < $x0.offset().left + $x0.width()) { + $x0.offset({ + 'left': $input.offset().left + $input.outerWidth() - $x0.outerWidth() + }); + } + }, + blur: function() { + $x0.hide().trigger('hide'); + }, + input: function() { + if ($input.val() === '') filter.val([slider_min(), slider_max()]); + }, + change: function() { + var v = $input.val().replace(/\s/g, ''); + if (v === '') return; + v = v.split('...'); + if (v.length !== 2) { + $input.parent().addClass('has-error'); + return; + } + if (v[0] === '') v[0] = slider_min(); + if (v[1] === '') v[1] = slider_max(); + $input.parent().removeClass('has-error'); + // treat date as UTC time at midnight + var strTime = function(x) { + var s = type === 'date' ? 'T00:00:00Z' : ''; + var t = new Date(x + s).getTime(); + // add 10 minutes to date since it does not hurt the date, and + // it helps avoid the tricky floating point arithmetic problems, + // e.g. sometimes the date may be a few milliseconds earlier + // than the midnight due to precision problems in noUiSlider + return type === 'date' ? t + 3600000 : t; + }; + if (inArray(type, ['date', 'time'])) { + v[0] = strTime(v[0]); + v[1] = strTime(v[1]); + } + if (v[0] != slider_min()) v[0] *= scale; + if (v[1] != slider_max()) v[1] *= scale; + filter.val(v); + } + }); + var formatDate = function(d) { + d = scaleBack(d, scale); + if (type === 'number') return d; + if (type === 'integer') return parseInt(d); + var x = new Date(+d); + if (type === 'date') { + var pad0 = function(x) { + return ('0' + x).substr(-2, 2); + }; + return x.getUTCFullYear() + '-' + pad0(1 + x.getUTCMonth()) + + '-' + pad0(x.getUTCDate()); + } else { + return x.toISOString(); + } + }; + var opts = type === 'date' ? { step: 60 * 60 * 1000 } : + type === 'integer' ? { step: 1 } : {}; + + opts.orientation = data.vertical ? 'vertical': 'horizontal'; + opts.direction = data.vertical ? 'rtl': 'ltr'; + + filter = $x.noUiSlider($.extend({ + start: [r1, r2], + range: {min: r1, max: r2}, + connect: true + }, opts, data.filterSettings.slider)); + if (scale > 1) (function() { + var t1 = r1, t2 = r2; + var val = filter.val(); + while (val[0] > r1 || val[1] < r2) { + if (val[0] > r1) { + t1 -= val[0] - r1; + } + if (val[1] < r2) { + t2 += r2 - val[1]; + } + filter = $x.noUiSlider($.extend({ + start: [t1, t2], + range: {min: t1, max: t2}, + connect: true + }, opts, data.filterSettings.slider), true); + val = filter.val(); + } + r1 = t1; r2 = t2; + })(); + // format with active column renderer, if defined + var colDef = data.options.columnDefs.find(function(def) { + return (def.targets === i || inArray(i, def.targets)) && 'render' in def; + }); + var updateSliderText = function(v1, v2) { + // we only know how to use function renderers + if (colDef && typeof colDef.render === 'function') { + var restore = function(v) { + v = scaleBack(v, scale); + return inArray(type, ['date', 'time']) ? new Date(+v) : v; + } + $span1.text(colDef.render(restore(v1), 'display')); + $span2.text(colDef.render(restore(v2), 'display')); + } else { + $span1.text(formatDate(v1)); + $span2.text(formatDate(v2)); + } + }; + updateSliderText(r1, r2); + var updateSlider = function(e) { + var val = filter.val(); + // turn off filter if in full range + $td.data('filter', val[0] > slider_min() || val[1] < slider_max()); + var v1 = formatDate(val[0]), v2 = formatDate(val[1]), ival; + if ($td.data('filter')) { + ival = v1 + ' ... ' + v2; + $input.attr('title', ival).val(ival).trigger('input'); + } else { + $input.attr('title', '').val(''); + } + updateSliderText(val[0], val[1]); + if (e.type === 'slide') return; // no searching when sliding only + if (server) { + searchColumn(i, $td.data('filter') ? ival : '').draw(); + return; + } + table.draw(); + }; + filter.on({ + set: updateSlider, + slide: updateSlider + }); + } + + // server-side processing will be handled by R (or whatever server + // language you use); the following code is only needed for client-side + // processing + if (server) { + // if a search string has been pre-set, search now + if (searchCol) $input.trigger('input').trigger('change'); + return; + } + + var customFilter = function(settings, data, dataIndex) { + // there is no way to attach a search function to a specific table, + // and we need to make sure a global search function is not applied to + // all tables (i.e. a range filter in a previous table should not be + // applied to the current table); we use the settings object to + // determine if we want to perform searching on the current table, + // since settings.sTableId will be different to different tables + if (table.settings()[0] !== settings) return true; + // no filter on this column or no need to filter this column + if (typeof filter === 'undefined' || !$td.data('filter')) return true; + + var r = filter.val(), v, r0, r1; + var i_data = function(i) { + if (!colReorderEnabled()) return i; + var order = table.colReorder.order(), k; + for (k = 0; k < order.length; ++k) if (order[k] === i) return k; + return i; // in theory it will never be here... + } + v = data[i_data(i)]; + if (type === 'number' || type === 'integer') { + v = parseFloat(v); + // how to handle NaN? currently exclude these rows + if (isNaN(v)) return(false); + r0 = parseFloat(scaleBack(r[0], scale)) + r1 = parseFloat(scaleBack(r[1], scale)); + if (v >= r0 && v <= r1) return true; + } else if (type === 'date' || type === 'time') { + v = new Date(v); + r0 = new Date(r[0] / scale); r1 = new Date(r[1] / scale); + if (v >= r0 && v <= r1) return true; + } else if (type === 'factor') { + if (r.length === 0 || inArray(v, r)) return true; + } else if (type === 'logical') { + if (r.length === 0) return true; + if (inArray(v === '' ? 'na' : v, r)) return true; + } + return false; + }; + + $.fn.dataTable.ext.search.push(customFilter); + + // search for the preset search strings if it is non-empty + if (searchCol) $input.trigger('input').trigger('change'); + + }); + + } + + // highlight search keywords + var highlight = function() { + var body = $(table.table().body()); + // removing the old highlighting first + body.unhighlight(); + + // don't highlight the "not found" row, so we get the rows using the api + if (table.rows({ filter: 'applied' }).data().length === 0) return; + // highlight global search keywords + body.highlight($.trim(table.search()).split(/\s+/)); + // then highlight keywords from individual column filters + if (filterRow) filterRow.each(function(i, td) { + var $td = $(td), type = $td.data('type'); + if (type !== 'character') return; + var $input = $td.children('div').first().children('input'); + var column = table.column(i).nodes().to$(), + val = $.trim($input.val()); + if (type !== 'character' || val === '') return; + column.highlight(val.split(/\s+/)); + }); + }; + + if (options.searchHighlight) { + table + .on('draw.dt.dth column-visibility.dt.dth column-reorder.dt.dth', highlight) + .on('destroy', function() { + // remove event handler + table.off('draw.dt.dth column-visibility.dt.dth column-reorder.dt.dth'); + }); + + // Set the option for escaping regex characters in our search string. This will be used + // for all future matching. + jQuery.fn.highlight.options.escapeRegex = (!options.search || !options.search.regex); + + // initial highlight for state saved conditions and initial states + highlight(); + } + + // run the callback function on the table instance + if (typeof data.callback === 'function') data.callback(table); + + // double click to edit the cell, row, column, or all cells + if (data.editable) table.on('dblclick.dt', 'tbody td', function(e) { + // only bring up the editor when the cell itself is dbclicked, and ignore + // other dbclick events bubbled up (e.g. from the ) + if (e.target !== this) return; + var target = [], immediate = false; + switch (data.editable.target) { + case 'cell': + target = [this]; + immediate = true; // edit will take effect immediately + break; + case 'row': + target = table.cells(table.cell(this).index().row, '*').nodes(); + break; + case 'column': + target = table.cells('*', table.cell(this).index().column).nodes(); + break; + case 'all': + target = table.cells().nodes(); + break; + default: + throw 'The editable parameter must be "cell", "row", "column", or "all"'; + } + var disableCols = data.editable.disable ? data.editable.disable.columns : null; + var numericCols = data.editable.numeric; + var areaCols = data.editable.area; + var dateCols = data.editable.date; + for (var i = 0; i < target.length; i++) { + (function(cell, current) { + var $cell = $(cell), html = $cell.html(); + var _cell = table.cell(cell), value = _cell.data(), index = _cell.index().column; + var $input; + if (inArray(index, numericCols)) { + $input = $(''); + } else if (inArray(index, areaCols)) { + $input = $(''); + } else if (inArray(index, dateCols)) { + $input = $(''); + } else { + $input = $(''); + } + if (!immediate) { + $cell.data('input', $input).data('html', html); + $input.attr('title', 'Hit Ctrl+Enter to finish editing, or Esc to cancel'); + } + $input.val(value); + if (inArray(index, disableCols)) { + $input.attr('readonly', '').css('filter', 'invert(25%)'); + } + $cell.empty().append($input); + if (cell === current) $input.focus(); + $input.css('width', '100%'); + + if (immediate) $input.on('blur', function(e) { + var valueNew = $input.val(); + if (valueNew !== value) { + _cell.data(valueNew); + if (HTMLWidgets.shinyMode) { + changeInput('cell_edit', [cellInfo(cell)], 'DT.cellInfo', null, {priority: 'event'}); + } + // for server-side processing, users have to call replaceData() to update the table + if (!server) table.draw(false); + } else { + $cell.html(html); + } + }).on('keyup', function(e) { + // hit Escape to cancel editing + if (e.keyCode === 27) $input.trigger('blur'); + }); + + // bulk edit (row, column, or all) + if (!immediate) $input.on('keyup', function(e) { + var removeInput = function($cell, restore) { + $cell.data('input').remove(); + if (restore) $cell.html($cell.data('html')); + } + if (e.keyCode === 27) { + for (var i = 0; i < target.length; i++) { + removeInput($(target[i]), true); + } + } else if (e.keyCode === 13 && e.ctrlKey) { + // Ctrl + Enter + var cell, $cell, _cell, cellData = []; + for (var i = 0; i < target.length; i++) { + cell = target[i]; $cell = $(cell); _cell = table.cell(cell); + _cell.data($cell.data('input').val()); + HTMLWidgets.shinyMode && cellData.push(cellInfo(cell)); + removeInput($cell, false); + } + if (HTMLWidgets.shinyMode) { + changeInput('cell_edit', cellData, 'DT.cellInfo', null, {priority: "event"}); + } + if (!server) table.draw(false); + } + }); + })(target[i], this); + } + }); + + // interaction with shiny + if (!HTMLWidgets.shinyMode && !crosstalkOptions.group) return; + + var methods = {}; + var shinyData = {}; + + methods.updateCaption = function(caption) { + if (!caption) return; + $table.children('caption').replaceWith(caption); + } + + // register clear functions to remove input values when the table is removed + instance.clearInputs = {}; + + var changeInput = function(id, value, type, noCrosstalk, opts) { + var event = id; + id = el.id + '_' + id; + if (type) id = id + ':' + type; + // do not update if the new value is the same as old value + if (event !== 'cell_edit' && !/_clicked$/.test(event) && shinyData.hasOwnProperty(id) && shinyData[id] === JSON.stringify(value)) + return; + shinyData[id] = JSON.stringify(value); + if (HTMLWidgets.shinyMode && Shiny.setInputValue) { + Shiny.setInputValue(id, value, opts); + if (!instance.clearInputs[id]) instance.clearInputs[id] = function() { + Shiny.setInputValue(id, null); + } + } + + // HACK + if (event === "rows_selected" && !noCrosstalk) { + if (crosstalkOptions.group) { + var keys = crosstalkOptions.key; + var selectedKeys = null; + if (value) { + selectedKeys = []; + for (var i = 0; i < value.length; i++) { + // The value array's contents use 1-based row numbers, so we must + // convert to 0-based before indexing into the keys array. + selectedKeys.push(keys[value[i] - 1]); + } + } + instance.ctselectHandle.set(selectedKeys); + } + } + }; + + var addOne = function(x) { + return x.map(function(i) { return 1 + i; }); + }; + + var unique = function(x) { + var ux = []; + $.each(x, function(i, el){ + if ($.inArray(el, ux) === -1) ux.push(el); + }); + return ux; + } + + // change the row index of a cell + var tweakCellIndex = function(cell) { + var info = cell.index(); + // some cell may not be valid. e.g, #759 + // when using the RowGroup extension, datatables will + // generate the row label and the cells are not part of + // the data thus contain no row/col info + if (info === undefined) + return {row: null, col: null}; + if (server) { + info.row = DT_rows_current[info.row]; + } else { + info.row += 1; + } + return {row: info.row, col: info.column}; + } + + var cleanSelectedValues = function() { + changeInput('rows_selected', []); + changeInput('columns_selected', []); + changeInput('cells_selected', transposeArray2D([]), 'shiny.matrix'); + } + // #828 we should clean the selection on the server-side when the table reloads + cleanSelectedValues(); + + // a flag to indicates if select extension is initialized or not + var flagSelectExt = table.settings()[0]._select !== undefined; + // the Select extension should only be used in the client mode and + // when the selection.mode is set to none + if (data.selection.mode === 'none' && !server && flagSelectExt) { + var updateRowsSelected = function() { + var rows = table.rows({selected: true}); + var selected = []; + $.each(rows.indexes().toArray(), function(i, v) { + selected.push(v + 1); + }); + changeInput('rows_selected', selected); + } + var updateColsSelected = function() { + var columns = table.columns({selected: true}); + changeInput('columns_selected', columns.indexes().toArray()); + } + var updateCellsSelected = function() { + var cells = table.cells({selected: true}); + var selected = []; + cells.every(function() { + var row = this.index().row; + var col = this.index().column; + selected = selected.concat([[row + 1, col]]); + }); + changeInput('cells_selected', transposeArray2D(selected), 'shiny.matrix'); + } + table.on('select deselect', function(e, dt, type, indexes) { + updateRowsSelected(); + updateColsSelected(); + updateCellsSelected(); + }) + updateRowsSelected(); + updateColsSelected(); + updateCellsSelected(); + } + + var selMode = data.selection.mode, selTarget = data.selection.target; + var selDisable = data.selection.selectable === false; + if (inArray(selMode, ['single', 'multiple'])) { + var selClass = inArray(data.style, ['bootstrap', 'bootstrap4']) ? 'active' : 'selected'; + // selected1: row indices; selected2: column indices + var initSel = function(x) { + if (x === null || typeof x === 'boolean' || selTarget === 'cell') { + return {rows: [], cols: []}; + } else if (selTarget === 'row') { + return {rows: $.makeArray(x), cols: []}; + } else if (selTarget === 'column') { + return {rows: [], cols: $.makeArray(x)}; + } else if (selTarget === 'row+column') { + return {rows: $.makeArray(x.rows), cols: $.makeArray(x.cols)}; + } + } + var selected = data.selection.selected; + var selected1 = initSel(selected).rows, selected2 = initSel(selected).cols; + // selectable should contain either all positive or all non-positive values, not both + // positive values indicate "selectable" while non-positive values means "nonselectable" + // the assertion is performed on R side. (only column indicides could be zero which indicates + // the row name) + var selectable = data.selection.selectable; + var selectable1 = initSel(selectable).rows, selectable2 = initSel(selectable).cols; + + // After users reorder the rows or filter the table, we cannot use the table index + // directly. Instead, we need this function to find out the rows between the two clicks. + // If user filter the table again between the start click and the end click, the behavior + // would be undefined, but it should not be a problem. + var shiftSelRowsIndex = function(start, end) { + var indexes = server ? DT_rows_all : table.rows({ search: 'applied' }).indexes().toArray(); + start = indexes.indexOf(start); end = indexes.indexOf(end); + // if start is larger than end, we need to swap + if (start > end) { + var tmp = end; end = start; start = tmp; + } + return indexes.slice(start, end + 1); + } + + var serverRowIndex = function(clientRowIndex) { + return server ? DT_rows_current[clientRowIndex] : clientRowIndex + 1; + } + + // row, column, or cell selection + var lastClickedRow; + if (inArray(selTarget, ['row', 'row+column'])) { + // Get the current selected rows. It will also + // update the selected1's value based on the current row selection state + // Note we can't put this function inside selectRows() directly, + // the reason is method.selectRows() will override selected1's value but this + // function will add rows to selected1 (keep the existing selection), which is + // inconsistent with column and cell selection. + var selectedRows = function() { + var rows = table.rows('.' + selClass); + var idx = rows.indexes().toArray(); + if (!server) { + selected1 = addOne(idx); + return selected1; + } + idx = idx.map(function(i) { + return DT_rows_current[i]; + }); + selected1 = selMode === 'multiple' ? unique(selected1.concat(idx)) : idx; + return selected1; + } + // Change selected1's value based on selectable1, then refresh the row state + var onlyKeepSelectableRows = function() { + if (selDisable) { // users can't select; useful when only want backend select + selected1 = []; + return; + } + if (selectable1.length === 0) return; + var nonselectable = selectable1[0] <= 0; + if (nonselectable) { + // should make selectable1 positive + selected1 = $(selected1).not(selectable1.map(function(i) { return -i; })).get(); + } else { + selected1 = $(selected1).filter(selectable1).get(); + } + } + // Change selected1's value based on selectable1, then + // refresh the row selection state according to values in selected1 + var selectRows = function(ignoreSelectable) { + if (!ignoreSelectable) onlyKeepSelectableRows(); + table.$('tr.' + selClass).removeClass(selClass); + if (selected1.length === 0) return; + if (server) { + table.rows({page: 'current'}).every(function() { + if (inArray(DT_rows_current[this.index()], selected1)) { + $(this.node()).addClass(selClass); + } + }); + } else { + var selected0 = selected1.map(function(i) { return i - 1; }); + $(table.rows(selected0).nodes()).addClass(selClass); + } + } + table.on('mousedown.dt', 'tbody tr', function(e) { + var $this = $(this), thisRow = table.row(this); + if (selMode === 'multiple') { + if (e.shiftKey && lastClickedRow !== undefined) { + // select or de-select depends on the last clicked row's status + var flagSel = !$this.hasClass(selClass); + var crtClickedRow = serverRowIndex(thisRow.index()); + if (server) { + var rowsIndex = shiftSelRowsIndex(lastClickedRow, crtClickedRow); + // update current page's selClass + rowsIndex.map(function(i) { + var rowIndex = DT_rows_current.indexOf(i); + if (rowIndex >= 0) { + var row = table.row(rowIndex).nodes().to$(); + var flagRowSel = !row.hasClass(selClass); + if (flagSel === flagRowSel) row.toggleClass(selClass); + } + }); + // update selected1 + if (flagSel) { + selected1 = unique(selected1.concat(rowsIndex)); + } else { + selected1 = selected1.filter(function(index) { + return !inArray(index, rowsIndex); + }); + } + } else { + // js starts from 0 + shiftSelRowsIndex(lastClickedRow - 1, crtClickedRow - 1).map(function(value) { + var row = table.row(value).nodes().to$(); + var flagRowSel = !row.hasClass(selClass); + if (flagSel === flagRowSel) row.toggleClass(selClass); + }); + } + e.preventDefault(); + } else { + $this.toggleClass(selClass); + } + } else { + if ($this.hasClass(selClass)) { + $this.removeClass(selClass); + } else { + table.$('tr.' + selClass).removeClass(selClass); + $this.addClass(selClass); + } + } + if (server && !$this.hasClass(selClass)) { + var id = DT_rows_current[thisRow.index()]; + // remove id from selected1 since its class .selected has been removed + if (inArray(id, selected1)) selected1.splice($.inArray(id, selected1), 1); + } + selectedRows(); // update selected1's value based on selClass + selectRows(false); // only keep the selectable rows + changeInput('rows_selected', selected1); + changeInput('row_last_clicked', serverRowIndex(thisRow.index()), null, null, {priority: 'event'}); + lastClickedRow = serverRowIndex(thisRow.index()); + }); + selectRows(false); // in case users have specified pre-selected rows + // restore selected rows after the table is redrawn (e.g. sort/search/page); + // client-side tables will preserve the selections automatically; for + // server-side tables, we have to *real* row indices are in `selected1` + changeInput('rows_selected', selected1); + if (server) table.on('draw.dt', function(e) { selectRows(false); }); + methods.selectRows = function(selected, ignoreSelectable) { + selected1 = $.makeArray(selected); + selectRows(ignoreSelectable); + changeInput('rows_selected', selected1); + } + } + + if (inArray(selTarget, ['column', 'row+column'])) { + if (selTarget === 'row+column') { + $(table.columns().footer()).css('cursor', 'pointer'); + } + // update selected2's value based on selectable2 + var onlyKeepSelectableCols = function() { + if (selDisable) { // users can't select; useful when only want backend select + selected2 = []; + return; + } + if (selectable2.length === 0) return; + var nonselectable = selectable2[0] <= 0; + if (nonselectable) { + // need to make selectable2 positive + selected2 = $(selected2).not(selectable2.map(function(i) { return -i; })).get(); + } else { + selected2 = $(selected2).filter(selectable2).get(); + } + } + // update selected2 and then + // refresh the col selection state according to values in selected2 + var selectCols = function(ignoreSelectable) { + if (!ignoreSelectable) onlyKeepSelectableCols(); + // if selected2 is not a valide index (e.g., larger than the column number) + // table.columns(selected2) will fail and result in a blank table + // this is different from the table.rows(), where the out-of-range indexes + // doesn't affect at all + selected2 = $(selected2).filter(table.columns().indexes()).get(); + table.columns().nodes().flatten().to$().removeClass(selClass); + if (selected2.length > 0) + table.columns(selected2).nodes().flatten().to$().addClass(selClass); + } + var callback = function() { + var colIdx = selTarget === 'column' ? table.cell(this).index().column : + $.inArray(this, table.columns().footer()), + thisCol = $(table.column(colIdx).nodes()); + if (colIdx === -1) return; + if (thisCol.hasClass(selClass)) { + thisCol.removeClass(selClass); + selected2.splice($.inArray(colIdx, selected2), 1); + } else { + if (selMode === 'single') $(table.cells().nodes()).removeClass(selClass); + thisCol.addClass(selClass); + selected2 = selMode === 'single' ? [colIdx] : unique(selected2.concat([colIdx])); + } + selectCols(false); // update selected2 based on selectable + changeInput('columns_selected', selected2); + } + if (selTarget === 'column') { + $(table.table().body()).on('click.dt', 'td', callback); + } else { + $(table.table().footer()).on('click.dt', 'tr th', callback); + } + selectCols(false); // in case users have specified pre-selected columns + changeInput('columns_selected', selected2); + if (server) table.on('draw.dt', function(e) { selectCols(false); }); + methods.selectColumns = function(selected, ignoreSelectable) { + selected2 = $.makeArray(selected); + selectCols(ignoreSelectable); + changeInput('columns_selected', selected2); + } + } + + if (selTarget === 'cell') { + var selected3 = [], selectable3 = []; + if (selected !== null) selected3 = selected; + if (selectable !== null && typeof selectable !== 'boolean') selectable3 = selectable; + var findIndex = function(ij, sel) { + for (var i = 0; i < sel.length; i++) { + if (ij[0] === sel[i][0] && ij[1] === sel[i][1]) return i; + } + return -1; + } + // Change selected3's value based on selectable3, then refresh the cell state + var onlyKeepSelectableCells = function() { + if (selDisable) { // users can't select; useful when only want backend select + selected3 = []; + return; + } + if (selectable3.length === 0) return; + var nonselectable = selectable3[0][0] <= 0; + var out = []; + if (nonselectable) { + selected3.map(function(ij) { + // should make selectable3 positive + if (findIndex([-ij[0], -ij[1]], selectable3) === -1) { out.push(ij); } + }); + } else { + selected3.map(function(ij) { + if (findIndex(ij, selectable3) > -1) { out.push(ij); } + }); + } + selected3 = out; + } + // Change selected3's value based on selectable3, then + // refresh the cell selection state according to values in selected3 + var selectCells = function(ignoreSelectable) { + if (!ignoreSelectable) onlyKeepSelectableCells(); + table.$('td.' + selClass).removeClass(selClass); + if (selected3.length === 0) return; + if (server) { + table.cells({page: 'current'}).every(function() { + var info = tweakCellIndex(this); + if (findIndex([info.row, info.col], selected3) > -1) + $(this.node()).addClass(selClass); + }); + } else { + selected3.map(function(ij) { + $(table.cell(ij[0] - 1, ij[1]).node()).addClass(selClass); + }); + } + }; + table.on('click.dt', 'tbody td', function() { + var $this = $(this), info = tweakCellIndex(table.cell(this)); + if ($this.hasClass(selClass)) { + $this.removeClass(selClass); + selected3.splice(findIndex([info.row, info.col], selected3), 1); + } else { + if (selMode === 'single') $(table.cells().nodes()).removeClass(selClass); + $this.addClass(selClass); + selected3 = selMode === 'single' ? [[info.row, info.col]] : + unique(selected3.concat([[info.row, info.col]])); + } + selectCells(false); // must call this to update selected3 based on selectable3 + changeInput('cells_selected', transposeArray2D(selected3), 'shiny.matrix'); + }); + selectCells(false); // in case users have specified pre-selected columns + changeInput('cells_selected', transposeArray2D(selected3), 'shiny.matrix'); + + if (server) table.on('draw.dt', function(e) { selectCells(false); }); + methods.selectCells = function(selected, ignoreSelectable) { + selected3 = selected ? selected : []; + selectCells(ignoreSelectable); + changeInput('cells_selected', transposeArray2D(selected3), 'shiny.matrix'); + } + } + } + + // expose some table info to Shiny + var updateTableInfo = function(e, settings) { + // TODO: is anyone interested in the page info? + // changeInput('page_info', table.page.info()); + var updateRowInfo = function(id, modifier) { + var idx; + if (server) { + idx = modifier.page === 'current' ? DT_rows_current : DT_rows_all; + } else { + var rows = table.rows($.extend({ + search: 'applied', + page: 'all' + }, modifier)); + idx = addOne(rows.indexes().toArray()); + } + changeInput('rows' + '_' + id, idx); + }; + updateRowInfo('current', {page: 'current'}); + updateRowInfo('all', {}); + } + table.on('draw.dt', updateTableInfo); + updateTableInfo(); + + // state info + table.on('draw.dt column-visibility.dt', function() { + changeInput('state', table.state()); + }); + changeInput('state', table.state()); + + // search info + var updateSearchInfo = function() { + changeInput('search', table.search()); + if (filterRow) changeInput('search_columns', filterRow.toArray().map(function(td) { + return $(td).find('input').first().val(); + })); + } + table.on('draw.dt', updateSearchInfo); + updateSearchInfo(); + + var cellInfo = function(thiz) { + var info = tweakCellIndex(table.cell(thiz)); + info.value = table.cell(thiz).data(); + return info; + } + // the current cell clicked on + table.on('click.dt', 'tbody td', function() { + changeInput('cell_clicked', cellInfo(this), null, null, {priority: 'event'}); + }) + changeInput('cell_clicked', {}); + + // do not trigger table selection when clicking on links unless they have classes + table.on('mousedown.dt', 'tbody td a', function(e) { + if (this.className === '') e.stopPropagation(); + }); + + methods.addRow = function(data, rowname, resetPaging) { + var n = table.columns().indexes().length, d = n - data.length; + if (d === 1) { + data = rowname.concat(data) + } else if (d !== 0) { + console.log(data); + console.log(table.columns().indexes()); + throw 'New data must be of the same length as current data (' + n + ')'; + }; + table.row.add(data).draw(resetPaging); + } + + methods.updateSearch = function(keywords) { + if (keywords.global !== null) + $(table.table().container()).find('input[type=search]').first() + .val(keywords.global).trigger('input'); + var columns = keywords.columns; + if (!filterRow || columns === null) return; + filterRow.toArray().map(function(td, i) { + var v = typeof columns === 'string' ? columns : columns[i]; + if (typeof v === 'undefined') { + console.log('The search keyword for column ' + i + ' is undefined') + return; + } + // Update column search string and values on linked filter widgets. + // 'input' for factor and char filters, 'change' for numeric filters. + $(td).find('input').first().val(v).trigger('input', [true]).trigger('change'); + }); + table.draw(); + } + + methods.hideCols = function(hide, reset) { + if (reset) table.columns().visible(true, false); + table.columns(hide).visible(false); + } + + methods.showCols = function(show, reset) { + if (reset) table.columns().visible(false, false); + table.columns(show).visible(true); + } + + methods.colReorder = function(order, origOrder) { + table.colReorder.order(order, origOrder); + } + + methods.selectPage = function(page) { + if (table.page.info().pages < page || page < 1) { + throw 'Selected page is out of range'; + }; + table.page(page - 1).draw(false); + } + + methods.reloadData = function(resetPaging, clearSelection) { + // empty selections first if necessary + if (methods.selectRows && inArray('row', clearSelection)) methods.selectRows([]); + if (methods.selectColumns && inArray('column', clearSelection)) methods.selectColumns([]); + if (methods.selectCells && inArray('cell', clearSelection)) methods.selectCells([]); + table.ajax.reload(null, resetPaging); + } + + // update table filters (set new limits of sliders) + methods.updateFilters = function(newProps) { + // loop through each filter in the filter row + filterRow.each(function(i, td) { + var k = i; + if (filterRow.length > newProps.length) { + if (i === 0) return; // first column is row names + k = i - 1; + } + // Update the filters to reflect the updated data. + // Allow "falsy" (e.g. NULL) to signify a no-op. + if (newProps[k]) { + setFilterProps(td, newProps[k]); + } + }); + }; + + table.shinyMethods = methods; + }, + resize: function(el, width, height, instance) { + if (instance.data) this.renderValue(el, instance.data, instance); + + // dynamically adjust height if fillContainer = TRUE + if (instance.fillContainer) + this.fillAvailableHeight(el, height); + + this.adjustWidth(el); + }, + + // dynamically set the scroll body to fill available height + // (used with fillContainer = TRUE) + fillAvailableHeight: function(el, availableHeight) { + + // see how much of the table is occupied by header/footer elements + // and use that to compute a target scroll body height + var dtWrapper = $(el).find('div.dataTables_wrapper'); + var dtScrollBody = $(el).find($('div.dataTables_scrollBody')); + var framingHeight = dtWrapper.innerHeight() - dtScrollBody.innerHeight(); + var scrollBodyHeight = availableHeight - framingHeight; + + // we need to set `max-height` to none as datatables library now sets this + // to a fixed height, disabling the ability to resize to fill the window, + // as it will be set to a fixed 100px under such circumstances, e.g., RStudio IDE, + // or FlexDashboard + // see https://github.com/rstudio/DT/issues/951#issuecomment-1026464509 + dtScrollBody.css('max-height', 'none'); + // set the height + dtScrollBody.height(scrollBodyHeight + 'px'); + }, + + // adjust the width of columns; remove the hard-coded widths on table and the + // scroll header when scrollX/Y are enabled + adjustWidth: function(el) { + var $el = $(el), table = $el.data('datatable'); + if (table) table.columns.adjust(); + $el.find('.dataTables_scrollHeadInner').css('width', '') + .children('table').css('margin-left', ''); + } +}); + + if (!HTMLWidgets.shinyMode) return; + + Shiny.addCustomMessageHandler('datatable-calls', function(data) { + var id = data.id; + var el = document.getElementById(id); + var table = el ? $(el).data('datatable') : null; + if (!table) { + console.log("Couldn't find table with id " + id); + return; + } + + var methods = table.shinyMethods, call = data.call; + if (methods[call.method]) { + methods[call.method].apply(table, call.args); + } else { + console.log("Unknown method " + call.method); + } + }); + +})(); diff --git a/docs/articles/variables_sheet_files/datatables-css-0.0.0/datatables-crosstalk.css b/docs/articles/variables_sheet_files/datatables-css-0.0.0/datatables-crosstalk.css index 43422d25..bd1159c8 100644 --- a/docs/articles/variables_sheet_files/datatables-css-0.0.0/datatables-crosstalk.css +++ b/docs/articles/variables_sheet_files/datatables-css-0.0.0/datatables-crosstalk.css @@ -5,3 +5,28 @@ html body div.DTS div.dataTables_scrollBody { background: none; } + + +/* +Fix https://github.com/rstudio/DT/issues/563 +If the `table.display` is set to "block" (e.g., pkgdown), the browser will display +datatable objects strangely. The search panel and the page buttons will still be +in full-width but the table body will be "compact" and shorter. +In therory, having this attributes will affect `dom="t"` +with `display: block` users. But in reality, there should be no one. +We may remove the below lines in the future if the upstream agree to have this there. +See https://github.com/DataTables/DataTablesSrc/issues/160 +*/ + +table.dataTable { + display: table; +} + + +/* +When DTOutput(fill = TRUE), it receives a .html-fill-item class (via htmltools::bindFillRole()), which effectively amounts to `flex: 1 1 auto`. That's mostly fine, but the case where `fillContainer=TRUE`+`height:auto`+`flex-basis:auto` and the container (e.g., a bslib::card()) doesn't have a defined height is a bit problematic since the table wants to fit the parent but the parent wants to fit the table, which results pretty small table height (maybe because there is a minimum height somewhere?). It seems better in this case to impose a 400px height default for the table, which we can do by setting `flex-basis` to 400px (the table is still allowed to grow/shrink when the container has an opinionated height). +*/ + +.html-fill-container > .html-fill-item.datatables { + flex-basis: 400px; +} diff --git a/docs/articles/variables_sheet_files/dt-core-1.13.6/css/jquery.dataTables.extra.css b/docs/articles/variables_sheet_files/dt-core-1.13.6/css/jquery.dataTables.extra.css new file mode 100644 index 00000000..b2dd141f --- /dev/null +++ b/docs/articles/variables_sheet_files/dt-core-1.13.6/css/jquery.dataTables.extra.css @@ -0,0 +1,28 @@ +/* Selected rows/cells */ +table.dataTable tr.selected td, table.dataTable td.selected { + background-color: #b0bed9 !important; +} +/* In case of scrollX/Y or FixedHeader */ +.dataTables_scrollBody .dataTables_sizing { + visibility: hidden; +} + +/* The datatables' theme CSS file doesn't define +the color but with white background. It leads to an issue that +when the HTML's body color is set to 'white', the user can't +see the text since the background is white. One case happens in the +RStudio's IDE when inline viewing the DT table inside an Rmd file, +if the IDE theme is set to "Cobalt". + +See https://github.com/rstudio/DT/issues/447 for more info + +This fixes should have little side-effects because all the other elements +of the default theme use the #333 font color. + +TODO: The upstream may use relative colors for both the table background +and the color. It means the table can display well without this patch +then. At that time, we need to remove the below CSS attributes. +*/ +div.datatables { + color: #333; +} diff --git a/docs/articles/variables_sheet_files/dt-core-1.13.6/css/jquery.dataTables.min.css b/docs/articles/variables_sheet_files/dt-core-1.13.6/css/jquery.dataTables.min.css new file mode 100644 index 00000000..ad59f843 --- /dev/null +++ b/docs/articles/variables_sheet_files/dt-core-1.13.6/css/jquery.dataTables.min.css @@ -0,0 +1 @@ +:root{--dt-row-selected: 13, 110, 253;--dt-row-selected-text: 255, 255, 255;--dt-row-selected-link: 9, 10, 11;--dt-row-stripe: 0, 0, 0;--dt-row-hover: 0, 0, 0;--dt-column-ordering: 0, 0, 0;--dt-html-background: white}:root.dark{--dt-html-background: rgb(33, 37, 41)}table.dataTable td.dt-control{text-align:center;cursor:pointer}table.dataTable td.dt-control:before{display:inline-block;color:rgba(0, 0, 0, 0.5);content:"►"}table.dataTable tr.dt-hasChild td.dt-control:before{content:"▼"}html.dark table.dataTable td.dt-control:before{color:rgba(255, 255, 255, 0.5)}html.dark table.dataTable tr.dt-hasChild td.dt-control:before{color:rgba(255, 255, 255, 0.5)}table.dataTable thead>tr>th.sorting,table.dataTable thead>tr>th.sorting_asc,table.dataTable thead>tr>th.sorting_desc,table.dataTable thead>tr>th.sorting_asc_disabled,table.dataTable thead>tr>th.sorting_desc_disabled,table.dataTable thead>tr>td.sorting,table.dataTable thead>tr>td.sorting_asc,table.dataTable thead>tr>td.sorting_desc,table.dataTable thead>tr>td.sorting_asc_disabled,table.dataTable thead>tr>td.sorting_desc_disabled{cursor:pointer;position:relative;padding-right:26px}table.dataTable thead>tr>th.sorting:before,table.dataTable thead>tr>th.sorting:after,table.dataTable thead>tr>th.sorting_asc:before,table.dataTable thead>tr>th.sorting_asc:after,table.dataTable thead>tr>th.sorting_desc:before,table.dataTable thead>tr>th.sorting_desc:after,table.dataTable thead>tr>th.sorting_asc_disabled:before,table.dataTable thead>tr>th.sorting_asc_disabled:after,table.dataTable thead>tr>th.sorting_desc_disabled:before,table.dataTable thead>tr>th.sorting_desc_disabled:after,table.dataTable thead>tr>td.sorting:before,table.dataTable thead>tr>td.sorting:after,table.dataTable thead>tr>td.sorting_asc:before,table.dataTable thead>tr>td.sorting_asc:after,table.dataTable thead>tr>td.sorting_desc:before,table.dataTable thead>tr>td.sorting_desc:after,table.dataTable thead>tr>td.sorting_asc_disabled:before,table.dataTable thead>tr>td.sorting_asc_disabled:after,table.dataTable thead>tr>td.sorting_desc_disabled:before,table.dataTable thead>tr>td.sorting_desc_disabled:after{position:absolute;display:block;opacity:.125;right:10px;line-height:9px;font-size:.8em}table.dataTable thead>tr>th.sorting:before,table.dataTable thead>tr>th.sorting_asc:before,table.dataTable thead>tr>th.sorting_desc:before,table.dataTable thead>tr>th.sorting_asc_disabled:before,table.dataTable thead>tr>th.sorting_desc_disabled:before,table.dataTable thead>tr>td.sorting:before,table.dataTable thead>tr>td.sorting_asc:before,table.dataTable thead>tr>td.sorting_desc:before,table.dataTable thead>tr>td.sorting_asc_disabled:before,table.dataTable thead>tr>td.sorting_desc_disabled:before{bottom:50%;content:"▲";content:"▲"/""}table.dataTable thead>tr>th.sorting:after,table.dataTable thead>tr>th.sorting_asc:after,table.dataTable thead>tr>th.sorting_desc:after,table.dataTable thead>tr>th.sorting_asc_disabled:after,table.dataTable thead>tr>th.sorting_desc_disabled:after,table.dataTable thead>tr>td.sorting:after,table.dataTable thead>tr>td.sorting_asc:after,table.dataTable thead>tr>td.sorting_desc:after,table.dataTable thead>tr>td.sorting_asc_disabled:after,table.dataTable thead>tr>td.sorting_desc_disabled:after{top:50%;content:"▼";content:"▼"/""}table.dataTable thead>tr>th.sorting_asc:before,table.dataTable thead>tr>th.sorting_desc:after,table.dataTable thead>tr>td.sorting_asc:before,table.dataTable thead>tr>td.sorting_desc:after{opacity:.6}table.dataTable thead>tr>th.sorting_desc_disabled:after,table.dataTable thead>tr>th.sorting_asc_disabled:before,table.dataTable thead>tr>td.sorting_desc_disabled:after,table.dataTable thead>tr>td.sorting_asc_disabled:before{display:none}table.dataTable thead>tr>th:active,table.dataTable thead>tr>td:active{outline:none}div.dataTables_scrollBody>table.dataTable>thead>tr>th:before,div.dataTables_scrollBody>table.dataTable>thead>tr>th:after,div.dataTables_scrollBody>table.dataTable>thead>tr>td:before,div.dataTables_scrollBody>table.dataTable>thead>tr>td:after{display:none}div.dataTables_processing{position:absolute;top:50%;left:50%;width:200px;margin-left:-100px;margin-top:-26px;text-align:center;padding:2px}div.dataTables_processing>div:last-child{position:relative;width:80px;height:15px;margin:1em auto}div.dataTables_processing>div:last-child>div{position:absolute;top:0;width:13px;height:13px;border-radius:50%;background:rgb(13, 110, 253);background:rgb(var(--dt-row-selected));animation-timing-function:cubic-bezier(0, 1, 1, 0)}div.dataTables_processing>div:last-child>div:nth-child(1){left:8px;animation:datatables-loader-1 .6s infinite}div.dataTables_processing>div:last-child>div:nth-child(2){left:8px;animation:datatables-loader-2 .6s infinite}div.dataTables_processing>div:last-child>div:nth-child(3){left:32px;animation:datatables-loader-2 .6s infinite}div.dataTables_processing>div:last-child>div:nth-child(4){left:56px;animation:datatables-loader-3 .6s infinite}@keyframes datatables-loader-1{0%{transform:scale(0)}100%{transform:scale(1)}}@keyframes datatables-loader-3{0%{transform:scale(1)}100%{transform:scale(0)}}@keyframes datatables-loader-2{0%{transform:translate(0, 0)}100%{transform:translate(24px, 0)}}table.dataTable.nowrap th,table.dataTable.nowrap td{white-space:nowrap}table.dataTable th.dt-left,table.dataTable td.dt-left{text-align:left}table.dataTable th.dt-center,table.dataTable td.dt-center,table.dataTable td.dataTables_empty{text-align:center}table.dataTable th.dt-right,table.dataTable td.dt-right{text-align:right}table.dataTable th.dt-justify,table.dataTable td.dt-justify{text-align:justify}table.dataTable th.dt-nowrap,table.dataTable td.dt-nowrap{white-space:nowrap}table.dataTable thead th,table.dataTable thead td,table.dataTable tfoot th,table.dataTable tfoot td{text-align:left}table.dataTable thead th.dt-head-left,table.dataTable thead td.dt-head-left,table.dataTable tfoot th.dt-head-left,table.dataTable tfoot td.dt-head-left{text-align:left}table.dataTable thead th.dt-head-center,table.dataTable thead td.dt-head-center,table.dataTable tfoot th.dt-head-center,table.dataTable tfoot td.dt-head-center{text-align:center}table.dataTable thead th.dt-head-right,table.dataTable thead td.dt-head-right,table.dataTable tfoot th.dt-head-right,table.dataTable tfoot td.dt-head-right{text-align:right}table.dataTable thead th.dt-head-justify,table.dataTable thead td.dt-head-justify,table.dataTable tfoot th.dt-head-justify,table.dataTable tfoot td.dt-head-justify{text-align:justify}table.dataTable thead th.dt-head-nowrap,table.dataTable thead td.dt-head-nowrap,table.dataTable tfoot th.dt-head-nowrap,table.dataTable tfoot td.dt-head-nowrap{white-space:nowrap}table.dataTable tbody th.dt-body-left,table.dataTable tbody td.dt-body-left{text-align:left}table.dataTable tbody th.dt-body-center,table.dataTable tbody td.dt-body-center{text-align:center}table.dataTable tbody th.dt-body-right,table.dataTable tbody td.dt-body-right{text-align:right}table.dataTable tbody th.dt-body-justify,table.dataTable tbody td.dt-body-justify{text-align:justify}table.dataTable tbody th.dt-body-nowrap,table.dataTable tbody td.dt-body-nowrap{white-space:nowrap}table.dataTable{width:100%;margin:0 auto;clear:both;border-collapse:separate;border-spacing:0}table.dataTable thead th,table.dataTable tfoot th{font-weight:bold}table.dataTable>thead>tr>th,table.dataTable>thead>tr>td{padding:10px;border-bottom:1px solid rgba(0, 0, 0, 0.3)}table.dataTable>thead>tr>th:active,table.dataTable>thead>tr>td:active{outline:none}table.dataTable>tfoot>tr>th,table.dataTable>tfoot>tr>td{padding:10px 10px 6px 10px;border-top:1px solid rgba(0, 0, 0, 0.3)}table.dataTable tbody tr{background-color:transparent}table.dataTable tbody tr.selected>*{box-shadow:inset 0 0 0 9999px rgba(13, 110, 253, 0.9);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.9);color:rgb(255, 255, 255);color:rgb(var(--dt-row-selected-text))}table.dataTable tbody tr.selected a{color:rgb(9, 10, 11);color:rgb(var(--dt-row-selected-link))}table.dataTable tbody th,table.dataTable tbody td{padding:8px 10px}table.dataTable.row-border>tbody>tr>th,table.dataTable.row-border>tbody>tr>td,table.dataTable.display>tbody>tr>th,table.dataTable.display>tbody>tr>td{border-top:1px solid rgba(0, 0, 0, 0.15)}table.dataTable.row-border>tbody>tr:first-child>th,table.dataTable.row-border>tbody>tr:first-child>td,table.dataTable.display>tbody>tr:first-child>th,table.dataTable.display>tbody>tr:first-child>td{border-top:none}table.dataTable.row-border>tbody>tr.selected+tr.selected>td,table.dataTable.display>tbody>tr.selected+tr.selected>td{border-top-color:#0262ef}table.dataTable.cell-border>tbody>tr>th,table.dataTable.cell-border>tbody>tr>td{border-top:1px solid rgba(0, 0, 0, 0.15);border-right:1px solid rgba(0, 0, 0, 0.15)}table.dataTable.cell-border>tbody>tr>th:first-child,table.dataTable.cell-border>tbody>tr>td:first-child{border-left:1px solid rgba(0, 0, 0, 0.15)}table.dataTable.cell-border>tbody>tr:first-child>th,table.dataTable.cell-border>tbody>tr:first-child>td{border-top:none}table.dataTable.stripe>tbody>tr.odd>*,table.dataTable.display>tbody>tr.odd>*{box-shadow:inset 0 0 0 9999px rgba(0, 0, 0, 0.023);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-stripe), 0.023)}table.dataTable.stripe>tbody>tr.odd.selected>*,table.dataTable.display>tbody>tr.odd.selected>*{box-shadow:inset 0 0 0 9999px rgba(13, 110, 253, 0.923);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.923)}table.dataTable.hover>tbody>tr:hover>*,table.dataTable.display>tbody>tr:hover>*{box-shadow:inset 0 0 0 9999px rgba(0, 0, 0, 0.035);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-hover), 0.035)}table.dataTable.hover>tbody>tr.selected:hover>*,table.dataTable.display>tbody>tr.selected:hover>*{box-shadow:inset 0 0 0 9999px #0d6efd !important;box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 1) !important}table.dataTable.order-column>tbody tr>.sorting_1,table.dataTable.order-column>tbody tr>.sorting_2,table.dataTable.order-column>tbody tr>.sorting_3,table.dataTable.display>tbody tr>.sorting_1,table.dataTable.display>tbody tr>.sorting_2,table.dataTable.display>tbody tr>.sorting_3{box-shadow:inset 0 0 0 9999px rgba(0, 0, 0, 0.019);box-shadow:inset 0 0 0 9999px rgba(var(--dt-column-ordering), 0.019)}table.dataTable.order-column>tbody tr.selected>.sorting_1,table.dataTable.order-column>tbody tr.selected>.sorting_2,table.dataTable.order-column>tbody tr.selected>.sorting_3,table.dataTable.display>tbody tr.selected>.sorting_1,table.dataTable.display>tbody tr.selected>.sorting_2,table.dataTable.display>tbody tr.selected>.sorting_3{box-shadow:inset 0 0 0 9999px rgba(13, 110, 253, 0.919);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.919)}table.dataTable.display>tbody>tr.odd>.sorting_1,table.dataTable.order-column.stripe>tbody>tr.odd>.sorting_1{box-shadow:inset 0 0 0 9999px rgba(0, 0, 0, 0.054);box-shadow:inset 0 0 0 9999px rgba(var(--dt-column-ordering), 0.054)}table.dataTable.display>tbody>tr.odd>.sorting_2,table.dataTable.order-column.stripe>tbody>tr.odd>.sorting_2{box-shadow:inset 0 0 0 9999px rgba(0, 0, 0, 0.047);box-shadow:inset 0 0 0 9999px rgba(var(--dt-column-ordering), 0.047)}table.dataTable.display>tbody>tr.odd>.sorting_3,table.dataTable.order-column.stripe>tbody>tr.odd>.sorting_3{box-shadow:inset 0 0 0 9999px rgba(0, 0, 0, 0.039);box-shadow:inset 0 0 0 9999px rgba(var(--dt-column-ordering), 0.039)}table.dataTable.display>tbody>tr.odd.selected>.sorting_1,table.dataTable.order-column.stripe>tbody>tr.odd.selected>.sorting_1{box-shadow:inset 0 0 0 9999px rgba(13, 110, 253, 0.954);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.954)}table.dataTable.display>tbody>tr.odd.selected>.sorting_2,table.dataTable.order-column.stripe>tbody>tr.odd.selected>.sorting_2{box-shadow:inset 0 0 0 9999px rgba(13, 110, 253, 0.947);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.947)}table.dataTable.display>tbody>tr.odd.selected>.sorting_3,table.dataTable.order-column.stripe>tbody>tr.odd.selected>.sorting_3{box-shadow:inset 0 0 0 9999px rgba(13, 110, 253, 0.939);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.939)}table.dataTable.display>tbody>tr.even>.sorting_1,table.dataTable.order-column.stripe>tbody>tr.even>.sorting_1{box-shadow:inset 0 0 0 9999px rgba(0, 0, 0, 0.019);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.019)}table.dataTable.display>tbody>tr.even>.sorting_2,table.dataTable.order-column.stripe>tbody>tr.even>.sorting_2{box-shadow:inset 0 0 0 9999px rgba(0, 0, 0, 0.011);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.011)}table.dataTable.display>tbody>tr.even>.sorting_3,table.dataTable.order-column.stripe>tbody>tr.even>.sorting_3{box-shadow:inset 0 0 0 9999px rgba(0, 0, 0, 0.003);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.003)}table.dataTable.display>tbody>tr.even.selected>.sorting_1,table.dataTable.order-column.stripe>tbody>tr.even.selected>.sorting_1{box-shadow:inset 0 0 0 9999px rgba(13, 110, 253, 0.919);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.919)}table.dataTable.display>tbody>tr.even.selected>.sorting_2,table.dataTable.order-column.stripe>tbody>tr.even.selected>.sorting_2{box-shadow:inset 0 0 0 9999px rgba(13, 110, 253, 0.911);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.911)}table.dataTable.display>tbody>tr.even.selected>.sorting_3,table.dataTable.order-column.stripe>tbody>tr.even.selected>.sorting_3{box-shadow:inset 0 0 0 9999px rgba(13, 110, 253, 0.903);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.903)}table.dataTable.display tbody tr:hover>.sorting_1,table.dataTable.order-column.hover tbody tr:hover>.sorting_1{box-shadow:inset 0 0 0 9999px rgba(0, 0, 0, 0.082);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-hover), 0.082)}table.dataTable.display tbody tr:hover>.sorting_2,table.dataTable.order-column.hover tbody tr:hover>.sorting_2{box-shadow:inset 0 0 0 9999px rgba(0, 0, 0, 0.074);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-hover), 0.074)}table.dataTable.display tbody tr:hover>.sorting_3,table.dataTable.order-column.hover tbody tr:hover>.sorting_3{box-shadow:inset 0 0 0 9999px rgba(0, 0, 0, 0.062);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-hover), 0.062)}table.dataTable.display tbody tr:hover.selected>.sorting_1,table.dataTable.order-column.hover tbody tr:hover.selected>.sorting_1{box-shadow:inset 0 0 0 9999px rgba(13, 110, 253, 0.982);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.982)}table.dataTable.display tbody tr:hover.selected>.sorting_2,table.dataTable.order-column.hover tbody tr:hover.selected>.sorting_2{box-shadow:inset 0 0 0 9999px rgba(13, 110, 253, 0.974);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.974)}table.dataTable.display tbody tr:hover.selected>.sorting_3,table.dataTable.order-column.hover tbody tr:hover.selected>.sorting_3{box-shadow:inset 0 0 0 9999px rgba(13, 110, 253, 0.962);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.962)}table.dataTable.no-footer{border-bottom:1px solid rgba(0, 0, 0, 0.3)}table.dataTable.compact thead th,table.dataTable.compact thead td,table.dataTable.compact tfoot th,table.dataTable.compact tfoot td,table.dataTable.compact tbody th,table.dataTable.compact tbody td{padding:4px}table.dataTable th,table.dataTable td{box-sizing:content-box}.dataTables_wrapper{position:relative;clear:both}.dataTables_wrapper .dataTables_length{float:left}.dataTables_wrapper .dataTables_length select{border:1px solid #aaa;border-radius:3px;padding:5px;background-color:transparent;color:inherit;padding:4px}.dataTables_wrapper .dataTables_filter{float:right;text-align:right}.dataTables_wrapper .dataTables_filter input{border:1px solid #aaa;border-radius:3px;padding:5px;background-color:transparent;color:inherit;margin-left:3px}.dataTables_wrapper .dataTables_info{clear:both;float:left;padding-top:.755em}.dataTables_wrapper .dataTables_paginate{float:right;text-align:right;padding-top:.25em}.dataTables_wrapper .dataTables_paginate .paginate_button{box-sizing:border-box;display:inline-block;min-width:1.5em;padding:.5em 1em;margin-left:2px;text-align:center;text-decoration:none !important;cursor:pointer;color:inherit !important;border:1px solid transparent;border-radius:2px;background:transparent}.dataTables_wrapper .dataTables_paginate .paginate_button.current,.dataTables_wrapper .dataTables_paginate .paginate_button.current:hover{color:inherit !important;border:1px solid rgba(0, 0, 0, 0.3);background-color:rgba(0, 0, 0, 0.05);background:-webkit-gradient(linear, left top, left bottom, color-stop(0%, rgba(230, 230, 230, 0.05)), color-stop(100%, rgba(0, 0, 0, 0.05)));background:-webkit-linear-gradient(top, rgba(230, 230, 230, 0.05) 0%, rgba(0, 0, 0, 0.05) 100%);background:-moz-linear-gradient(top, rgba(230, 230, 230, 0.05) 0%, rgba(0, 0, 0, 0.05) 100%);background:-ms-linear-gradient(top, rgba(230, 230, 230, 0.05) 0%, rgba(0, 0, 0, 0.05) 100%);background:-o-linear-gradient(top, rgba(230, 230, 230, 0.05) 0%, rgba(0, 0, 0, 0.05) 100%);background:linear-gradient(to bottom, rgba(230, 230, 230, 0.05) 0%, rgba(0, 0, 0, 0.05) 100%)}.dataTables_wrapper .dataTables_paginate .paginate_button.disabled,.dataTables_wrapper .dataTables_paginate .paginate_button.disabled:hover,.dataTables_wrapper .dataTables_paginate .paginate_button.disabled:active{cursor:default;color:#666 !important;border:1px solid transparent;background:transparent;box-shadow:none}.dataTables_wrapper .dataTables_paginate .paginate_button:hover{color:white !important;border:1px solid #111;background-color:#111;background:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #585858), color-stop(100%, #111));background:-webkit-linear-gradient(top, #585858 0%, #111 100%);background:-moz-linear-gradient(top, #585858 0%, #111 100%);background:-ms-linear-gradient(top, #585858 0%, #111 100%);background:-o-linear-gradient(top, #585858 0%, #111 100%);background:linear-gradient(to bottom, #585858 0%, #111 100%)}.dataTables_wrapper .dataTables_paginate .paginate_button:active{outline:none;background-color:#0c0c0c;background:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #2b2b2b), color-stop(100%, #0c0c0c));background:-webkit-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);background:-moz-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);background:-ms-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);background:-o-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);background:linear-gradient(to bottom, #2b2b2b 0%, #0c0c0c 100%);box-shadow:inset 0 0 3px #111}.dataTables_wrapper .dataTables_paginate .ellipsis{padding:0 1em}.dataTables_wrapper .dataTables_length,.dataTables_wrapper .dataTables_filter,.dataTables_wrapper .dataTables_info,.dataTables_wrapper .dataTables_processing,.dataTables_wrapper .dataTables_paginate{color:inherit}.dataTables_wrapper .dataTables_scroll{clear:both}.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody{-webkit-overflow-scrolling:touch}.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>thead>tr>th,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>thead>tr>td,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>tbody>tr>th,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>tbody>tr>td{vertical-align:middle}.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>thead>tr>th>div.dataTables_sizing,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>thead>tr>td>div.dataTables_sizing,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>tbody>tr>th>div.dataTables_sizing,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>tbody>tr>td>div.dataTables_sizing{height:0;overflow:hidden;margin:0 !important;padding:0 !important}.dataTables_wrapper.no-footer .dataTables_scrollBody{border-bottom:1px solid rgba(0, 0, 0, 0.3)}.dataTables_wrapper.no-footer div.dataTables_scrollHead table.dataTable,.dataTables_wrapper.no-footer div.dataTables_scrollBody>table{border-bottom:none}.dataTables_wrapper:after{visibility:hidden;display:block;content:"";clear:both;height:0}@media screen and (max-width: 767px){.dataTables_wrapper .dataTables_info,.dataTables_wrapper .dataTables_paginate{float:none;text-align:center}.dataTables_wrapper .dataTables_paginate{margin-top:.5em}}@media screen and (max-width: 640px){.dataTables_wrapper .dataTables_length,.dataTables_wrapper .dataTables_filter{float:none;text-align:center}.dataTables_wrapper .dataTables_filter{margin-top:.5em}}html.dark{--dt-row-hover: 255, 255, 255;--dt-row-stripe: 255, 255, 255;--dt-column-ordering: 255, 255, 255}html.dark table.dataTable>thead>tr>th,html.dark table.dataTable>thead>tr>td{border-bottom:1px solid rgb(89, 91, 94)}html.dark table.dataTable>thead>tr>th:active,html.dark table.dataTable>thead>tr>td:active{outline:none}html.dark table.dataTable>tfoot>tr>th,html.dark table.dataTable>tfoot>tr>td{border-top:1px solid rgb(89, 91, 94)}html.dark table.dataTable.row-border>tbody>tr>th,html.dark table.dataTable.row-border>tbody>tr>td,html.dark table.dataTable.display>tbody>tr>th,html.dark table.dataTable.display>tbody>tr>td{border-top:1px solid rgb(64, 67, 70)}html.dark table.dataTable.row-border>tbody>tr.selected+tr.selected>td,html.dark table.dataTable.display>tbody>tr.selected+tr.selected>td{border-top-color:#0257d5}html.dark table.dataTable.cell-border>tbody>tr>th,html.dark table.dataTable.cell-border>tbody>tr>td{border-top:1px solid rgb(64, 67, 70);border-right:1px solid rgb(64, 67, 70)}html.dark table.dataTable.cell-border>tbody>tr>th:first-child,html.dark table.dataTable.cell-border>tbody>tr>td:first-child{border-left:1px solid rgb(64, 67, 70)}html.dark .dataTables_wrapper .dataTables_filter input,html.dark .dataTables_wrapper .dataTables_length select{border:1px solid rgba(255, 255, 255, 0.2);background-color:var(--dt-html-background)}html.dark .dataTables_wrapper .dataTables_paginate .paginate_button.current,html.dark .dataTables_wrapper .dataTables_paginate .paginate_button.current:hover{border:1px solid rgb(89, 91, 94);background:rgba(255, 255, 255, 0.15)}html.dark .dataTables_wrapper .dataTables_paginate .paginate_button.disabled,html.dark .dataTables_wrapper .dataTables_paginate .paginate_button.disabled:hover,html.dark .dataTables_wrapper .dataTables_paginate .paginate_button.disabled:active{color:#666 !important}html.dark .dataTables_wrapper .dataTables_paginate .paginate_button:hover{border:1px solid rgb(53, 53, 53);background:rgb(53, 53, 53)}html.dark .dataTables_wrapper .dataTables_paginate .paginate_button:active{background:#3a3a3a} diff --git a/docs/articles/variables_sheet_files/dt-core-1.13.6/js/jquery.dataTables.min.js b/docs/articles/variables_sheet_files/dt-core-1.13.6/js/jquery.dataTables.min.js new file mode 100644 index 00000000..f786b0da --- /dev/null +++ b/docs/articles/variables_sheet_files/dt-core-1.13.6/js/jquery.dataTables.min.js @@ -0,0 +1,4 @@ +/*! DataTables 1.13.6 + * ©2008-2023 SpryMedia Ltd - datatables.net/license + */ +!function(n){"use strict";var a;"function"==typeof define&&define.amd?define(["jquery"],function(t){return n(t,window,document)}):"object"==typeof exports?(a=require("jquery"),"undefined"==typeof window?module.exports=function(t,e){return t=t||window,e=e||a(t),n(e,t,t.document)}:n(a,window,window.document)):window.DataTable=n(jQuery,window,document)}(function(P,j,v,H){"use strict";function d(t){var e=parseInt(t,10);return!isNaN(e)&&isFinite(t)?e:null}function l(t,e,n){var a=typeof t,r="string"==a;return"number"==a||"bigint"==a||!!h(t)||(e&&r&&(t=$(t,e)),n&&r&&(t=t.replace(q,"")),!isNaN(parseFloat(t))&&isFinite(t))}function a(t,e,n){var a;return!!h(t)||(h(a=t)||"string"==typeof a)&&!!l(t.replace(V,"").replace(/ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Authors and Citation • recodeflow - + - - - -
-
-
-
+
- @@ -184,22 +122,20 @@

Authors

-
- +
+ + - - - + diff --git a/docs/index.html b/docs/index.html index 8e040ca5..b72e1e2e 100644 --- a/docs/index.html +++ b/docs/index.html @@ -12,13 +12,13 @@ - + - + + +
-
-