Compare commits

..

No commits in common. "a59b980a950ff21429a599da28a943c43ad5f4d2" and "2249ba06db3e192963d214cd48fc412d9b99269f" have entirely different histories.

29 changed files with 1736 additions and 555 deletions

View file

@ -12,4 +12,3 @@
^docs$
^pkgdown$
^dev$
^data-raw$

View file

@ -15,9 +15,9 @@ Imports:
dplyr,
glue,
gtsummary,
haven,
here,
quarto,
haven,
readODS,
readr,
shiny,
@ -29,14 +29,17 @@ Imports:
parameters,
DT,
performance,
ggiraph,
qqplotr,
see,
patchwork,
easystats,
DHARMa,
IDEAFilter,
sparkline,
datamods,
toastui,
webshot,
lubridate,
bsicons,
thematic,
@ -45,11 +48,18 @@ Imports:
classInt,
htmltools,
rlang,
data.table,
apexcharter,
esquisse,
janitor,
flextable,
gt,
kableExtra,
rankinPlot,
sjPlot,
gvlma,
psych,
jtools,
Hmisc,
ggstats,
rempsyc,
@ -64,7 +74,6 @@ Suggests:
styler,
devtools,
rhub,
webshot,
usethis,
roxygen2,
pak,
@ -78,6 +87,3 @@ URL: https://github.com/agdamsbo/FreesearchR, https://agdamsbo.github.io/Freesea
BugReports: https://github.com/agdamsbo/FreesearchR/issues
VignetteBuilder: knitr
Config/testthat/edition: 3
Depends:
R (>= 3.5)
LazyData: true

View file

@ -1 +1 @@
app_version <- function()'v25.4.3.250423'
app_version <- function()'Version: 25.4.3.250422'

View file

