diff --git a/.Rhistory b/.Rhistory index e57ef8c..3abf73f 100644 --- a/.Rhistory +++ b/.Rhistory @@ -1,207 +1,512 @@ -library(devtools) -load_all(".") -freq -freq.data.frame(esoph[, c("alcgp", "agegp")]) -unclass(freq.data.frame(esoph[, c("alcgp", "agegp")])) -q("no") -library(devtools) -args(build) -build(binary=T) -q("no") -args(print) -cross(cbind(...) ~ agegp, data = esoph, test = T) -library(biostat2) -cross(cbind(...) ~ agegp, data = esoph, test = T) -x = cross(cbind(...) ~ agegp, data = esoph, test = T) -res -res -load_all() -library(devtools) -load_all() -x = cross(cbind(...) ~ agegp, data = esoph, test = T) -x -q("no") -library(devtools) -load_all() -x = cross(cbind(...) ~ agegp, data = esoph, test = T) -x -class(x) -load_all() -x = cross(cbind(...) ~ agegp, data = esoph, test = T) -) -load_all() -x = cross(cbind(...) ~ agegp, data = esoph, test = T) -x -x -x -library(pander) -pander(x) -install.packages("pander") -library(pander) -pander(x) -knitr::kable(x) -x -unclass(x) -x -x = cross(cbind(...) ~ agegp, data = esoph, test = T) -x -as.data.frame(x) -fun(x) -length(esoph) -is.list(x) -is.data.frame(x) -x -x -x = cross(... ~ agegp, data = esoph, test = T) +varnames = names(data) +varnames = names(data) +parsed = parse_formula(formula, varnames) +data = parse_data(expand_formula(formula, varnames), data) +names(data) = remove_blank(names(data)) +varform = names(data) +if (regroup) { +numdata = varform[sapply(data, function(x) is.numeric(x) & !is.Surv(x))] +catdata = varform[sapply(data, is.character.or.factor)] +survdata = varform[sapply(data, is.Surv)] +parsed$left = regroup(parsed$left, numdata, catdata, survdata) +parsed$right = regroup(parsed$right, numdata, catdata, survdata) +} +eg = expand.grid(left=parsed$left, right=parsed$right, stringsAsFactors = F) +comb = eg %>% +pmap(list) %>% +modify_depth(2, ~{ +if(.x==".") return(NULL) +of = .x %>% .[.!="."] %>% elements %>% remove_blank +data %>% select(one_of(of)) +}) +results = comb %>% +map(cross_list, +funs=funs, ..., margin=margin, total=total, digits=digits, showNA=showNA, method=method, times=times, followup=followup, test=test, test.summarize=test.summarize, test.tabular=test.tabular, test.survival=test.survival, show.test=show.test, plim=plim, effect=effect, effect.summarize=effect.summarize, effect.tabular=effect.tabular, effect.survival=effect.survival, conf.level=conf.level, show.method=show.method, label=label) +results +comb +cross_list(comb[[1]], funs=funs, ..., margin=margin, total=total, digits=digits, showNA=showNA, method=method, times=times, followup=followup, test=test, test.summarize=test.summarize, test.tabular=test.tabular, test.survival=test.survival, show.test=show.test, plim=plim, effect=effect, effect.summarize=effect.summarize, effect.tabular=effect.tabular, effect.survival=effect.survival, conf.level=conf.level, show.method=show.method, label=label) +comb[[1]] +cross_list x -load_all() -x = cross(... ~ agegp, data = esoph, test = T) -load_all() -load_all() -x = cross(... ~ agegp, data = esoph, test = T) -q("no") -library(devtools);load_all() -x = cross(... ~ agegp, data = esoph, test = T) x -x = cross(cbind(...) ~ agegp, data = esoph, test = T) +x() +eg +eg +eg %>% +pmap(list) +results = data %>% select(x) %>% cross_list(funs=funs, ..., margin=margin, total=total, digits=digits, showNA=showNA, method=method, times=times, followup=followup, test=test, test.summarize=test.summarize, test.tabular=test.tabular, test.survival=test.survival, show.test=show.test, plim=plim, effect=effect, effect.summarize=effect.summarize, effect.tabular=effect.tabular, effect.survival=effect.survival, conf.level=conf.level, show.method=show.method, label=label) +vars_select(data, x) +tidyselect::vars_select(data, x) +tidyselect::vars_select(names(data), x) +cross_list +data %>% select(tidyselect::vars_select(names(data), x)) +tidyselect::vars_select(names(data), x) %>% class +data %>% select(tidyselect::vars_select(names(data), x)) %>% cross_list(funs=funs, ..., margin=margin, total=total, digits=digits, showNA=showNA, method=method, times=times, followup=followup, test=test, test.summarize=test.summarize, test.tabular=test.tabular, test.survival=test.survival, show.test=show.test, plim=plim, effect=effect, effect.summarize=effect.summarize, effect.tabular=effect.tabular, effect.survival=effect.survival, conf.level=conf.level, show.method=show.method, label=label) +results = data %>% select(tidyselect::vars_select(names(data), x)) %>% cross_list(data=., funs=funs, ..., margin=margin, total=total, digits=digits, showNA=showNA, method=method, times=times, followup=followup, test=test, test.summarize=test.summarize, test.tabular=test.tabular, test.survival=test.survival, show.test=show.test, plim=plim, effect=effect, effect.summarize=effect.summarize, effect.tabular=effect.tabular, effect.survival=effect.survival, conf.level=conf.level, show.method=show.method, label=label) +cross_all +comb +data +cross_list +source('F:/GITHUB/fork_biostat2/R/crosstable.r', encoding = 'UTF-8') +# Formula parsing ***************************************************** +browser() +varnames = names(data) +varnames = names(data) +parsed = parse_formula(formula, varnames) +data = parse_data(expand_formula(formula, varnames), data) +names(data) = remove_blank(names(data)) +varform = names(data) +if (regroup) { +numdata = varform[sapply(data, function(x) is.numeric(x) & !is.Surv(x))] +catdata = varform[sapply(data, is.character.or.factor)] +survdata = varform[sapply(data, is.Surv)] +parsed$left = regroup(parsed$left, numdata, catdata, survdata) +parsed$right = regroup(parsed$right, numdata, catdata, survdata) +} +eg = expand.grid(left=parsed$left, right=parsed$right, stringsAsFactors = F) +comb = eg %>% +pmap(list) %>% +modify_depth(2, ~{ +if(.x==".") return(NULL) +of = .x %>% .[.!="."] %>% elements %>% remove_blank +data %>% select(one_of(of)) +}) +data %>% select(tidyselect::vars_select(names(data), x)) +cross_list +comb +results = data %>% select(tidyselect::vars_select(names(data), x)) %>% cross_all(funs=funs, ..., margin=margin, total=total, digits=digits, showNA=showNA, method=method, times=times, followup=followup, test=test, test.summarize=test.summarize, test.tabular=test.tabular, test.survival=test.survival, show.test=show.test, plim=plim, effect=effect, effect.summarize=effect.summarize, effect.tabular=effect.tabular, effect.survival=effect.survival, conf.level=conf.level, show.method=show.method, label=label) +results +by +data %>% select(tidyselect::vars_select(names(data), by)) +x2 = data %>% select(tidyselect::vars_select(names(data), x)) +y2 +y2=NULL +cross_all(x2, y2, funs=funs, ..., margin=margin, total=total, digits=digits, showNA=showNA, method=method, times=times, followup=followup, test=test, test.summarize=test.summarize, test.tabular=test.tabular, test.survival=test.survival, show.test=show.test, plim=plim, effect=effect, effect.summarize=effect.summarize, effect.tabular=effect.tabular, effect.survival=effect.survival, conf.level=conf.level, show.method=show.method, label=label) +?select_ +cross_all x +x=starts_with("Sepal") x -unclass(x) -as.data.frame(x) -x -is.list(x) -unclass(x) -data.frame(unclass(x)) -data.frame(x) -library(devtools);load_all() -x = cross(cbind(...) ~ agegp, data = esoph, test = T) -x -class(x) -x = cross(... ~ agegp, data = esoph, test = T) -x -class(x) -class(x[[1]]) -check() -q("no") -q("no") -library(devtools) -document() -check() -check() -rename -x -load_all() -x = cross(... ~ agegp, data = esoph, test = T) -x -x = cross(cbind(...) ~ agegp, data = esoph, test = T) -x -names(x) -names(x)[1] <- "modalité" -x -load_all() -x = cross(cbind(...) ~ agegp, data = esoph, test = T) -names(x)[1] <- "modalité" -x -names(x)[1] <- "Variable" -x -build() -build(binary = T) -install_local("../biostat2_0.1.zip") -q("no") -library(devtools) -build() -build(binary = TRUE) -q("no") -load_all() -library(devtools) -load_all() -library(survival) -cross(Surv(time, status) ~ x, data = aml, total= T, test = T) -q("no") -library(devtools) -build() -build(binary = T) -install.packages("../biostat2_0.2.zip") -q("no") -args(t.test) -?t.test -?wilcox.test -sapply(esoph$ncases, esoph$alcgp) -sapply(esoph$ncases, esoph$alcgp, c) -tapply(esoph$ncases, esoph$alcgp, c) -tapply(esoph$ncases, esoph$alcgp, c, simplify = FALSE) -?wilcox.test -?t.test -load.all() -library(devtools) -load_all() -cross(cbind(...) ~ alcgp, data = esoph, test = T) -esoph$trt <- rep(c("A", "B"), length = nrow(esoph)) -cross(cbind(...) ~ alcgp, data = esoph, test = T) -esoph$num <- rnorm(nrow(esoph)) -cross(cbind(...) ~ alcgp, data = esoph, test = T) -cross(cbind(...) ~ trt, data = esoph, test = T) -?wilcox.test -kruskal.test(esoph$ncases, esoph$trt) -kruskal.test(esoph$ncases ~ esoph$trt) -esoph$trt -esoph$ncases -kruskal.test(esoph$ncases, esoph$trt) -kruskal.test(esoph$ncases, factor(esoph$trt)) -wilcox.test(esoph$ncases ~factor(esoph$trt), correct = F) -?kruskall -?kruskall.t -?kruskal.test -oneway.test(esoph$num ~ esoph$trt, var.equal = FALSE) -oneway.test(esoph$num ~ esoph$trt, var.equal = TRUE) -t.test(esoph$num ~ esoph$trt, var.equal = TRUE) -t.test(esoph$num ~ esoph$trt, var.equal = FALSE) -?t.test -check() -check() -load_all() -cross(cbind(...) ~ trt, data = esoph, test = T) -cross(cbind(...) ~ trt, data = esoph, test = T, test.summarize = test.summarize.kruskal) -load_all() -cross(cbind(...) ~ trt, data = esoph, test = T, test.summarize = test.summarize.kruskal) -cross(cbind(...) ~ trt, data = esoph, test = T) -cross(cbind(...) ~ trt, data = esoph, test = T, test.summarize = test.summarize.kruskal) -cross(cbind(...) ~ trt, data = esoph, test = T, test.summarize = test.summarize.oneway.equal) -cross(cbind(...) ~ trt, data = esoph, test = T, test.summarize = test.summarize.oneway.equalvar) -cross(cbind(...) ~ trt, data = esoph, test = T, test.summarize = test.summarize.oneway.unequalvar) -cross(cbind(...) ~ trt, data = esoph, test = T, test.summarize = test.summarize.kruskal) -cross(cbind(num) ~ trt, data = esoph, test = T, test.summarize = test.summarize.kruskal) -cross(cbind(ncases) ~ trt, data = esoph, test = T, test.summarize = test.summarize.kruskal) -wilcox.test(esoph$num ~ esoph$trt) -cross(cbind(num) ~ trt, data = esoph, test = T, test.summarize = test.summarize.kruskal) -cross(cbind(ncases) ~ trt, data = esoph, test = T, test.summarize = test.summarize.kruskal) -cross(cbind(num) ~ trt, data = esoph, test = T, test.summarize = test.summarize.kruskal) -cross(cbind(num) ~ alcgp, data = esoph, test = T, test.summarize = test.summarize.kruskal) -build() -build(binary = TRUE) -install.packages("../biostat2_0.5.zip") -q("no") -library(devtools) -document() -build() -load_all() -FlexCrossTable -?FlexCrossTable - library(ReporteRs) - mytable <- cross(cbind(...) ~ tobgp, esoph, test = TRUE) - CrossFlexTable(mytable) - -document() -load_all() - library(ReporteRs) - mytable <- cross(cbind(...) ~ tobgp, esoph, test = TRUE) - CrossFlexTable(mytable) - -load_all() - FlexCrossTable(mytable) - FlexCrossTable(mytable, TRUE) -build() -build(binary = TRUE) -q("no") -install.packages("../biostat2_0.6.zip", repos = NULL) -q("no") +source('F:/GITHUB/fork_biostat2/R/crosstable.r', encoding = 'UTF-8') +tidyselect::vars_select(names(data), x) %>% class +tidyselect::vars_select(names(data), x) +source('F:/GITHUB/fork_biostat2/R/crosstable.r', encoding = 'UTF-8') +tidyselect::vars_select(names(data), x) +y2 = data %>% select(tidyselect::vars_select(names(data), by)) +y2 +x2 = data %>% select(tidyselect::vars_select(names(data), x, -by)) +x2 +results = cross_all(x2, y2, funs=funs, ..., margin=margin, total=total, digits=digits, showNA=showNA, method=method, times=times, followup=followup, test=test, test.summarize=test.summarize, test.tabular=test.tabular, test.survival=test.survival, show.test=show.test, plim=plim, effect=effect, effect.summarize=effect.summarize, effect.tabular=effect.tabular, effect.survival=effect.survival, conf.level=conf.level, show.method=show.method, label=label) +results +assert_scalar +y2 +byname = tidyselect::vars_select(names(data), by) +byname +assert_scalar(byname) +x2 +assert_scalar(y2) +check_scalar(byname) +check_scalar(y2) +test_scalar(y2) +install.packages("assertive") +assertive::assert_is_scalar(byname) +assertive::assert_is_scalar(y2) +y2 +xname = tidyselect::vars_select(names(data), x, -by) +assertive::assert_is_scalar(xname) +assert_scalar(xname) +assert_scalar(xname, .var.name = "frfrfr") +cross_all +##' @export +##' @import checkmate dplyr purrr +crosstable = function(data, x=everything(), by=NULL, formula = cbind(...) ~ ., funs = c(" " = cross_summary), ..., margin = c("all", "row", "column", "cell"), total = c("none", "all", "row", "column", "FALSE", "TRUE", 0, 1, 2), digits = 2, showNA = c("no", "ifany", "always"), method = c("pearson", "kendall", "spearman"), times = NULL, followup = FALSE, test = FALSE, test.summarize = test.summarize.auto, test.survival = test.survival.logrank, test.tabular = test.tabular.auto, show.test = display.test, plim = 4, show.method = TRUE, effect = FALSE, effect.summarize = diff.mean.auto, effect.tabular = or.row.by.col, effect.survival = effect.survival.coxph, conf.level = 0.95, label = TRUE, regroup = FALSE) { +# Arguments checks **************************************************** +coll = makeAssertCollection() +# assertFormula(formula, add=coll) +assertDataFrame(data, add=coll) +assertCount(digits, add=coll) +assertLogical(label, add=coll) +if (!is.character(funs)) { +nomf = names(funs) +funs = as.character(as.list(substitute(funs))) +funs = funs[funs != "c" & funs != "list"] +names(funs) = nomf +} +if (missing(margin)) margin = "all" +if (is.character(margin)) { +assertSubset(margin, c("all", "row", "column", "cell"), add=coll) +if(is.null(margin)) { +margin=0:2 #defaulting +} else { +marginopts = list(all = 0:2, +row = 1, +column = 2, +cell = 0) +margin = unname(unlist(marginopts[margin])) +} +} +if (missing(total)) total = "none" +if (is.character(total)) { +assertChoice(total, c("none", "both", "all", "row", "column"), add=coll) +if(is.null(total)) { +total=0 #defaulting +} else { +totalopts = list(all = 1:2, +both = 1:2, +row = 1, +column = 2, +none = 0) +total = unname(unlist(totalopts[total])) +} +} +if (is_formula(formula)) +formula = paste(deparse(formula, 500), collapse="") +reportAssertions(coll) +byname = tidyselect::vars_select(names(data), by) +xnames = tidyselect::vars_select(names(data), x, -by) +assert_scalar(byname, .var.name = "by") +assert_(xnames, .var.name = "x") +# Formula parsing ***************************************************** +# varnames = names(data) +# parsed = parse_formula(formula, varnames) +# # parsed$left = gsub("\\n *", "", parsed$left) +# +# data = parse_data(expand_formula(formula, varnames), data) +# names(data) = remove_blank(names(data)) +# varform = names(data) +# +# if (regroup) { +# numdata = varform[sapply(data, function(x) is.numeric(x) & !is.Surv(x))] +# catdata = varform[sapply(data, is.character.or.factor)] +# survdata = varform[sapply(data, is.Surv)] +# +# parsed$left = regroup(parsed$left, numdata, catdata, survdata) +# parsed$right = regroup(parsed$right, numdata, catdata, survdata) +# } +# +# eg = expand.grid(left=parsed$left, right=parsed$right, stringsAsFactors = F) +# #eg (DF) : chaque ligne est une combinaison by en fonction du nombre de + +# +# +# comb = eg %>% +# pmap(list) %>% +# modify_depth(2, ~{ +# if(.x==".") return(NULL) +# of = .x %>% .[.!="."] %>% elements %>% remove_blank +# data %>% select(one_of(of)) +# }) +# +# +# # Results ***************************************************** +# +# results = comb %>% +# map(cross_list, funs=funs, ..., margin=margin, total=total, digits=digits, showNA=showNA, method=method, times=times, followup=followup, test=test, test.summarize=test.summarize, test.tabular=test.tabular, test.survival=test.survival, show.test=show.test, plim=plim, effect=effect, effect.summarize=effect.summarize, effect.tabular=effect.tabular, effect.survival=effect.survival, conf.level=conf.level, show.method=show.method, label=label) +# browser() +tidyselect::vars_select(names(data), x) +y2 = data %>% select(byname) +x2 = data %>% select(xnames) +results = cross_all(x2, y2, funs=funs, ..., margin=margin, total=total, digits=digits, showNA=showNA, method=method, times=times, followup=followup, test=test, test.summarize=test.summarize, test.tabular=test.tabular, test.survival=test.survival, show.test=show.test, plim=plim, effect=effect, effect.summarize=effect.summarize, effect.tabular=effect.tabular, effect.survival=effect.survival, conf.level=conf.level, show.method=show.method, label=label) +if (length(results) == 1) { +results = results[[1]] +class(results) = c("crosstable", "data.frame") +} else { +results = results[results != "What?"] +} +# attr(results, "formula") = formula +# attr(results, "left") = parsed$left +# attr(results, "right") = parsed$right +# attr(results, "by") = parsed$by +# attr(results, "data") = data +return(results) +} +crosstable(data = iris, x=starts_with("S"), by="Species") +source('F:/GITHUB/fork_biostat2/R/crosstable.r', encoding = 'UTF-8') +crosstable(data = iris, x=starts_with("S"), by="Species") +cross_list +source('F:/GITHUB/fork_biostat2/R/crosstable.r', encoding = 'UTF-8') +data +varnames = names(data) +parsed = parse_formula(formula, varnames) +parse_data(expand_formula(formula, varnames), data) +x2 = data %>% select(xnames) +y2 = data %>% select(byname) +x2 +y2 +cross_all(x2, y2, funs=funs, ..., margin=margin, total=total, digits=digits, showNA=showNA, method=method, times=times, followup=followup, test=test, test.summarize=test.summarize, test.tabular=test.tabular, test.survival=test.survival, show.test=show.test, plim=plim, effect=effect, effect.summarize=effect.summarize, effect.tabular=effect.tabular, effect.survival=effect.survival, conf.level=conf.level, show.method=show.method, label=label) +source('F:/GITHUB/fork_biostat2/R/crosstable.r', encoding = 'UTF-8') +crosstable(data = iris, x=starts_with("S"), by="Species") +crosstable(data = iris, x=everything(), by="Species") +crosstable(data = iris, x=everything()) +source('F:/GITHUB/fork_biostat2/R/crosstable.r', encoding = 'UTF-8') +by +tidyselect::vars_select(names(data), x, -by) +byname = tidyselect::vars_select(names(data), by) +byname +tidyselect::vars_select(names(data), x, -byname) +source('F:/GITHUB/fork_biostat2/R/crosstable.r', encoding = 'UTF-8') +source('F:/GITHUB/fork_biostat2/R/crosstable.r', encoding = 'UTF-8') +crosstable(data = iris, x=starts_with("S")) +crosstable(data = iris, x=everything()) +##' @export +##' @import checkmate dplyr purrr +crosstable = function(data, x=everything(), by=NULL, formula = cbind(...) ~ ., funs = c(" " = cross_summary), ..., margin = c("all", "row", "column", "cell"), total = c("none", "all", "row", "column", "FALSE", "TRUE", 0, 1, 2), digits = 2, showNA = c("no", "ifany", "always"), method = c("pearson", "kendall", "spearman"), times = NULL, followup = FALSE, test = FALSE, test.summarize = test.summarize.auto, test.survival = test.survival.logrank, test.tabular = test.tabular.auto, show.test = display.test, plim = 4, show.method = TRUE, effect = FALSE, effect.summarize = diff.mean.auto, effect.tabular = or.row.by.col, effect.survival = effect.survival.coxph, conf.level = 0.95, label = TRUE, regroup = FALSE) { +# Arguments checks **************************************************** +coll = makeAssertCollection() +# assertFormula(formula, add=coll) +assertDataFrame(data, add=coll) +assertCount(digits, add=coll) +assertLogical(label, add=coll) +if (!is.character(funs)) { +nomf = names(funs) +funs = as.character(as.list(substitute(funs))) +funs = funs[funs != "c" & funs != "list"] +names(funs) = nomf +} +if (missing(margin)) margin = "all" +if (is.character(margin)) { +assertSubset(margin, c("all", "row", "column", "cell"), add=coll) +if(is.null(margin)) { +margin=0:2 #defaulting +} else { +marginopts = list(all = 0:2, +row = 1, +column = 2, +cell = 0) +margin = unname(unlist(marginopts[margin])) +} +} +if (missing(total)) total = "none" +if (is.character(total)) { +assertChoice(total, c("none", "both", "all", "row", "column"), add=coll) +if(is.null(total)) { +total=0 #defaulting +} else { +totalopts = list(all = 1:2, +both = 1:2, +row = 1, +column = 2, +none = 0) +total = unname(unlist(totalopts[total])) +} +} +if (is_formula(formula)) +formula = paste(deparse(formula, 500), collapse="") +reportAssertions(coll) +# browser() +byname = tidyselect::vars_select(names(data), by) +xnames = tidyselect::vars_select(names(data), x, -byname) +assert_scalar(byname, .var.name = "by") +# Formula parsing ***************************************************** +# varnames = names(data) +# parsed = parse_formula(formula, varnames) +# # parsed$left = gsub("\\n *", "", parsed$left) +# +# data = parse_data(expand_formula(formula, varnames), data) +# names(data) = remove_blank(names(data)) +# varform = names(data) +# +# if (regroup) { +# numdata = varform[sapply(data, function(x) is.numeric(x) & !is.Surv(x))] +# catdata = varform[sapply(data, is.character.or.factor)] +# survdata = varform[sapply(data, is.Surv)] +# +# parsed$left = regroup(parsed$left, numdata, catdata, survdata) +# parsed$right = regroup(parsed$right, numdata, catdata, survdata) +# } +# +# eg = expand.grid(left=parsed$left, right=parsed$right, stringsAsFactors = F) +# #eg (DF) : chaque ligne est une combinaison by en fonction du nombre de + +# +# +# comb = eg %>% +# pmap(list) %>% +# modify_depth(2, ~{ +# if(.x==".") return(NULL) +# of = .x %>% .[.!="."] %>% elements %>% remove_blank +# data %>% select(one_of(of)) +# }) +# +# +# # Results ***************************************************** +# +# results = comb %>% +# map(cross_list, funs=funs, ..., margin=margin, total=total, digits=digits, showNA=showNA, method=method, times=times, followup=followup, test=test, test.summarize=test.summarize, test.tabular=test.tabular, test.survival=test.survival, show.test=show.test, plim=plim, effect=effect, effect.summarize=effect.summarize, effect.tabular=effect.tabular, effect.survival=effect.survival, conf.level=conf.level, show.method=show.method, label=label) +# browser() +# tidyselect::vars_select(names(data), x) +x2 = data %>% select(xnames) +y2 = data %>% select(byname) +results = cross_all(x2, y2, funs=funs, ..., margin=margin, total=total, digits=digits, showNA=showNA, method=method, times=times, followup=followup, test=test, test.summarize=test.summarize, test.tabular=test.tabular, test.survival=test.survival, show.test=show.test, plim=plim, effect=effect, effect.summarize=effect.summarize, effect.tabular=effect.tabular, effect.survival=effect.survival, conf.level=conf.level, show.method=show.method, label=label) +# if (length(results) == 1) { +# results = results[[1]] +# } else { +# results = results[results != "What?"] +# } +class(results) = c("crosstable", "data.frame") +# attr(results, "formula") = formula +# attr(results, "left") = parsed$left +# attr(results, "right") = parsed$right +# attr(results, "by") = parsed$by +# attr(results, "data") = data +return(results) +} +crosstable(data = iris, x=starts_with("S"), by="Species") +crosstable(data = iris, x=starts_with("S")) +source('F:/GITHUB/fork_biostat2/R/crosstable.r', encoding = 'UTF-8') +source('F:/GITHUB/fork_biostat2/R/crosstable.r', encoding = 'UTF-8') +crosstable(data = iris, x=starts_with("S"), by="Species") +crosstable(data = iris, x=starts_with("S")) +crosstable(data = iris, x=everything()) +source('F:/GITHUB/fork_biostat2/R/crosstable.r', encoding = 'UTF-8') +byname = tidyselect::vars_select(names(data), by) +byname +xnames = tidyselect::vars_select(names(data), x, -byname) +xnames +assert_scalar(byname, .var.name = "by", null.ok = T) +byname = tidyselect::vars_select(names(data), by) +xnames = tidyselect::vars_select(names(data), x, -byname) +byname +xnames +x2 = data %>% select(xnames) +y2 = data %>% select(byname) +x2 +y2 +install.packages("assertive") +ncol(y2) +source('F:/GITHUB/fork_biostat2/R/crosstable.r', encoding = 'UTF-8') +##' @export +##' @import checkmate dplyr purrr +crosstable = function(data, x=everything(), by=NULL, formula = cbind(...) ~ ., funs = c(" " = cross_summary), ..., margin = c("all", "row", "column", "cell"), total = c("none", "all", "row", "column", "FALSE", "TRUE", 0, 1, 2), digits = 2, showNA = c("no", "ifany", "always"), method = c("pearson", "kendall", "spearman"), times = NULL, followup = FALSE, test = FALSE, test.summarize = test.summarize.auto, test.survival = test.survival.logrank, test.tabular = test.tabular.auto, show.test = display.test, plim = 4, show.method = TRUE, effect = FALSE, effect.summarize = diff.mean.auto, effect.tabular = or.row.by.col, effect.survival = effect.survival.coxph, conf.level = 0.95, label = TRUE, regroup = FALSE) { +# Arguments checks **************************************************** +coll = makeAssertCollection() +# assertFormula(formula, add=coll) +assertDataFrame(data, add=coll) +assertCount(digits, add=coll) +assertLogical(label, add=coll) +if (!is.character(funs)) { +nomf = names(funs) +funs = as.character(as.list(substitute(funs))) +funs = funs[funs != "c" & funs != "list"] +names(funs) = nomf +} +if (missing(margin)) margin = "all" +if (is.character(margin)) { +assertSubset(margin, c("all", "row", "column", "cell"), add=coll) +if(is.null(margin)) { +margin=0:2 #defaulting +} else { +marginopts = list(all = 0:2, +row = 1, +column = 2, +cell = 0) +margin = unname(unlist(marginopts[margin])) +} +} +if (missing(total)) total = "none" +if (is.character(total)) { +assertChoice(total, c("none", "both", "all", "row", "column"), add=coll) +if(is.null(total)) { +total=0 #defaulting +} else { +totalopts = list(all = 1:2, +both = 1:2, +row = 1, +column = 2, +none = 0) +total = unname(unlist(totalopts[total])) +} +} +if (is_formula(formula)) +formula = paste(deparse(formula, 500), collapse="") +reportAssertions(coll) +# browser() +byname = tidyselect::vars_select(names(data), by) +xnames = tidyselect::vars_select(names(data), x, -byname) +assert_scalar(byname, .var.name = "by", null.ok = T) +# Formula parsing ***************************************************** +# varnames = names(data) +# parsed = parse_formula(formula, varnames) +# # parsed$left = gsub("\\n *", "", parsed$left) +# +# data = parse_data(expand_formula(formula, varnames), data) +# names(data) = remove_blank(names(data)) +# varform = names(data) +# +# if (regroup) { +# numdata = varform[sapply(data, function(x) is.numeric(x) & !is.Surv(x))] +# catdata = varform[sapply(data, is.character.or.factor)] +# survdata = varform[sapply(data, is.Surv)] +# +# parsed$left = regroup(parsed$left, numdata, catdata, survdata) +# parsed$right = regroup(parsed$right, numdata, catdata, survdata) +# } +# +# eg = expand.grid(left=parsed$left, right=parsed$right, stringsAsFactors = F) +# #eg (DF) : chaque ligne est une combinaison by en fonction du nombre de + +# +# +# comb = eg %>% +# pmap(list) %>% +# modify_depth(2, ~{ +# if(.x==".") return(NULL) +# of = .x %>% .[.!="."] %>% elements %>% remove_blank +# data %>% select(one_of(of)) +# }) +# +# +# # Results ***************************************************** +# +# results = comb %>% +# map(cross_list, funs=funs, ..., margin=margin, total=total, digits=digits, showNA=showNA, method=method, times=times, followup=followup, test=test, test.summarize=test.summarize, test.tabular=test.tabular, test.survival=test.survival, show.test=show.test, plim=plim, effect=effect, effect.summarize=effect.summarize, effect.tabular=effect.tabular, effect.survival=effect.survival, conf.level=conf.level, show.method=show.method, label=label) +# browser() +# tidyselect::vars_select(names(data), x) +x2 = data %>% select(xnames) +y2 = data %>% select(byname) +if(ncol(y2)==0) y2=NULL +results = cross_all(x2, y2, funs=funs, ..., margin=margin, total=total, digits=digits, showNA=showNA, method=method, times=times, followup=followup, test=test, test.summarize=test.summarize, test.tabular=test.tabular, test.survival=test.survival, show.test=show.test, plim=plim, effect=effect, effect.summarize=effect.summarize, effect.tabular=effect.tabular, effect.survival=effect.survival, conf.level=conf.level, show.method=show.method, label=label) +# if (length(results) == 1) { +# results = results[[1]] +# } else { +# results = results[results != "What?"] +# } +class(results) = c("crosstable", "data.frame") +# attr(results, "formula") = formula +# attr(results, "left") = parsed$left +# attr(results, "right") = parsed$right +# attr(results, "by") = parsed$by +# attr(results, "data") = data +return(results) +} +crosstable(data = iris, x=starts_with("S"), by="Species") +crosstable(data = iris, x=starts_with("S")) +source('F:/GITHUB/fork_biostat2/R/crosstable.r', encoding = 'UTF-8') +crosstable(data = iris, x=starts_with("S"), by="Species") +crosstable(data = iris, x=starts_with("S")) +crosstable(data = iris, x=everything()) +crosstable(data = iris, x=Sepal.Length, by="Species") +select +dplyr:::select.data.frame +dplyr:::select_impl +`!!!` +?`!!!` +crosstable(data = iris, x="Sepal.Length", by="Species") +?mean_by +??mean_by +tbl_vars +dplyr:::tbl_vars.data.frame +dplyr:::tbl_vars.tbl_cube +tbl_cube +?tbl_cube +nasa +head(as.data.frame(nasa)) +titanic <- as.tbl_cube(Titanic) +head(as.data.frame(titanic)) +as.tbl_cube(Titanic) %>% head +as.tbl_cube(Titanic) +(Titanic) +cross_all +cross_one +library(gmodels) +data(infert, package = "datasets") +CrossTable(infert$education, infert$induced, expected = TRUE) +library(biostat2) +library(biostat2) diff --git a/.gitignore b/.gitignore index 3b26574..8aae547 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,16 @@ + +# RStudio internals +.Rproj.user +*.RData +*.Rhistory +.Rhistory + +# MS Word files +test*.docx +~*.docx + + + # Windows image file caches Thumbs.db ehthumbs.db @@ -21,21 +34,18 @@ $RECYCLE.BIN/ # OSX # ========================= -.DS_Store -.AppleDouble -.LSOverride - -# Icon must ends with two \r. -Icon - -# Thumbnails -._* - -# Files that might appear on external disk -.Spotlight-V100 -.Trashes +.DS_Store +.AppleDouble +.LSOverride + +# Icon must ends with two \r. +Icon + + +# Thumbnails +._* + +# Files that might appear on external disk +.Spotlight-V100 +.Trashes *~ -*.Rhistory -*.Rhistory -*.Rhistory -.Rproj.user diff --git a/DESCRIPTION b/DESCRIPTION index 7c47516..1cd7058 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,19 +1,33 @@ Package: biostat2 Title: biostat, mais 2 -Version: 0.9.0 -Authors@R: person("David", "Hajage", email = "david.hajage@lmr.aphp.fr", role = - c("aut", "cre")) -Description: Fonctions facilitant la description et l'analyse +Encoding: UTF-8 +Version: 0.13.0 +Authors@R: c( + person("David", "Hajage", email = "david.hajage@lmr.aphp.fr", role = c("aut", "cre")), + person("Dan", "Chaltiel", email = "dan.chaltiel@gmail.com", role = c("ctb"))) +Description: Fonctions facilitant la description et l'analyse. Depends: R (>= 3.1.0) Imports: stats, plyr, + dplyr, + purrr, + checkmate, reshape2, Hmisc, survival, - ReporteRs, + methods, + gmodels, + DescTools, + officer, + flextable, + lifecycle, nortest License: GPL (>= 2) LazyData: true -RoxygenNote: 6.0.1 +RoxygenNote: 7.1.0 +Suggests: + testthat, + ReporteRs +RdMacros: lifecycle diff --git a/NAMESPACE b/NAMESPACE index 1e50824..fa3281f 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -1,8 +1,10 @@ # Generated by roxygen2: do not edit by hand +S3method(diff,mean.auto) +S3method(diff,mean.boot) +S3method(diff,mean.student) +S3method(diff,median) export(FlexCrossTable) -export(Max) -export(Min) export(addAlert) export(addCode) export(addComment) @@ -13,28 +15,61 @@ export(addNormal) export(addPlotlegend) export(addTablegend) export(addVerbatim) +export(as.crosstable) +export(body_add_crosstable) +export(body_add_crosstable_bak) +export(body_add_glued) +export(body_add_normal) +export(body_add_table_legend) +export(body_add_title) +export(compact) export(create.report) export(cross) +export(cross_to_flextable) export(display.effect) export(display.test) +export(effect.survival.coxph) export(expand) +export(format_fixed) +export(mediqr) +export(minmax) +export(moystd) export(n) export(na) +export(nna) +export(or.col.by.row) +export(or.row.by.col) export(paste.matrix) export(plim) export(rbind_crosstable) +export(rd.col.by.row) +export(rd.row.by.col) +export(rr.col.by.row) +export(rr.row.by.col) export(simple.table) export(test.summarize.auto) export(test.summarize.auto.old) +export(test.summarize.contrasts.lin) export(test.summarize.kruskal) export(test.summarize.oneway.equalvar) export(test.summarize.oneway.unequalvar) export(test.survival.logrank) export(test.tabular.auto) export(test.tabular.fisher) -import(ReporteRs) +import(checkmate) +import(flextable) +import(gmodels) +import(officer) +import(stats) import(survival) +importFrom(DescTools,CochranArmitageTest) importFrom(Hmisc,label) +importFrom(dplyr,"%>%") +importFrom(dplyr,lead) +importFrom(dplyr,select) +importFrom(dplyr,sym) +importFrom(lifecycle,deprecate_warn) +importFrom(methods,is) importFrom(nortest,ad.test) importFrom(plyr,.) importFrom(plyr,alply) diff --git a/R/addCrossTable.r b/R/body_add_crosstable.r similarity index 55% rename from R/addCrossTable.r rename to R/body_add_crosstable.r index 2d08bef..4ad7ac7 100644 --- a/R/addCrossTable.r +++ b/R/body_add_crosstable.r @@ -1,10 +1,13 @@ ##' Compact the result of cross function ##' -##' @param x x +##' @param x a crosstable, the result of \code{cross} function ##' @author David Hajage -##' @keywords internal -##' @importFrom plyr alply -##' @importFrom plyr dlply +##' @importFrom plyr alply dlply +##' @export +##' +##' @examples +##' mytable <- cross(cbind(...) ~ tobgp, esoph, test = TRUE) +##' compact(mytable) compact <- function(x) { ordre <- unique(x$.id) if ("p" %in% names(x) | "effect" %in% names(x)) { @@ -76,35 +79,338 @@ compact <- function(x) { res[res[, 1] == " Effect", which(colnames(res) == "variable")] <- " Effect" } + res <- as.data.frame(res) + attr(res, "noms.col") <- attr(x, "noms.col") + attr(res, "labs.col") <- attr(x, "labs.col") + class(res) <- c("cross", "data.frame", "compacted") res } -##' Create a FlexTable object from a table made by the cross function -##' -##' @name FlexCrossTable-ReporteRs -##' @param crosstable the result of \code{cross} function -##' @param compact compact the table? -##' @param id name of the 'id' column -##' @param variable name of the 'variable' column -##' @param value name of the 'value' column -##' @param effect name of the 'effect' column -##' @param p name of the 'p' column -##' @return -##' A \code{FlexTable} object (see \code{ReporteRs} package) -##' @author David Hajage -##' @examples -##' \dontrun{ -##' library(biostat2) -##' library(ReporteRs) -##' mytable <- cross(cbind(...) ~ tobgp, esoph, test = TRUE) -##' FlexCrossTable(mytable) -##' FlexCrossTable(mytable, TRUE) -##' } -##' @keywords univar -##' @export -##' @import ReporteRs -FlexCrossTable <- function(crosstable, compact = FALSE, id = ".id", variable = "variable", value = "value", effect = "effect", p = "p") { +#TODO: implement +# compact_dataframe = function(data, name_from, name_to, rtn_flextable=T){ +# tmp=data.frame() +# id=(data[[name_from]]!=lag(data[[name_from]])) %>% replace_na(TRUE) +# for (i in 1:sum(id)) { +# x1=which(id)[i] +# x2=which(id)[i+1]-1 +# if(is.na(x2)) x2=nrow(data) +# row = data[1,] %>% mutate_all(~"") %>% mutate(!!sym(name_to):=data[x1,name_from]) +# tmp=rbind(tmp, row, data[x1:x2,]) +# } +# tmp=tmp %>% select(-!!sym(name_from)) +# if(rtn_flextable){ +# id2=which(id)+(0:(sum(id)-1)) +# tmp = tmp %>% flextable %>% border(id2, border.top = fp_border()) %>% +# bold(id2) %>% align(id2, align="left") +# } +# tmp +# } + + + + +#' Crosstables output +#' @description \code{cross_to_flextable} turns a table made by the cross function into a flextable. +#' +#' @param crosstable the result of \code{cross} function +#' @param compact whether to compact the table +#' @param auto.fit whether to \code{flextable::autofit} the table +#' @param id name of the 'id' column +#' @param variable name of the 'variable' column +#' @param label name of the 'label' column +#' @param value name of the 'value' column +#' @param p name of the 'p' column +#' @param show.test.name in the p column, show the test name +#' +#' @return A \code{rdocx} object +#' @author Dan Chaltiel +#' @importFrom dplyr select lead sym %>% +#' @importFrom methods is +#' @import officer flextable +#' @export +#' +#' @examples +#' ### cross_to_flextable +#' library(dplyr) #for the pipe operator +#' library(officer) +#' cross(cbind(...) ~ tobgp, esoph, test = TRUE) %>% cross_to_flextable +#' cross(cbind(...) ~ Species, iris, test = TRUE) %>% cross_to_flextable +#' cross(cbind(...) ~ ., esoph) %>% cross_to_flextable +#' +cross_to_flextable = + function (crosstable, compact = FALSE, auto.fit = FALSE, + id = ".id", variable = "variable", label = "label", value = "value", p = "p", effect="effect", total="Total", + show.test.name = F, generic.labels=c(id, variable, label, value, p, effect, total)) { + stopifnot(is.data.frame(crosstable)) + border1 <- fp_border(color = "black", style = "solid", width = 1) + border2 <- fp_border(color = "black", style = "solid", width = 1.5) + labs.col <- attr(crosstable, "labs.col") + labs.names <- crosstable %>% names %>% .[!(. %in% generic.labels)] + is_tested = crosstable %>% names %>% grepl(p, .) %>% any + is_multiple = crosstable %>% names %>% grepl(value, .) %>% any %>% `!` + has_total = crosstable %>% names %>% grepl(total, .) %>% any + has_effect = crosstable %>% names %>% grepl(effect, .) %>% any + rtn = crosstable + if (is_tested && !show.test.name) { + rtn$p = rtn$p %>% gsub(" \\(.*\\)", "", .) + } + if (compact && !is(rtn, "compacted")) { + rtn <- compact(rtn) + } + if (is(rtn, "compacted")) { + sep.rows <- which(rtn[, 1] %in% crosstable$label)[-1] + rtn <- rtn %>% as.data.frame %>% flextable %>% hline(i=sep.rows - 1, border=border1) + if (is_multiple) { + header_colwidths = if (is_tested) c(1, ncol(crosstable) - 4) + else c(1, ncol(crosstable) - 3) + rtn <- rtn %>% + add_header_row(values=c(variable, labs.col), colwidths=header_colwidths) %>% + merge_v(j = 1, part = "head") %>% + merge_h(i = c(1, sep.rows, sep.rows + 1)) %>% + bold(i = c(1, sep.rows)) + } + } + else { + sep.rows <- which(rtn$label != lead(rtn$label)) + rtn <- rtn %>% select(-!!sym(id)) %>% flextable %>% hline(i=sep.rows, border=border1) + if (is_multiple) { + r = labs.names %>% + gsub("([\\\\\\^\\$\\.\\|\\?\\*\\+\\(\\)\\[\\{])", "\\\\\\1", .) %>% + paste(collapse="|") + header_values = crosstable %>% select(-id) %>% names %>% + gsub(r, labs.col, .) %>% unique + header_colwidths = ifelse(header_values==labs.col, sum(names(crosstable) %in% labs.names), 1) + # browser() + + head_merge = header_values[!header_values %in% labs.col] + rtn <- rtn %>% + add_header_row(values = header_values, colwidths = header_colwidths) %>% + merge_v(j = head_merge, part = "head") + } + body_merge = if (is_tested) c(label, p) else label + body_merge = if (has_effect) c(body_merge, effect) else body_merge + rtn <- rtn %>% + merge_v(j = label, target=body_merge, part = "body") + } + rtn <- rtn %>% + bold(part = "head") %>% + align(align = "left", part = "all") %>% + align(i = 1, align = "center", part = "head") %>% + hline_top(border = border2, part = "head") %>% + hline_bottom(border = border2, part = "head") %>% + border_inner_h(border = border2, part = "head") %>% + fix_border_issues + + if (auto.fit) { + rtn <- autofit(rtn) + } + return(rtn) +} + + +#' body_add_crosstable +#' @description \code{body_add_crosstable2} adds a table made by the cross function into an officer document +#' +#' @param doc a \code{rdocx} object created by \code{read_docx} function (see \code{officer} package) +#' @param ... arguments for \code{cross_to_flextable} +#' +#' @export +#' @rdname cross_to_flextable +#' +#' @examples +#' ### body_add_crosstable +#' #mytable <- cross(cbind(...) ~ tobgp, esoph, test = TRUE) +#' #mytable <- cross(cbind(...) ~ Species, iris, test = TRUE) +#' mytable <- cross(cbind(...) ~ ., esoph) +#' doc <- read_docx() %>% +#' body_add_crosstable(mytable) %>% +#' body_add_break %>% +#' body_add_crosstable(mytable, compact=TRUE) +#' +#' \dontrun{ +#' dfile <- "test_doc.docx" +#' print(doc, target = dfile) +#' shell.exec(dfile) +#' } +body_add_crosstable = function (doc, ...) { + ft = cross_to_flextable(...) + doc <- body_add_flextable(doc, ft) + return(doc) +} + + + + + + +#' Coerce to a Crosstable (for officer docx addition) +#' +#' @param df a data.frame +#' @param labs.col the name of the grouping variable +#' +#' @return a cross +#' @export +#' +#' @examples +#' library(dplyr) #for the pipe operator +#' library(officer) +#' mytable = cross(cbind(Sepal.Length, I(Sepal.Width^2)) ~ Species, iris) %>% +#' as.data.frame %>% #loses attributes +#' as.crosstable(labs.col = "Species") +#' +#' doc <- read_docx() %>% +#' body_add_crosstable(mytable) +#' +#' \dontrun{ +#' dfile <- "test_doc.docx" +#' print(doc, target = dfile) +#' shell.exec(dfile) +#' } +#' +as.crosstable = function(df, labs.col = "???"){ + class(df) = c("cross", "data.frame") + attr(df, "labs.col") = labs.col + df +} + + + +# LEGACY ------------------------------------------------------------------ + + +#' OLD: Adds a table made by the cross function into an officer document +#' +#' @param doc a \code{rdocx} object created by \code{read_docx} function (see \code{officer} package) +#' @param crosstable the result of \code{cross} function +#' @param compact whether to compact the table +#' @param auto.fit whether to \code{flextable::autofit} the table +#' @param id name of the 'id' column +#' @param variable name of the 'variable' column +#' @param label name of the 'label' column +#' @param value name of the 'value' column +#' @param p name of the 'p' column +#' @param show.test.name in the p column, show the test name +#' +#' @return A \code{rdocx} object +#' @author Dan Chaltiel +#' @importFrom dplyr select lead sym %>% +#' @importFrom methods is +#' @import officer flextable +#' @export +#' +#' @examples +#' library(dplyr) #for the pipe operator +#' library(officer) +#' mytable <- cross(cbind(...) ~ tobgp, esoph, test = TRUE) +#' mytable <- cross(cbind(...) ~ Species, iris, test = TRUE) +#' mytable <- cross(cbind(...) ~ ., esoph) +#' doc <- read_docx() %>% +#' body_add_crosstable(mytable) %>% +#' body_add_break %>% +#' body_add_crosstable(mytable, TRUE) +#' +#' \dontrun{ +#' dfile <- "test_doc.docx" +#' print(doc, target = dfile) +#' shell.exec(dfile) +#' } +body_add_crosstable_bak = function(doc, crosstable, compact = FALSE, auto.fit = FALSE, id = ".id", variable = "variable", label = "label", value="value", p = "p", show.test.name=F){ + border1 <- fp_border(color = "black", style = "solid", width = 1) + border2 <- fp_border(color = "black", style = "solid", width = 1.5) + + labs.col <- attr(crosstable, "labs.col") + rtn = crosstable + + is_tested = rtn %>% names %>% grepl(p,.) %>% any + is_multiple = rtn %>% names %>% grepl(value,.) %>% any %>% `!` + + if(is_tested && !show.test.name){ + rtn$p = rtn$p %>% gsub(" \\(.*\\)","", .) + } + if(compact && !is(rtn, "compacted")) { + rtn <- compact(rtn) + } + #TODO : si une seule fonction (funs=moystd) et compact + #TODO : implémenter si compact arrive avant la fonction + + if(is(rtn, "compacted")) { + sep.rows <- which(rtn[,1] %in% crosstable$label)[-1] #$label ou $.id ? + + rtn <- rtn %>% + as.data.frame %>% + flextable %>% + hline(i=sep.rows-1, border = border1) + + if(is_multiple){ + header_colwidths = if(is_tested) c(1, ncol(crosstable)-4) else c(1, ncol(crosstable)-3) + rtn <- rtn %>% + add_header_row(values=c(variable, labs.col), colwidths=header_colwidths) %>% + merge_v(j=1, part = "head") %>% + merge_h(i=c(1, sep.rows, sep.rows+1)) %>% + bold(i=c(1, sep.rows)) + } + } else { + sep.rows <- which(rtn$label != lead(rtn$label)) #$label ou $.id ? + rtn <- rtn %>% + select(-!!sym(id)) %>% + flextable %>% + hline(i=sep.rows, border = border1) + if(is_multiple){ + header_values = if(is_tested) c(label, variable, labs.col, p) else c(label, variable, value) + header_colwidths = if(is_tested) c(1, 1, ncol(crosstable)-4, 1) else c(1, 1, ncol(crosstable)-3) + body_merge = if(is_tested) c("label", p) else c("label") + rtn <- rtn %>% + add_header_row(values=header_values, + colwidths=header_colwidths) %>% + merge_v(j=c(1,2,ncol(crosstable)-1), part = "head") %>% + merge_v(j = body_merge) + } + } + rtn <- rtn %>% + bold(part="head") %>% + align(align = "left", part="all") %>% + align(i=1, align = "center", part="head") %>% + hline_top(border = border2, part = "head") %>% + hline_bottom(border = border2, part = "head") %>% + border_inner_h(border = border2, part = "head") + if(auto.fit){ + rtn <- autofit(rtn) + } + doc <- body_add_flextable(doc, rtn) + return(doc) +} + +#' Deprecated +#' Create a FlexTable object from a table made by the cross function +#' +#' **Deprecation** : Since \code{ReporteRs} is deprecated and not available on CRAN, please use \code{flextable} and \code{officer} packages instead. +#' +#' @name FlexCrossTable-ReporteRs +#' @param crosstable the result of \code{cross} function +#' @param compact compact the table? +#' @param id name of the 'id' column +#' @param variable name of the 'variable' column +#' @param value name of the 'value' column +#' @param effect name of the 'effect' column +#' @param p name of the 'p' column +#' @import stats +#' @return +#' A \code{FlexTable} object (see \code{ReporteRs} package) +#' @author David Hajage +#' @examples +#' \dontrun{ +#' library(biostat2) +#' library(ReporteRs) +#' mytable <- cross(cbind(...) ~ tobgp, esoph, test = TRUE) +#' FlexCrossTable(mytable) +#' FlexCrossTable(mytable, TRUE) +#' } +#' @keywords univar +#' @export +FlexCrossTable <- function(crosstable, compact = FALSE, id = ".id", variable = "variable", value = "value", effect = "effect", p = "p") { + check_reporter_dependency() + header <- names(crosstable)[names(crosstable) != "label"] names(header) <- header header[header == ".id"] <- id @@ -119,7 +425,7 @@ FlexCrossTable <- function(crosstable, compact = FALSE, id = ".id", variable = " if ("p" %in% names(crosstable)) { ft <- spanFlexTableRows(ft, j = c(1, which(names(crosstable) == "p")-1), runs = crosstable$`.id`) } - if ("effect" %in% names(crosstable)) { + if ("effect" %in% names(crosstable)) { ft <- spanFlexTableRows(ft, j = c(1, which(names(crosstable) == "effect")-1), runs = crosstable$`.id`) } if (length(attr(crosstable, "noms.col")) > 0) { @@ -141,11 +447,11 @@ FlexCrossTable <- function(crosstable, compact = FALSE, id = ".id", variable = " ft <- addHeaderRow(ft, value = c(sapply(attr(crosstable, "labs.col"), function(x) c("", x))), colspan = colspan, par.properties = parProperties(text.align = "center")) } ft <- addHeaderRow(ft, value = header) - + ft <- setFlexTableBorders(ft, inner.vertical = borderProperties(width = 0), inner.horizontal = borderProperties(width = 0), outer.vertical = borderProperties(width = 0), outer.horizontal = borderProperties(width = 3)) - + if ("p" %in% names(crosstable) | "effect" %in% names(crosstable)) { if ("effect" %in% names(crosstable)) { bord <- grep(" Effect", crosstable2[, "variable"]) @@ -156,7 +462,7 @@ FlexCrossTable <- function(crosstable, compact = FALSE, id = ".id", variable = " bord2 <- cumsum(table(factor(crosstable$.id, unique(crosstable$.id)))+nb+1) - (table(factor(crosstable$.id, unique(crosstable$.id)))+nb) bord3 <- grep(" Effect| Test", crosstable2[, "variable"]) - + ft[bord[-length(bord)], , side = "bottom"] = borderProperties(width = 1) ft[bord- (nb-1), , side = "top"] = borderProperties(style = "dashed") ft[bord2, ] <- textProperties(font.style = "italic") @@ -184,32 +490,38 @@ FlexCrossTable <- function(crosstable, compact = FALSE, id = ".id", variable = " } -##' add a table made by the cross function into a ReporteRs document -##' -##' @param doc a \code{docx} object created by \code{docx} function (see \code{ReporteRs} package) -##' @param crosstable the result of \code{cross} function -##' @param compact compact the table? -##' @param id name of the 'id' column -##' @param variable name of the 'variable' column -##' @param value name of the 'value' column -##' @param p name of the 'p' column -##' @return -##' A \code{docx} object -##' @author David Hajage -##' @examples -##' \dontrun{ -##' library(biostat2) -##' library(ReporteRs) -##' mytable <- cross(cbind(...) ~ tobgp, esoph, test = TRUE) -##' doc <- docx() -##' doc <- addCrossTable(doc, mytable) -##' doc <- addPageBreak(doc) -##' doc <- addCrossTable(doc, mytable, TRUE) -##' } -##' @keywords univar -##' @export -##' @import ReporteRs +#' Deprecated +#' add a table made by the cross function into a ReporteRs document +#' +#' **Deprecation** : Since \code{ReporteRs} is deprecated and not available on CRAN, please use \code{officer} and \code{biostats2::body_add_crosstable} instead. +#' +#' @param doc a \code{docx} object created by \code{docx} function (see \code{ReporteRs} package) +#' @param crosstable the result of \code{cross} function +#' @param compact compact the table? +#' @param id name of the 'id' column +#' @param variable name of the 'variable' column +#' @param value name of the 'value' column +#' @param p name of the 'p' column +#' @return +#' A \code{docx} object +#' @author David Hajage +#' @examples +#' \dontrun{ +#' library(biostat2) +#' library(ReporteRs) +#' mytable <- cross(cbind(...) ~ tobgp, esoph, test = TRUE) +#' doc <- docx() +#' doc <- addCrossTable(doc, mytable) +#' doc <- addPageBreak(doc) +#' doc <- addCrossTable(doc, mytable, TRUE) +#' dfile <- "test_doc.docx" +#' print(doc, target = dfile) +#' shell.exec(dfile) +#' } +#' @keywords univar +#' @export addCrossTable <- function(doc, crosstable, compact = FALSE, id = ".id", variable = "variable", value = "value", p = "p") { + check_reporter_dependency() if (!inherits(crosstable, "FlexTable")) { ft <- FlexCrossTable(crosstable, compact, id, variable, value, p) } else { @@ -218,6 +530,13 @@ addCrossTable <- function(doc, crosstable, compact = FALSE, id = ".id", variable doc <- addFlexTable(doc, ft) return(doc) } + + + + + + + # # ##' add_header_list # ##' diff --git a/R/body_add_legend.r b/R/body_add_legend.r new file mode 100644 index 0000000..57dd974 --- /dev/null +++ b/R/body_add_legend.r @@ -0,0 +1,20 @@ +#' Add a table legend +#' +#' @param x a docx object +#' @param legend the table legend +#' @param legend_style may depend on the docx template +#' @param style the legend style (strnog, italic...) +#' @param seqfield to figure this out, in a docx file, insert a table legend, right click on the inserted number and select "Toggle Field Codes". This argument should be the value of the field, with extra escaping. +#' +#' @export +body_add_table_legend = function(x, legend, legend_style="table title", style="strong", + seqfield="SEQ Table \\* Arabic"){ + x %>% + body_add_par(value=legend, style=legend_style) %>% + slip_in_text(str=": ", style=style, pos="before") %>% + slip_in_seqfield(str=seqfield, + style=style, pos="before") %>% + slip_in_text(str="Table ", style=style, + pos="before") %>% + identity +} \ No newline at end of file diff --git a/R/remix.r b/R/cross.r similarity index 89% rename from R/remix.r rename to R/cross.r index eeafed5..2c24519 100644 --- a/R/remix.r +++ b/R/cross.r @@ -1,3 +1,4 @@ + ##' test ##' ##' @param x x @@ -393,6 +394,8 @@ regroup <- function(vars, numdata, catdata, survdata) { ##' group everything in the same table, but only if it is possible... ##' ##' +##' \lifecycle{superseded} +##' \Sexpr[results=rd, stage=render]{lifecycle::badge("superseded")} ##' @return ##' A data.frame, or a list of data.frames. ##' @author David Hajage, inspired by the design and the code of @@ -403,34 +406,80 @@ regroup <- function(vars, numdata, catdata, survdata) { ##' ##' library(biostat2) ##' cross(data = iris) -##' cross(cbind(...) ~ ., iris[, sapply(iris, is.numeric)], funs = c(median, mad, min, max)) -##' cross(cbind(Sepal.Length, I(Sepal.Width^2)) ~ Species, iris, funs = quantile, probs = c(1/3, 2/3)) +##' cross(cbind(...) ~ ., iris[, sapply(iris, is.numeric)], funs=c(median, mad, min, max)) +##' cross(cbind(Sepal.Length, I(Sepal.Width^2)) ~ Species, iris, funs=quantile, probs=c(1/3, 2/3), total="row") #tertiles 1 and 2 by Species ##' cross(Sepal.Length + Sepal.Width ~ Petal.Length + Petal.Width, iris) ##' cross(cbind(Sepal.Length, Sepal.Width) ~ cbind(Petal.Length, Petal.Width), iris) -##' cross(... ~ ., esoph) -##' cross(alcgp ~ tobgp, esoph, test = TRUE) +##' cross(... ~ ., esoph) #returns a list +##' cross(alcgp ~ tobgp, esoph, margin="row", total="both", test=TRUE) +##' cross(cbind(hp, mpg) ~ factor(am), mtcars, effect=TRUE, test=TRUE, show.method=FALSE) ##' library(survival) ##' cross(Surv(time, status) ~ x, data = aml) +##' ##' @keywords univar ##' @export -##' @importFrom plyr is.formula -##' @importFrom plyr llply -cross <- function(formula = cbind(...) ~ ., data = NULL, funs = c(" " = mysummary), ..., margin = 0:2, total = FALSE, digits = 2, showNA = c("no", "ifany", "always"), method = c("pearson", "kendall", "spearman"), times = NULL, followup = FALSE, test = FALSE, test.summarize = test.summarize.auto, test.survival = test.survival.logrank, test.tabular = test.tabular.auto, show.test = display.test, plim = 4, show.method = TRUE, effect = FALSE, effect.summarize = diff.mean.auto, effect.tabular = or.row.by.col, effect.survival = effect.survival.coxph, conf.level = 0.95, label = FALSE, regroup = FALSE) { - +##' @import checkmate +##' @importFrom plyr llply is.formula +##' @importFrom lifecycle deprecate_warn +cross <- function(formula = cbind(...) ~ ., data = NULL, funs = c(" " = cross_summary), ..., margin = c("all", "row", "column", "cell"), total = c("none", "all", "row", "column", "FALSE", "TRUE", 0, 1, 2), digits = 2, showNA = c("no", "ifany", "always"), method = c("pearson", "kendall", "spearman"), times = NULL, followup = FALSE, test = FALSE, test.summarize = test.summarize.auto, test.survival = test.survival.logrank, test.tabular = test.tabular.auto, show.test = display.test, plim = 4, show.method = TRUE, effect = FALSE, effect.summarize = diff.mean.auto, effect.tabular = or.row.by.col, effect.survival = effect.survival.coxph, conf.level = 0.95, label = TRUE, regroup = FALSE) { + + deprecate_warn("0.13.0", "cross()", + details="Please use the package `crosstable` instead.") + + coll = makeAssertCollection() + assertFormula(formula, add=coll) + assertDataFrame(data, add=coll) + assertCount(digits, add=coll) + assertLogical(label, add=coll) + if (is.formula(formula)) formula <- paste(deparse(formula, 500), collapse = "") - + if (!is.character(funs)) { - nomf <- names(funs) - funs <- as.character(as.list(substitute(funs))) - funs <- funs[funs != "c" & funs != "list"] - names(funs) <- nomf + nomf <- names(funs) + funs <- as.character(as.list(substitute(funs))) + funs <- funs[funs != "c" & funs != "list"] + names(funs) <- nomf } - + + if (missing(margin)) margin = "all" + if (is.character(margin)) { + assertSubset(margin, c("all", "row", "column", "cell"), add=coll) + if(is.null(margin)) { + margin=0:2 #defaulting + } else { + marginopts = list(all = 0:2, + row = 1, + column = 2, + cell = 0) + margin <- unname(unlist(marginopts[margin])) + } + } + + if (missing(total)) total = "none" + if (total=="line") total = "row" + if (is.character(total)) { + assertChoice(total, c("none", "both", "all", "row", "column"), add=coll) + if(is.null(total)) { + total=0 #defaulting to none + } else { + totalopts = list(all = 1:2, + both = 1:2, + row = 1, + column = 2, + none = 0) + total <- unname(unlist(totalopts[total])) + } + } + + reportAssertions(coll) + + varnames <- names(data) parsed <- parse_formula(formula, varnames) - - data <- parse_data(expand_formula(formula, varnames), data) + # parsed$left = gsub("\\n *", "", parsed$left) + + data <- parse_data(expand_formula(formula, varnames), data) names(data) <- remove_blank(names(data)) varform <- names(data) @@ -453,13 +502,13 @@ cross <- function(formula = cbind(...) ~ ., data = NULL, funs = c(" " = mysummar lapply(y, function(z) data[, remove_blank(elements(z)), drop = FALSE]) }) - # results <- llply(comb, function(x) cross_list(x, funs = funs, margin = margin, total = total, digits = digits, showNA = showNA, method = method, times = times, followup = followup, test = test, test.summarize = test.summarize, test.tabular = test.tabular, test.survival = test.survival, show.test = show.test, plim = plim, effect = effect, effect.summarize = effect.summarize, effect.tabular = effect.tabular, effect.survival = effect.survival, conf.level = conf.level, show.method = show.method, label = label)) - - results <- llply(comb, function(x) cross_list(x, funs = funs, ..., margin = margin, total = total, digits = digits, showNA = showNA, method = method, times = times, followup = followup, test = test, test.summarize = test.summarize, test.tabular = test.tabular, test.survival = test.survival, show.test = show.test, plim = plim, effect = effect, effect.summarize = effect.summarize, effect.tabular = effect.tabular, effect.survival = effect.survival, conf.level = conf.level, show.method = show.method, label = label)) + + results <- llply(comb, function(x) + cross_list(x, funs = funs, ..., margin = margin, total = total, digits = digits, showNA = showNA, method = method, times = times, followup = followup, test = test, test.summarize = test.summarize, test.tabular = test.tabular, test.survival = test.survival, show.test = show.test, plim = plim, effect = effect, effect.summarize = effect.summarize, effect.tabular = effect.tabular, effect.survival = effect.survival, conf.level = conf.level, show.method = show.method, label = label)) if (length(results) == 1) { results <- results[[1]] - ## class(results) <- c("cross", "data.frame") + class(results) <- c("cross", "data.frame") } else { results <- results[results != "What?"] @@ -475,10 +524,18 @@ cross <- function(formula = cbind(...) ~ ., data = NULL, funs = c(" " = mysummar ## attr(results, "data") <- data ## attr(results, "test") <- test + results } + + + +# Old --------------------------------------------------------------------- + + + ## ##' Print a cross object ## ##' ## ##' Print cross object using ascii package diff --git a/R/effect.r b/R/effect.r index 937edfa..d966be5 100644 --- a/R/effect.r +++ b/R/effect.r @@ -5,9 +5,10 @@ #' #' @export display.effect <- function(effect, digits = 4) { - if (all(sapply(effect, is.null))) - "No effect" - else { + if (all(sapply(effect, is.null))){ + warning("Could not calculate effect. Is there not 2 groups exactly?", immediate.=T) + return("No effect?") + }else { paste(paste0(effect$effect.type, " (", effect$effect.name, "): ", formatC(effect$effect, format = "f", digits = digits), " CI", effect$conf.level*100, "%[", paste(formatC(effect$ci[, 1], format = "f", digits = digits), formatC(effect$ci[, 2], format = "f", digits = digits), sep = " to "), "]"), collapse = "\n") } } @@ -29,7 +30,7 @@ display.effect <- function(effect, digits = 4) { # rd.row.by.col <- function (x, y, conf.level = 0.95) { # tab <- table(x, y) # if (ncol(tab) <= 1 | ncol(tab) > 2) { -# ## Je ne sais pas quel effet calculer par défaut quand il existe plus de 2 catégories en colonne +# ## Je ne sais pas quel effet calculer par d?faut quand il existe plus de 2 cat?gories en colonne # effect <- NULL # ci <- NULL # effect.name <- NULL @@ -61,7 +62,7 @@ display.effect <- function(effect, digits = 4) { # rr.row.by.col <- function (x, y, conf.level = 0.95) { # tab <- table(x, y) # if (ncol(tab) <= 1 | ncol(tab) > 2) { -# ## Je ne sais pas quel effet calculer par défaut quand il existe plus de 2 catégories en colonne +# ## Je ne sais pas quel effet calculer par d?faut quand il existe plus de 2 cat?gories en colonne # effect <- NULL # ci <- NULL # effect.name <- NULL @@ -93,7 +94,7 @@ display.effect <- function(effect, digits = 4) { # or.row.by.col <- function (x, y, conf.level = 0.95) { # tab <- table(x, y) # if (ncol(tab) <= 1 | ncol(tab) > 2) { -# ## Je ne sais pas quel effet calculer par défaut quand il existe plus de 2 catégories en colonne +# ## Je ne sais pas quel effet calculer par d?faut quand il existe plus de 2 cat?gories en colonne # effect <- NULL # ci <- NULL # effect.name <- NULL @@ -309,7 +310,7 @@ rd.col.by.row <- function (x, y, conf.level = 0.95) { diff.mean.auto <- function(x, g, conf.level = 0.95, R = 500) { ng <- table(g) if (length(ng) <= 1 | length(ng) > 2) { - ## Je ne sais pas quel effet calculer par défaut quand il existe plus de 2 catégories en colonne + ## Je ne sais pas quel effet calculer par d?faut quand il existe plus de 2 cat?gories en colonne effect <- NULL ci <- NULL effect.name <- NULL @@ -369,7 +370,7 @@ diff.mean.auto <- function(x, g, conf.level = 0.95, R = 500) { diff.mean.boot <- function(x, g, conf.level = 0.95, R = 500) { ng <- table(g) if (length(ng) <= 1 | length(ng) > 2) { - ## Je ne sais pas quel effet calculer par défaut quand il existe plus de 2 catégories en colonne + ## Je ne sais pas quel effet calculer par d?faut quand il existe plus de 2 cat?gories en colonne effect <- NULL ci <- NULL effect.name <- NULL @@ -404,7 +405,7 @@ diff.mean.boot <- function(x, g, conf.level = 0.95, R = 500) { diff.mean.student <- function(x, g, conf.level = 0.95) { ng <- table(g) if (length(ng) <= 1 | length(ng) > 2) { - ## Je ne sais pas quel effet calculer par défaut quand il existe plus de 2 catégories en colonne + ## Je ne sais pas quel effet calculer par d?faut quand il existe plus de 2 cat?gories en colonne effect <- NULL ci <- NULL effect.name <- NULL @@ -443,7 +444,7 @@ diff.mean.student <- function(x, g, conf.level = 0.95) { diff.median <- function(x, g, conf.level = 0.95, R = 500) { ng <- table(g) if (length(ng) <= 1 | length(ng) > 2) { - ## Je ne sais pas quel effet calculer par défaut quand il existe plus de 2 catégories en colonne + ## Je ne sais pas quel effet calculer par d?faut quand il existe plus de 2 cat?gories en colonne effect <- NULL ci <- NULL effect.type <- NULL diff --git a/R/funs.r b/R/funs.r index d5c2732..3f8b992 100644 --- a/R/funs.r +++ b/R/funs.r @@ -1,111 +1,196 @@ -##' Remove blancks at the begining and the end -##' -##' @param x x -##' @author David Hajage -##' @keywords internal -trim <- function (x) { - x <- sub("^ +", "", x) - x <- sub(" +$", "", x) - x -} -##' Concatenate functions -##' -##' @param ... functions -##' @author David Hajage -##' @keywords internal -funs2fun <- function(...) { - fnames <- as.character(match.call()[-1]) - fs <- list(...) - fnames2 <- names(fs) - if (!is.null(fnames2)) { - fnames[fnames2 != ""] <- fnames2[fnames2 != ""] - } - n <- length(fs) - function(x, ...) { - results <- NULL - args <- list(...) - namesargs <- names(args) - for (i in 1:n) { - func <- match.fun(fs[[i]]) - forms <- formals(func) # Pour min et max (et les autres - # primitives), il faudrait mettre - # 'formals(args(func))'. Le probleme est - # que min et max retourne le minimum de - # tout ce qui n'est pas 'na.rm', donc si - # je met un autre argument (genre probs = - # 1/3), min et max prennent en compte sa - # valeur, d'ou surprises... Je prefere - # laisser comme ca. - namesforms <- names(forms) - if (all(namesforms != "...")) { - finalargs <- c(list(x = x), args[namesargs %in% namesforms]) - } else { - finalargs <- c(list(x = x), args) - } - tmp <- do.call(func, finalargs) - names(tmp) <- trim(paste(fnames[i], names(tmp))) - results <- c(results, as.list(tmp)) +#' Format numbers with same number of decimals, including trailing zeros +#' +#' @param x a numeric vector to format +#' @param digits number of decimals +#' @param zero_digits number of significant digits for values rounded to 0 (set to NULL to keep the original 0 value) +#' @param only_round util option, to simply return rounded value instead of formatted +#' +#' @return a character vector of formatted numbers +#' @author Dan Chaltiel +#' @export +#' +#' @examples +#' x = c(1, 1.2, 12.78749, pi, 0.00000012) +#' format_fixed(x, digits=3) +#' format_fixed(x, digits=3, zero_digits=2) +#' format_fixed(x, digits=3, zero_digits=NULL) +#' x = iris$Sepal.Length/10000 +#' x %>% +#' sd(na.rm=na.rm) %>% +#' format_fixed(dig=3, zero_digits=2, only_round=T) +format_fixed = function(x, digits, zero_digits=1, only_round=FALSE){ + stopifnot(is.numeric(x), + is.numeric(digits), + is.logical(only_round), + is.null(zero_digits)||is.numeric(zero_digits) + ) + if(only_round) { + return(round(x,digits)) + } else { + rtn = formatC(x, format='f', digits=digits) + if(!is.null(zero_digits) && !is.na(zero_digits)){ + rtn = ifelse(as.numeric(rtn)==0, signif(x, digits=zero_digits), rtn) } - data.frame(results, check.names = FALSE) + return(rtn) } } -## Default summary function - -##' Return min and max -##' -##' @param x a numeric vector -##' @param na.rm \code{TRUE} as default -##' @param dig number of digits -##' @keywords internal -minmax <- function(x, na.rm = TRUE, dig = 2) { - mi <- ifelse(!all(is.na(x)), round(min(x, na.rm = na.rm), dig), NA) - ma <- ifelse(!all(is.na(x)), round(max(x, na.rm = na.rm), dig), NA) - paste(mi, "/", ma) + +# summary functions -------------------------------------------------------- + + +#' Summary functions +#' +#' Summary functions to use with \code{\link{cross}} or anywhere else. +#' +#' @section Fixed format: +#' The use of the \code{fixed_format} argument allows to have trailing zeros after rounded values. +#' In the case when the output of rounded values is zero, the use of the \code{zero_digits} argument allows to keep some significant digits for this specific case only. +#' +#' @param x a numeric vector +#' @param na.rm \code{TRUE} as default +#' @param dig number of digits +#' @param fixed_format use \code{\link{format_fixed}} instead of round (default) +#' @param zero_digits is fixed_format==TRUE, number of significant digits for values rounded to 0 (set to NULL to keep the original 0 value) +#' +#' +#' @examples +#' moystd(iris$Sepal.Length, dig=3) +#' minmax(iris$Sepal.Length, dig=3) +#' mediqr(iris$Sepal.Length, dig=3) +#' nna(iris$Sepal.Length, dig=3) +#' +#' x = iris$Sepal.Length/10000 #closer to zero +#' +#' moystd(x, dig=3, fixed_format=T) +#' moystd(x, dig=3, fixed_format=T, zero_digits=NULL) +#' options("biostat2_fixed_format"=T) +#' moystd(x, dig=3, zero_digits=2) +#' options("biostat2_fixed_format"=NULL) +#' +#' @author Dan Chaltiel +#' @author David Hajage +#' +#' @seealso \code{\link{format_fixed}} +#' +#' @name biostats2SummaryFunctions +NULL + + +#' @describeIn biostats2SummaryFunctions returns mean and std error +#' @export +moystd = function(x, na.rm = TRUE, dig = 2, + fixed_format=getOption("biostat2_fixed_format", FALSE), zero_digits=1) { + moy = x %>% + mean(na.rm=na.rm) %>% + format_fixed(digits=dig, zero_digits=zero_digits, only_round=!fixed_format) + std = x %>% + sd(na.rm=na.rm) %>% + format_fixed(digits=dig, zero_digits=zero_digits, only_round=!fixed_format) + paste0(moy, " (", std, ")") } -##' Return median and IQR -##' -##' @param x a numeric vector -##' @param na.rm \code{TRUE} as default -##' @param dig number of digits -##' @keywords internal -mediqr <- function(x, na.rm = TRUE, dig = 2) { - med <- round(median(x, na.rm = na.rm), dig) - iqr <- round(quantile(x, probs = c(0.25, 0.75), na.rm = na.rm), dig) - paste(med, " [", iqr[1], "-", iqr[2], "]", sep = "") +#' @describeIn biostats2SummaryFunctions returns median and IQR +#' @export +mediqr = function(x, na.rm = TRUE, dig = 2, + fixed_format=getOption("biostat2_fixed_format", FALSE), zero_digits=1) { + med = x %>% + median(na.rm=na.rm) %>% + format_fixed(digits=dig, zero_digits=zero_digits, only_round=!fixed_format) + iqr = x %>% + quantile(probs=c(0.25, 0.75), na.rm=na.rm) %>% + format_fixed(digits=dig, zero_digits=zero_digits, only_round=!fixed_format) + paste0(med, " [", iqr[1], ";", iqr[2], "]") } -##' Return mean and sd -##' -##' @param x a numeric vector -##' @param na.rm \code{TRUE} as default -##' @param dig number of digits -##' @keywords internal -moystd <- function(x, na.rm = TRUE, dig = 2) { - moy <- round(mean(x, na.rm = na.rm), dig) - std <- round(sd(x, na.rm = na.rm), dig) - paste(moy, " (", std, ")", sep = "") +#' @describeIn biostats2SummaryFunctions returns minimum and maximum +#' @export +minmax = function(x, na.rm = TRUE, dig = 2) { + mi = ifelse(!all(is.na(x)), round(min(x, na.rm = na.rm), dig), NA) + ma = ifelse(!all(is.na(x)), round(max(x, na.rm = na.rm), dig), NA) + paste(mi, "/", ma) } -##' Return n and na -##' -##' @param x a numeric vector -##' @keywords internal -nna <- function(x) { - paste(n(x), " (", na(x), ")", sep = "") +#' @describeIn biostats2SummaryFunctions returns number of observations and number of missing values +#' @export +nna = function(x) { + paste0(n(x), " (", na(x), ")") } -##' Summarize a numeric vector -##' -##' @param x a numeric vector -##' @param na.rm \code{TRUE} as default -##' @param dig number of digits -##' @keywords internal -mysummary <- function(x, na.rm = TRUE, dig = 2) { - return(c("Min / Max" = minmax(x), "Med [IQR]" = mediqr(x), "Moy (std)" = moystd(x), "N (NA)" = nna(x))) + +#' Summarize a numeric vector +#' +#' @param x a numeric vector +#' @param dig number of digits +#' @keywords internal +#' @section Note: +#' Function \code{mysummary} is kept for compatibility with old codes. It produces the same exact object than \code{cross_summary}, which should be preferred. +cross_summary = function(x, dig=2) { + return(c("Min / Max" = minmax(x, dig=dig), "Med [IQR]" = mediqr(x, dig=dig), + "Moy (std)" = moystd(x, dig=dig), "N (NA)" = nna(x))) } +#' @rdname cross_summary +mysummary=cross_summary + +# Utils functions --------------------------------------------------------- + + +#' Remove blancks at the begining and the end +#' +#' @param x x +#' @author David Hajage +#' @keywords internal +trim = function (x) { + x = sub("^ +", "", x) + x = sub(" +$", "", x) + x +} + + +#' Concatenate functions +#' +#' @param ... functions +#' @author David Hajage +#' @keywords internal +funs2fun = function(...) { + fnames = as.character(match.call()[-1]) + fs = list(...) + fnames2 = names(fs) + + if (!is.null(fnames2)) { + fnames[fnames2 != ""] = fnames2[fnames2 != ""] + } + + n = length(fs) + function(x, ...) { + results = NULL + args = list(...) + namesargs = names(args) + for (i in 1:n) { + func = match.fun(fs[[i]]) + forms = formals(func) # Pour min et max (et les autres + # primitives), il faudrait mettre + # 'formals(args(func))'. Le probleme est + # que min et max retourne le minimum de + # tout ce qui n'est pas 'na.rm', donc si + # je met un autre argument (genre probs = + # 1/3), min et max prennent en compte sa + # valeur, d'ou surprises... Je prefere + # laisser comme ca. + namesforms = names(forms) + if (all(namesforms != "...")) { + finalargs = c(list(x = x), args[namesargs %in% namesforms]) + } else { + finalargs = c(list(x = x), args) + } + tmp = do.call(func, finalargs) + names(tmp) = trim(paste(fnames[i], names(tmp))) + results = c(results, as.list(tmp)) + } + data.frame(results, check.names = FALSE) + } +} \ No newline at end of file diff --git a/R/na.r b/R/na.r index 820d8ee..4cd3105 100644 --- a/R/na.r +++ b/R/na.r @@ -19,23 +19,3 @@ n <- function(x, na.rm = FALSE) { na <- function(x, na.rm = FALSE) { sum(is.na(x)) } - -##' Return the min (and have formals) -##' -##' @export -##' @param x a vector -##' @param na.rm Remove NA? -##' @author David Hajage -##' @keywords univar -Min <- function(x, na.rm = FALSE) - min(x, na.rm = na.rm) - -##' Return the max (and have formals) -##' -##' @export -##' @param x a vector -##' @param na.rm Remove NA? -##' @author David Hajage -##' @keywords univar -Max <- function(x, na.rm = FALSE) - max(x, na.rm = na.rm) diff --git a/R/officer.r b/R/officer.r new file mode 100644 index 0000000..a3c208b --- /dev/null +++ b/R/officer.r @@ -0,0 +1,74 @@ + + +#' Add a new paragraph with a Normal style, inserting variables with \code{base::paste} +#' +#' @name body_add_normal +#' @param doc the doc object (created with the \code{read_docx} function of \code{officer} package) +#' @param ... one or several character strings, collapsed into a paragraph with \code{base::paste} +#' @return a new doc object +#' @author Dan Chaltiel +#' @examples +#' \dontrun{ +#' library(officer) +#' library(biostat2) +#' library(dplyr) +#' doc = read_docx() +#' doc = doc %>% body_add_normal("La table iris a ", ncol(iris), " colonnes.") +#' } +#' @export +body_add_normal <- function(doc, ...) { + value = paste0(..., collapse = "") + body_add_par(doc, value, style = "Normal") +} + +#' Add a new paragraph with a Normal style, inserting variables with \code{glue::glue} +#' +#' @name body_add_normal +#' @param doc the doc object (created with the \code{read_docx} function of \code{officer} package) +#' @param x the string with \code{glue::glue} patterns (Expressions enclosed by braces will be evaluated as R code) +#' @param ... parameters to be passed to \code{glue::glue} +#' @return a new doc object +#' @author Dan Chaltiel +#' @examples +#' \dontrun{ +#' library(officer) +#' library(biostat2) +#' library(dplyr) +#' doc = read_docx() +#' doc = body_add_glued(doc, "La table iris a {ncol(iris)} colonnes.") +#' } +#' @export +body_add_glued <- function(doc, x, ...) { + value = glue::glue(x, ...,.envir = parent.frame()) + body_add_par(doc, value, style = "Normal") + # value +} + + +#' Add a new title +#' +#' @name body_add_title +#' @param doc the doc object (created with the \code{read_docx} function of \code{officer} package) +#' @param value a character string +#' @param level the level of the title. See \code{styles_info(doc)} to know the possibilities. +#' @return a new doc object +#' @author Dan Chaltiel +#' @examples +#' \dontrun{ +#' library(officer) +#' library(biostat2) +#' library(dplyr) +#' doc = read_docx() +#' doc = doc %>% +#' body_add_title(doc, "La table iris", 1) %>% +#' body_add_title(doc, "Description", 2) %>% +#' addNormal(doc, "La table iris a ", ncol(iris), " colonnes.") +#' } +#' @export +body_add_title <- function(x, value, level = 1, style = "heading") { + style <- paste(style, level) + body_add_par(x, value, style = style) +} + + +#TODO: extends all https://github.com/eusebe/biostat2/blob/master/R/officer.r diff --git a/R/pretty.r b/R/pretty.r index 757e011..428375c 100644 --- a/R/pretty.r +++ b/R/pretty.r @@ -1,31 +1,31 @@ -rdv <- function(x, ...) { - UseMethod("rdv") -} - -remove.term <- function(f, term) { - lr <- left_right(f) - l <- lr$left - r <- lr$right - r2 <- r[!grepl(paste("^", term, "$", sep = ""), r) & !grepl(paste("^", term, ":", sep = ""), r) & !grepl(paste(":", term, "$", sep = ""), r) & !grepl(paste(":", term, ":", sep = ""), r)] - paste(l, "~", paste(r2, collapse = "+")) -} - -rdv.glm <- function(x, ...) { - -} - -rdv.coxph <- function(x, ...) { - -} - -pretty <- function (x, ...) { - UseMethod("pretty") -} - -pretty.glm <- function(x, ...) { - -} - -pretty.coxph <- function(x, ...) { - -} +# rdv <- function(x, ...) { +# UseMethod("rdv") +# } +# +# remove.term <- function(f, term) { +# lr <- left_right(f) +# l <- lr$left +# r <- lr$right +# r2 <- r[!grepl(paste("^", term, "$", sep = ""), r) & !grepl(paste("^", term, ":", sep = ""), r) & !grepl(paste(":", term, "$", sep = ""), r) & !grepl(paste(":", term, ":", sep = ""), r)] +# paste(l, "~", paste(r2, collapse = "+")) +# } +# +# rdv.glm <- function(x, ...) { +# +# } +# +# rdv.coxph <- function(x, ...) { +# +# } +# +# pretty <- function (x, ...) { +# UseMethod("pretty") +# } +# +# pretty.glm <- function(x, ...) { +# +# } +# +# pretty.coxph <- function(x, ...) { +# +# } diff --git a/R/reporters.r b/R/reporters.r index 760c68e..b58ce3e 100644 --- a/R/reporters.r +++ b/R/reporters.r @@ -1,3 +1,11 @@ + +check_reporter_dependency <- function(){ + if (!requireNamespace("ReporteRs", quietly = TRUE)) { + stop("Package \"ReporteRs\" is deprecated but needed for this function to work. \nIf you really want to use this function, please install it", + call. = FALSE) + } +} + ##' Add a new paragraph with a Normal style ##' ##' @name addNormal @@ -16,8 +24,8 @@ ##' } ##' @keywords univar ##' @export -##' @import ReporteRs addNormal <- function(doc, value, stylename = "Normal", ...) { + check_reporter_dependency() if (class(value) == "character") { value <- do.call("set_of_paragraphs", args = lapply(value, pot)) } @@ -42,8 +50,8 @@ addNormal <- function(doc, value, stylename = "Normal", ...) { ##' } ##' @keywords univar ##' @export -##' @import ReporteRs addComment <- function(doc, value, stylename = "Comment", ...) { + check_reporter_dependency() addParagraph(doc, value, stylename = stylename) } @@ -65,8 +73,8 @@ addComment <- function(doc, value, stylename = "Comment", ...) { ##' } ##' @keywords univar ##' @export -##' @import ReporteRs addAlert <- function(doc, value, stylename = "Alert", ...) { + check_reporter_dependency() addParagraph(doc, value, stylename = stylename) } @@ -88,8 +96,8 @@ addAlert <- function(doc, value, stylename = "Alert", ...) { ##' } ##' @keywords univar ##' @export -##' @import ReporteRs addVerbatim <- function(doc, value, stylename = "Verbatim", ...) { + check_reporter_dependency() addParagraph(doc, value, stylename = stylename, ...) } @@ -110,8 +118,8 @@ addVerbatim <- function(doc, value, stylename = "Verbatim", ...) { ##' } ##' @keywords univar ##' @export -##' @import ReporteRs addCode <- function(doc, value, ...) { + check_reporter_dependency() addRScript(doc, text = value, par.properties = parProperties(shading.color = "#eeeeee")) } @@ -133,8 +141,8 @@ addCode <- function(doc, value, ...) { ##' } ##' @keywords univar ##' @export -##' @import ReporteRs addPlotlegend <- function(doc, value, stylename = "figurereference", ...) { + check_reporter_dependency() addParagraph(doc, value, stylename = stylename) } @@ -155,9 +163,9 @@ addPlotlegend <- function(doc, value, stylename = "figurereference", ...) { ##' doc <- addTablegend(doc, "Coucou") ##' } ##' @keywords univar -##' @export -##' @import ReporteRs +##' @export addTablegend <- function(doc, value, stylename = "tablereference", ...) { + check_reporter_dependency() addParagraph(doc, value, stylename = stylename) } @@ -179,8 +187,8 @@ addTablegend <- function(doc, value, stylename = "tablereference", ...) { ##' } ##' @keywords univar ##' @export -##' @import ReporteRs addItemize <- function(doc, value, level = 1, ...) { + check_reporter_dependency() unordered.list.level1 <- parProperties(list.style = "unordered", level = 1) unordered.list.level2 <- parProperties(list.style = "unordered", level = 2) unordered.list.level3 <- parProperties(list.style = "unordered", level = 3) @@ -216,8 +224,8 @@ addItemize <- function(doc, value, level = 1, ...) { ##' } ##' @keywords univar ##' @export -##' @import ReporteRs addEnumerate <- function(doc, value, level = 1, ...) { + check_reporter_dependency() ordered.list.level1 <- parProperties(list.style = "ordered", level = 1) ordered.list.level2 <- parProperties(list.style = "ordered", level = 2) ordered.list.level3 <- parProperties(list.style = "ordered", level = 3) @@ -251,8 +259,8 @@ addEnumerate <- function(doc, value, level = 1, ...) { ##' } ##' @keywords univar ##' @export -##' @import ReporteRs simple.table <- function(dataset, add.rownames = FALSE) { + check_reporter_dependency() ft = FlexTable(dataset, add.rownames = add.rownames) ft[, , to = "header"] = textBold() # ft[, , to = "header"] = parRight() @@ -315,9 +323,9 @@ simple.table <- function(dataset, add.rownames = FALSE) { ##' } ##' @keywords univar ##' @export -##' @import ReporteRs create.report <- function(template = c("gerc", "urc", "cephepi"), title = "", acronym = "", version = "", npromo = "", nct = "", invest = "", biostat = "", methodo = "", date_lastmodif = "", date_freez = "", date_update = "", history = NULL) { + check_reporter_dependency() URC <- FALSE if (template[1] == "urc") { template.file <- system.file("templates/template_urc.docx", package = "biostat2") diff --git a/R/summarize.by.r b/R/summarize.by.r index 713705f..dc54c03 100644 --- a/R/summarize.by.r +++ b/R/summarize.by.r @@ -21,7 +21,6 @@ summarize.by <- function(x, by, funs = c(mean, sd, quantile, n, na), ..., showNA = c("no", "ifany", "always"), total = FALSE, digits = 2, test = FALSE, test.summarize = test.summarize.auto, show.test = display.test, plim = 4, show.method = TRUE, effect = FALSE, effect.summarize = diff.mean.auto, conf.level = 0.95, show.effect = display.effect) { showNA <- showNA[1] - by2 <- by if (showNA == "always" | (showNA == "ifany" & anyNA(by))) { by2 <- addNA(by2) @@ -53,13 +52,7 @@ summarize.by <- function(x, by, funs = c(mean, sd, quantile, n, na), ..., showNA if (identical(total, 1) | identical(total, 1:2) | identical(total, TRUE)) { results$Total <- summarize(x, funs = funs, ..., digits = digits)[, 2] } - ## results <- sapply(results, function(x) if (is.numeric(x)) as.character(round(x, digits)) else as.character(x)) - ## Si NA n'est pas dans le facteur, on met la colonne apres "Total" - if ((any(colnames(results) == "NA") & any(colnames(results) == "Total")) & !anyNA(levels(by))) { - tmp <- results[, "NA"] - results <- cbind(results[, colnames(results) != "NA"], "NA" = tmp) - } if (effect) { results <- cbind(results, effect = show.effect(effect.summarize(x, by, conf.level), digits = digits)) diff --git a/R/test.r b/R/test.r index 9b37c45..29e3187 100644 --- a/R/test.r +++ b/R/test.r @@ -6,14 +6,14 @@ ##' @export ##' @author David Hajage plim <- function (p, digits = 4) { - pround <- round(p, digits) - lim <- 10^(-digits) - ptxt <- vector("character", length(p)) - ptxt[pround < lim] <- paste("<", "0.", paste(rep("0", digits - - 1), collapse = ""), "1", sep = "") - ptxt[pround >= lim] <- formatC(pround[pround >= lim], format = "f", - digits = digits) - return(ptxt) + pround <- round(p, digits) + lim <- 10^(-digits) + ptxt <- vector("character", length(p)) + ptxt[pround < lim] <- paste("<", "0.", paste(rep("0", digits - + 1), collapse = ""), "1", sep = "") + ptxt[pround >= lim] <- formatC(pround[pround >= lim], format = "f", + digits = digits) + return(ptxt) } ##' Display a test result @@ -30,9 +30,9 @@ display.test <- function(test, digits = 4, method = TRUE) { else { p <- plim(test$p.value, digits = digits) if (method) - paste("p value: ", p, " (", test$method, ")", sep = "") - else - paste("p value: ", p, sep = "") + paste("p value: ", p, " \n(", test$method, ")", sep = "") + else + p } } @@ -57,7 +57,7 @@ test.tabular.auto <- function(x, y) { ## test <- suppressWarnings(chisq.test(x, y, correct = TRUE)) else test <- fisher.test(x, y) - + p <- test$p.value method <- test$method list(p.value = p, method = method) @@ -77,7 +77,7 @@ test.tabular.fisher <- function(x, y) { test <- list(p.value = NULL, method = NULL) else test <- fisher.test(x, y) - + p <- test$p.value method <- test$method list(p.value = p, method = method) @@ -95,18 +95,18 @@ test.tabular.fisher <- function(x, y) { ##' @export test.summarize.auto.old <- function(x, g) { ng <- table(g) - + if (length(ng) <= 1) { p <- NULL method <- NULL } else { shapirog <- tapply(x, g, function(x) shapiro.test(x)$p.value) if (any(ng < 30) | any(shapirog < 0.05)) { - if (length(ng) == 2) { - type <- "wilcox" - } else { - type <- "kruskal" - } + if (length(ng) == 2) { + type <- "wilcox" + } else { + type <- "kruskal" + } } else { bartlettg <- bartlett.test(x, g)$p.value if (bartlettg < 0.05 & length(ng) == 2) { @@ -144,46 +144,46 @@ test.summarize.auto.old <- function(x, g) { ##' @importFrom nortest ad.test ##' @export test.summarize.auto <- function(x, g) { - ng <- table(g) - - if (length(ng) <= 1) { - p <- NULL - method <- NULL + ng <- table(g) + + if (length(ng) <= 1) { + p <- NULL + method <- NULL + } else { + if (any(ng < 50)) { + normg <- tapply(x, g, function(x) shapiro.test(x)$p.value) } else { - if (any(ng < 50)) { - normg <- tapply(x, g, function(x) shapiro.test(x)$p.value) - } else { - normg <- tapply(x, g, function(x) ad.test(x)$p.value) - } - if (any(normg < 0.05)) { - if (length(ng) == 2) { - type <- "wilcox" - } else { - type <- "kruskal" - } - } else { - bartlettg <- bartlett.test(x, g)$p.value - if (bartlettg < 0.05 & length(ng) == 2) { - type <- "t.unequalvar" - } else if (bartlettg < 0.05 & length(ng) > 2) { - type <- "a.unequalvar" - } else if (bartlettg > 0.05 & length(ng) == 2) { - type <- "t.equalvar" - } else if (bartlettg > 0.05 & length(ng) > 2) { - type <- "a.equalvar" - } - } - test <- switch(type, - wilcox = wilcox.test(x ~ g, correct = FALSE), - kruskal = kruskal.test(x, g), - t.unequalvar = t.test(x ~ g, var.equal = FALSE), - t.equalvar = t.test(x ~ g, var.equal = TRUE), - a.unequalvar = oneway.test(x ~ g, var.equal = FALSE), - a.equalvar = oneway.test(x ~ g, var.equal = TRUE)) - p <- test$p.value - method <- test$method + normg <- tapply(x, g, function(x) ad.test(x)$p.value) } - list(p.value = p, method = method) + if (any(normg < 0.05)) { + if (length(ng) == 2) { + type <- "wilcox" + } else { + type <- "kruskal" + } + } else { + bartlettg <- bartlett.test(x, g)$p.value + if (bartlettg < 0.05 & length(ng) == 2) { + type <- "t.unequalvar" + } else if (bartlettg < 0.05 & length(ng) > 2) { + type <- "a.unequalvar" + } else if (bartlettg >= 0.05 & length(ng) == 2) { + type <- "t.equalvar" + } else if (bartlettg >= 0.05 & length(ng) > 2) { + type <- "a.equalvar" + } + } + test <- switch(type, + wilcox = wilcox.test(x ~ g, correct = FALSE), + kruskal = kruskal.test(x, g), + t.unequalvar = t.test(x ~ g, var.equal = FALSE), + t.equalvar = t.test(x ~ g, var.equal = TRUE), + a.unequalvar = oneway.test(x ~ g, var.equal = FALSE), + a.equalvar = oneway.test(x ~ g, var.equal = TRUE)) + p <- test$p.value + method <- test$method + } + list(p.value = p, method = method) } ##' test for mean comparison @@ -198,16 +198,16 @@ test.summarize.auto <- function(x, g) { test.summarize.kruskal <- function(x, g) { ng <- table(g) if (length(ng) <= 1) { - p <- NULL - method <- NULL + p <- NULL + method <- NULL } else if (length(ng) == 2) { - test <- wilcox.test(x ~ g, correct = FALSE) - p <- test$p.value - method <- test$method + test <- wilcox.test(x ~ g, correct = FALSE) + p <- test$p.value + method <- test$method } else if (length(ng) > 2) { - test <- kruskal.test(x, g) - p <- test$p.value - method <- test$method + test <- kruskal.test(x, g) + p <- test$p.value + method <- test$method } list(p.value = p, method = method) } @@ -280,3 +280,104 @@ test.survival.logrank <- function(formula) { list(p.value = p, method = "Logrank test") } + + + +# DAN --------------------------------------------------------------------- + + +#' Test for linear trend across ordered factor with contrasts +#' +#' @param x vector +#' @param y ordered factor +#' +#' @return a list with two componments: p.value and method +#' @author Dan Chaltiel +#' @export +#' @import gmodels +#' @importFrom DescTools CochranArmitageTest +#' +#' @examples +#' library(dplyr) +#' iris %>% +#' mutate(Petal.Width.qt = paste0("Q", ntile(Petal.Width, 5)) %>% ordered()) %>% +#' cross(Petal.Length ~ Petal.Width.qt, data=., test=T, test.summarize = test.summarize.contrasts.lin) +test.summarize.contrasts.lin = function(x, y){ + stopifnot(is.ordered(y)) + levels_seq = 1:length(levels(y)) + contr = levels_seq - mean(levels_seq) #centered on 0, step of 1 + m = lm(x ~ y) + t = gmodels::fit.contrast(m, y, coeff=contr) + list(p.value=t[,"Pr(>|t|)"], method="Contrast test for linear trend") +} + + +#TODO faire tout ça ! + +test.summarize.auto.dan = function (x, g) { + ng <- table(g) + if (length(ng) <= 1) { + p <- NULL + method <- NULL + } else { + if(length(x)<3){ #shapiro.test throws an error if n<3 + shapirog=0 + } else if(length(x)<5000){ + shapirog <- tapply(x, g, function(x) shapiro.test(x)$p.value) + } else { #on large samples, shapiro.test is not relevant + shapirog=1 + } + + if (any(ng < 30) | any(shapirog < 0.05)) { + if (length(ng) == 2) { + type <- "wilcox" + } else { + type <- "kruskal" + } + } + else { + bartlettg <- bartlett.test(x, g)$p.value + if (bartlettg < 0.05 & length(ng) == 2) { + type <- "t.unequalvar" + } + else if (bartlettg < 0.05 & length(ng) > 2) { + type <- "a.unequalvar" + } + else if (bartlettg >= 0.05 & length(ng) == 2) {#DAN ajoute un egal au cas où bartlettg==0.05! + type <- "t.equalvar" + } + else if (bartlettg >= 0.05 & length(ng) > 2) { + type <- "a.equalvar" + } + } + test <- switch(type, + wilcox = wilcox.test(x ~ g, correct = FALSE), + kruskal = kruskal.test(x, g), + t.unequalvar = t.test(x ~ g, var.equal = FALSE), + t.equalvar = t.test(x ~ g, var.equal = TRUE), + a.unequalvar = oneway.test(x ~ g, var.equal = FALSE), + a.equalvar = oneway.test(x ~ g, var.equal = TRUE)) + p <- test$p.value + method <- test$method + } + list(p.value = p, method = method) +} + +test.tabular.auto.dan = function (x, y) { + tab <- table(x, y) + if(is.ordered(x) & is.ordered(y)){ + test <- cor.test(as.numeric(x), as.numeric(y), method = "spearman", exact = FALSE) + } else if((is.ordered(x) | is.ordered(y)) & any(dim(tab)==2)){ + test <- DescTools::CochranArmitageTest(tab, alternative = "two.sided") + } else{ + exp <- rowSums(tab) %*% t(colSums(tab))/sum(tab) + if (any(dim(table(x, y)) == 1)) + test <- list(p.value = NULL, method = NULL) + else if (all(exp >= 5)) + test <- suppressWarnings(chisq.test(x, y, correct = FALSE)) + else test <- fisher.test(x, y) + } + p <- test$p.value + method <- test$method + list(p.value = p, method = method) +} diff --git a/README.Rmd b/README.Rmd new file mode 100644 index 0000000..d5cdd62 --- /dev/null +++ b/README.Rmd @@ -0,0 +1,170 @@ +--- + output: github_document +--- + + + +```{r setup, include=FALSE} +knitr::opts_chunk$set( + collapse=TRUE, + comment="#>", + fig.path="man/figures/README-", + out.width="100%" +) +options(Encoding="UTF-8") +library(knitr) +library(biostat2) +library(Hmisc) +library(officer) +library(dplyr) +# cross(cbind(agegp, ncases) ~ tobgp, esoph, margin="row", test = TRUE) %>% cross_to_flextable %>% autofit %>% save_as_image("img/cross_esoph.png", zoom=30) +# cross(cbind(Sepal.Length, Sepal.Width) ~ Species, iris, test = TRUE, total="column") %>% cross_to_flextable %>% autofit %>% save_as_image("img/cross_iris.png", zoom=30) +# cross(cbind(mpg, qsec) ~ factor(am), mtcars2, effect=T, test=TRUE, show.method=F) %>% cross_to_flextable %>% autofit %>% save_as_image("img/cross_mtcars.png", zoom=30) +``` + +# biostat2 + +[![Lifecycle: superseded](https://img.shields.io/badge/lifecycle-superseded-blue.svg)](https://www.tidyverse.org/lifecycle/#superseded) + +Ceci est un fork du super package [`biostat2`](https://github.com/eusebe/biostat2) de David Hajage. + +Il est centré sur la fonction `cross` qui permet de générer très facilement les *statistiques descriptives* d'une étude et s'intègre naturellement au package `officer` permettant de faire un rapport automatisé. + +# Important + +Ce fork a été totalement réécrit et optimisé dans un nouveau package :[`crosstable`](https://github.com/DanChaltiel/crosstable). Celui-ci permet une nouvelle syntaxe plus efficace avec l'utilisation des helpers de `tidyselect`, des fonctions predicates, et l'output (`flextable`) a été amélioré. Aucune mise-à-jour ne sera effectuée sur ce fork, je vous conseille donc vivement d'utiliser soit le package [`biostat2`](https://github.com/eusebe/biostat2) original, soit le nouveau package [`crosstable`](https://github.com/DanChaltiel/crosstable). + +## Installation + +```{r install, eval=FALSE} +install.packages("devtools") +remotes::install_github("DanChaltiel/biostat2") +library(biostat2) +# cross=biostat2::cross #lancer si purrr est chargé pour overrider purrr::cross +``` + +## Utilisation + +### Description + +On décrit une table avec une formule. On utilise `cbind` pour récupérer une dataframe en sortie, mais on pourrait aussi utiliser des `+` et récupérer une liste de descriptions par variable. A droite du `~` on trouve la variable de groupe ou un `.` sinon. Par défaut, `cross` donnera la moyenne, écart-type, médiane, IQR, min, max, nombre d'observations et nombre de manquants. + +```{r cross1, echo=TRUE} +cross(cbind(Sepal.Length, Petal.Length) ~ Species, data=iris) + +cross(cbind(Sepal.Length, Petal.Length, Species) ~ ., data=iris) +``` + +On peut spécifier des calculs spécifiques dans la formule avec la fonction `I()`, on peut utiliser n'importe quelle fonction de description (ajouter les arguments à la suite, comme l'argument `probs` de la fonction `quantile` ici) et on peut demander des totaux en ligne, en colonne ou les deux. + +```{r cross2, echo=TRUE} +cross(cbind(Sepal.Length, I(Sepal.Width^2)) ~ Species, iris, funs=quantile, probs=c(1/3, 2/3), total="row") #T1 & T2 by Species +``` + +Les pourcentages sont donnés par défaut par ligne, colonne et cellule, mais on peut restreindre avec l'argument `margin`. L'argument `test` permet de faire le test adéquat en fonction de règles définies. + +```{r cross3, echo=TRUE} +cross(alcgp ~ tobgp, esoph, margin="row", total="both", test=TRUE) +``` + +Si le groupement n'a que deux niveau, il est possible de calculer un effet grâce à l'argument `effect`. +```{r cross4, echo=TRUE} +cross(cbind(mpg, qsec) ~ factor(am), mtcars, effect=T, test=TRUE, show.method=F) +``` + +Enfin, si la variable de groupe est numérique, `cross` sortira les coefficients de corrélation. +```{r cross5, echo=TRUE} +cross(cbind(Sepal.Length, Sepal.Width) ~ cbind(Petal.Length, Petal.Width), iris) +``` + +### Labels + +`cross` est interfacé avec la fonction `label` du package `Hmisc`, ce qui permet d'avoir des tableaux plus clairs. +```{r cross6, echo=TRUE} +library(Hmisc) +# ?mtcars +mtcars2=mtcars +label(mtcars2$mpg) = "Miles/(US) gallon" +label(mtcars2$qsec) = "1/4 mile time in seconds" +mtcars2$am = factor(mtcars2$am, levels=0:1, labels=c("automatic", "manual")) +cross(cbind(mpg, qsec) ~ am, mtcars2) +``` + + +## Reporting + +### Tableaux HTML + +Il est possible de transformer une table en HTML via la fonction `cross_to_flextable())`. + +```{r packages2, message=FALSE, warning=FALSE, include=FALSE} +library(flextable) +library(dplyr) #for the pipe operator +``` + +```{r flextable1, echo=TRUE, eval=FALSE} +cross(cbind(agegp, ncases) ~ tobgp, esoph, margin="row", test = TRUE) %>% cross_to_flextable +``` +
+ +```{r flextable2, echo=TRUE, eval=FALSE} +cross(cbind(Sepal.Length, Sepal.Width) ~ Species, iris, test = TRUE, total="column") %>% cross_to_flextable +``` +
+ +```{r flextable3, echo=TRUE, eval=FALSE} +cross(cbind(mpg, qsec) ~ factor(am), mtcars2, effect=T, test=TRUE, show.method=F) %>% cross_to_flextable +``` +
+ +### Intégration avec `officer` + +Grâce au package `officer`, il est possible de réaliser des fichiers MS Word. On peut ajouter des tableaux `cross` de cette façon : + + ```{r officer, echo=TRUE, eval=FALSE} + library(officer) + library(dplyr) #for the pipe operator + c1 = cross(cbind(Sepal.Length, Petal.Length) ~ Species, test=TRUE, show.method=F, data=iris) + c2 = cross(cbind(mpg, qsec) ~ factor(am), mtcars2, test=TRUE, show.method=F) + read_docx() %>% + body_add_title("Cross + officer = <3", 1) %>% + body_add_title("Premier exemple : iris", 2) %>% + body_add_crosstable(c1) %>% + body_add_title("Deuxième exemple : mtcars", 2) %>% + body_add_crosstable(c2, auto.fit=T) %>% + print("exemples/cross_officer.docx") + ``` + +A noter toutefois que les tableaux devront être agrandis avec l'ajustement automatique de Word, l'argument `auto.fit` pouvant largement dépasser les marges de la page. Le fichier de sortie est donc disponible ici : [cross_officer.docx](exemples/cross_officer.docx) + +### Intégration avec `Rmarkdown` + + + +Tricoter (`knitr::knit()` ou via **RStudio**) ce code `Rmd` produit un fichier MS Word. L'avantage ici est l'utilisation de `bookdown` pour générer la numérotation automatique des tableaux. + +````markdown + +--- +title: "Iris" +output: bookdown::word_document2 +--- + +`r ''````{r setup, include=FALSE} +library(biostat2) +library(flextable) +library(dplyr) #pour le pipe %>% +``` + +Table iris is given in Table \@ref(tab:irisTable). + +`r ''````{r description, echo=FALSE, results='asis'} +cat(" (\\#tab:irisTable) Table Iris \n\r ") +cross(cbind(Sepal.Length, Sepal.Width) ~ Species, iris, test = TRUE, total="column") %>% cross_to_flextable %>% autofit +``` + +```` + +Le fichier `Rmarkdown` est disponible ici : [cross_markdown.Rmd](exemples/cross_markdown.Rmd) et le fichier de sortie est disponible ici : [cross_markdown.docx](exemples/cross_markdown.docx) + + diff --git a/README.md b/README.md index b079d9c..a123f49 100644 --- a/README.md +++ b/README.md @@ -1 +1,297 @@ -For now, the package implements `cross` (a partial rewrite of `remix`) \ No newline at end of file + + + +# biostat2 + +[![Lifecycle: +superseded](https://img.shields.io/badge/lifecycle-superseded-blue.svg)](https://www.tidyverse.org/lifecycle/#superseded) + +Ceci est un fork du super package +[`biostat2`](https://github.com/eusebe/biostat2) de David Hajage. + +Il est centré sur la fonction `cross` qui permet de générer très +facilement les *statistiques descriptives* d’une étude et s’intègre +naturellement au package `officer` permettant de faire un rapport +automatisé. + +# Important + +Ce fork a été totalement réécrit et optimisé dans un nouveau package +:[`crosstable`](https://github.com/DanChaltiel/crosstable). Celui-ci +permet une nouvelle syntaxe plus efficace avec l’utilisation des helpers +de `tidyselect`, des fonctions predicates, et l’output (`flextable`) a +été amélioré. Aucune mise-à-jour ne sera effectuée sur ce fork, je vous +conseille donc vivement d’utiliser soit le package +[`biostat2`](https://github.com/eusebe/biostat2) original, soit le +nouveau package +[`crosstable`](https://github.com/DanChaltiel/crosstable). + +## Installation + +``` r +install.packages("devtools") +remotes::install_github("DanChaltiel/biostat2") +library(biostat2) +# cross=biostat2::cross #lancer si purrr est chargé pour overrider purrr::cross +``` + +## Utilisation + +### Description + +On décrit une table avec une formule. On utilise `cbind` pour récupérer +une dataframe en sortie, mais on pourrait aussi utiliser des `+` et +récupérer une liste de descriptions par variable. A droite du `~` on +trouve la variable de groupe ou un `.` sinon. Par défaut, `cross` +donnera la moyenne, écart-type, médiane, IQR, min, max, nombre +d’observations et nombre de manquants. + +``` r +cross(cbind(Sepal.Length, Petal.Length) ~ Species, data=iris) +#> .id label variable setosa versicolor +#> 1 Sepal.Length Sepal.Length Min / Max 4.3 / 5.8 4.9 / 7 +#> 2 Sepal.Length Sepal.Length Med [IQR] 5 [4.8;5.2] 5.9 [5.6;6.3] +#> 3 Sepal.Length Sepal.Length Moy (std) 5.01 (0.35) 5.94 (0.52) +#> 4 Sepal.Length Sepal.Length N (NA) 50 (0) 50 (0) +#> 5 Petal.Length Petal.Length Min / Max 1 / 1.9 3 / 5.1 +#> 6 Petal.Length Petal.Length Med [IQR] 1.5 [1.4;1.58] 4.35 [4;4.6] +#> 7 Petal.Length Petal.Length Moy (std) 1.46 (0.17) 4.26 (0.47) +#> 8 Petal.Length Petal.Length N (NA) 50 (0) 50 (0) +#> virginica +#> 1 4.9 / 7.9 +#> 2 6.5 [6.23;6.9] +#> 3 6.59 (0.64) +#> 4 50 (0) +#> 5 4.5 / 6.9 +#> 6 5.55 [5.1;5.88] +#> 7 5.55 (0.55) +#> 8 50 (0) + +cross(cbind(Sepal.Length, Petal.Length, Species) ~ ., data=iris) +#> .id label variable value +#> 1 Sepal.Length Sepal.Length Min / Max 4.3 / 7.9 +#> 2 Sepal.Length Sepal.Length Med [IQR] 5.8 [5.1;6.4] +#> 3 Sepal.Length Sepal.Length Moy (std) 5.84 (0.83) +#> 4 Sepal.Length Sepal.Length N (NA) 150 (0) +#> 5 Petal.Length Petal.Length Min / Max 1 / 6.9 +#> 6 Petal.Length Petal.Length Med [IQR] 4.35 [1.6;5.1] +#> 7 Petal.Length Petal.Length Moy (std) 3.76 (1.77) +#> 8 Petal.Length Petal.Length N (NA) 150 (0) +#> 9 Species Species setosa 50 (33.33%) +#> 10 Species Species versicolor 50 (33.33%) +#> 11 Species Species virginica 50 (33.33%) +``` + +On peut spécifier des calculs spécifiques dans la formule avec la +fonction `I()`, on peut utiliser n’importe quelle fonction de +description (ajouter les arguments à la suite, comme l’argument `probs` +de la fonction `quantile` ici) et on peut demander des totaux en ligne, +en colonne ou les deux. + +``` r +cross(cbind(Sepal.Length, I(Sepal.Width^2)) ~ Species, iris, funs=quantile, probs=c(1/3, 2/3), total="row") #T1 & T2 by Species +#> .id label variable setosa versicolor +#> 1 Sepal.Length Sepal.Length quantile 33.33333% 4.9 5.7 +#> 2 Sepal.Length Sepal.Length quantile 66.66667% 5.1 6.1 +#> 3 I(Sepal.Width^2) I(Sepal.Width^2) quantile 33.33333% 10.46 7.29 +#> 4 I(Sepal.Width^2) I(Sepal.Width^2) quantile 66.66667% 12.25 8.41 +#> virginica Total +#> 1 6.3 5.4 +#> 2 6.77 6.3 +#> 3 7.84 8.41 +#> 4 9.41 10.24 +``` + +Les pourcentages sont donnés par défaut par ligne, colonne et cellule, +mais on peut restreindre avec l’argument `margin`. L’argument `test` +permet de faire le test adéquat en fonction de règles définies. + +``` r +cross(alcgp ~ tobgp, esoph, margin="row", total="both", test=TRUE) +#> .id label variable 0-9g/day 10-19 20-29 30+ +#> 1 alcgp alcgp 0-39g/day 6 (26.09%) 6 (26.09%) 5 (21.74%) 6 (26.09%) +#> 2 alcgp alcgp 40-79 6 (26.09%) 6 (26.09%) 6 (26.09%) 5 (21.74%) +#> 3 alcgp alcgp 80-119 6 (28.57%) 6 (28.57%) 4 (19.05%) 5 (23.81%) +#> 4 alcgp alcgp 120+ 6 (28.57%) 6 (28.57%) 5 (23.81%) 4 (19.05%) +#> 5 alcgp alcgp Total 24 (27.27%) 24 (27.27%) 20 (22.73%) 20 (22.73%) +#> Total p +#> 1 23 (26.14%) p value: 0.9999 \n(Fisher's Exact Test for Count Data) +#> 2 23 (26.14%) p value: 0.9999 \n(Fisher's Exact Test for Count Data) +#> 3 21 (23.86%) p value: 0.9999 \n(Fisher's Exact Test for Count Data) +#> 4 21 (23.86%) p value: 0.9999 \n(Fisher's Exact Test for Count Data) +#> 5 88 (100%) p value: 0.9999 \n(Fisher's Exact Test for Count Data) +``` + +Si le groupement n’a que deux niveau, il est possible de calculer un +effet grâce à l’argument `effect`. + +``` r +cross(cbind(mpg, qsec) ~ factor(am), mtcars, effect=T, test=TRUE, show.method=F) +#> .id label variable 0 1 +#> 1 mpg mpg Min / Max 10.4 / 24.4 15 / 33.9 +#> 2 mpg mpg Med [IQR] 17.3 [14.95;19.2] 22.8 [21;30.4] +#> 3 mpg mpg Moy (std) 17.15 (3.83) 24.39 (6.17) +#> 4 mpg mpg N (NA) 19 (0) 13 (0) +#> 5 qsec qsec Min / Max 15.41 / 22.9 14.5 / 19.9 +#> 6 qsec qsec Med [IQR] 17.82 [17.18;19.17] 17.02 [16.46;18.61] +#> 7 qsec qsec Moy (std) 18.18 (1.75) 17.36 (1.79) +#> 8 qsec qsec N (NA) 19 (0) 13 (0) +#> effect +#> 1 Difference in means (t-test CI) (0 minus 1): -7.24 CI95%[-10.85 to -3.64] +#> 2 Difference in means (t-test CI) (0 minus 1): -7.24 CI95%[-10.85 to -3.64] +#> 3 Difference in means (t-test CI) (0 minus 1): -7.24 CI95%[-10.85 to -3.64] +#> 4 Difference in means (t-test CI) (0 minus 1): -7.24 CI95%[-10.85 to -3.64] +#> 5 Difference in means (t-test CI) (0 minus 1): 0.82 CI95%[-0.48 to 2.12] +#> 6 Difference in means (t-test CI) (0 minus 1): 0.82 CI95%[-0.48 to 2.12] +#> 7 Difference in means (t-test CI) (0 minus 1): 0.82 CI95%[-0.48 to 2.12] +#> 8 Difference in means (t-test CI) (0 minus 1): 0.82 CI95%[-0.48 to 2.12] +#> p +#> 1 0.0003 +#> 2 0.0003 +#> 3 0.0003 +#> 4 0.0003 +#> 5 0.2057 +#> 6 0.2057 +#> 7 0.2057 +#> 8 0.2057 +``` + +Enfin, si la variable de groupe est numérique, `cross` sortira les +coefficients de corrélation. + +``` r +cross(cbind(Sepal.Length, Sepal.Width) ~ cbind(Petal.Length, Petal.Width), iris) +#> .id label variable Petal.Length variable Petal.Width +#> 1 Sepal.Length Sepal.Length pearson 0.87 pearson 0.82 +#> 2 Sepal.Width Sepal.Width pearson -0.43 pearson -0.37 +``` + +### Labels + +`cross` est interfacé avec la fonction `label` du package `Hmisc`, ce +qui permet d’avoir des tableaux plus clairs. + +``` r +library(Hmisc) +# ?mtcars +mtcars2=mtcars +label(mtcars2$mpg) = "Miles/(US) gallon" +label(mtcars2$qsec) = "1/4 mile time in seconds" +mtcars2$am = factor(mtcars2$am, levels=0:1, labels=c("automatic", "manual")) +cross(cbind(mpg, qsec) ~ am, mtcars2) +#> .id label variable automatic +#> 1 mpg Miles/(US) gallon Min / Max 10.4 / 24.4 +#> 2 mpg Miles/(US) gallon Med [IQR] 17.3 [14.95;19.2] +#> 3 mpg Miles/(US) gallon Moy (std) 17.15 (3.83) +#> 4 mpg Miles/(US) gallon N (NA) 19 (0) +#> 5 qsec 1/4 mile time in seconds Min / Max 15.41 / 22.9 +#> 6 qsec 1/4 mile time in seconds Med [IQR] 17.82 [17.18;19.17] +#> 7 qsec 1/4 mile time in seconds Moy (std) 18.18 (1.75) +#> 8 qsec 1/4 mile time in seconds N (NA) 19 (0) +#> manual +#> 1 15 / 33.9 +#> 2 22.8 [21;30.4] +#> 3 24.39 (6.17) +#> 4 13 (0) +#> 5 14.5 / 19.9 +#> 6 17.02 [16.46;18.61] +#> 7 17.36 (1.79) +#> 8 13 (0) +``` + +## Reporting + +### Tableaux HTML + +Il est possible de transformer une table en HTML via la fonction +`cross_to_flextable())`. + +``` r +cross(cbind(agegp, ncases) ~ tobgp, esoph, margin="row", test = TRUE) %>% cross_to_flextable +``` + +
+ + + +
+ +``` r +cross(cbind(Sepal.Length, Sepal.Width) ~ Species, iris, test = TRUE, total="column") %>% cross_to_flextable +``` + +
+ + + +
+ +``` r +cross(cbind(mpg, qsec) ~ factor(am), mtcars2, effect=T, test=TRUE, show.method=F) %>% cross_to_flextable +``` + +
+ + + +
+ +### Intégration avec `officer` + +Grâce au package `officer`, il est possible de réaliser des fichiers MS +Word. On peut ajouter des tableaux `cross` de cette façon : + + ```r + library(officer) + library(dplyr) #for the pipe operator + c1 = cross(cbind(Sepal.Length, Petal.Length) ~ Species, test=TRUE, show.method=F, data=iris) + c2 = cross(cbind(mpg, qsec) ~ factor(am), mtcars2, test=TRUE, show.method=F) + read_docx() %>% + body_add_title("Cross + officer = <3", 1) %>% + body_add_title("Premier exemple : iris", 2) %>% + body_add_crosstable(c1) %>% + body_add_title("Deuxième exemple : mtcars", 2) %>% + body_add_crosstable(c2, auto.fit=T) %>% + print("exemples/cross_officer.docx") + ``` + +A noter toutefois que les tableaux devront être agrandis avec +l’ajustement automatique de Word, l’argument `auto.fit` pouvant +largement dépasser les marges de la page. Le fichier de sortie est donc +disponible ici : [cross\_officer.docx](exemples/cross_officer.docx) + +### Intégration avec `Rmarkdown` + + + + + +Tricoter (`knitr::knit()` ou via **RStudio**) ce code `Rmd` produit un +fichier MS Word. L’avantage ici est l’utilisation de `bookdown` pour +générer la numérotation automatique des tableaux. + +```` markdown + +--- +title: "Iris" +output: bookdown::word_document2 +--- + +```{r setup, include=FALSE} +library(biostat2) +library(flextable) +library(dplyr) #pour le pipe %>% +``` + +Table iris is given in Table \@ref(tab:irisTable). + +```{r description, echo=FALSE, results='asis'} +cat(" (\\#tab:irisTable) Table Iris \n\r ") +cross(cbind(Sepal.Length, Sepal.Width) ~ Species, iris, test = TRUE, total="column") %>% cross_to_flextable %>% autofit +``` +```` + +Le fichier `Rmarkdown` est disponible ici : +[cross\_markdown.Rmd](exemples/cross_markdown.Rmd) et le fichier de +sortie est disponible ici : +[cross\_markdown.docx](exemples/cross_markdown.docx) diff --git a/biostat2.Rproj b/biostat2.Rproj index 4fa70f0..828602d 100644 --- a/biostat2.Rproj +++ b/biostat2.Rproj @@ -7,7 +7,7 @@ AlwaysSaveHistory: Default EnableCodeIndexing: Yes UseSpacesForTab: Yes NumSpacesForTab: 4 -Encoding: ISO8859-1 +Encoding: UTF-8 RnwWeave: Sweave LaTeX: pdfLaTeX @@ -15,3 +15,4 @@ LaTeX: pdfLaTeX BuildType: Package PackageUseDevtools: Yes PackageInstallArgs: --no-multiarch --with-keep.source +PackageRoxygenize: rd,collate,namespace diff --git a/exemples/cross_markdown.Rmd b/exemples/cross_markdown.Rmd new file mode 100644 index 0000000..d46316f --- /dev/null +++ b/exemples/cross_markdown.Rmd @@ -0,0 +1,19 @@ +--- + title: "Iris" + output: bookdown::word_document2 + output_file: "cross_markdown.docx" +--- + + +```{r setup, include=FALSE} +library(biostat2) +library(flextable) +library(dplyr) #pour le pipe %>% +``` + +Table iris is given in Table \@ref(tab:irisTable). + +```{r description, echo=FALSE, results='asis'} +cat(" (\\#tab:irisTable) Table Iris \n\r ") +cross(cbind(Sepal.Length, Sepal.Width) ~ Species, iris, test = TRUE, total="column") %>% cross_to_flextable %>% autofit +``` \ No newline at end of file diff --git a/exemples/cross_markdown.docx b/exemples/cross_markdown.docx new file mode 100644 index 0000000..3ab6473 Binary files /dev/null and b/exemples/cross_markdown.docx differ diff --git a/exemples/cross_officer.docx b/exemples/cross_officer.docx new file mode 100644 index 0000000..38b319c Binary files /dev/null and b/exemples/cross_officer.docx differ diff --git a/img/cross_esoph.png b/img/cross_esoph.png new file mode 100644 index 0000000..e098c53 Binary files /dev/null and b/img/cross_esoph.png differ diff --git a/img/cross_iris.png b/img/cross_iris.png new file mode 100644 index 0000000..9ab9a16 Binary files /dev/null and b/img/cross_iris.png differ diff --git a/img/cross_mtcars.png b/img/cross_mtcars.png new file mode 100644 index 0000000..2704dd4 Binary files /dev/null and b/img/cross_mtcars.png differ diff --git a/man/FlexCrossTable-ReporteRs.Rd b/man/FlexCrossTable-ReporteRs.Rd index 08cf156..633f567 100644 --- a/man/FlexCrossTable-ReporteRs.Rd +++ b/man/FlexCrossTable-ReporteRs.Rd @@ -1,12 +1,20 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/addCrossTable.r +% Please edit documentation in R/body_add_crosstable.r \name{FlexCrossTable-ReporteRs} \alias{FlexCrossTable-ReporteRs} \alias{FlexCrossTable} -\title{Create a FlexTable object from a table made by the cross function} +\title{Deprecated +Create a FlexTable object from a table made by the cross function} \usage{ -FlexCrossTable(crosstable, compact = FALSE, id = ".id", - variable = "variable", value = "value", effect = "effect", p = "p") +FlexCrossTable( + crosstable, + compact = FALSE, + id = ".id", + variable = "variable", + value = "value", + effect = "effect", + p = "p" +) } \arguments{ \item{crosstable}{the result of \code{cross} function} @@ -27,7 +35,7 @@ FlexCrossTable(crosstable, compact = FALSE, id = ".id", A \code{FlexTable} object (see \code{ReporteRs} package) } \description{ -Create a FlexTable object from a table made by the cross function +**Deprecation** : Since \code{ReporteRs} is deprecated and not available on CRAN, please use \code{flextable} and \code{officer} packages instead. } \examples{ \dontrun{ diff --git a/man/Max.Rd b/man/Max.Rd deleted file mode 100644 index 25d9138..0000000 --- a/man/Max.Rd +++ /dev/null @@ -1,20 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/na.r -\name{Max} -\alias{Max} -\title{Return the max (and have formals)} -\usage{ -Max(x, na.rm = FALSE) -} -\arguments{ -\item{x}{a vector} - -\item{na.rm}{Remove NA?} -} -\description{ -Return the max (and have formals) -} -\author{ -David Hajage -} -\keyword{univar} diff --git a/man/Min.Rd b/man/Min.Rd deleted file mode 100644 index d96ddcf..0000000 --- a/man/Min.Rd +++ /dev/null @@ -1,20 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/na.r -\name{Min} -\alias{Min} -\title{Return the min (and have formals)} -\usage{ -Min(x, na.rm = FALSE) -} -\arguments{ -\item{x}{a vector} - -\item{na.rm}{Remove NA?} -} -\description{ -Return the min (and have formals) -} -\author{ -David Hajage -} -\keyword{univar} diff --git a/man/addCrossTable.Rd b/man/addCrossTable.Rd index e530373..c9927c5 100644 --- a/man/addCrossTable.Rd +++ b/man/addCrossTable.Rd @@ -1,11 +1,19 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/addCrossTable.r +% Please edit documentation in R/body_add_crosstable.r \name{addCrossTable} \alias{addCrossTable} -\title{add a table made by the cross function into a ReporteRs document} +\title{Deprecated +add a table made by the cross function into a ReporteRs document} \usage{ -addCrossTable(doc, crosstable, compact = FALSE, id = ".id", - variable = "variable", value = "value", p = "p") +addCrossTable( + doc, + crosstable, + compact = FALSE, + id = ".id", + variable = "variable", + value = "value", + p = "p" +) } \arguments{ \item{doc}{a \code{docx} object created by \code{docx} function (see \code{ReporteRs} package)} @@ -26,7 +34,7 @@ addCrossTable(doc, crosstable, compact = FALSE, id = ".id", A \code{docx} object } \description{ -add a table made by the cross function into a ReporteRs document +**Deprecation** : Since \code{ReporteRs} is deprecated and not available on CRAN, please use \code{officer} and \code{biostats2::body_add_crosstable} instead. } \examples{ \dontrun{ @@ -37,6 +45,9 @@ doc <- docx() doc <- addCrossTable(doc, mytable) doc <- addPageBreak(doc) doc <- addCrossTable(doc, mytable, TRUE) +dfile <- "test_doc.docx" +print(doc, target = dfile) +shell.exec(dfile) } } \author{ diff --git a/man/as.crosstable.Rd b/man/as.crosstable.Rd new file mode 100644 index 0000000..619139b --- /dev/null +++ b/man/as.crosstable.Rd @@ -0,0 +1,36 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/body_add_crosstable.r +\name{as.crosstable} +\alias{as.crosstable} +\title{Coerce to a Crosstable (for officer docx addition)} +\usage{ +as.crosstable(df, labs.col = "???") +} +\arguments{ +\item{df}{a data.frame} + +\item{labs.col}{the name of the grouping variable} +} +\value{ +a cross +} +\description{ +Coerce to a Crosstable (for officer docx addition) +} +\examples{ +library(dplyr) #for the pipe operator +library(officer) +mytable = cross(cbind(Sepal.Length, I(Sepal.Width^2)) ~ Species, iris) \%>\% + as.data.frame \%>\% #loses attributes + as.crosstable(labs.col = "Species") + +doc <- read_docx() \%>\% + body_add_crosstable(mytable) + +\dontrun{ +dfile <- "test_doc.docx" +print(doc, target = dfile) +shell.exec(dfile) +} + +} diff --git a/man/biostats2SummaryFunctions.Rd b/man/biostats2SummaryFunctions.Rd new file mode 100644 index 0000000..e9c8c01 --- /dev/null +++ b/man/biostats2SummaryFunctions.Rd @@ -0,0 +1,84 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/funs.r +\name{biostats2SummaryFunctions} +\alias{biostats2SummaryFunctions} +\alias{moystd} +\alias{mediqr} +\alias{minmax} +\alias{nna} +\title{Summary functions} +\usage{ +moystd( + x, + na.rm = TRUE, + dig = 2, + fixed_format = getOption("biostat2_fixed_format", FALSE), + zero_digits = 1 +) + +mediqr( + x, + na.rm = TRUE, + dig = 2, + fixed_format = getOption("biostat2_fixed_format", FALSE), + zero_digits = 1 +) + +minmax(x, na.rm = TRUE, dig = 2) + +nna(x) +} +\arguments{ +\item{x}{a numeric vector} + +\item{na.rm}{\code{TRUE} as default} + +\item{dig}{number of digits} + +\item{fixed_format}{use \code{\link{format_fixed}} instead of round (default)} + +\item{zero_digits}{is fixed_format==TRUE, number of significant digits for values rounded to 0 (set to NULL to keep the original 0 value)} +} +\description{ +Summary functions to use with \code{\link{cross}} or anywhere else. +} +\section{Functions}{ +\itemize{ +\item \code{moystd}: returns mean and std error + +\item \code{mediqr}: returns median and IQR + +\item \code{minmax}: returns minimum and maximum + +\item \code{nna}: returns number of observations and number of missing values +}} + +\section{Fixed format}{ + +The use of the \code{fixed_format} argument allows to have trailing zeros after rounded values. +In the case when the output of rounded values is zero, the use of the \code{zero_digits} argument allows to keep some significant digits for this specific case only. +} + +\examples{ +moystd(iris$Sepal.Length, dig=3) +minmax(iris$Sepal.Length, dig=3) +mediqr(iris$Sepal.Length, dig=3) +nna(iris$Sepal.Length, dig=3) + +x = iris$Sepal.Length/10000 #closer to zero + +moystd(x, dig=3, fixed_format=T) +moystd(x, dig=3, fixed_format=T, zero_digits=NULL) +options("biostat2_fixed_format"=T) +moystd(x, dig=3, zero_digits=2) +options("biostat2_fixed_format"=NULL) + +} +\seealso{ +\code{\link{format_fixed}} +} +\author{ +Dan Chaltiel + +David Hajage +} diff --git a/man/body_add_crosstable_bak.Rd b/man/body_add_crosstable_bak.Rd new file mode 100644 index 0000000..91f77ed --- /dev/null +++ b/man/body_add_crosstable_bak.Rd @@ -0,0 +1,66 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/body_add_crosstable.r +\name{body_add_crosstable_bak} +\alias{body_add_crosstable_bak} +\title{OLD: Adds a table made by the cross function into an officer document} +\usage{ +body_add_crosstable_bak( + doc, + crosstable, + compact = FALSE, + auto.fit = FALSE, + id = ".id", + variable = "variable", + label = "label", + value = "value", + p = "p", + show.test.name = F +) +} +\arguments{ +\item{doc}{a \code{rdocx} object created by \code{read_docx} function (see \code{officer} package)} + +\item{crosstable}{the result of \code{cross} function} + +\item{compact}{whether to compact the table} + +\item{auto.fit}{whether to \code{flextable::autofit} the table} + +\item{id}{name of the 'id' column} + +\item{variable}{name of the 'variable' column} + +\item{label}{name of the 'label' column} + +\item{value}{name of the 'value' column} + +\item{p}{name of the 'p' column} + +\item{show.test.name}{in the p column, show the test name} +} +\value{ +A \code{rdocx} object +} +\description{ +OLD: Adds a table made by the cross function into an officer document +} +\examples{ +library(dplyr) #for the pipe operator +library(officer) +mytable <- cross(cbind(...) ~ tobgp, esoph, test = TRUE) +mytable <- cross(cbind(...) ~ Species, iris, test = TRUE) +mytable <- cross(cbind(...) ~ ., esoph) +doc <- read_docx() \%>\% + body_add_crosstable(mytable) \%>\% + body_add_break \%>\% + body_add_crosstable(mytable, TRUE) + +\dontrun{ +dfile <- "test_doc.docx" +print(doc, target = dfile) +shell.exec(dfile) +} +} +\author{ +Dan Chaltiel +} diff --git a/man/body_add_normal.Rd b/man/body_add_normal.Rd new file mode 100644 index 0000000..57d931d --- /dev/null +++ b/man/body_add_normal.Rd @@ -0,0 +1,49 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/officer.r +\name{body_add_normal} +\alias{body_add_normal} +\alias{body_add_glued} +\title{Add a new paragraph with a Normal style, inserting variables with \code{base::paste}} +\usage{ +body_add_normal(doc, ...) + +body_add_glued(doc, x, ...) +} +\arguments{ +\item{doc}{the doc object (created with the \code{read_docx} function of \code{officer} package)} + +\item{...}{parameters to be passed to \code{glue::glue}} + +\item{x}{the string with \code{glue::glue} patterns (Expressions enclosed by braces will be evaluated as R code)} +} +\value{ +a new doc object + +a new doc object +} +\description{ +Add a new paragraph with a Normal style, inserting variables with \code{base::paste} + +Add a new paragraph with a Normal style, inserting variables with \code{glue::glue} +} +\examples{ +\dontrun{ +library(officer) +library(biostat2) +library(dplyr) +doc = read_docx() +doc = doc \%>\% body_add_normal("La table iris a ", ncol(iris), " colonnes.") +} +\dontrun{ +library(officer) +library(biostat2) +library(dplyr) +doc = read_docx() +doc = body_add_glued(doc, "La table iris a {ncol(iris)} colonnes.") +} +} +\author{ +Dan Chaltiel + +Dan Chaltiel +} diff --git a/man/body_add_table_legend.Rd b/man/body_add_table_legend.Rd new file mode 100644 index 0000000..5008f8b --- /dev/null +++ b/man/body_add_table_legend.Rd @@ -0,0 +1,28 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/body_add_legend.r +\name{body_add_table_legend} +\alias{body_add_table_legend} +\title{Add a table legend} +\usage{ +body_add_table_legend( + x, + legend, + legend_style = "table title", + style = "strong", + seqfield = "SEQ Table \\\\* Arabic" +) +} +\arguments{ +\item{x}{a docx object} + +\item{legend}{the table legend} + +\item{legend_style}{may depend on the docx template} + +\item{style}{the legend style (strnog, italic...)} + +\item{seqfield}{to figure this out, in a docx file, insert a table legend, right click on the inserted number and select "Toggle Field Codes". This argument should be the value of the field, with extra escaping.} +} +\description{ +Add a table legend +} diff --git a/man/body_add_title.Rd b/man/body_add_title.Rd new file mode 100644 index 0000000..a05a3f9 --- /dev/null +++ b/man/body_add_title.Rd @@ -0,0 +1,36 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/officer.r +\name{body_add_title} +\alias{body_add_title} +\title{Add a new title} +\usage{ +body_add_title(x, value, level = 1, style = "heading") +} +\arguments{ +\item{value}{a character string} + +\item{level}{the level of the title. See \code{styles_info(doc)} to know the possibilities.} + +\item{doc}{the doc object (created with the \code{read_docx} function of \code{officer} package)} +} +\value{ +a new doc object +} +\description{ +Add a new title +} +\examples{ +\dontrun{ +library(officer) +library(biostat2) +library(dplyr) +doc = read_docx() +doc = doc \%>\% + body_add_title(doc, "La table iris", 1) \%>\% + body_add_title(doc, "Description", 2) \%>\% + addNormal(doc, "La table iris a ", ncol(iris), " colonnes.") +} +} +\author{ +Dan Chaltiel +} diff --git a/man/compact.Rd b/man/compact.Rd index c3b83a8..ce11408 100644 --- a/man/compact.Rd +++ b/man/compact.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/addCrossTable.r +% Please edit documentation in R/body_add_crosstable.r \name{compact} \alias{compact} \title{Compact the result of cross function} @@ -7,12 +7,15 @@ compact(x) } \arguments{ -\item{x}{x} +\item{x}{a crosstable, the result of \code{cross} function} } \description{ Compact the result of cross function } +\examples{ +mytable <- cross(cbind(...) ~ tobgp, esoph, test = TRUE) +compact(mytable) +} \author{ David Hajage } -\keyword{internal} diff --git a/man/correlation.data.frame.Rd b/man/correlation.data.frame.Rd index 275dd36..10b6190 100644 --- a/man/correlation.data.frame.Rd +++ b/man/correlation.data.frame.Rd @@ -4,8 +4,13 @@ \alias{correlation.data.frame} \title{Compute correlation (data.frame input)} \usage{ -correlation.data.frame(dfx, dfy, method = c("pearson", "kendall", "spearman"), - digits = 2, label = FALSE) +correlation.data.frame( + dfx, + dfy, + method = c("pearson", "kendall", "spearman"), + digits = 2, + label = FALSE +) } \arguments{ \item{dfx}{data.frame} diff --git a/man/create.report.Rd b/man/create.report.Rd index ec27db0..655aaf1 100644 --- a/man/create.report.Rd +++ b/man/create.report.Rd @@ -4,10 +4,21 @@ \alias{create.report} \title{Create a docx object with a specific template and informations already inserted} \usage{ -create.report(template = c("gerc", "urc", "cephepi"), title = "", - acronym = "", version = "", npromo = "", nct = "", invest = "", - biostat = "", methodo = "", date_lastmodif = "", date_freez = "", - date_update = "", history = NULL) +create.report( + template = c("gerc", "urc", "cephepi"), + title = "", + acronym = "", + version = "", + npromo = "", + nct = "", + invest = "", + biostat = "", + methodo = "", + date_lastmodif = "", + date_freez = "", + date_update = "", + history = NULL +) } \arguments{ \item{template}{either 'gerc', 'urc', or 'cephepi'} diff --git a/man/cross.Rd b/man/cross.Rd index 35aa9b1..b02957b 100644 --- a/man/cross.Rd +++ b/man/cross.Rd @@ -1,19 +1,36 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/remix.r +% Please edit documentation in R/cross.r \name{cross} \alias{cross} \title{Describe everything} \usage{ -cross(formula = cbind(...) ~ ., data = NULL, funs = c(` ` = mysummary), - ..., margin = 0:2, total = FALSE, digits = 2, showNA = c("no", - "ifany", "always"), method = c("pearson", "kendall", "spearman"), - times = NULL, followup = FALSE, test = FALSE, +cross( + formula = cbind(...) ~ ., + data = NULL, + funs = c(` ` = cross_summary), + ..., + margin = c("all", "row", "column", "cell"), + total = c("none", "all", "row", "column", "FALSE", "TRUE", 0, 1, 2), + digits = 2, + showNA = c("no", "ifany", "always"), + method = c("pearson", "kendall", "spearman"), + times = NULL, + followup = FALSE, + test = FALSE, test.summarize = test.summarize.auto, - test.survival = test.survival.logrank, test.tabular = test.tabular.auto, - show.test = display.test, plim = 4, show.method = TRUE, - effect = FALSE, effect.summarize = diff.mean.auto, - effect.tabular = or.row.by.col, effect.survival = effect.survival.coxph, - conf.level = 0.95, label = FALSE, regroup = FALSE) + test.survival = test.survival.logrank, + test.tabular = test.tabular.auto, + show.test = display.test, + plim = 4, + show.method = TRUE, + effect = FALSE, + effect.summarize = diff.mean.auto, + effect.tabular = or.row.by.col, + effect.survival = effect.survival.coxph, + conf.level = 0.95, + label = TRUE, + regroup = FALSE +) } \arguments{ \item{formula}{a formula (see Details).} @@ -147,19 +164,25 @@ grouped in the same table. \code{cbind(...)} works (ie regroups all variables of the data.frame together). When a \code{cbind} is in both sides of the formula, \code{cross} will do its best to group everything in the same table, but only if it is possible... + + +\lifecycle{superseded} +\Sexpr[results=rd, stage=render]{lifecycle::badge("superseded")} } \examples{ library(biostat2) cross(data = iris) -cross(cbind(...) ~ ., iris[, sapply(iris, is.numeric)], funs = c(median, mad, min, max)) -cross(cbind(Sepal.Length, I(Sepal.Width^2)) ~ Species, iris, funs = quantile, probs = c(1/3, 2/3)) +cross(cbind(...) ~ ., iris[, sapply(iris, is.numeric)], funs=c(median, mad, min, max)) +cross(cbind(Sepal.Length, I(Sepal.Width^2)) ~ Species, iris, funs=quantile, probs=c(1/3, 2/3), total="row") #tertiles 1 and 2 by Species cross(Sepal.Length + Sepal.Width ~ Petal.Length + Petal.Width, iris) cross(cbind(Sepal.Length, Sepal.Width) ~ cbind(Petal.Length, Petal.Width), iris) -cross(... ~ ., esoph) -cross(alcgp ~ tobgp, esoph, test = TRUE) +cross(... ~ ., esoph) #returns a list +cross(alcgp ~ tobgp, esoph, margin="row", total="both", test=TRUE) +cross(cbind(hp, mpg) ~ factor(am), mtcars, effect=TRUE, test=TRUE, show.method=FALSE) library(survival) cross(Surv(time, status) ~ x, data = aml) + } \seealso{ \code{cast} (reshape) and \code{summary.formula} (Hmisc). diff --git a/man/cross_all.Rd b/man/cross_all.Rd index 3b5f0ce..6c9d96c 100644 --- a/man/cross_all.Rd +++ b/man/cross_all.Rd @@ -1,19 +1,35 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/remix.r +% Please edit documentation in R/cross.r \name{cross_all} \alias{cross_all} \title{Cross all x with all y} \usage{ -cross_all(x, y = NULL, funs = c(mean, sd, quantile, n, na), ..., - margin = 0:2, total = FALSE, digits = 2, showNA = c("no", "ifany", - "always"), method = c("pearson", "kendall", "spearman"), times = NULL, - followup = FALSE, test = FALSE, test.tabular = test.tabular.auto, +cross_all( + x, + y = NULL, + funs = c(mean, sd, quantile, n, na), + ..., + margin = 0:2, + total = FALSE, + digits = 2, + showNA = c("no", "ifany", "always"), + method = c("pearson", "kendall", "spearman"), + times = NULL, + followup = FALSE, + test = FALSE, + test.tabular = test.tabular.auto, test.summarize = test.summarize.auto, - test.survival = test.survival.logrank, show.test = display.test, - plim = 4, show.method = TRUE, effect = FALSE, - effect.summarize = diff.mean.auto, effect.tabular = or.row.by.col, - effect.survival = effect.survival.coxph, conf.level = 0.95, - label = FALSE) + test.survival = test.survival.logrank, + show.test = display.test, + plim = 4, + show.method = TRUE, + effect = FALSE, + effect.summarize = diff.mean.auto, + effect.tabular = or.row.by.col, + effect.survival = effect.survival.coxph, + conf.level = 0.95, + label = FALSE +) } \arguments{ \item{x}{x} diff --git a/man/cross_list.Rd b/man/cross_list.Rd index d197327..bda09b5 100644 --- a/man/cross_list.Rd +++ b/man/cross_list.Rd @@ -1,18 +1,34 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/remix.r +% Please edit documentation in R/cross.r \name{cross_list} \alias{cross_list} \title{Cross variables in a list} \usage{ -cross_list(l, funs = c(mean, sd, quantile, n, na), ..., margin = 0:2, - total = FALSE, digits = 2, showNA = c("no", "ifany", "always"), - method = c("pearson", "kendall", "spearman"), times = NULL, - followup = FALSE, test = FALSE, test.summarize = test.summarize.auto, - test.survival = test.survival.logrank, test.tabular = test.tabular.auto, - show.test = display.test, plim = 4, show.method = TRUE, - effect = FALSE, effect.summarize = diff.mean.auto, - effect.tabular = or.row.by.col, effect.survival = effect.survival.coxph, - conf.level = 0.95, label = FALSE) +cross_list( + l, + funs = c(mean, sd, quantile, n, na), + ..., + margin = 0:2, + total = FALSE, + digits = 2, + showNA = c("no", "ifany", "always"), + method = c("pearson", "kendall", "spearman"), + times = NULL, + followup = FALSE, + test = FALSE, + test.summarize = test.summarize.auto, + test.survival = test.survival.logrank, + test.tabular = test.tabular.auto, + show.test = display.test, + plim = 4, + show.method = TRUE, + effect = FALSE, + effect.summarize = diff.mean.auto, + effect.tabular = or.row.by.col, + effect.survival = effect.survival.coxph, + conf.level = 0.95, + label = FALSE +) } \arguments{ \item{l}{l} diff --git a/man/cross_one.Rd b/man/cross_one.Rd index d56fb21..dc48e55 100644 --- a/man/cross_one.Rd +++ b/man/cross_one.Rd @@ -1,19 +1,35 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/remix.r +% Please edit documentation in R/cross.r \name{cross_one} \alias{cross_one} \title{Cross one x and one y} \usage{ -cross_one(x, y = NULL, funs = c(mean, sd, quantile, n, na), ..., - margin = 0:2, total = FALSE, digits = 2, showNA = c("no", "ifany", - "always"), method = c("pearson", "kendall", "spearman"), times = NULL, - followup = FALSE, test = FALSE, test.tabular = test.tabular.auto, +cross_one( + x, + y = NULL, + funs = c(mean, sd, quantile, n, na), + ..., + margin = 0:2, + total = FALSE, + digits = 2, + showNA = c("no", "ifany", "always"), + method = c("pearson", "kendall", "spearman"), + times = NULL, + followup = FALSE, + test = FALSE, + test.tabular = test.tabular.auto, test.summarize = test.summarize.auto, - test.survival = test.survival.logrank, show.test = display.test, - plim = 4, show.method = TRUE, effect = FALSE, - effect.summarize = diff.mean.auto, effect.tabular = or.row.by.col, - effect.survival = effect.survival.coxph, conf.level = 0.95, - label = FALSE) + test.survival = test.survival.logrank, + show.test = display.test, + plim = 4, + show.method = TRUE, + effect = FALSE, + effect.summarize = diff.mean.auto, + effect.tabular = or.row.by.col, + effect.survival = effect.survival.coxph, + conf.level = 0.95, + label = FALSE +) } \arguments{ \item{x}{x} diff --git a/man/mysummary.Rd b/man/cross_summary.Rd similarity index 51% rename from man/mysummary.Rd rename to man/cross_summary.Rd index ec3ca05..4c62ee7 100644 --- a/man/mysummary.Rd +++ b/man/cross_summary.Rd @@ -1,19 +1,25 @@ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/funs.r -\name{mysummary} +\name{cross_summary} +\alias{cross_summary} \alias{mysummary} \title{Summarize a numeric vector} \usage{ -mysummary(x, na.rm = TRUE, dig = 2) +cross_summary(x, dig = 2) + +mysummary(x, dig = 2) } \arguments{ \item{x}{a numeric vector} -\item{na.rm}{\code{TRUE} as default} - \item{dig}{number of digits} } \description{ Summarize a numeric vector } +\section{Note}{ + +Function \code{mysummary} is kept for compatibility with old codes. It produces the same exact object than \code{cross_summary}, which should be preferred. +} + \keyword{internal} diff --git a/man/cross_to_flextable.Rd b/man/cross_to_flextable.Rd new file mode 100644 index 0000000..3149852 --- /dev/null +++ b/man/cross_to_flextable.Rd @@ -0,0 +1,81 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/body_add_crosstable.r +\name{cross_to_flextable} +\alias{cross_to_flextable} +\alias{body_add_crosstable} +\title{Crosstables output} +\usage{ +cross_to_flextable( + crosstable, + compact = FALSE, + auto.fit = FALSE, + id = ".id", + variable = "variable", + label = "label", + value = "value", + p = "p", + effect = "effect", + total = "Total", + show.test.name = F, + generic.labels = c(id, variable, label, value, p, effect, total) +) + +body_add_crosstable(doc, ...) +} +\arguments{ +\item{crosstable}{the result of \code{cross} function} + +\item{compact}{whether to compact the table} + +\item{auto.fit}{whether to \code{flextable::autofit} the table} + +\item{id}{name of the 'id' column} + +\item{variable}{name of the 'variable' column} + +\item{label}{name of the 'label' column} + +\item{value}{name of the 'value' column} + +\item{p}{name of the 'p' column} + +\item{show.test.name}{in the p column, show the test name} + +\item{doc}{a \code{rdocx} object created by \code{read_docx} function (see \code{officer} package)} + +\item{...}{arguments for \code{cross_to_flextable}} +} +\value{ +A \code{rdocx} object +} +\description{ +\code{cross_to_flextable} turns a table made by the cross function into a flextable. + +\code{body_add_crosstable2} adds a table made by the cross function into an officer document +} +\examples{ +### cross_to_flextable +library(dplyr) #for the pipe operator +library(officer) +cross(cbind(...) ~ tobgp, esoph, test = TRUE) \%>\% cross_to_flextable +cross(cbind(...) ~ Species, iris, test = TRUE) \%>\% cross_to_flextable +cross(cbind(...) ~ ., esoph) \%>\% cross_to_flextable + +### body_add_crosstable +#mytable <- cross(cbind(...) ~ tobgp, esoph, test = TRUE) +#mytable <- cross(cbind(...) ~ Species, iris, test = TRUE) +mytable <- cross(cbind(...) ~ ., esoph) +doc <- read_docx() \%>\% + body_add_crosstable(mytable) \%>\% + body_add_break \%>\% + body_add_crosstable(mytable, compact=TRUE) + +\dontrun{ +dfile <- "test_doc.docx" +print(doc, target = dfile) +shell.exec(dfile) +} +} +\author{ +Dan Chaltiel +} diff --git a/man/diff.mean.auto.Rd b/man/diff.mean.auto.Rd new file mode 100644 index 0000000..9739227 --- /dev/null +++ b/man/diff.mean.auto.Rd @@ -0,0 +1,23 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/effect.r +\name{diff.mean.auto} +\alias{diff.mean.auto} +\title{Effect measure for association between one continuous and one categorical variable} +\usage{ +\method{diff}{mean.auto}(x, g, conf.level = 0.95, R = 500) +} +\arguments{ +\item{x}{vector} + +\item{conf.level}{confidence interval level} + +\item{R}{number of bootstrap replication} + +\item{y}{another vector} +} +\value{ +a list with five componments +} +\description{ +Effect measure for association between one continuous and one categorical variable +} diff --git a/man/diff.mean.boot.Rd b/man/diff.mean.boot.Rd new file mode 100644 index 0000000..1424189 --- /dev/null +++ b/man/diff.mean.boot.Rd @@ -0,0 +1,23 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/effect.r +\name{diff.mean.boot} +\alias{diff.mean.boot} +\title{Effect measure for association between one continuous and one categorical variable} +\usage{ +\method{diff}{mean.boot}(x, g, conf.level = 0.95, R = 500) +} +\arguments{ +\item{x}{vector} + +\item{conf.level}{confidence interval level} + +\item{R}{number of bootstrap replication} + +\item{y}{another vector} +} +\value{ +a list with five componments +} +\description{ +Effect measure for association between one continuous and one categorical variable +} diff --git a/man/diff.mean.student.Rd b/man/diff.mean.student.Rd new file mode 100644 index 0000000..a273bab --- /dev/null +++ b/man/diff.mean.student.Rd @@ -0,0 +1,21 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/effect.r +\name{diff.mean.student} +\alias{diff.mean.student} +\title{Effect measure for association between one continuous and one categorical variable} +\usage{ +\method{diff}{mean.student}(x, g, conf.level = 0.95) +} +\arguments{ +\item{x}{vector} + +\item{conf.level}{confidence interval level} + +\item{y}{another vector} +} +\value{ +a list with five componments +} +\description{ +Effect measure for association between one continuous and one categorical variable +} diff --git a/man/diff.median.Rd b/man/diff.median.Rd new file mode 100644 index 0000000..b1f5b86 --- /dev/null +++ b/man/diff.median.Rd @@ -0,0 +1,23 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/effect.r +\name{diff.median} +\alias{diff.median} +\title{Effect measure for association between one continuous and one categorical variable} +\usage{ +\method{diff}{median}(x, g, conf.level = 0.95, R = 500) +} +\arguments{ +\item{x}{vector} + +\item{conf.level}{confidence interval level} + +\item{R}{number of bootstrap replication} + +\item{y}{another vector} +} +\value{ +a list with five componments +} +\description{ +Effect measure for association between one continuous and one categorical variable +} diff --git a/man/effect.survival.coxph.Rd b/man/effect.survival.coxph.Rd new file mode 100644 index 0000000..f8f6116 --- /dev/null +++ b/man/effect.survival.coxph.Rd @@ -0,0 +1,20 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/effect.r +\name{effect.survival.coxph} +\alias{effect.survival.coxph} +\title{Effect measure for association between one consored variable and one categorical variable} +\usage{ +effect.survival.coxph(formula, conf.level = 0.95) +} +\arguments{ +\item{formula}{a formula} +} +\value{ +a list with two componments: p.value and method +} +\description{ +Effect measure for association between one consored variable and one categorical variable +} +\author{ +David Hajage +} diff --git a/man/figures/lifecycle-archived.svg b/man/figures/lifecycle-archived.svg new file mode 100644 index 0000000..48f72a6 --- /dev/null +++ b/man/figures/lifecycle-archived.svg @@ -0,0 +1 @@ + lifecyclelifecyclearchivedarchived \ No newline at end of file diff --git a/man/figures/lifecycle-defunct.svg b/man/figures/lifecycle-defunct.svg new file mode 100644 index 0000000..01452e5 --- /dev/null +++ b/man/figures/lifecycle-defunct.svg @@ -0,0 +1 @@ +lifecyclelifecycledefunctdefunct \ No newline at end of file diff --git a/man/figures/lifecycle-deprecated.svg b/man/figures/lifecycle-deprecated.svg new file mode 100644 index 0000000..4baaee0 --- /dev/null +++ b/man/figures/lifecycle-deprecated.svg @@ -0,0 +1 @@ +lifecyclelifecycledeprecateddeprecated \ No newline at end of file diff --git a/man/figures/lifecycle-experimental.svg b/man/figures/lifecycle-experimental.svg new file mode 100644 index 0000000..d1d060e --- /dev/null +++ b/man/figures/lifecycle-experimental.svg @@ -0,0 +1 @@ +lifecyclelifecycleexperimentalexperimental \ No newline at end of file diff --git a/man/figures/lifecycle-maturing.svg b/man/figures/lifecycle-maturing.svg new file mode 100644 index 0000000..df71310 --- /dev/null +++ b/man/figures/lifecycle-maturing.svg @@ -0,0 +1 @@ +lifecyclelifecyclematuringmaturing \ No newline at end of file diff --git a/man/figures/lifecycle-questioning.svg b/man/figures/lifecycle-questioning.svg new file mode 100644 index 0000000..08ee0c9 --- /dev/null +++ b/man/figures/lifecycle-questioning.svg @@ -0,0 +1 @@ +lifecyclelifecyclequestioningquestioning \ No newline at end of file diff --git a/man/figures/lifecycle-soft-deprecated.svg b/man/figures/lifecycle-soft-deprecated.svg new file mode 100644 index 0000000..9f014fd --- /dev/null +++ b/man/figures/lifecycle-soft-deprecated.svg @@ -0,0 +1 @@ +lifecyclelifecyclesoft-deprecatedsoft-deprecated \ No newline at end of file diff --git a/man/figures/lifecycle-stable.svg b/man/figures/lifecycle-stable.svg new file mode 100644 index 0000000..e015dc8 --- /dev/null +++ b/man/figures/lifecycle-stable.svg @@ -0,0 +1 @@ +lifecyclelifecyclestablestable \ No newline at end of file diff --git a/man/figures/lifecycle-superseded.svg b/man/figures/lifecycle-superseded.svg new file mode 100644 index 0000000..75f24f5 --- /dev/null +++ b/man/figures/lifecycle-superseded.svg @@ -0,0 +1 @@ + lifecyclelifecyclesupersededsuperseded \ No newline at end of file diff --git a/man/format_fixed.Rd b/man/format_fixed.Rd new file mode 100644 index 0000000..ebec969 --- /dev/null +++ b/man/format_fixed.Rd @@ -0,0 +1,36 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/funs.r +\name{format_fixed} +\alias{format_fixed} +\title{Format numbers with same number of decimals, including trailing zeros} +\usage{ +format_fixed(x, digits, zero_digits = 1, only_round = FALSE) +} +\arguments{ +\item{x}{a numeric vector to format} + +\item{digits}{number of decimals} + +\item{zero_digits}{number of significant digits for values rounded to 0 (set to NULL to keep the original 0 value)} + +\item{only_round}{util option, to simply return rounded value instead of formatted} +} +\value{ +a character vector of formatted numbers +} +\description{ +Format numbers with same number of decimals, including trailing zeros +} +\examples{ +x = c(1, 1.2, 12.78749, pi, 0.00000012) +format_fixed(x, digits=3) +format_fixed(x, digits=3, zero_digits=2) +format_fixed(x, digits=3, zero_digits=NULL) +x = iris$Sepal.Length/10000 +x \%>\% +sd(na.rm=na.rm) \%>\% + format_fixed(dig=3, zero_digits=2, only_round=T) +} +\author{ +Dan Chaltiel +} diff --git a/man/freq.data.frame.Rd b/man/freq.data.frame.Rd index 818b6d0..03bc137 100644 --- a/man/freq.data.frame.Rd +++ b/man/freq.data.frame.Rd @@ -4,8 +4,13 @@ \alias{freq.data.frame} \title{Compute frequencies (data.frame input)} \usage{ -freq.data.frame(df, showNA = c("no", "ifany", "always"), total = FALSE, - digits = 2, label = FALSE) +freq.data.frame( + df, + showNA = c("no", "ifany", "always"), + total = FALSE, + digits = 2, + label = FALSE +) } \arguments{ \item{df}{data.frame} diff --git a/man/is.character.or.factor.Rd b/man/is.character.or.factor.Rd index 2204a2e..5c37645 100644 --- a/man/is.character.or.factor.Rd +++ b/man/is.character.or.factor.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/remix.r +% Please edit documentation in R/cross.r \name{is.character.or.factor} \alias{is.character.or.factor} \title{test} diff --git a/man/is.numeric.and.not.surv.Rd b/man/is.numeric.and.not.surv.Rd index 8d00cde..3d1fb41 100644 --- a/man/is.numeric.and.not.surv.Rd +++ b/man/is.numeric.and.not.surv.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/remix.r +% Please edit documentation in R/cross.r \name{is.numeric.and.not.surv} \alias{is.numeric.and.not.surv} \title{test} diff --git a/man/mediqr.Rd b/man/mediqr.Rd deleted file mode 100644 index a846143..0000000 --- a/man/mediqr.Rd +++ /dev/null @@ -1,19 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/funs.r -\name{mediqr} -\alias{mediqr} -\title{Return median and IQR} -\usage{ -mediqr(x, na.rm = TRUE, dig = 2) -} -\arguments{ -\item{x}{a numeric vector} - -\item{na.rm}{\code{TRUE} as default} - -\item{dig}{number of digits} -} -\description{ -Return median and IQR -} -\keyword{internal} diff --git a/man/minmax.Rd b/man/minmax.Rd deleted file mode 100644 index ae2f729..0000000 --- a/man/minmax.Rd +++ /dev/null @@ -1,19 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/funs.r -\name{minmax} -\alias{minmax} -\title{Return min and max} -\usage{ -minmax(x, na.rm = TRUE, dig = 2) -} -\arguments{ -\item{x}{a numeric vector} - -\item{na.rm}{\code{TRUE} as default} - -\item{dig}{number of digits} -} -\description{ -Return min and max -} -\keyword{internal} diff --git a/man/moystd.Rd b/man/moystd.Rd deleted file mode 100644 index 2c502e8..0000000 --- a/man/moystd.Rd +++ /dev/null @@ -1,19 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/funs.r -\name{moystd} -\alias{moystd} -\title{Return mean and sd} -\usage{ -moystd(x, na.rm = TRUE, dig = 2) -} -\arguments{ -\item{x}{a numeric vector} - -\item{na.rm}{\code{TRUE} as default} - -\item{dig}{number of digits} -} -\description{ -Return mean and sd -} -\keyword{internal} diff --git a/man/nna.Rd b/man/nna.Rd deleted file mode 100644 index cf72c8b..0000000 --- a/man/nna.Rd +++ /dev/null @@ -1,15 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/funs.r -\name{nna} -\alias{nna} -\title{Return n and na} -\usage{ -nna(x) -} -\arguments{ -\item{x}{a numeric vector} -} -\description{ -Return n and na -} -\keyword{internal} diff --git a/man/or.col.by.row.Rd b/man/or.col.by.row.Rd new file mode 100644 index 0000000..0df1f35 --- /dev/null +++ b/man/or.col.by.row.Rd @@ -0,0 +1,21 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/effect.r +\name{or.col.by.row} +\alias{or.col.by.row} +\title{Effect measure for association between two factors} +\usage{ +or.col.by.row(x, y, conf.level = 0.95) +} +\arguments{ +\item{x}{vector} + +\item{y}{another vector} + +\item{conf.level}{confidence interval level} +} +\value{ +a list with five componments +} +\description{ +Effect measure for association between two factors +} diff --git a/man/or.row.by.col.Rd b/man/or.row.by.col.Rd new file mode 100644 index 0000000..8ba1724 --- /dev/null +++ b/man/or.row.by.col.Rd @@ -0,0 +1,21 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/effect.r +\name{or.row.by.col} +\alias{or.row.by.col} +\title{Effect measure for association between two factors} +\usage{ +or.row.by.col(x, y, conf.level = 0.95) +} +\arguments{ +\item{x}{vector} + +\item{y}{another vector} + +\item{conf.level}{confidence interval level} +} +\value{ +a list with five componments +} +\description{ +Effect measure for association between two factors +} diff --git a/man/paste.matrix.Rd b/man/paste.matrix.Rd index 9447ee6..460aa53 100644 --- a/man/paste.matrix.Rd +++ b/man/paste.matrix.Rd @@ -4,8 +4,13 @@ \alias{paste.matrix} \title{paste.matrix} \usage{ -paste.matrix(..., sep = " ", transpose.vector = FALSE, collapse = NULL, - byrow = FALSE) +paste.matrix( + ..., + sep = " ", + transpose.vector = FALSE, + collapse = NULL, + byrow = FALSE +) } \arguments{ \item{...}{...} diff --git a/man/rd.col.by.row.Rd b/man/rd.col.by.row.Rd new file mode 100644 index 0000000..f4f48dc --- /dev/null +++ b/man/rd.col.by.row.Rd @@ -0,0 +1,21 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/effect.r +\name{rd.col.by.row} +\alias{rd.col.by.row} +\title{Effect measure for association between two factors} +\usage{ +rd.col.by.row(x, y, conf.level = 0.95) +} +\arguments{ +\item{x}{vector} + +\item{y}{another vector} + +\item{conf.level}{confidence interval level} +} +\value{ +a list with five componments +} +\description{ +Effect measure for association between two factors +} diff --git a/man/rd.row.by.col.Rd b/man/rd.row.by.col.Rd new file mode 100644 index 0000000..7568896 --- /dev/null +++ b/man/rd.row.by.col.Rd @@ -0,0 +1,21 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/effect.r +\name{rd.row.by.col} +\alias{rd.row.by.col} +\title{Effect measure for association between two factors} +\usage{ +rd.row.by.col(x, y, conf.level = 0.95) +} +\arguments{ +\item{x}{vector} + +\item{y}{another vector} + +\item{conf.level}{confidence interval level} +} +\value{ +a list with five componments +} +\description{ +Effect measure for association between two factors +} diff --git a/man/regroup.Rd b/man/regroup.Rd index 4dd9846..a890e9f 100644 --- a/man/regroup.Rd +++ b/man/regroup.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/remix.r +% Please edit documentation in R/cross.r \name{regroup} \alias{regroup} \title{Regroup factors with factors, and numerical variables with numerical variables} diff --git a/man/rr.col.by.row.Rd b/man/rr.col.by.row.Rd new file mode 100644 index 0000000..86a8dcc --- /dev/null +++ b/man/rr.col.by.row.Rd @@ -0,0 +1,21 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/effect.r +\name{rr.col.by.row} +\alias{rr.col.by.row} +\title{Effect measure for association between two factors} +\usage{ +rr.col.by.row(x, y, conf.level = 0.95) +} +\arguments{ +\item{x}{vector} + +\item{y}{another vector} + +\item{conf.level}{confidence interval level} +} +\value{ +a list with five componments +} +\description{ +Effect measure for association between two factors +} diff --git a/man/rr.row.by.col.Rd b/man/rr.row.by.col.Rd new file mode 100644 index 0000000..35adc36 --- /dev/null +++ b/man/rr.row.by.col.Rd @@ -0,0 +1,21 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/effect.r +\name{rr.row.by.col} +\alias{rr.row.by.col} +\title{Effect measure for association between two factors} +\usage{ +rr.row.by.col(x, y, conf.level = 0.95) +} +\arguments{ +\item{x}{vector} + +\item{y}{another vector} + +\item{conf.level}{confidence interval level} +} +\value{ +a list with five componments +} +\description{ +Effect measure for association between two factors +} diff --git a/man/summarize.by.Rd b/man/summarize.by.Rd index 50619e8..f0d987e 100644 --- a/man/summarize.by.Rd +++ b/man/summarize.by.Rd @@ -4,12 +4,24 @@ \alias{summarize.by} \title{Compute summary statistics according to a factor} \usage{ -summarize.by(x, by, funs = c(mean, sd, quantile, n, na), ..., - showNA = c("no", "ifany", "always"), total = FALSE, digits = 2, - test = FALSE, test.summarize = test.summarize.auto, - show.test = display.test, plim = 4, show.method = TRUE, - effect = FALSE, effect.summarize = diff.mean.auto, conf.level = 0.95, - show.effect = display.effect) +summarize.by( + x, + by, + funs = c(mean, sd, quantile, n, na), + ..., + showNA = c("no", "ifany", "always"), + total = FALSE, + digits = 2, + test = FALSE, + test.summarize = test.summarize.auto, + show.test = display.test, + plim = 4, + show.method = TRUE, + effect = FALSE, + effect.summarize = diff.mean.auto, + conf.level = 0.95, + show.effect = display.effect +) } \arguments{ \item{x}{numeric object} diff --git a/man/summarize.data.frame.Rd b/man/summarize.data.frame.Rd index e089ddb..bda6d14 100644 --- a/man/summarize.data.frame.Rd +++ b/man/summarize.data.frame.Rd @@ -4,8 +4,13 @@ \alias{summarize.data.frame} \title{Compute summary statistics (data.frame input)} \usage{ -summarize.data.frame(df, funs = c(mean, sd, quantile, n, na), ..., - digits = 2, label = FALSE) +summarize.data.frame( + df, + funs = c(mean, sd, quantile, n, na), + ..., + digits = 2, + label = FALSE +) } \arguments{ \item{df}{a data.frame} diff --git a/man/summarize.data.frame.by.Rd b/man/summarize.data.frame.by.Rd index f9097b7..af64165 100644 --- a/man/summarize.data.frame.by.Rd +++ b/man/summarize.data.frame.by.Rd @@ -4,12 +4,25 @@ \alias{summarize.data.frame.by} \title{Compute summary statistics according to a factor (data.frame input)} \usage{ -summarize.data.frame.by(df, by, funs = c(mean, sd, quantile, n, na), ..., - showNA = c("no", "ifany", "always"), total = FALSE, digits = 2, - test = FALSE, test.summarize = test.summarize.auto, - show.test = display.test, plim = 4, show.method = TRUE, label = FALSE, - effect = FALSE, effect.summarize = diff.mean.auto, conf.level = 0.95, - show.effect = display.effect) +summarize.data.frame.by( + df, + by, + funs = c(mean, sd, quantile, n, na), + ..., + showNA = c("no", "ifany", "always"), + total = FALSE, + digits = 2, + test = FALSE, + test.summarize = test.summarize.auto, + show.test = display.test, + plim = 4, + show.method = TRUE, + label = FALSE, + effect = FALSE, + effect.summarize = diff.mean.auto, + conf.level = 0.95, + show.effect = display.effect +) } \arguments{ \item{df}{data.frame} diff --git a/man/survival.Rd b/man/survival.Rd index ee44307..cd86ae2 100644 --- a/man/survival.Rd +++ b/man/survival.Rd @@ -4,11 +4,24 @@ \alias{survival} \title{Compute survival} \usage{ -survival(surv, by = NULL, times = NULL, followup = FALSE, total = FALSE, - digits = 2, test = FALSE, test.survival = test.survival.logrank, - show.test = display.test, plim = 4, show.method = TRUE, - effect = FALSE, effect.survival = effect.survival.coxph, - show.effect = display.effect, conf.level = 0.95, label = FALSE) +survival( + surv, + by = NULL, + times = NULL, + followup = FALSE, + total = FALSE, + digits = 2, + test = FALSE, + test.survival = test.survival.logrank, + show.test = display.test, + plim = 4, + show.method = TRUE, + effect = FALSE, + effect.survival = effect.survival.coxph, + show.effect = display.effect, + conf.level = 0.95, + label = FALSE +) } \arguments{ \item{surv}{a Surv object} diff --git a/man/survival.data.frame.Rd b/man/survival.data.frame.Rd index 743a12e..13e53bc 100644 --- a/man/survival.data.frame.Rd +++ b/man/survival.data.frame.Rd @@ -4,8 +4,13 @@ \alias{survival.data.frame} \title{Compute survival (data.frame input)} \usage{ -survival.data.frame(df, times = NULL, digits = 2, followup = FALSE, - label = FALSE) +survival.data.frame( + df, + times = NULL, + digits = 2, + followup = FALSE, + label = FALSE +) } \arguments{ \item{df}{df} diff --git a/man/survival.data.frame.by.Rd b/man/survival.data.frame.by.Rd index 51cc2d2..217d5b0 100644 --- a/man/survival.data.frame.by.Rd +++ b/man/survival.data.frame.by.Rd @@ -4,12 +4,24 @@ \alias{survival.data.frame.by} \title{Compute survival according to a factor (data.frame input)} \usage{ -survival.data.frame.by(df, by, times = NULL, followup = FALSE, - total = FALSE, digits = 2, test = FALSE, - test.survival = test.survival.logrank, show.test = display.test, - plim = 4, show.method = TRUE, effect = FALSE, - effect.survival = effect.survival.coxph, show.effect = display.effect, - conf.level = 0.95, label = FALSE) +survival.data.frame.by( + df, + by, + times = NULL, + followup = FALSE, + total = FALSE, + digits = 2, + test = FALSE, + test.survival = test.survival.logrank, + show.test = display.test, + plim = 4, + show.method = TRUE, + effect = FALSE, + effect.survival = effect.survival.coxph, + show.effect = display.effect, + conf.level = 0.95, + label = FALSE +) } \arguments{ \item{df}{df} diff --git a/man/tabular.Rd b/man/tabular.Rd index c297bad..32cb6f0 100644 --- a/man/tabular.Rd +++ b/man/tabular.Rd @@ -4,11 +4,23 @@ \alias{tabular} \title{Compute a contingency table} \usage{ -tabular(x, y, showNA = c("no", "ifany", "always"), margin = 0:2, - total = FALSE, digits = 2, test = FALSE, - test.tabular = test.tabular.auto, show.test = display.test, plim = 4, - show.method = TRUE, effect = FALSE, effect.tabular = or.row.by.col, - conf.level = 0.95, show.effect = display.effect) +tabular( + x, + y, + showNA = c("no", "ifany", "always"), + margin = 0:2, + total = FALSE, + digits = 2, + test = FALSE, + test.tabular = test.tabular.auto, + show.test = display.test, + plim = 4, + show.method = TRUE, + effect = FALSE, + effect.tabular = or.row.by.col, + conf.level = 0.95, + show.effect = display.effect +) } \arguments{ \item{x}{x} diff --git a/man/tabular.data.frame.Rd b/man/tabular.data.frame.Rd index 4689891..080c420 100644 --- a/man/tabular.data.frame.Rd +++ b/man/tabular.data.frame.Rd @@ -4,11 +4,24 @@ \alias{tabular.data.frame} \title{Compute a contingency table (data.frame input)} \usage{ -tabular.data.frame(dfx, dfy, margin = 0:2, showNA = c("no", "ifany", - "always"), total = FALSE, digits = 2, test = FALSE, - test.tabular = test.tabular.auto, show.test = display.test, plim = 4, - show.method = TRUE, effect = FALSE, effect.tabular = or.row.by.col, - conf.level = 0.95, show.effect = display.effect, label = FALSE) +tabular.data.frame( + dfx, + dfy, + margin = 0:2, + showNA = c("no", "ifany", "always"), + total = FALSE, + digits = 2, + test = FALSE, + test.tabular = test.tabular.auto, + show.test = display.test, + plim = 4, + show.method = TRUE, + effect = FALSE, + effect.tabular = or.row.by.col, + conf.level = 0.95, + show.effect = display.effect, + label = FALSE +) } \arguments{ \item{dfx}{data.frame} diff --git a/man/test.summarize.contrasts.lin.Rd b/man/test.summarize.contrasts.lin.Rd new file mode 100644 index 0000000..2ae091a --- /dev/null +++ b/man/test.summarize.contrasts.lin.Rd @@ -0,0 +1,28 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/test.r +\name{test.summarize.contrasts.lin} +\alias{test.summarize.contrasts.lin} +\title{Test for linear trend across ordered factor with contrasts} +\usage{ +test.summarize.contrasts.lin(x, y) +} +\arguments{ +\item{x}{vector} + +\item{y}{ordered factor} +} +\value{ +a list with two componments: p.value and method +} +\description{ +Test for linear trend across ordered factor with contrasts +} +\examples{ +library(dplyr) +iris \%>\% + mutate(Petal.Width.qt = paste0("Q", ntile(Petal.Width, 5)) \%>\% ordered()) \%>\% + cross(Petal.Length ~ Petal.Width.qt, data=., test=T, test.summarize = test.summarize.contrasts.lin) +} +\author{ +Dan Chaltiel +} diff --git a/tests/testthat.R b/tests/testthat.R new file mode 100644 index 0000000..785b9df --- /dev/null +++ b/tests/testthat.R @@ -0,0 +1,4 @@ +library(testthat) +library(biostat2) + +test_check("biostat2") diff --git a/tests/testthat/test-cross.R b/tests/testthat/test-cross.R new file mode 100644 index 0000000..57f0614 --- /dev/null +++ b/tests/testthat/test-cross.R @@ -0,0 +1,56 @@ +context("cross tables") + +library(Hmisc) +label(iris$Species) = "Espèce" +label(iris$Sepal.Length) = "Longueur du Sépale" +label(iris$Sepal.Width) = "Longueur du Sépale" +label(iris$Petal.Length) = "Longueur du Pétale" +label(iris$Petal.Width) = "Largeur du Pétale" + + + +test_that("cross OK", { + mytable <- cross(cbind(...) ~ tobgp, esoph, test = TRUE) + + expect_equal(dim(mytable), c(18,8)) #Maybe not the most clever test... + expect_is(mytable, c("data.frame")) + expect_is(mytable, c("cross")) +}) + +test_that("compact OK", { + mytable <- cross(cbind(...) ~ tobgp, esoph, test = TRUE) %>% + compact + + expect_equal(dim(mytable), c(26,5)) + expect_is(mytable, c("data.frame")) + expect_is(mytable, c("compacted")) + expect_is(mytable, c("cross")) +}) + + +test_that("Long formula OK", { + + mytable <- cross(cbind(Sepal.Length, Sepal.Length, Sepal.Length, Sepal.Length, Sepal.Length, Sepal.Length, Sepal.Length, + Sepal.Length, Sepal.Length, Sepal.Length, Sepal.Length, Sepal.Length, Sepal.Length, Sepal.Length, + Sepal.Length, Sepal.Length, Sepal.Length, Sepal.Length, Sepal.Length, Sepal.Length, Sepal.Length, + Sepal.Length, Sepal.Length, Sepal.Length, Sepal.Width, Sepal.Length, Sepal.Length, Sepal.Length, + Sepal.Length, Sepal.Length, Sepal.Length, Sepal.Length, Sepal.Length, Sepal.Length, Sepal.Length, + Sepal.Length, Sepal.Length, Sepal.Length, Sepal.Length, I(Sepal.Width^2), Sepal.Length, Sepal.Length, + Sepal.Length, Sepal.Length, Sepal.Length, Sepal.Length, I(Sepal.Width^2), Sepal.Length, Sepal.Length, + Sepal.Length, Sepal.Length, Sepal.Length, Sepal.Length, Sepal.Length, Sepal.Length, Sepal.Length, + I(Sepal.Width^2), Sepal.Length, Sepal.Length, Sepal.Width, Sepal.Length, Sepal.Length, Sepal.Length, + Sepal.Length, Sepal.Length, Sepal.Length, Sepal.Length, Sepal.Length, Sepal.Length, Sepal.Length, + Sepal.Length, Sepal.Length, Sepal.Length, Sepal.Length) ~ Species, iris) + + expect_equal(dim(mytable), c(296,6)) + expect_is(mytable, c("data.frame")) + expect_is(mytable, c("cross")) +}) + + + +# cross(cbind(Petal.Length, Species) ~ cbind(Petal.Length, Petal.Width), iris) +# cross(Petal.Length + Species ~ Petal.Length + Petal.Width, iris) + +# crosstable(cbind(mpg, factor(vs)) + cbind(drat, hp) ~ cbind(cyl, factor(am)), mtcars) #boss de fin + diff --git a/tests/testthat/test-officer.R b/tests/testthat/test-officer.R new file mode 100644 index 0000000..557574e --- /dev/null +++ b/tests/testthat/test-officer.R @@ -0,0 +1,104 @@ +context("officer") + +crosstables = list( + simple_test = cross(cbind(...) ~ ., esoph, test = TRUE), + double_test = cross(cbind(mpg,cyl,disp) ~ factor(am), mtcars, test = TRUE), + triple_test = cross(cbind(...) ~ Species, iris, test = TRUE), + simple_no_test = cross(cbind(...) ~ ., esoph, test = F), + double_no_test = cross(cbind(mpg,cyl,disp) ~ factor(am), mtcars, test = F), + triple_no_test = cross(cbind(...) ~ Species, iris, test = F) + #des warnings sur wilcoxon mais OSEF +) + +#TODO body_add_crosstable when compacted before function + +test_that("crosstables don't throw errors in officer", { + doc <- read_docx() + #test with compact=F et compact=T + for (i in names(crosstables)) { + # print(i) + crosstable = crosstables[[i]] + expect_is(crosstable, c("cross")) + doc = doc %>% + body_add_title(i, 1) %>% + body_add_title("Not compacted", 2) %>% + body_add_crosstable(crosstable, show.test.name = F, auto.fit = T) %>% + body_add_break %>% + body_add_title("Compacted in function", 2) %>% + body_add_crosstable(crosstable, TRUE, show.test.name = F, auto.fit = T) %>% + body_add_break %>% + body_add_title("Compacted before function", 2) %>% + body_add_normal("TODO") %>% + # body_add_crosstable(compact(crosstable), show.test.name = F, auto.fit = T) %>% + body_add_break + } + print(doc, "test_cross_officer.docx") +}) + + + +test_that("crosstables are OK as flextables", { + library(purrr) + cross=biostat2::cross + library(dplyr) + library(officer) + library(Hmisc) + showNA = c("no", "ifany") + test = c(T,F) + effect = c(T,F) + label = T + total = list(F,T,1,2) + + #TODO: si total et (NA dans variable BY), mettre un footer "les chiffres sont pas bons" + #TODO: no effect for categorical variables + mtcars2 = mtcars %>% + mutate( + gear=ifelse(row_number() %in% 17:18, NA, gear), + gear=as.factor(gear), + drat=ifelse(between(drat, 3.5, 3.7), NA, drat), + qsec=ifelse(between(qsec, 17, 17.5), NA, drat), + am=ifelse(am==0, "automatic", "manual"), + am=ifelse(row_number() %in% 3:4, NA, am) + ) + label(mtcars2$drat) = "Rear axle ratio" + label(mtcars2$gear) = "Number of forward gears" + label(mtcars2$qsec) = "Time for a quarter mile" + label(mtcars2$am) = "Transmission" + + x = expand.grid(showNA, test, effect, label, total, stringsAsFactors = F) %>% + set_names(c("showNA", "test", "effect", "label", "total")) %>% + arrange #32 possibilities + + cross_tables = x %>% pmap(~{ + # print(paste(..1, ..2, ..3, ..4, ..5)) + rtn=cross( + cbind(gear, qsec) ~ am, + data=mtcars2, + showNA = ..1, + margin = 2, + test=..2, + effect=..3, + label=..4, + total=..5 + ) + expect_is(rtn, c("cross")) + rtn + }) + + # # Une table au hasard + # x %>% sample_n(1) %>% pmap(~{ + # print(paste(..1, ..2, ..3, ..4, ..5, sep=" -- ")) + # cross( + # cbind(drat, gear) ~ am, + # data=mtcars2, + # margin = 2, + # show.method = F, + # showNA = ..1, + # test=..2, + # effect=..3, + # label=..4, + # total=..5 + # ) + # }) %>% first %>% cross_to_flextable + +})