@ -695,7 +695,7 @@ line_break <- function(data, lineLength = 20, force = FALSE) {
#' @export
#'
wrap_plot_list <- function(data, tag_levels = NULL) {
if (ggplot2::is_ggplot(data[[1]])) {
if (ggplot2::is.ggplot(data[[1]])) {
if (length(data) > 1) {
out <- data |>
(\(.x){
@ -732,7 +732,7 @@ wrap_plot_list <- function(data, tag_levels = NULL) {
align_axes <- function(...) {
# https://stackoverflow.com/questions/62818776/get-axis-limits-from-ggplot-object
# https://github.com/thomasp85/patchwork/blob/main/R/plot_multipage.R#L150
if (ggplot2::is_ggplot(..1)) {
if (ggplot2::is.ggplot(..1)) {
## Assumes list of ggplots
p <- list(...)
} else if (is.list(..1)) {

View file

@ -87,7 +87,7 @@ read_input <- function(file, consider.na = c("NA", '""', "")) {
if (ext == "csv") {
df <- readr::read_csv(file = file, na = consider.na)
} else if (ext %in% c("xls", "xlsx")) {
df <- readxl::read_excel(file = file, na.strings = consider.na)
df <- openxlsx2::read_xlsx(file = file, na.strings = consider.na)
} else if (ext == "dta") {
df <- haven::read_dta(file = file)
} else if (ext == "ods") {
@ -428,7 +428,7 @@ sort_by <- function(x, y, na.rm = FALSE, ...) {
get_ggplot_label <- function(data, label) {
assertthat::assert_that(ggplot2::is_ggplot(data))
assertthat::assert_that(ggplot2::is.ggplot(data))
data$labels[[label]]
}

View file

@ -298,8 +298,7 @@ import_file_server <- function(id,
)
observeEvent(input$see_data, {
tryCatch(
{
tryCatch({
datamods:::show_data(default_parsing(temporary_rv$data), title = datamods:::i18n("Imported data"), type = show_data_in)
},
# warning = function(warn) {
@ -313,10 +312,9 @@ import_file_server <- function(id,
output$table <- toastui::renderDatagrid2({
req(temporary_rv$data)
tryCatch(
{
tryCatch({
toastui::datagrid(
data = setNames(head(temporary_rv$data, 5), make.names(names(temporary_rv$data), unique = TRUE)),
data = setNames(head(temporary_rv$data, 5),make.names(names(temporary_rv$data),unique = TRUE)),
theme = "striped",
colwidths = "guess",
minBodyHeight = 250
@ -420,22 +418,13 @@ import_xls <- function(file, sheet, skip, na.strings) {
sheet |>
purrr::map(\(.x){
readxl::read_excel(
path = file,
openxlsx2::read_xlsx(
file = file,
sheet = .x,
na = na.strings,
skip = skip,
.name_repair = "unique_quiet",
trim_ws = TRUE
skip_empty_rows = TRUE,
start_row = skip - 1,
na.strings = na.strings
)
# openxlsx2::read_xlsx(
# file = file,
# sheet = .x,
# skip_empty_rows = TRUE,
# start_row = skip - 1,
# na.strings = na.strings
# )
}) |>
purrr::reduce(dplyr::full_join)
},

View file

@ -46,7 +46,7 @@ plot_box_single <- function(data, pri, sec=NULL, seed = 2103) {
if (is.null(sec)) {
sec <- "All"
data[[sec]] <- sec
data[[y]] <- sec
}
discrete <- !data_type(data[[sec]]) %in% "continuous"

View file

@ -22,7 +22,7 @@ sankey_ready <- function(data, pri, sec, numbers = "count", ...) {
data[c(pri, sec)] <- data[c(pri, sec)] |>
dplyr::mutate(dplyr::across(!dplyr::where(is.factor), forcats::as_factor))
out <- dplyr::count(data, !!dplyr::sym(pri), !!dplyr::sym(sec), .drop = FALSE)
out <- dplyr::count(data, !!dplyr::sym(pri), !!dplyr::sym(sec))
out <- out |>
dplyr::group_by(!!dplyr::sym(pri)) |>
@ -73,17 +73,9 @@ str_remove_last <- function(data, pattern = "\n") {
#' @examples
#' ds <- data.frame(g = sample(LETTERS[1:2], 100, TRUE), first = REDCapCAST::as_factor(sample(letters[1:4], 100, TRUE)), last = REDCapCAST::as_factor(sample(letters[1:4], 100, TRUE)))
#' ds |> plot_sankey("first", "last")
#' ds |> plot_sankey("first", "last", color.group = "sec")
#' ds |> plot_sankey("first", "last", ter = "g", color.group = "sec")
#' mtcars |>
#' default_parsing() |>
#' plot_sankey("cyl", "gear", "am", color.group = "pri")
#' ## In this case, the last plot as the secondary variable in wrong order
#' ## Dont know why...
#' mtcars |>
#' default_parsing() |>
#' plot_sankey("cyl", "gear", "vs", color.group = "pri")
plot_sankey <- function(data, pri, sec, ter = NULL, color.group = "pri", colors = NULL) {
#' ds |> plot_sankey("first", "last", color.group = "y")
#' ds |> plot_sankey("first", "last", z = "g", color.group = "y")
plot_sankey <- function(data, pri, sec, ter = NULL, color.group = "x", colors = NULL) {
if (!is.null(ter)) {
ds <- split(data, data[ter])
} else {
@ -91,12 +83,16 @@ plot_sankey <- function(data, pri, sec, ter = NULL, color.group = "pri", colors
}
out <- lapply(ds, \(.ds){
plot_sankey_single(.ds, pri = pri, sec = sec, color.group = color.group, colors = colors)
plot_sankey_single(.ds, x = pri, y = sec, color.group = color.group, colors = colors)
})
patchwork::wrap_plots(out)
}
default_theme <- function() {
theme_void()
}
#' Beautiful sankey plot
#'
#' @param color.group set group to colour by. "x" or "y".
@ -110,26 +106,15 @@ plot_sankey <- function(data, pri, sec, ter = NULL, color.group = "pri", colors
#' @examples
#' ds <- data.frame(g = sample(LETTERS[1:2], 100, TRUE), first = REDCapCAST::as_factor(sample(letters[1:4], 100, TRUE)), last = REDCapCAST::as_factor(sample(letters[1:4], 100, TRUE)))
#' ds |> plot_sankey_single("first", "last")
#' ds |> plot_sankey_single("first", "last", color.group = "sec")
#' ds |> plot_sankey_single("first", "last", color.group = "y")
#' data.frame(
#' g = sample(LETTERS[1:2], 100, TRUE),
#' first = REDCapCAST::as_factor(sample(letters[1:4], 100, TRUE)),
#' last = sample(c(TRUE, FALSE, FALSE), 100, TRUE)
#' ) |>
#' plot_sankey_single("first", "last", color.group = "pri")
#' mtcars |>
#' default_parsing() |>
#' str()
#' plot_sankey_single("cyl", "vs", color.group = "pri")
plot_sankey_single <- function(data, pri, sec, color.group = c("pri", "sec"), colors = NULL, ...) {
color.group <- match.arg(color.group)
data_orig <- data
data[c(pri, sec)] <- data[c(pri, sec)] |>
dplyr::mutate(dplyr::across(dplyr::where(is.factor), forcats::fct_drop))
# browser()
data <- data |> sankey_ready(pri = pri, sec = sec, ...)
library(ggalluvial)
@ -139,17 +124,11 @@ plot_sankey_single <- function(data, pri, sec, color.group = c("pri", "sec"), co
if (is.null(colors)) {
if (color.group == "sec") {
main.colors <- viridisLite::viridis(n = length(levels(data_orig[[sec]])))
## Only keep colors for included levels
main.colors <- main.colors[match(levels(data[[sec]]), levels(data_orig[[sec]]))]
main.colors <- viridisLite::viridis(n = length(levels(data[[sec]])))
secondary.colors <- rep(na.color, length(levels(data[[pri]])))
label.colors <- Reduce(c, lapply(list(secondary.colors, rev(main.colors)), contrast_text))
} else {
main.colors <- viridisLite::viridis(n = length(levels(data_orig[[pri]])))
## Only keep colors for included levels
main.colors <- main.colors[match(levels(data[[pri]]), levels(data_orig[[pri]]))]
main.colors <- viridisLite::viridis(n = length(levels(data[[pri]])))
secondary.colors <- rep(na.color, length(levels(data[[sec]])))
label.colors <- Reduce(c, lapply(list(rev(main.colors), secondary.colors), contrast_text))
}
@ -167,11 +146,7 @@ plot_sankey_single <- function(data, pri, sec, color.group = c("pri", "sec"), co
if (color.group == "sec") {
p <- p +
ggalluvial::geom_alluvium(
ggplot2::aes(
fill = !!dplyr::sym(sec) # ,
## Including will print strings when levels are empty
# color = !!dplyr::sym(sec)
),
ggplot2::aes(fill = !!dplyr::sym(sec), color = !!dplyr::sym(sec)),
width = 1 / 16,
alpha = .8,
knot.pos = 0.4,
@ -183,10 +158,7 @@ plot_sankey_single <- function(data, pri, sec, color.group = c("pri", "sec"), co
} else {
p <- p +
ggalluvial::geom_alluvium(
ggplot2::aes(
fill = !!dplyr::sym(pri) # ,
# color = !!dplyr::sym(pri)
),
ggplot2::aes(fill = !!dplyr::sym(pri), color = !!dplyr::sym(pri)),
width = 1 / 16,
alpha = .8,
knot.pos = 0.4,
@ -210,7 +182,7 @@ plot_sankey_single <- function(data, pri, sec, color.group = c("pri", "sec"), co
labels = group_labels
) +
ggplot2::scale_fill_manual(values = colors[-1], na.value = colors[1]) +
# ggplot2::scale_color_manual(values = main.colors) +
ggplot2::scale_color_manual(values = main.colors) +
ggplot2::theme_void() +
ggplot2::theme(
legend.position = "none",

Binary file not shown.

View file

@ -1,4 +1,4 @@
# FreesearchR <img style="float: right;" src="logo-text-white-250.png">
# FreesearchR
<!-- badges: start -->
[![Lifecycle: experimental](https://img.shields.io/badge/lifecycle-experimental-orange.svg)](https://lifecycle.r-lib.org/articles/stages.html#experimental)
@ -48,5 +48,3 @@ Like any other project, this project was never possible without the great work o
- [gtsummary](https://www.danieldsjoberg.com/gtsummary/): superb and flexible way to create publication-ready analytical and summary tables.
- [dreamRs](https://github.com/dreamRs): maintainers of a broad selection of great extensions and tools for [Shiny](https://shiny.posit.co/).
This project was all written by a human and not by any AI-based tools.

View file

@ -1,166 +0,0 @@
--------------------------------------------------------------------------------
-------------------------------- R environment ---------------------------------
--------------------------------------------------------------------------------
|setting |value |
|:-----------|:------------------------------------------|
|version |R version 4.4.1 (2024-06-14) |
|os |macOS 15.3.1 |
|system |aarch64, darwin20 |
|ui |RStudio |
|language |(EN) |
|collate |en_US.UTF-8 |
|ctype |en_US.UTF-8 |
|tz |Europe/Copenhagen |
|date |2025-04-23 |
|rstudio |2024.12.1+563 Kousa Dogwood (desktop) |
|pandoc |3.6.4 @ /opt/homebrew/bin/ (via rmarkdown) |
|quarto |1.6.40 @ /usr/local/bin/quarto |
|FreesearchR |25.4.3.250423 |
--------------------------------------------------------------------------------
----------------------------------- packages -----------------------------------
--------------------------------------------------------------------------------
|package |loadedversion |date |source |
|:-------------|:-------------|:----------|:--------------|
|apexcharter |0.4.4 |2024-09-06 |CRAN (R 4.4.1) |
|askpass |1.2.1 |2024-10-04 |CRAN (R 4.4.1) |
|assertthat |0.2.1 |2019-03-21 |CRAN (R 4.4.1) |
|backports |1.5.0 |2024-05-23 |CRAN (R 4.4.1) |
|bayestestR |0.15.2 |2025-02-07 |CRAN (R 4.4.1) |
|bit |4.6.0 |2025-03-06 |CRAN (R 4.4.1) |
|bit64 |4.6.0-1 |2025-01-16 |CRAN (R 4.4.1) |
|boot |1.3-31 |2024-08-28 |CRAN (R 4.4.1) |
|broom |1.0.8 |2025-03-28 |CRAN (R 4.4.1) |
|broom.helpers |1.20.0 |2025-03-06 |CRAN (R 4.4.1) |
|bsicons |0.1.2 |2023-11-04 |CRAN (R 4.4.0) |
|bslib |0.9.0 |2025-01-30 |CRAN (R 4.4.1) |
|cachem |1.1.0 |2024-05-16 |CRAN (R 4.4.1) |
|cellranger |1.1.0 |2016-07-27 |CRAN (R 4.4.0) |
|class |7.3-23 |2025-01-01 |CRAN (R 4.4.1) |
|classInt |0.4-11 |2025-01-08 |CRAN (R 4.4.1) |
|cli |3.6.4 |2025-02-13 |CRAN (R 4.4.1) |
|colorspace |2.1-1 |2024-07-26 |CRAN (R 4.4.1) |
|commonmark |1.9.5 |2025-03-17 |CRAN (R 4.4.1) |
|correlation |0.8.7 |2025-03-03 |CRAN (R 4.4.1) |
|crayon |1.5.3 |2024-06-20 |CRAN (R 4.4.1) |
|credentials |2.0.2 |2024-10-04 |CRAN (R 4.4.1) |
|crosstalk |1.2.1 |2023-11-23 |CRAN (R 4.4.0) |
|data.table |1.17.0 |2025-02-22 |CRAN (R 4.4.1) |
|datamods |1.5.3 |2024-10-02 |CRAN (R 4.4.1) |
|datawizard |1.0.2 |2025-03-24 |CRAN (R 4.4.1) |
|desc |1.4.3 |2023-12-10 |CRAN (R 4.4.1) |
|devtools |2.4.5 |2022-10-11 |CRAN (R 4.4.0) |
|DHARMa |0.4.7 |2024-10-18 |CRAN (R 4.4.1) |
|digest |0.6.37 |2024-08-19 |CRAN (R 4.4.1) |
|dplyr |1.1.4 |2023-11-17 |CRAN (R 4.4.0) |
|DT |0.33 |2024-04-04 |CRAN (R 4.4.0) |
|e1071 |1.7-16 |2024-09-16 |CRAN (R 4.4.1) |
|easystats |0.7.4 |2025-02-06 |CRAN (R 4.4.1) |
|effectsize |1.0.0 |2024-12-10 |CRAN (R 4.4.1) |
|ellipsis |0.3.2 |2021-04-29 |CRAN (R 4.4.1) |
|esquisse |2.1.0 |2025-02-21 |CRAN (R 4.4.1) |
|evaluate |1.0.3 |2025-01-10 |CRAN (R 4.4.1) |
|farver |2.1.2 |2024-05-13 |CRAN (R 4.4.1) |
|fastmap |1.2.0 |2024-05-15 |CRAN (R 4.4.1) |
|fontawesome |0.5.3 |2024-11-16 |CRAN (R 4.4.1) |
|forcats |1.0.0 |2023-01-29 |CRAN (R 4.4.0) |
|FreesearchR |25.4.3 |NA |NA |
|fs |1.6.6 |2025-04-12 |CRAN (R 4.4.1) |
|generics |0.1.3 |2022-07-05 |CRAN (R 4.4.1) |
|gert |2.1.5 |2025-03-25 |CRAN (R 4.4.1) |
|ggplot2 |3.5.2 |2025-04-09 |CRAN (R 4.4.1) |
|glue |1.8.0 |2024-09-30 |CRAN (R 4.4.1) |
|gt |1.0.0 |2025-04-05 |CRAN (R 4.4.1) |
|gtable |0.3.6 |2024-10-25 |CRAN (R 4.4.1) |
|gtsummary |2.2.0 |2025-04-14 |CRAN (R 4.4.1) |
|haven |2.5.4 |2023-11-30 |CRAN (R 4.4.0) |
|here |1.0.1 |2020-12-13 |CRAN (R 4.4.1) |
|hms |1.1.3 |2023-03-21 |CRAN (R 4.4.0) |
|htmltools |0.5.8.1 |2024-04-04 |CRAN (R 4.4.1) |
|htmlwidgets |1.6.4 |2023-12-06 |CRAN (R 4.4.0) |
|httpuv |1.6.16 |2025-04-16 |CRAN (R 4.4.1) |
|IDEAFilter |0.2.0 |2024-04-15 |CRAN (R 4.4.0) |
|insight |1.2.0 |2025-04-22 |CRAN (R 4.4.1) |
|jquerylib |0.1.4 |2021-04-26 |CRAN (R 4.4.0) |
|jsonlite |2.0.0 |2025-03-27 |CRAN (R 4.4.1) |
|KernSmooth |2.23-26 |2025-01-01 |CRAN (R 4.4.1) |
|knitr |1.50 |2025-03-16 |CRAN (R 4.4.1) |
|later |1.4.2 |2025-04-08 |CRAN (R 4.4.1) |
|lattice |0.22-7 |2025-04-02 |CRAN (R 4.4.1) |
|lifecycle |1.0.4 |2023-11-07 |CRAN (R 4.4.1) |
|lme4 |1.1-37 |2025-03-26 |CRAN (R 4.4.1) |
|magrittr |2.0.3 |2022-03-30 |CRAN (R 4.4.1) |
|MASS |7.3-65 |2025-02-28 |CRAN (R 4.4.1) |
|Matrix |1.7-3 |2025-03-11 |CRAN (R 4.4.1) |
|memoise |2.0.1 |2021-11-26 |CRAN (R 4.4.0) |
|mime |0.13 |2025-03-17 |CRAN (R 4.4.1) |
|miniUI |0.1.2 |2025-04-17 |CRAN (R 4.4.1) |
|minqa |1.2.8 |2024-08-17 |CRAN (R 4.4.1) |
|modelbased |0.10.0 |2025-03-10 |CRAN (R 4.4.1) |
|munsell |0.5.1 |2024-04-01 |CRAN (R 4.4.1) |
|nlme |3.1-168 |2025-03-31 |CRAN (R 4.4.1) |
|nloptr |2.2.1 |2025-03-17 |CRAN (R 4.4.1) |
|openssl |2.3.2 |2025-02-03 |CRAN (R 4.4.1) |
|openxlsx2 |1.14 |2025-03-20 |CRAN (R 4.4.1) |
|parameters |0.24.2 |2025-03-04 |CRAN (R 4.4.1) |
|patchwork |1.3.0 |2024-09-16 |CRAN (R 4.4.1) |
|performance |0.13.0 |2025-01-15 |CRAN (R 4.4.1) |
|phosphoricons |0.2.1 |2024-04-08 |CRAN (R 4.4.0) |
|pillar |1.10.2 |2025-04-05 |CRAN (R 4.4.1) |
|pkgbuild |1.4.7 |2025-03-24 |CRAN (R 4.4.1) |
|pkgconfig |2.0.3 |2019-09-22 |CRAN (R 4.4.1) |
|pkgload |1.4.0 |2024-06-28 |CRAN (R 4.4.0) |
|processx |3.8.6 |2025-02-21 |CRAN (R 4.4.1) |
|profvis |0.4.0 |2024-09-20 |CRAN (R 4.4.1) |
|promises |1.3.2 |2024-11-28 |CRAN (R 4.4.1) |
|proxy |0.4-27 |2022-06-09 |CRAN (R 4.4.1) |
|ps |1.9.1 |2025-04-12 |CRAN (R 4.4.1) |
|purrr |1.0.4 |2025-02-05 |CRAN (R 4.4.1) |
|quarto |1.4.4 |2024-07-20 |CRAN (R 4.4.0) |
|R6 |2.6.1 |2025-02-15 |CRAN (R 4.4.1) |
|rbibutils |2.3 |2024-10-04 |CRAN (R 4.4.1) |
|RColorBrewer |1.1-3 |2022-04-03 |CRAN (R 4.4.1) |
|Rcpp |1.0.14 |2025-01-12 |CRAN (R 4.4.1) |
|Rdpack |2.6.4 |2025-04-09 |CRAN (R 4.4.1) |
|reactable |0.4.4 |2023-03-12 |CRAN (R 4.4.0) |
|readODS |2.3.2 |2025-01-13 |CRAN (R 4.4.1) |
|readr |2.1.5 |2024-01-10 |CRAN (R 4.4.0) |
|readxl |1.4.5 |2025-03-07 |CRAN (R 4.4.1) |
|reformulas |0.4.0 |2024-11-03 |CRAN (R 4.4.1) |
|remotes |2.5.0 |2024-03-17 |CRAN (R 4.4.1) |
|renv |1.1.4 |2025-03-20 |CRAN (R 4.4.1) |
|report |0.6.1 |2025-02-07 |CRAN (R 4.4.1) |
|rio |1.2.3 |2024-09-25 |CRAN (R 4.4.1) |
|rlang |1.1.6 |2025-04-11 |CRAN (R 4.4.1) |
|rmarkdown |2.29 |2024-11-04 |CRAN (R 4.4.1) |
|rprojroot |2.0.4 |2023-11-05 |CRAN (R 4.4.1) |
|rsconnect |1.3.4 |2025-01-22 |CRAN (R 4.4.1) |
|rstudioapi |0.17.1 |2024-10-22 |CRAN (R 4.4.1) |
|sass |0.4.10 |2025-04-11 |CRAN (R 4.4.1) |
|scales |1.3.0 |2023-11-28 |CRAN (R 4.4.0) |
|see |0.11.0 |2025-03-11 |CRAN (R 4.4.1) |
|sessioninfo |1.2.3 |2025-02-05 |CRAN (R 4.4.1) |
|shiny |1.10.0 |2024-12-14 |CRAN (R 4.4.1) |
|shinybusy |0.3.3 |2024-03-09 |CRAN (R 4.4.0) |
|shinyTime |1.0.3 |2022-08-19 |CRAN (R 4.4.0) |
|shinyWidgets |0.9.0 |2025-02-21 |CRAN (R 4.4.1) |
|stringi |1.8.7 |2025-03-27 |CRAN (R 4.4.1) |
|sys |3.4.3 |2024-10-04 |CRAN (R 4.4.1) |
|tibble |3.2.1 |2023-03-20 |CRAN (R 4.4.0) |
|tidyr |1.3.1 |2024-01-24 |CRAN (R 4.4.1) |
|tidyselect |1.2.1 |2024-03-11 |CRAN (R 4.4.0) |
|toastui |0.4.0 |2025-04-03 |CRAN (R 4.4.1) |
|tzdb |0.5.0 |2025-03-15 |CRAN (R 4.4.1) |
|urlchecker |1.0.1 |2021-11-30 |CRAN (R 4.4.1) |
|usethis |3.1.0 |2024-11-26 |CRAN (R 4.4.1) |
|vctrs |0.6.5 |2023-12-01 |CRAN (R 4.4.0) |
|vroom |1.6.5 |2023-12-05 |CRAN (R 4.4.0) |
|whisker |0.4.1 |2022-12-05 |CRAN (R 4.4.1) |
|withr |3.0.2 |2024-10-28 |CRAN (R 4.4.1) |
|writexl |1.5.4 |2025-04-15 |CRAN (R 4.4.1) |
|xfun |0.52 |2025-04-02 |CRAN (R 4.4.1) |
|xml2 |1.3.8 |2025-03-14 |CRAN (R 4.4.1) |
|xtable |1.8-4 |2019-04-21 |CRAN (R 4.4.1) |
|yaml |2.3.10 |2024-07-26 |CRAN (R 4.4.1) |
|zip |2.3.2 |2025-02-01 |CRAN (R 4.4.1) |

View file

@ -8,14 +8,13 @@ template:
base_font: {google: "Montserrat"}
heading_font: {google: "Public Sans"}
# code_font: {google: "Open Sans"}
# Adding the switch destroys the theme colors
light-switch: false
navbar:
bg: primary
structure:
left: [intro, reference, articles, roadmap, q_a, news]
right: [search, github]
right: [search, github, lightswitch]
components:
roadmap:
text: Roadmap

View file

@ -1,19 +0,0 @@
## code to prepare `session` dataset goes here
session <- devtools::session_info()
platform <- c(session$platform,
"FreesearchR"=paste(gsub("Version: ","",readLines(here::here('DESCRIPTION'))[3]),format(Sys.time(),format = '%y%m%d'),sep='.'))
platform <- data.frame(option=names(platform),value=Reduce(c,platform))
libs <- as.data.frame(session$packages)[names(session$packages) %in% c("package","loadedversion","date","source")]
rownames(libs) <- NULL
session_data <- list(
platform=platform,
libs=libs
)
usethis::use_data(session_data,internal = TRUE, overwrite = TRUE)

View file

@ -10,7 +10,7 @@
#### Current file: /Users/au301842/FreesearchR/R//app_version.R
########
app_version <- function()'v25.4.3.250423'
app_version <- function()'Version: 25.4.3.250422'
########
@ -1801,7 +1801,7 @@ line_break <- function(data, lineLength = 20, force = FALSE) {
#' @export
#'
wrap_plot_list <- function(data, tag_levels = NULL) {
if (ggplot2::is_ggplot(data[[1]])) {
if (ggplot2::is.ggplot(data[[1]])) {
if (length(data) > 1) {
out <- data |>
(\(.x){
@ -1838,7 +1838,7 @@ wrap_plot_list <- function(data, tag_levels = NULL) {
align_axes <- function(...) {
# https://stackoverflow.com/questions/62818776/get-axis-limits-from-ggplot-object
# https://github.com/thomasp85/patchwork/blob/main/R/plot_multipage.R#L150
if (ggplot2::is_ggplot(..1)) {
if (ggplot2::is.ggplot(..1)) {
## Assumes list of ggplots
p <- list(...)
} else if (is.list(..1)) {
@ -2497,7 +2497,7 @@ read_input <- function(file, consider.na = c("NA", '""', "")) {
if (ext == "csv") {
df <- readr::read_csv(file = file, na = consider.na)
} else if (ext %in% c("xls", "xlsx")) {
df <- readxl::read_excel(file = file, na.strings = consider.na)
df <- openxlsx2::read_xlsx(file = file, na.strings = consider.na)
} else if (ext == "dta") {
df <- haven::read_dta(file = file)
} else if (ext == "ods") {
@ -2838,7 +2838,7 @@ sort_by <- function(x, y, na.rm = FALSE, ...) {
get_ggplot_label <- function(data, label) {
assertthat::assert_that(ggplot2::is_ggplot(data))
assertthat::assert_that(ggplot2::is.ggplot(data))
data$labels[[label]]
}
@ -3368,8 +3368,7 @@ import_file_server <- function(id,
)
observeEvent(input$see_data, {
tryCatch(
{
tryCatch({
datamods:::show_data(default_parsing(temporary_rv$data), title = datamods:::i18n("Imported data"), type = show_data_in)
},
# warning = function(warn) {
@ -3383,10 +3382,9 @@ import_file_server <- function(id,
output$table <- toastui::renderDatagrid2({
req(temporary_rv$data)
tryCatch(
{
tryCatch({
toastui::datagrid(
data = setNames(head(temporary_rv$data, 5), make.names(names(temporary_rv$data), unique = TRUE)),
data = setNames(head(temporary_rv$data, 5),make.names(names(temporary_rv$data),unique = TRUE)),
theme = "striped",
colwidths = "guess",
minBodyHeight = 250
@ -3490,22 +3488,13 @@ import_xls <- function(file, sheet, skip, na.strings) {
sheet |>
purrr::map(\(.x){
readxl::read_excel(
path = file,
openxlsx2::read_xlsx(
file = file,
sheet = .x,
na = na.strings,
skip = skip,
.name_repair = "unique_quiet",
trim_ws = TRUE
skip_empty_rows = TRUE,
start_row = skip - 1,
na.strings = na.strings
)
# openxlsx2::read_xlsx(
# file = file,
# sheet = .x,
# skip_empty_rows = TRUE,
# start_row = skip - 1,
# na.strings = na.strings
# )
}) |>
purrr::reduce(dplyr::full_join)
},
@ -3749,14 +3738,13 @@ plot_box <- function(data, pri, sec, ter = NULL) {
#' @export
#'
#' @examples
#' mtcars |> plot_box_single("mpg")
#' mtcars |> plot_box_single("mpg","cyl")
plot_box_single <- function(data, pri, sec=NULL, seed = 2103) {
set.seed(seed)
if (is.null(sec)) {
sec <- "All"
data[[sec]] <- sec
data[[y]] <- sec
}
discrete <- !data_type(data[[sec]]) %in% "continuous"
@ -4087,7 +4075,7 @@ sankey_ready <- function(data, pri, sec, numbers = "count", ...) {
data[c(pri, sec)] <- data[c(pri, sec)] |>
dplyr::mutate(dplyr::across(!dplyr::where(is.factor), forcats::as_factor))
out <- dplyr::count(data, !!dplyr::sym(pri), !!dplyr::sym(sec), .drop = FALSE)
out <- dplyr::count(data, !!dplyr::sym(pri), !!dplyr::sym(sec))
out <- out |>
dplyr::group_by(!!dplyr::sym(pri)) |>
@ -4138,17 +4126,9 @@ str_remove_last <- function(data, pattern = "\n") {
#' @examples
#' ds <- data.frame(g = sample(LETTERS[1:2], 100, TRUE), first = REDCapCAST::as_factor(sample(letters[1:4], 100, TRUE)), last = REDCapCAST::as_factor(sample(letters[1:4], 100, TRUE)))
#' ds |> plot_sankey("first", "last")
#' ds |> plot_sankey("first", "last", color.group = "sec")
#' ds |> plot_sankey("first", "last", ter = "g", color.group = "sec")
#' mtcars |>
#' default_parsing() |>
#' plot_sankey("cyl", "gear", "am", color.group = "pri")
#' ## In this case, the last plot as the secondary variable in wrong order
#' ## Dont know why...
#' mtcars |>
#' default_parsing() |>
#' plot_sankey("cyl", "gear", "vs", color.group = "pri")
plot_sankey <- function(data, pri, sec, ter = NULL, color.group = "pri", colors = NULL) {
#' ds |> plot_sankey("first", "last", color.group = "y")
#' ds |> plot_sankey("first", "last", z = "g", color.group = "y")
plot_sankey <- function(data, pri, sec, ter = NULL, color.group = "x", colors = NULL) {
if (!is.null(ter)) {
ds <- split(data, data[ter])
} else {
@ -4156,12 +4136,16 @@ plot_sankey <- function(data, pri, sec, ter = NULL, color.group = "pri", colors
}
out <- lapply(ds, \(.ds){
plot_sankey_single(.ds, pri = pri, sec = sec, color.group = color.group, colors = colors)
plot_sankey_single(.ds, x = pri, y = sec, color.group = color.group, colors = colors)
})
patchwork::wrap_plots(out)
}
default_theme <- function() {
theme_void()
}
#' Beautiful sankey plot
#'
#' @param color.group set group to colour by. "x" or "y".
@ -4175,26 +4159,15 @@ plot_sankey <- function(data, pri, sec, ter = NULL, color.group = "pri", colors
#' @examples
#' ds <- data.frame(g = sample(LETTERS[1:2], 100, TRUE), first = REDCapCAST::as_factor(sample(letters[1:4], 100, TRUE)), last = REDCapCAST::as_factor(sample(letters[1:4], 100, TRUE)))
#' ds |> plot_sankey_single("first", "last")
#' ds |> plot_sankey_single("first", "last", color.group = "sec")
#' ds |> plot_sankey_single("first", "last", color.group = "y")
#' data.frame(
#' g = sample(LETTERS[1:2], 100, TRUE),
#' first = REDCapCAST::as_factor(sample(letters[1:4], 100, TRUE)),
#' last = sample(c(TRUE, FALSE, FALSE), 100, TRUE)
#' ) |>
#' plot_sankey_single("first", "last", color.group = "pri")
#' mtcars |>
#' default_parsing() |>
#' str()
#' plot_sankey_single("cyl", "vs", color.group = "pri")
plot_sankey_single <- function(data, pri, sec, color.group = c("pri", "sec"), colors = NULL, ...) {
color.group <- match.arg(color.group)
data_orig <- data
data[c(pri, sec)] <- data[c(pri, sec)] |>
dplyr::mutate(dplyr::across(dplyr::where(is.factor), forcats::fct_drop))
# browser()
data <- data |> sankey_ready(pri = pri, sec = sec, ...)
library(ggalluvial)
@ -4204,17 +4177,11 @@ plot_sankey_single <- function(data, pri, sec, color.group = c("pri", "sec"), co
if (is.null(colors)) {
if (color.group == "sec") {
main.colors <- viridisLite::viridis(n = length(levels(data_orig[[sec]])))
## Only keep colors for included levels
main.colors <- main.colors[match(levels(data[[sec]]), levels(data_orig[[sec]]))]
main.colors <- viridisLite::viridis(n = length(levels(data[[sec]])))
secondary.colors <- rep(na.color, length(levels(data[[pri]])))
label.colors <- Reduce(c, lapply(list(secondary.colors, rev(main.colors)), contrast_text))
} else {
main.colors <- viridisLite::viridis(n = length(levels(data_orig[[pri]])))
## Only keep colors for included levels
main.colors <- main.colors[match(levels(data[[pri]]), levels(data_orig[[pri]]))]
main.colors <- viridisLite::viridis(n = length(levels(data[[pri]])))
secondary.colors <- rep(na.color, length(levels(data[[sec]])))
label.colors <- Reduce(c, lapply(list(rev(main.colors), secondary.colors), contrast_text))
}
@ -4232,11 +4199,7 @@ plot_sankey_single <- function(data, pri, sec, color.group = c("pri", "sec"), co
if (color.group == "sec") {
p <- p +
ggalluvial::geom_alluvium(
ggplot2::aes(
fill = !!dplyr::sym(sec) # ,
## Including will print strings when levels are empty
# color = !!dplyr::sym(sec)
),
ggplot2::aes(fill = !!dplyr::sym(sec), color = !!dplyr::sym(sec)),
width = 1 / 16,
alpha = .8,
knot.pos = 0.4,
@ -4248,10 +4211,7 @@ plot_sankey_single <- function(data, pri, sec, color.group = c("pri", "sec"), co
} else {
p <- p +
ggalluvial::geom_alluvium(
ggplot2::aes(
fill = !!dplyr::sym(pri) # ,
# color = !!dplyr::sym(pri)
),
ggplot2::aes(fill = !!dplyr::sym(pri), color = !!dplyr::sym(pri)),
width = 1 / 16,
alpha = .8,
knot.pos = 0.4,
@ -4275,7 +4235,7 @@ plot_sankey_single <- function(data, pri, sec, color.group = c("pri", "sec"), co
labels = group_labels
) +
ggplot2::scale_fill_manual(values = colors[-1], na.value = colors[1]) +
# ggplot2::scale_color_manual(values = main.colors) +
ggplot2::scale_color_manual(values = main.colors) +
ggplot2::theme_void() +
ggplot2::theme(
legend.position = "none",
@ -8439,7 +8399,7 @@ ui_elements <- list(
shiny::uiOutput(outputId = "column_filter"),
shiny::helpText("Variable ", tags$a(
"data type",
href = "https://agdamsbo.github.io/FreesearchR/articles/data-types.html",
href = "https://agdamsbo.github.io/FreesearchR/articles/FreesearchR.html",
target = "_blank",
rel = "noopener noreferrer"
), " filtering."),
@ -8636,13 +8596,15 @@ ui_elements <- list(
data_visuals_ui("visuals"),
shiny::tagList(
bslib::nav_spacer(),
bslib::nav_item(
# shiny::img(shiny::icon("book")),
shiny::tags$a(
href = "https://agdamsbo.github.io/FreesearchR/articles/visuals.html",
"Notes (external)",
target = "_blank",
rel = "noopener noreferrer"
bslib::nav_panel(
title = "Notes",
shiny::fluidRow(
shiny::column(width = 2),
shiny::column(
width = 8,
shiny::markdown(readLines("www/notes_visuals.md")),
shiny::column(width = 2)
)
)
)
)
@ -8812,11 +8774,11 @@ ui <- bslib::page_fixed(
style = "background-color: #14131326; padding: 4px; text-align: center; bottom: 0; width: 100%;",
shiny::p(
style = "margin: 1",
"Data is only stored for analyses and deleted when the app is closed."
"Data is only stored for analyses and deleted immediately afterwards."
),
shiny::p(
style = "margin: 1; color: #888;",
shiny::tags$a("AG Damsbo", href = "https://andreas.gdamsbo.dk/", target = "_blank", rel = "noopener noreferrer")," | ", app_version(), " | ", shiny::tags$a("License: AGPLv3", href = "https://github.com/agdamsbo/FreesearchR/blob/main/LICENSE.md", target = "_blank", rel = "noopener noreferrer"), " | ", shiny::tags$a("Source", href = "https://github.com/agdamsbo/FreesearchR/", target = "_blank", rel = "noopener noreferrer")
"AG Damsbo | v", app_version(), " | ", shiny::tags$a("AGPLv3 license", href = "https://github.com/agdamsbo/FreesearchR/blob/main/LICENSE.md", target = "_blank", rel = "noopener noreferrer"), " | ", shiny::tags$a("Source on Github", href = "https://github.com/agdamsbo/FreesearchR/", target = "_blank", rel = "noopener noreferrer")
),
)
)

View file

@ -359,13 +359,15 @@ ui_elements <- list(
data_visuals_ui("visuals"),
shiny::tagList(
bslib::nav_spacer(),
bslib::nav_item(
# shiny::img(shiny::icon("book")),
shiny::tags$a(
href = "https://agdamsbo.github.io/FreesearchR/articles/visuals.html",
"Notes (external)",
target = "_blank",
rel = "noopener noreferrer"
bslib::nav_panel(
title = "Notes",
shiny::fluidRow(
shiny::column(width = 2),
shiny::column(
width = 8,
shiny::markdown(readLines("www/notes_visuals.md")),
shiny::column(width = 2)
)
)
)
)
@ -535,11 +537,11 @@ ui <- bslib::page_fixed(
style = "background-color: #14131326; padding: 4px; text-align: center; bottom: 0; width: 100%;",
shiny::p(
style = "margin: 1",
"Data is only stored for analyses and deleted when the app is closed."
"Data is only stored for analyses and deleted immediately afterwards."
),
shiny::p(
style = "margin: 1; color: #888;",
shiny::tags$a("AG Damsbo", href = "https://andreas.gdamsbo.dk/", target = "_blank", rel = "noopener noreferrer")," | ", app_version(), " | ", shiny::tags$a("License: AGPLv3", href = "https://github.com/agdamsbo/FreesearchR/blob/main/LICENSE.md", target = "_blank", rel = "noopener noreferrer"), " | ", shiny::tags$a("Source", href = "https://github.com/agdamsbo/FreesearchR/", target = "_blank", rel = "noopener noreferrer")
"AG Damsbo | v", app_version(), " | ", shiny::tags$a("AGPLv3 license", href = "https://github.com/agdamsbo/FreesearchR/blob/main/LICENSE.md", target = "_blank", rel = "noopener noreferrer"), " | ", shiny::tags$a("Source on Github", href = "https://github.com/agdamsbo/FreesearchR/", target = "_blank", rel = "noopener noreferrer")
),
)
)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 31 KiB

View file

@ -1,4 +1,4 @@
# Welcome <img style="float: right;" src="logo-text-white-250.png">
# Welcome
This is the ***FreesearchR*** data analysis tool. We intend the ***FreesearchR*** to be a powerful and free tool for easy data evaluation and analysis at the hands of the clinician. If you need more advanced tools for regression models or plotting, you'll probably be better off using *R* or similar directly on your own machine.
@ -6,7 +6,7 @@ By intention, this tool has been designed to be simple to use with a minimum of
There are some simple steps to go through (see corresponding tabs in the top):
1. Import data to get started. This can be a spreadsheet/file on your machine, direct export from a REDCap server, sample data or data from a your local environment if run locally.
1. Import data (a spreadsheet/file on your machine, direct export from a REDCap server, or a local file provided with a package) to get started.
1. Data inspection and modification (change variable classes, create new variables (categorical from numeric or time data, or completely new variables from the data)
@ -20,14 +20,10 @@ There are some simple steps to go through (see corresponding tabs in the top):
- Plot regression analysis coefficients
- Evaluate model assumptions
- Evaluation of model assumptions
1. Export results
1. Export the the analyses results for MS Word or [LibreOffice](https://www.libreoffice.org/) as well as the data with preserved metadata.
- Descriptive and regression analyses results for MS Word or [LibreOffice](https://www.libreoffice.org/)
The full [project documentation is here](https://agdamsbo.github.io/FreesearchR/) for documenting the project, functions, road map and more. If you're interested in the source code, then [everything is open and you are free to read, copy, modify and improve](https://github.com/agdamsbo/FreesearchR), and please let us know if you want to contribute!
- Modified data with preserved metadata
- Code to recreate all steps locally
The full [project documentation is here](https://agdamsbo.github.io/FreesearchR/) and all code used is [freely available to read, copy, modify and improve](https://github.com/agdamsbo/FreesearchR) under an [open source license](https://github.com/agdamsbo/FreesearchR/blob/main/LICENSE.md)! Contributions are welcome and much appreciated and can be reporting issues, suggesting new functionality, improving code or any other feedback [here](https://github.com/agdamsbo/FreesearchR/issues).
Contributions can be reporting issues, suggesting new functionality, improving code or any other feedback. [It all goes here](https://github.com/agdamsbo/FreesearchR/issues).

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,11 @@
# Basic visualisations
The goal of ***FreesearchR*** is to keep things simple. Visuals can get very complicated. We provide a selection of plots, that helps visualise typical clinical and will be enough for most use cases, and for publishing to most journals.
If you want to go further, have a look at these sites with suggestions and sample code for data plotting:
- [*R* Charts](https://r-charts.com/): Extensive gallery with great plots
- [*R* Graph gallery](https://r-graph-gallery.com/): Another gallery with great graphs
- [graphics principles](https://graphicsprinciples.github.io/): Easy to follow recommendations for clear visuals.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

View file

@ -32,7 +32,7 @@ plot_ridge(data, x, y, z = NULL, ...)
sankey_ready(data, pri, sec, numbers = "count", ...)
plot_sankey(data, pri, sec, ter = NULL, color.group = "pri", colors = NULL)
plot_sankey(data, pri, sec, ter = NULL, color.group = "x", colors = NULL)
plot_scatter(data, pri, sec, ter = NULL)
@ -103,7 +103,6 @@ mtcars |> plot_box(pri = "mpg", sec = "cyl", ter = "gear")
mtcars |>
default_parsing() |>
plot_box(pri = "mpg", sec = "cyl", ter = "gear")
mtcars |> plot_box_single("mpg")
mtcars |> plot_box_single("mpg","cyl")
mtcars |> plot_hbars(pri = "carb", sec = "cyl")
mtcars |> plot_hbars(pri = "carb", sec = NULL)
@ -122,16 +121,8 @@ data.frame(
sankey_ready("first", "last")
ds <- data.frame(g = sample(LETTERS[1:2], 100, TRUE), first = REDCapCAST::as_factor(sample(letters[1:4], 100, TRUE)), last = REDCapCAST::as_factor(sample(letters[1:4], 100, TRUE)))
ds |> plot_sankey("first", "last")
ds |> plot_sankey("first", "last", color.group = "sec")
ds |> plot_sankey("first", "last", ter = "g", color.group = "sec")
mtcars |>
default_parsing() |>
plot_sankey("cyl", "gear", "am", color.group = "pri")
## In this case, the last plot as the secondary variable in wrong order
## Dont know why...
mtcars |>
default_parsing() |>
plot_sankey("cyl", "gear", "vs", color.group = "pri")
ds |> plot_sankey("first", "last", color.group = "y")
ds |> plot_sankey("first", "last", z = "g", color.group = "y")
mtcars |> plot_scatter(pri = "mpg", sec = "wt")
mtcars |> plot_violin(pri = "mpg", sec = "cyl", ter = "gear")
}

View file

@ -30,15 +30,11 @@ Beautiful sankey plot
\examples{
ds <- data.frame(g = sample(LETTERS[1:2], 100, TRUE), first = REDCapCAST::as_factor(sample(letters[1:4], 100, TRUE)), last = REDCapCAST::as_factor(sample(letters[1:4], 100, TRUE)))
ds |> plot_sankey_single("first", "last")
ds |> plot_sankey_single("first", "last", color.group = "sec")
ds |> plot_sankey_single("first", "last", color.group = "y")
data.frame(
g = sample(LETTERS[1:2], 100, TRUE),
first = REDCapCAST::as_factor(sample(letters[1:4], 100, TRUE)),
last = sample(c(TRUE, FALSE, FALSE), 100, TRUE)
) |>
plot_sankey_single("first", "last", color.group = "pri")
mtcars |>
default_parsing() |>
str()
plot_sankey_single("cyl", "vs", color.group = "pri")
}

1215
renv.lock

File diff suppressed because it is too large Load diff

View file

@ -46,7 +46,7 @@ test_that("create_plot works", {
p <- p_list[[1]] + ggplot2::labs(title = "Test plot")
expect_equal(length(p_list), 2)
expect_true(ggplot2::is_ggplot(p))
expect_true(ggplot2::is.ggplot(p))
# Includes helper functions
# wrap_plot_list
@ -60,7 +60,7 @@ test_that("create_plot works", {
)
lapply(p_list, \(.x){
expect_true(ggplot2::is_ggplot(.x))
expect_true(ggplot2::is.ggplot(.x))
})
purrr::map2(p_list, list(11, 11), \(.x, .y){

View file

@ -12,7 +12,6 @@ knitr::opts_chunk$set(
collapse = TRUE,
comment = "#>"
)
options(rmarkdown.html_vignette.check_title = FALSE)
```
```{r setup}

View file

@ -1,35 +0,0 @@
---
title: "Session info"
output: rmarkdown::html_vignette
vignette: >
%\VignetteIndexEntry{session}
%\VignetteEngine{knitr::rmarkdown}
%\VignetteEncoding{UTF-8}
---
```{r, include = FALSE}
knitr::opts_chunk$set(
collapse = TRUE,
comment = "#>"
)
options(rmarkdown.html_vignette.check_title = FALSE)
```
```{r setup}
library(FreesearchR)
```
This is the session info on the primary build machine. Inspect loaded packages and the latest build info.
## Platform info
```{r}
FreesearchR:::session_data$platform |> knitr::kable()
```
## Libraries
```{r}
FreesearchR:::session_data$libs|> knitr::kable()
```

View file

@ -1,55 +0,0 @@
---
title: "On visuals"
output: rmarkdown::html_vignette
vignette: >
%\VignetteIndexEntry{visuals}
%\VignetteEngine{knitr::rmarkdown}
%\VignetteEncoding{UTF-8}
---
```{r, include = FALSE}
knitr::opts_chunk$set(
collapse = TRUE,
comment = "#>"
)
options(rmarkdown.html_vignette.check_title = FALSE)
```
```{r setup}
library(FreesearchR)
```
## Basic visualisations
The goal of ***FreesearchR*** is to keep things simple. Visuals can get very complicated. We provide a selection of plots, that helps visualise typical clinical and will be enough for most use cases, and for publishing to most journals.
If you want to go further, have a look at these sites with suggestions and sample code for data plotting:
- [*R* Charts](https://r-charts.com/): Extensive gallery with great plots
- [*R* Graph gallery](https://r-graph-gallery.com/): Another gallery with great graphs
- [graphics principles](https://graphicsprinciples.github.io/): Easy to follow recommendations for clear visuals.
### Available plots
Below are the available plot types listed.
```{r echo = FALSE, eval = TRUE}
c("continuous", "dichotomous", "categorical") |>
lapply(\(.x){
dplyr::bind_cols(
dplyr::tibble("Data type"=.x),
supported_plots() |>
lapply(\(.y){
if (.x %in% .y$primary.type){
.y[c("descr","note")]|> dplyr::bind_cols()
}
})|>
dplyr::bind_rows() |>
setNames(c("Plot type","Description")))
}) |>
dplyr::bind_rows() |>
knitr::kable()
```