├── _pkgdown.yml ├── .github ├── .gitignore └── workflows │ └── R-CMD-check.yaml ├── .Rprofile ├── inst ├── tiny_demo │ ├── helpfiles │ │ └── geom_segment-plot.md │ ├── ui.R │ └── server.R ├── WORDLIST └── example_app │ ├── helpfiles │ ├── airquality_basic-data.md │ ├── airquality_basic-plot.md │ ├── airquality_advanced-data.md │ └── airquality_advanced-plot.md │ └── example_app.R ├── renv ├── .gitignore ├── settings.dcf └── activate.R ├── .gitignore ├── tests ├── testthat.R ├── spelling.R └── testthat │ └── test-create_tooltip.R ├── .Rbuildignore ├── R ├── tiny_demo_gui.R ├── download_button.R ├── shinydetails-package.R ├── custom_help_files.R ├── elements_h.R ├── tooltip.R └── plot_panel.R ├── man ├── run_tiny_demo.Rd ├── shinydetails-package.Rd ├── dt_format.Rd ├── beam_downloadButton.Rd ├── create_help_files_custom.Rd ├── plotOutput_h.Rd ├── tableOutput_h.Rd ├── sliderInput_h.Rd ├── numericInput_h.Rd ├── extract_tt_data_row.Rd ├── flip_ggplot_build.Rd ├── beam_tooltip.Rd ├── beam_plot_panel_UI.Rd └── beam_plot_panel_SERVER.Rd ├── shinydetails.Rproj ├── README.md ├── DESCRIPTION ├── NAMESPACE └── renv.lock /_pkgdown.yml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.github/.gitignore: -------------------------------------------------------------------------------- 1 | *.html 2 | -------------------------------------------------------------------------------- /.Rprofile: -------------------------------------------------------------------------------- 1 | source("renv/activate.R") 2 | -------------------------------------------------------------------------------- /inst/tiny_demo/helpfiles/geom_segment-plot.md: -------------------------------------------------------------------------------- 1 | lalalalalala 2 | -------------------------------------------------------------------------------- /renv/.gitignore: -------------------------------------------------------------------------------- 1 | library/ 2 | lock/ 3 | python/ 4 | staging/ 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .Rproj.user 2 | .Rhistory 3 | .RData 4 | .Ruserdata 5 | docs 6 | -------------------------------------------------------------------------------- /inst/WORDLIST: -------------------------------------------------------------------------------- 1 | Tooltip 2 | UI 3 | jpeg 4 | png 5 | svg 6 | tabset 7 | tooltip 8 | ui 9 | -------------------------------------------------------------------------------- /tests/testthat.R: -------------------------------------------------------------------------------- 1 | library(testthat) 2 | library(shinydetails) 3 | 4 | test_check("shinydetails") 5 | -------------------------------------------------------------------------------- /.Rbuildignore: -------------------------------------------------------------------------------- 1 | ^renv$ 2 | ^renv\.lock$ 3 | ^.*\.Rproj$ 4 | ^\.Rproj\.user$ 5 | ^\.github$ 6 | ^_pkgdown\.yml$ 7 | ^docs$ 8 | ^pkgdown$ 9 | -------------------------------------------------------------------------------- /tests/spelling.R: -------------------------------------------------------------------------------- 1 | if(requireNamespace('spelling', quietly = TRUE)) 2 | spelling::spell_check_test(vignettes = TRUE, error = FALSE, 3 | skip_on_cran = TRUE) 4 | -------------------------------------------------------------------------------- /inst/example_app/helpfiles/airquality_basic-data.md: -------------------------------------------------------------------------------- 1 | ### helpfiles/airquality_basic-data.md - Under Development 2 | 3 | *** 4 | 5 | 6 | This help file was generated automatically. 7 | 8 | 9 | -------------------------------------------------------------------------------- /inst/example_app/helpfiles/airquality_basic-plot.md: -------------------------------------------------------------------------------- 1 | ### helpfiles/airquality_basic-plot.md - Under Development 2 | 3 | *** 4 | 5 | 6 | This help file was generated automatically. 7 | 8 | 9 | -------------------------------------------------------------------------------- /inst/example_app/helpfiles/airquality_advanced-data.md: -------------------------------------------------------------------------------- 1 | ### helpfiles/airquality_advanced-data.md - Under Development 2 | 3 | *** 4 | 5 | 6 | This help file was generated automatically. 7 | 8 | 9 | -------------------------------------------------------------------------------- /inst/example_app/helpfiles/airquality_advanced-plot.md: -------------------------------------------------------------------------------- 1 | ### helpfiles/airquality_advanced-plot.md - Under Development 2 | 3 | *** 4 | 5 | 6 | This help file was generated automatically. 7 | 8 | 9 | -------------------------------------------------------------------------------- /renv/settings.dcf: -------------------------------------------------------------------------------- 1 | external.libraries: 2 | ignored.packages: 3 | package.dependency.fields: Imports, Depends, LinkingTo 4 | r.version: 5 | snapshot.type: implicit 6 | use.cache: TRUE 7 | vcs.ignore.library: TRUE 8 | -------------------------------------------------------------------------------- /R/tiny_demo_gui.R: -------------------------------------------------------------------------------- 1 | #' @title An example component 2 | #' @description Run an example app using \code{shinydetails} 3 | #' @importFrom shiny runApp 4 | #' @export 5 | run_tiny_demo <- function() { 6 | runApp(system.file("tiny_demo", package = "shinydetails")) 7 | } 8 | -------------------------------------------------------------------------------- /man/run_tiny_demo.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/tiny_demo_gui.R 3 | \name{run_tiny_demo} 4 | \alias{run_tiny_demo} 5 | \title{An example component} 6 | \usage{ 7 | run_tiny_demo() 8 | } 9 | \description{ 10 | Run an example app using \code{shinydetails} 11 | } 12 | -------------------------------------------------------------------------------- /man/shinydetails-package.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/shinydetails-package.R 3 | \docType{package} 4 | \name{shinydetails-package} 5 | \alias{shinydetails-package} 6 | \alias{shinydetails} 7 | \title{shinydetails} 8 | \description{ 9 | Useful Shiny stuff. 10 | } 11 | -------------------------------------------------------------------------------- /shinydetails.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | 3 | RestoreWorkspace: Default 4 | SaveWorkspace: Default 5 | AlwaysSaveHistory: Default 6 | 7 | EnableCodeIndexing: Yes 8 | UseSpacesForTab: Yes 9 | NumSpacesForTab: 2 10 | Encoding: UTF-8 11 | 12 | RnwWeave: Sweave 13 | LaTeX: pdfLaTeX 14 | 15 | AutoAppendNewline: Yes 16 | StripTrailingWhitespace: Yes 17 | 18 | BuildType: Package 19 | PackageUseDevtools: Yes 20 | PackageInstallArgs: --no-multiarch --with-keep.source 21 | PackageRoxygenize: rd,collate,namespace,vignette 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | [![R build status](https://github.com/hadexversum/shinyKrysia/workflows/R-CMD-check/badge.svg)](https://github.com/hadexversum/shinyKrysia/actions) 3 | 4 | ## shinydetails: useful components for Shiny apps 5 | 6 | This package implements a module containing a tabset that is composed of dwo panels with plot and table. 7 | 8 | Development version can be downloaded from Github: 9 | 10 | ``` 11 | if (!require(devtools)) { 12 | install.packages('devtools') 13 | } 14 | devtools::install_github("BioGenies/shinydetails") 15 | ``` 16 | -------------------------------------------------------------------------------- /man/dt_format.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/plot_panel.R 3 | \name{dt_format} 4 | \alias{dt_format} 5 | \title{Table widget} 6 | \usage{ 7 | dt_format(dat, colnames = colnames(dat)) 8 | } 9 | \arguments{ 10 | \item{dat}{a data object - a matrix or a data frame.} 11 | 12 | \item{colnames}{Names of columns to display in the table. By default it is 13 | equal to the names of the columns from the \code{dat}. Parameter \code{colnames} is 14 | correspond the argument \code{colnames} from \code{\link[DT]{datatable}}.} 15 | } 16 | \description{ 17 | \code{dt_format} is a function for creating a graphical 18 | widget containing a table with download buttons (Excel and CSV). 19 | } 20 | \details{ 21 | This function uses \code{\link[DT]{datatable}}. 22 | } 23 | -------------------------------------------------------------------------------- /R/download_button.R: -------------------------------------------------------------------------------- 1 | #' @title Download button for plot 2 | #' @description Generates download button for a plot with dimensions of 300x400mm. 3 | #' @param id Unique id of download button. 4 | #' @param plot_out Plot to save. 5 | #' @inheritParams ggplot2::ggsave 6 | #' @return \code{generate_downloadButton} returns the output of \code{downloadHandler} 7 | #' for given plot and device. 8 | #' @details This function uses \code{\link[shiny]{downloadHandler}} and \code{\link[ggplot2]{ggsave}}. 9 | #' @export 10 | #' @importFrom ggplot2 ggsave 11 | 12 | beam_downloadButton <- function(id, plot_out, device) { 13 | downloadHandler(filename = paste0(id, "_plot.", device), 14 | content = function(file){ 15 | ggsave(file, plot_out, device = device, height = 300, 16 | width = 400, units = "mm")}) 17 | } 18 | -------------------------------------------------------------------------------- /inst/tiny_demo/ui.R: -------------------------------------------------------------------------------- 1 | library(shiny) 2 | 3 | shinyUI(fluidPage(mainPanel( 4 | tabsetPanel(tabPanel(title = "geom_segment", 5 | column(width = 3), 6 | column(width = 9, 7 | tabsetPanel_UI("geom_segment"))), 8 | tabPanel("geom_segment", 9 | column(width = 3), 10 | column(width = 9, 11 | tabsetPanel_UI("geom_segment2"))), 12 | tabPanel("geom_point", 13 | column(width = 3), 14 | column(width = 9, 15 | tabsetPanel_UI("geom_point"))), 16 | tabPanel("geom_col", 17 | column(width = 3), 18 | column(width = 9, 19 | tabsetPanel_UI("geom_col"))) 20 | ) 21 | ))) 22 | -------------------------------------------------------------------------------- /man/beam_downloadButton.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/download_button.R 3 | \name{beam_downloadButton} 4 | \alias{beam_downloadButton} 5 | \title{Download button for plot} 6 | \usage{ 7 | beam_downloadButton(id, plot_out, device) 8 | } 9 | \arguments{ 10 | \item{id}{Unique id of download button.} 11 | 12 | \item{plot_out}{Plot to save.} 13 | 14 | \item{device}{Device to use. Can either be a device function 15 | (e.g. \code{\link[=png]{png()}}), or one of "eps", "ps", "tex" (pictex), 16 | "pdf", "jpeg", "tiff", "png", "bmp", "svg" or "wmf" (windows only).} 17 | } 18 | \value{ 19 | \code{generate_downloadButton} returns the output of \code{downloadHandler} 20 | for given plot and device. 21 | } 22 | \description{ 23 | Generates download button for a plot with dimensions of 300x400mm. 24 | } 25 | \details{ 26 | This function uses \code{\link[shiny]{downloadHandler}} and \code{\link[ggplot2]{ggsave}}. 27 | } 28 | -------------------------------------------------------------------------------- /man/create_help_files_custom.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/custom_help_files.R 3 | \name{create_help_files_custom} 4 | \alias{create_help_files_custom} 5 | \title{Creating new help file} 6 | \usage{ 7 | create_help_files_custom( 8 | files, 9 | help_dir = "helpfiles", 10 | content = "This helpfile is not finished yet." 11 | ) 12 | } 13 | \arguments{ 14 | \item{files}{A character vector of names to use in creating help files.} 15 | 16 | \item{help_dir}{A character string of the directory to use for help files.} 17 | 18 | \item{content}{A character string to display in the automatically created help file.} 19 | } 20 | \description{ 21 | This function creates help file (unless it already exists) with 22 | custom content. 23 | } 24 | \details{ 25 | This function is based on \code{\link[shinyhelper]{create_help_files}} a lot. 26 | The option for providing custom \code{content} is the only improvement. 27 | } 28 | -------------------------------------------------------------------------------- /man/plotOutput_h.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/elements_h.R 3 | \name{plotOutput_h} 4 | \alias{plotOutput_h} 5 | \title{Plot output with helper} 6 | \usage{ 7 | plotOutput_h(outputId, helpfiles = "helpfiles", ...) 8 | } 9 | \arguments{ 10 | \item{outputId}{output variable to read the plot/image from.} 11 | 12 | \item{helpfiles}{A character string denoting directory to save empty help files. 13 | Default \code{'helpfiles'}.} 14 | 15 | \item{...}{Optional arguments for \code{plotOutput}.} 16 | } 17 | \description{ 18 | Renders plot with helper within an application. 19 | Same as \code{helper(plotOutput(outputId, ...))}. Creates help file and/or 20 | directory if it does not exist. 21 | } 22 | \details{ 23 | This function uses \code{\link[shinyhelper]{helper}}. 24 | } 25 | \seealso{ 26 | For more elements with helpers see \code{\link[shinydetails]{numericInput_h}}, 27 | \code{\link[shinydetails]{tableOutput_h}}, 28 | \code{\link[shinydetails]{sliderInput_h}} 29 | } 30 | -------------------------------------------------------------------------------- /man/tableOutput_h.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/elements_h.R 3 | \name{tableOutput_h} 4 | \alias{tableOutput_h} 5 | \title{Table output with helper.} 6 | \usage{ 7 | tableOutput_h(outputId, helpfiles = "helpfiles", ...) 8 | } 9 | \arguments{ 10 | \item{outputId}{output variable to read the table from} 11 | 12 | \item{helpfiles}{A character string denoting directory to save empty help files. 13 | Default \code{'helpfiles'}.} 14 | 15 | \item{...}{Optional arguments for \code{plotOutput}.} 16 | } 17 | \description{ 18 | Renders table with helper within an application. Creates help file and/or 19 | directory if it does not exist. 20 | Same as \code{helper(dataTableOutput(outputId, ...))} 21 | } 22 | \details{ 23 | This function uses \code{\link[shinyhelper]{helper}}. 24 | } 25 | \seealso{ 26 | For more elements with helpers see \code{\link[shinydetails]{numericInput_h}}, 27 | \code{\link[shinydetails]{plotOutput_h}}, \code{\link[shinydetails]{sliderInput_h}} 28 | } 29 | -------------------------------------------------------------------------------- /man/sliderInput_h.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/elements_h.R 3 | \name{sliderInput_h} 4 | \alias{sliderInput_h} 5 | \title{Slider input with helper} 6 | \usage{ 7 | sliderInput_h(inputId, helpfiles = "helpfiles", ...) 8 | } 9 | \arguments{ 10 | \item{inputId}{The \code{input} slot that will be used to access the value.} 11 | 12 | \item{helpfiles}{A character string denoting directory to save empty help files. 13 | Default \code{'helpfiles'}.} 14 | 15 | \item{...}{Optional arguments for \code{sliderInput}.} 16 | } 17 | \description{ 18 | Constructs a slider widget with helper. 19 | Same as \code{helper(sliderInput(outputId, ...))}. Creates help file and/or 20 | directory if it does not exist. 21 | } 22 | \details{ 23 | This function uses \code{\link[shinyhelper]{helper}}. 24 | } 25 | \seealso{ 26 | For more elements with helpers see \code{\link[shinydetails]{numericInput_h}}, 27 | \code{\link[shinydetails]{plotOutput_h}}, \code{\link[shinydetails]{tableOutput_h}} 28 | } 29 | -------------------------------------------------------------------------------- /man/numericInput_h.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/elements_h.R 3 | \name{numericInput_h} 4 | \alias{numericInput_h} 5 | \title{Numeric input with helper.} 6 | \usage{ 7 | numericInput_h(inputId, helpfiles = "helpfiles", ...) 8 | } 9 | \arguments{ 10 | \item{inputId}{The \code{input} slot that will be used to access the value.} 11 | 12 | \item{helpfiles}{A character string denoting directory to save empty help files. 13 | Default \code{'helpfiles'}.} 14 | 15 | \item{...}{Optional arguments for \code{numericInput}.} 16 | } 17 | \description{ 18 | Constructs a numeric input with helper. 19 | Same as \code{helper(numericInput(outputId, ...))}. Creates help file and/or 20 | directory if it does not exist. 21 | } 22 | \details{ 23 | This function uses \code{\link[shinyhelper]{helper}}. 24 | } 25 | \seealso{ 26 | For more elements with helpers see \code{\link[shinydetails]{plotOutput_h}}, 27 | \code{\link[shinydetails]{tableOutput_h}}, \code{\link[shinydetails]{sliderInput_h}} 28 | } 29 | -------------------------------------------------------------------------------- /DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: shinydetails 2 | Type: Package 3 | Title: A collection of useful components for Shiny apps 4 | Version: 0.1.0 5 | Authors@R: c(person("Krystyna", "Grzesiak", 6 | email = "krygrz11@gmail.com", 7 | comment = c(ORCID = "0000-0003-2581-7722"), 8 | role = c("cre", "aut")), 9 | person("Weronika", "Puchala", 10 | email = "puchala.weronika@gmail.com", 11 | comment = c(ORCID = "0000-0003-2163-1429"), 12 | role = c("aut")), 13 | person("Michal", "Burdukiewicz", 14 | email = "michalburdukiewicz@gmail.com", 15 | comment = c(ORCID = "0000-0001-8926-582X"), 16 | role = c("aut"))) 17 | Description: More about what it does (maybe more than one line) 18 | Use four spaces when indenting paragraphs within the Description. 19 | License: GPL-3 20 | Imports: 21 | DT, 22 | ggplot2, 23 | shiny, 24 | shinyhelper 25 | Encoding: UTF-8 26 | LazyData: true 27 | RoxygenNote: 7.1.1 28 | Suggests: 29 | testthat, 30 | spelling 31 | Language: en-US 32 | -------------------------------------------------------------------------------- /R/shinydetails-package.R: -------------------------------------------------------------------------------- 1 | #' shinydetails 2 | #' 3 | #' @description Useful Shiny stuff. 4 | #' @docType package 5 | #' @name shinydetails-package 6 | #' @aliases shinydetails 7 | #' @importFrom ggplot2 ggplot_build 8 | #' @importFrom ggplot2 ggsave 9 | #' @importFrom shiny tabsetPanel 10 | #' @importFrom shiny reactive 11 | #' @importFrom shiny tabPanel 12 | #' @importFrom shiny tagList 13 | #' @importFrom shiny downloadButton 14 | #' @importFrom shiny moduleServer 15 | #' @importFrom shiny plotOutput 16 | #' @importFrom shiny downloadHandler 17 | #' @importFrom shiny sliderInput 18 | #' @importFrom shiny numericInput 19 | #' @importFrom shiny dataTableOutput 20 | #' @importFrom shiny nearPoints 21 | #' @importFrom shiny div 22 | #' @importFrom shiny HTML 23 | #' @importFrom shiny p 24 | #' @importFrom shiny uiOutput 25 | #' @importFrom shiny hoverOpts 26 | #' @importFrom shiny NS 27 | #' @importFrom shiny renderPlot 28 | #' @importFrom shiny renderUI 29 | #' @importFrom shiny br 30 | #' @importFrom shinyhelper helper 31 | #' @importFrom shinyhelper observe_helpers 32 | #' @importFrom shinyhelper create_help_files 33 | #' @importFrom DT datatable 34 | #' 35 | NULL 36 | -------------------------------------------------------------------------------- /tests/testthat/test-create_tooltip.R: -------------------------------------------------------------------------------- 1 | test_that("right row from data is selected by extract_tt_data_row", { 2 | 3 | library(ggplot2) 4 | data <- data.frame(x = c(1,2,5,6,8), 5 | y = c(3,6,2,8,7), 6 | vx = c(1,1.5,0.8,0.5,1.3), 7 | vy = c(0.2,1.3,1.7,0.8,1.4)) 8 | plot <- ggplot() + 9 | geom_segment(data = data, 10 | mapping = aes(x = x, y = y, xend = x + vx, yend = y + vy), 11 | size = 2, color = "blue") 12 | 13 | plot_data <- ggplot_build(plot)[["data"]][[1]] 14 | plot_type = "geom_segment" 15 | tt_range = 1 16 | 17 | hv <- list() 18 | hv[["x"]] <- 5 19 | hv[["y"]] <- 3 20 | result1 <- extract_tt_data_row(hv, plot_data, data, plot_type = plot_type, tt_range = tt_range) 21 | expect_equal(result1, data[3, ]) 22 | 23 | hv[["x"]] <- 8 24 | hv[["y"]] <- 2 25 | result2 <- extract_tt_data_row(hv, plot_data, data, plot_type = plot_type, tt_range = tt_range) 26 | expect_equal(nrow(result2), 0) 27 | 28 | hv[["x"]] <- 8 29 | hv[["y"]] <- 7 30 | result3 <- extract_tt_data_row(hv, plot_data, data, plot_type = plot_type, tt_range = tt_range) 31 | expect_equal(result3, data[5, ]) 32 | }) 33 | -------------------------------------------------------------------------------- /NAMESPACE: -------------------------------------------------------------------------------- 1 | # Generated by roxygen2: do not edit by hand 2 | 3 | export(beam_downloadButton) 4 | export(beam_plot_panel_SERVER) 5 | export(beam_plot_panel_UI) 6 | export(beam_tooltip) 7 | export(extract_tt_data_row) 8 | export(flip_ggplot_build) 9 | export(numericInput_h) 10 | export(plotOutput_h) 11 | export(run_tiny_demo) 12 | export(sliderInput_h) 13 | export(tableOutput_h) 14 | importFrom(DT,datatable) 15 | importFrom(DT,renderDataTable) 16 | importFrom(ggplot2,ggplot_build) 17 | importFrom(ggplot2,ggsave) 18 | importFrom(shiny,HTML) 19 | importFrom(shiny,NS) 20 | importFrom(shiny,br) 21 | importFrom(shiny,dataTableOutput) 22 | importFrom(shiny,div) 23 | importFrom(shiny,downloadButton) 24 | importFrom(shiny,downloadHandler) 25 | importFrom(shiny,hoverOpts) 26 | importFrom(shiny,moduleServer) 27 | importFrom(shiny,nearPoints) 28 | importFrom(shiny,numericInput) 29 | importFrom(shiny,p) 30 | importFrom(shiny,plotOutput) 31 | importFrom(shiny,reactive) 32 | importFrom(shiny,renderPlot) 33 | importFrom(shiny,renderUI) 34 | importFrom(shiny,runApp) 35 | importFrom(shiny,sliderInput) 36 | importFrom(shiny,tabPanel) 37 | importFrom(shiny,tabsetPanel) 38 | importFrom(shiny,tagList) 39 | importFrom(shiny,uiOutput) 40 | importFrom(shinyhelper,create_help_files) 41 | importFrom(shinyhelper,helper) 42 | importFrom(shinyhelper,observe_helpers) 43 | -------------------------------------------------------------------------------- /man/extract_tt_data_row.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/tooltip.R 3 | \name{extract_tt_data_row} 4 | \alias{extract_tt_data_row} 5 | \title{Tooltip data} 6 | \usage{ 7 | extract_tt_data_row( 8 | hv, 9 | plot_info, 10 | plot_data, 11 | plot_type = "geom_point", 12 | tt_range = 5 13 | ) 14 | } 15 | \arguments{ 16 | \item{hv}{Hoover.} 17 | 18 | \item{plot_info}{chosen mapping from the \code{data} object from the output of \code{\link[ggplot2]{ggplot_build}} for displayed plot.} 19 | 20 | \item{plot_data}{data on which the ggplot is based} 21 | 22 | \item{plot_type}{Type of plot corresponding to the data from first mapping. 23 | Accepts either \code{'geom_point'}, \code{'geom_segment'} 24 | or \code{'geom_col'}. Default \code{'geom_point'}.} 25 | 26 | \item{tt_range}{A number denoting maximum distance between hoover and objects on the plot. 27 | The row, whose distance to the hoover is less than \code{tt_range} will be selected from the whole data. Default 5.} 28 | } 29 | \value{ 30 | \code{prepare_tt_data} returns prepared data frame containing one record. 31 | } 32 | \description{ 33 | Prepares data in order that it may be displayed in tooltip. 34 | The row from the data which fits to the hover the most will be selected. 35 | } 36 | \details{ 37 | This function filters one row of the imputed data in order that it 38 | corresponds the most to the hoover coordinates. 39 | } 40 | -------------------------------------------------------------------------------- /R/custom_help_files.R: -------------------------------------------------------------------------------- 1 | 2 | #' @title Creating new help file 3 | #' @description This function creates help file (unless it already exists) with 4 | #' custom content. 5 | #' @inheritParams shinyhelper::create_help_files 6 | #' @param content A character string to display in the automatically created help file. 7 | #' @details This function is based on \code{\link[shinyhelper]{create_help_files}} a lot. 8 | #' The option for providing custom \code{content} is the only improvement. 9 | #' 10 | #' 11 | 12 | create_help_files_custom <- function (files, 13 | help_dir = "helpfiles", 14 | content = "This helpfile is not finished yet.") 15 | { 16 | if (!interactive()) { 17 | message("Must be called from an interactive session") 18 | return(invisible(files)) 19 | } 20 | if (!dir.exists(help_dir)) { 21 | message("* Creating directory `", help_dir, "`.") 22 | dir.create(help_dir) 23 | } 24 | files <- file.path(help_dir, paste0(files, ".md")) 25 | new_file <- function(file) { 26 | if (!file.exists(file)) { 27 | file.create(file) 28 | writeLines(text = c(paste("###", file, "- Under Development\n"), 29 | "***\n\n", content, "\n"), 30 | con = file) 31 | } 32 | else { 33 | message("* `", file, "` already exists - not overwriting") 34 | } 35 | } 36 | lapply(files, new_file) 37 | return(invisible(files)) 38 | } 39 | -------------------------------------------------------------------------------- /man/flip_ggplot_build.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/plot_panel.R 3 | \name{flip_ggplot_build} 4 | \alias{flip_ggplot_build} 5 | \title{Ggplot_build for flipped plots} 6 | \usage{ 7 | flip_ggplot_build(ggplot_build_data) 8 | } 9 | \arguments{ 10 | \item{ggplot_build_data}{output of \code{\link[ggplot2]{ggplot_build}}} 11 | } 12 | \description{ 13 | \code{flip_ggplot_build} is a supplementary function for ggplot_build. 14 | Changes ggplot_build output in order to make it compatible with the 15 | plot when coordinates are flipped. 16 | } 17 | \details{ 18 | \code{data} from the output of \code{\link[ggplot2]{ggplot_build}} has 19 | names of columns compatible with the mapping. In case when coordinates are flipped, 20 | it is not consistent with the displayed plot. \code{flip_ggplot_build} changes 21 | the names so that coordinates from the output of \code{\link[ggplot2]{ggplot_build}} 22 | are compatible with the plot and returns it. In case when coordinates are not flipped 23 | \code{flip_ggplot_build} returns \code{ggplot_build_data}. 24 | } 25 | \examples{ 26 | \dontrun{ 27 | 28 | # returns plot info without any change because coordinates are not flipped 29 | p <- ggplot(Orange, aes(x = age, y = circumference, col = Tree)) + 30 | geom_point() + 31 | geom_line() 32 | plot_info <- ggplot_build(p) 33 | flip_ggplot_build(plot_info) # it is the same as plot_info 34 | 35 | # returns plot info with data modified for flipped coordinates 36 | p <- ggplot(Orange, aes(x = age, y = circumference, col = Tree)) + 37 | geom_point() + 38 | geom_line() + 39 | coord_flip() 40 | plot_info <- ggplot_build(p) 41 | flip_ggplot_build(plot_info) 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /man/beam_tooltip.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/tooltip.R 3 | \name{beam_tooltip} 4 | \alias{beam_tooltip} 5 | \title{Generate tooltip} 6 | \usage{ 7 | beam_tooltip(hv, plot_info, plot_data, plot_type, tt_content, tt_range = 5) 8 | } 9 | \arguments{ 10 | \item{hv}{Hoover.} 11 | 12 | \item{plot_info}{chosen mapping from the \code{data} object from the output of \code{\link[ggplot2]{ggplot_build}} for displayed plot.} 13 | 14 | \item{plot_data}{data on which the ggplot is based} 15 | 16 | \item{plot_type}{Type of plot corresponding to the data from first mapping. 17 | Accepts either \code{'geom_point'}, \code{'geom_segment'} 18 | or \code{'geom_col'}. Default \code{'geom_point'}.} 19 | 20 | \item{tt_content}{Optional. If \code{NULL} in the tooltip will be displayed names of 21 | columns with corresponding values from data. One can customize tooltip content 22 | adding parameter \code{tt_content} here. It should be a list of \code{chosen_cols} 23 | and \code{row_text}. To display some values from the data in the content one 24 | should reference to the relevant column from the \code{chosen_cols} and in 25 | \code{row_text} write appropriate type of that variable like in the function 26 | \code{\link[base]{sprintf}} (for example \code{'\%s'} in case when chosen variable 27 | is a character string).} 28 | 29 | \item{tt_range}{A number denoting maximum distance between hoover and objects on the plot. 30 | The row, whose distance to the hoover is less than \code{tt_range} will be selected from the whole data. Default 5.} 31 | } 32 | \description{ 33 | Generates tooltip for plot. 34 | } 35 | \details{ 36 | This function uses \code{\link[shinydetails]{extract_tt_data_row}}. 37 | } 38 | -------------------------------------------------------------------------------- /inst/example_app/example_app.R: -------------------------------------------------------------------------------- 1 | library(shiny) 2 | library(ggplot2) 3 | 4 | ui <- fluidPage(title = "Example app", 5 | beam_plot_panel_UI("airquality_basic"), 6 | beam_plot_panel_UI("airquality_advanced", 7 | tab_plot = "An advanced plot", 8 | tab_table = "An elegant table for an advanced plot", 9 | helpfiles = "custom_helpfiles") 10 | ) 11 | 12 | server <- function(input, output, session) { 13 | 14 | airquality_basic_plot <- reactive({ 15 | ggplot(airquality, aes(x = Wind, y = Temp, col = as.character(Month))) + 16 | geom_point() 17 | }) 18 | 19 | airquality_basic_data <- reactive({ 20 | airquality 21 | }) 22 | 23 | beam_plot_panel_SERVER("airquality_basic", 24 | plot_out = airquality_basic_plot(), 25 | table_out = airquality_basic_data()) 26 | 27 | airquality_advanced_data <- reactive({ 28 | 29 | df <- data.frame(aggregate(. ~ Month, airquality, function(x) c(mean = mean(x), sd = sd(x)))[, c(1, 5)]) 30 | df[["Month"]] <- month.name[df[["Month"]]] 31 | data.frame(Month = df[["Month"]], 32 | Temp_mean = df$Temp[, 1], 33 | Error = df$Temp[, 2], 34 | Year = 1973) 35 | }) 36 | 37 | 38 | airquality_advanced_plot <- reactive({ 39 | ggplot(airquality_advanced_data(), aes(y = 0, yend = Temp_mean, x = Month, xend = Month)) + 40 | geom_segment() + 41 | geom_point(mapping = aes(x = Month, y = Temp_mean), size = 3) + 42 | geom_point() + 43 | ylab("average temperature") 44 | }) 45 | 46 | beam_plot_panel_SERVER("airquality_advanced", 47 | plot_out = airquality_advanced_plot(), 48 | table_out = airquality_advanced_data(), 49 | plot_type = "geom_segment", 50 | tt_content = list(row_text = c("Date: %s %i", 51 | "Average temperature: %f °F", 52 | "Error: %f", 53 | "Place: La Guardia Airport"), 54 | chosen_cols = c("Month", "Year", "Temp_mean", "Error"))) 55 | 56 | 57 | 58 | } 59 | 60 | 61 | shinyApp(ui, server) 62 | 63 | -------------------------------------------------------------------------------- /.github/workflows/R-CMD-check.yaml: -------------------------------------------------------------------------------- 1 | # For help debugging build failures open an issue on the RStudio community with the 'github-actions' tag. 2 | # https://community.rstudio.com/new-topic?category=Package%20development&tags=github-actions 3 | on: 4 | push: 5 | branches: 6 | - main 7 | - master 8 | pull_request: 9 | branches: 10 | - main 11 | - master 12 | 13 | name: R-CMD-check 14 | 15 | jobs: 16 | R-CMD-check: 17 | runs-on: ${{ matrix.config.os }} 18 | 19 | name: ${{ matrix.config.os }} (${{ matrix.config.r }}) 20 | 21 | strategy: 22 | fail-fast: false 23 | matrix: 24 | config: 25 | - {os: windows-latest, r: 'release'} 26 | - {os: macOS-latest, r: 'release'} 27 | - {os: ubuntu-20.04, r: 'release', rspm: "https://packagemanager.rstudio.com/cran/__linux__/focal/latest"} 28 | - {os: ubuntu-20.04, r: 'devel', rspm: "https://packagemanager.rstudio.com/cran/__linux__/focal/latest"} 29 | 30 | env: 31 | R_REMOTES_NO_ERRORS_FROM_WARNINGS: true 32 | RSPM: ${{ matrix.config.rspm }} 33 | 34 | steps: 35 | - uses: actions/checkout@v2 36 | 37 | - uses: r-lib/actions/setup-r@v1 38 | with: 39 | r-version: ${{ matrix.config.r }} 40 | 41 | - uses: r-lib/actions/setup-pandoc@v1 42 | 43 | - name: Query dependencies 44 | run: | 45 | install.packages('remotes') 46 | saveRDS(remotes::dev_package_deps(dependencies = TRUE), ".github/depends.Rds", version = 2) 47 | writeLines(sprintf("R-%i.%i", getRversion()$major, getRversion()$minor), ".github/R-version") 48 | shell: Rscript {0} 49 | 50 | - name: Cache R packages 51 | if: runner.os != 'Windows' 52 | uses: actions/cache@v2 53 | with: 54 | path: ${{ env.R_LIBS_USER }} 55 | key: ${{ runner.os }}-${{ hashFiles('.github/R-version') }}-1-${{ hashFiles('.github/depends.Rds') }} 56 | restore-keys: ${{ runner.os }}-${{ hashFiles('.github/R-version') }}-1- 57 | 58 | - name: Install system dependencies 59 | if: runner.os == 'Linux' 60 | run: | 61 | while read -r cmd 62 | do 63 | eval sudo $cmd 64 | done < <(Rscript -e 'writeLines(remotes::system_requirements("ubuntu", "20.04"))') 65 | 66 | - name: Install dependencies 67 | run: | 68 | remotes::install_deps(dependencies = TRUE) 69 | remotes::install_cran("rcmdcheck") 70 | shell: Rscript {0} 71 | 72 | - name: Check 73 | env: 74 | _R_CHECK_CRAN_INCOMING_REMOTE_: false 75 | run: rcmdcheck::rcmdcheck(args = c("--no-manual", "--as-cran"), error_on = "warning", check_dir = "check") 76 | shell: Rscript {0} 77 | 78 | - name: Upload check results 79 | if: failure() 80 | uses: actions/upload-artifact@main 81 | with: 82 | name: ${{ runner.os }}-r${{ matrix.config.r }}-results 83 | path: check 84 | -------------------------------------------------------------------------------- /inst/tiny_demo/server.R: -------------------------------------------------------------------------------- 1 | library(shiny) 2 | library(shinyhelper) 3 | library(ggplot2) 4 | 5 | server <- shinyServer(function(input, output) { 6 | 7 | observe_helpers(session = getDefaultReactiveDomain(), help_dir = "helpfiles") 8 | 9 | #geom_segment 10 | geom_segment_data <- reactive({ 11 | data.frame(mtcars, 12 | car = rownames(mtcars)) 13 | }) 14 | 15 | geom_segment_plot_out <- reactive({ 16 | ggplot(geom_segment_data(), mapping = aes(y = 0, 17 | x = car, 18 | yend = mpg, 19 | xend = car)) + 20 | geom_segment(color = "black") + 21 | geom_point(stat ='identity', fill="black") + 22 | coord_flip() 23 | }) 24 | 25 | tabsetPanel_SERVER(id = "geom_segment", 26 | plot_out = geom_segment_plot_out, 27 | table_out = geom_segment_data, 28 | plot_type = "geom_segment", 29 | tt_content = list(row_text = c("Mpg: %f", "Car: %s"), 30 | chosen_cols = c("mpg", "car"))) 31 | 32 | #geom_segment 33 | geom_segment_data2 <- reactive({ 34 | data.frame(x = c(1,2,5,6,8), 35 | y = c(3,6,2,8,7), 36 | vx = c(1,1.5,0.8,0.5,1.3), 37 | vy = c(0.2,1.3,1.7,0.8,1.4)) 38 | }) 39 | 40 | geom_segment_plot_out2 <- reactive({ 41 | ggplot() + 42 | geom_segment(data = geom_segment_data2(), 43 | mapping = aes(x = x, y = y, xend = x + vx, yend = y + vy), 44 | size = 2, color = "blue") 45 | }) 46 | 47 | tabsetPanel_SERVER(id = "geom_segment2", 48 | plot_out = geom_segment_plot_out2, 49 | table_out = geom_segment_data2, 50 | plot_type = "geom_segment", 51 | tt_range = 10) 52 | 53 | #geom_point 54 | 55 | geom_point_data <- reactive({ 56 | iris 57 | }) 58 | 59 | geom_point_plot <- reactive({ 60 | ggplot(geom_point_data(), 61 | aes(x = Sepal.Length, y = Sepal.Width, col = Species)) + 62 | geom_point() 63 | }) 64 | 65 | tabsetPanel_SERVER(id = "geom_point", 66 | plot_out = geom_point_plot, 67 | table_out = geom_point_data, 68 | plot_type = "geom_point", 69 | tt_range = 10) 70 | 71 | #geom_bar 72 | 73 | geom_bar_data <- reactive({ 74 | data.frame(Sepal.Length = table(cut(iris[["Sepal.Length"]], seq(4, 8, length.out = 10)))) 75 | }) 76 | 77 | geom_bar_plot <- reactive({ 78 | ggplot(geom_bar_data(), 79 | aes(x = Sepal.Length.Var1, y = Sepal.Length.Freq)) + 80 | geom_col() 81 | }) 82 | 83 | tabsetPanel_SERVER(id = "geom_col", 84 | plot_out = geom_bar_plot, 85 | table_out = geom_bar_data, 86 | plot_type = "geom_col", 87 | tt_range = 10) 88 | 89 | 90 | 91 | }) 92 | -------------------------------------------------------------------------------- /man/beam_plot_panel_UI.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/plot_panel.R 3 | \name{beam_plot_panel_UI} 4 | \alias{beam_plot_panel_UI} 5 | \title{Creating UI for a Shiny module with plot and data} 6 | \usage{ 7 | beam_plot_panel_UI( 8 | id, 9 | tab_plot = paste(id, "plot"), 10 | tab_table = paste(id, "data"), 11 | helpfiles = "helpfiles" 12 | ) 13 | } 14 | \arguments{ 15 | \item{id}{unique ID name of tabset. The same ID as in the corresponding server for 16 | a module} 17 | 18 | \item{tab_plot}{Character. Title of tab containing plot. Default to 19 | \code{paste(id, "plot")}.} 20 | 21 | \item{tab_table}{Character. Title of tab containing table. Default to 22 | \code{paste(id, "data")}.} 23 | 24 | \item{helpfiles}{A character string denoting directory to save empty help files. 25 | Default \code{'helpfiles'}.} 26 | } 27 | \description{ 28 | Creates module's UI for tabset panel containing two tabs - with 29 | plot and an elegant table with data. 30 | } 31 | \details{ 32 | Module's UI involves a panel with two tabs. The first tab consists of 33 | displayed plot and three download buttons (png, svg and jpeg). There is also a 34 | compatible with the plot tooltip. The second tab consists of a table 35 | with two download buttons (Excel and CSV). For both table and plot there are 36 | provided helpers. \ 37 | For more information see \code{\link[shinydetails]{plotOutput_h}} and 38 | \code{\link[shinydetails]{tableOutput_h}} 39 | } 40 | \examples{ 41 | \dontrun{ 42 | ui <- fluidPage(title = "Example app", 43 | beam_plot_panel_UI("airquality_basic"), 44 | beam_plot_panel_UI("airquality_advanced", 45 | tab_plot = "An advanced plot", 46 | tab_table = "An elegant table for an advanced plot", 47 | helpfiles = "custom_helpfiles")) 48 | 49 | server <- function(input, output, session) { 50 | airquality_basic_plot <- reactive({ 51 | ggplot(airquality, aes(x = Wind, y = Temp, col = as.character(Month))) + 52 | geom_point() 53 | }) 54 | airquality_basic_data <- reactive({ 55 | airquality 56 | }) 57 | beam_plot_panel_SERVER("airquality_basic", 58 | plot_out = airquality_basic_plot(), 59 | table_out = airquality_basic_data()) 60 | 61 | airquality_advanced_data <- reactive({ 62 | df <- data.frame(aggregate(. ~ Month, airquality, function(x) c(mean = mean(x), sd = sd(x)))[, c(1, 5)]) 63 | df[["Month"]] <- month.name[df[["Month"]]] 64 | data.frame(Month = df[["Month"]], 65 | Temp_mean = df$Temp[, 1], 66 | Error = df$Temp[, 2], 67 | Year = 1973)}) 68 | 69 | airquality_advanced_plot <- reactive({ 70 | ggplot(airquality_advanced_data(), aes(y = 0, yend = Temp_mean, x = Month, xend = Month)) + 71 | geom_segment() + 72 | geom_point(mapping = aes(x = Month, y = Temp_mean), size = 3) + 73 | geom_point() + 74 | ylab("average temperature") 75 | }) 76 | beam_plot_panel_SERVER("airquality_advanced", 77 | plot_out = airquality_advanced_plot(), 78 | table_out = airquality_advanced_data(), 79 | plot_type = "geom_segment", 80 | tt_content = list(row_text = c("Date: \%s \%i", 81 | "Average temperature: \%f °F", 82 | "Error: \%f", 83 | "Place: La Guardia Airport"), 84 | chosen_cols = c("Month", 85 | "Year", 86 | "Temp_mean", 87 | "Error")) 88 | ) 89 | 90 | } 91 | } 92 | } 93 | \seealso{ 94 | To build Shiny module within a Shiny app using \code{beam_plot_panel_UI} 95 | see \code{\link[shinydetails]{beam_plot_panel_SERVER}}. 96 | } 97 | -------------------------------------------------------------------------------- /R/elements_h.R: -------------------------------------------------------------------------------- 1 | 2 | #' @title Slider input with helper 3 | #' @description Constructs a slider widget with helper. 4 | #' Same as \code{helper(sliderInput(outputId, ...))}. Creates help file and/or 5 | #' directory if it does not exist. 6 | #' @inheritParams shiny::sliderInput 7 | #' @inheritParams plotOutput_h 8 | #' @param ... Optional arguments for \code{sliderInput}. 9 | #' @details This function uses \code{\link[shinyhelper]{helper}}. 10 | #' @seealso For more elements with helpers see \code{\link[shinydetails]{numericInput_h}}, 11 | #' \code{\link[shinydetails]{plotOutput_h}}, \code{\link[shinydetails]{tableOutput_h}} 12 | #' @export 13 | #' 14 | 15 | sliderInput_h <- function(inputId, helpfiles = "helpfiles", ...) { 16 | suppressMessages({create_help_files_custom(files = inputId, 17 | help_dir = helpfiles)}) 18 | helper(sliderInput(inputId, ...), 19 | content = inputId, 20 | type = "markdown") 21 | } 22 | 23 | #' @title Numeric input with helper. 24 | #' @description Constructs a numeric input with helper. 25 | #' Same as \code{helper(numericInput(outputId, ...))}. Creates help file and/or 26 | #' directory if it does not exist. 27 | #' @inheritParams shiny::numericInput 28 | #' @inheritParams plotOutput_h 29 | #' @param ... Optional arguments for \code{numericInput}. 30 | #' @details This function uses \code{\link[shinyhelper]{helper}}. 31 | #' @seealso For more elements with helpers see \code{\link[shinydetails]{plotOutput_h}}, 32 | #' \code{\link[shinydetails]{tableOutput_h}}, \code{\link[shinydetails]{sliderInput_h}} 33 | #' @export 34 | #' 35 | 36 | numericInput_h <- function(inputId, helpfiles = "helpfiles", ...) { 37 | suppressMessages({create_help_files_custom(files = inputId, 38 | help_dir = helpfiles)}) 39 | helper(numericInput(inputId, ...), 40 | content = inputId, 41 | type = "markdown") 42 | } 43 | 44 | 45 | #' @title Plot output with helper 46 | #' @description Renders plot with helper within an application. 47 | #' Same as \code{helper(plotOutput(outputId, ...))}. Creates help file and/or 48 | #' directory if it does not exist. 49 | #' @inheritParams shiny::plotOutput 50 | #' @param helpfiles A character string denoting directory to save empty help files. 51 | #' Default \code{'helpfiles'}. 52 | #' @param ... Optional arguments for \code{plotOutput}. 53 | #' @details This function uses \code{\link[shinyhelper]{helper}}. 54 | #' @seealso For more elements with helpers see \code{\link[shinydetails]{numericInput_h}}, 55 | #' \code{\link[shinydetails]{tableOutput_h}}, 56 | #' \code{\link[shinydetails]{sliderInput_h}} 57 | #' @export 58 | #' 59 | 60 | plotOutput_h <- function(outputId, helpfiles = "helpfiles", ...) { 61 | suppressMessages({create_help_files_custom(files = outputId, 62 | help_dir = "helpfiles", 63 | content = "This help file was generated automatically.")}) 64 | helper(plotOutput(outputId, ...), 65 | content = outputId, 66 | type = "markdown") 67 | } 68 | 69 | 70 | #' @title Table output with helper. 71 | #' @description Renders table with helper within an application. Creates help file and/or 72 | #' directory if it does not exist. 73 | #' Same as \code{helper(dataTableOutput(outputId, ...))} 74 | #' @inheritParams shiny::dataTableOutput 75 | #' @inheritParams plotOutput_h 76 | #' @details This function uses \code{\link[shinyhelper]{helper}}. 77 | #' @seealso For more elements with helpers see \code{\link[shinydetails]{numericInput_h}}, 78 | #' \code{\link[shinydetails]{plotOutput_h}}, \code{\link[shinydetails]{sliderInput_h}} 79 | #' @export 80 | #' 81 | 82 | 83 | tableOutput_h <- function(outputId, helpfiles = "helpfiles", ...) { 84 | suppressMessages({create_help_files_custom(files = outputId, 85 | help_dir = "helpfiles", 86 | content = "This help file was generated automatically.")}) 87 | helper(DT::dataTableOutput(outputId, ...), 88 | content = outputId, 89 | type = "markdown") 90 | } 91 | 92 | -------------------------------------------------------------------------------- /R/tooltip.R: -------------------------------------------------------------------------------- 1 | 2 | #' @title Tooltip data 3 | #' @description Prepares data in order that it may be displayed in tooltip. 4 | #' The row from the data which fits to the hover the most will be selected. 5 | #' @param hv Hoover. 6 | #' @param plot_info chosen mapping from the \code{data} object from the output of \code{\link[ggplot2]{ggplot_build}} for displayed plot. 7 | #' @param plot_data data on which the ggplot is based 8 | #' @param plot_type Type of plot corresponding to the data from first mapping. 9 | #' Accepts either \code{'geom_point'}, \code{'geom_segment'} 10 | #' or \code{'geom_col'}. Default \code{'geom_point'}. 11 | #' @param tt_range A number denoting maximum distance between hoover and objects on the plot. 12 | #' The row, whose distance to the hoover is less than \code{tt_range} will be selected from the whole data. Default 5. 13 | #' @return \code{prepare_tt_data} returns prepared data frame containing one record. 14 | #' @details This function filters one row of the imputed data in order that it 15 | #' corresponds the most to the hoover coordinates. 16 | #' @export 17 | 18 | 19 | extract_tt_data_row <- function(hv, plot_info, plot_data, plot_type = "geom_point", tt_range = 5) { 20 | 21 | match.arg(plot_type, c("geom_col", "geom_point", "geom_segment"), several.ok = FALSE) 22 | 23 | switch(plot_type, 24 | geom_col = { 25 | hv_data <- data.frame(x = hv[["x"]], 26 | y = hv[["y"]], 27 | xmin = plot_info[["xmin"]], 28 | xmax = plot_info[["xmax"]], 29 | plot_data) 30 | tt_df <- hv_data[hv_data[["x"]] < hv_data[["xmax"]] & 31 | hv_data[["x"]] >= hv_data[["xmin"]], 32 | !(colnames(hv_data) %in% c("x", "y", "xmax", "xmin"))] 33 | }, 34 | geom_point = { 35 | tt_df <- nearPoints(df = plot_data, coordinfo = hv, maxpoints = 1, threshold = tt_range) 36 | }, 37 | geom_segment = { 38 | x_start <- plot_info[["x"]] 39 | x_end <- plot_info[["xend"]] 40 | y_start <- plot_info[["y"]] 41 | y_end <- plot_info[["yend"]] 42 | A <- y_start - y_end 43 | B <- x_end - x_start 44 | C <- y_end*(x_start - x_end) - x_end*(y_start - y_end) 45 | 46 | hv_data <- data.frame(dist = abs((hv[["x"]]*A + hv[["y"]]*B + C))/sqrt(A^2 + B^2), 47 | plot_data) 48 | 49 | tt_df <- hv_data[x_start - tt_range <= hv[["x"]] & 50 | x_end + tt_range >= hv[["x"]] & 51 | y_start - tt_range <= hv[["y"]] & 52 | y_end + tt_range >= hv[["y"]] & 53 | hv_data[["dist"]] <= tt_range & 54 | hv_data[["dist"]] == min(hv_data[["dist"]]), 55 | !(colnames(hv_data) %in% c("dist"))] 56 | } 57 | ) 58 | tt_df 59 | } 60 | 61 | 62 | #' @title Generate tooltip 63 | #' @description Generates tooltip for plot. 64 | #' @inheritParams extract_tt_data_row 65 | #' @param tt_content Optional. If \code{NULL} in the tooltip will be displayed names of 66 | #' columns with corresponding values from data. One can customize tooltip content 67 | #' adding parameter \code{tt_content} here. It should be a list of \code{chosen_cols} 68 | #' and \code{row_text}. To display some values from the data in the content one 69 | #' should reference to the relevant column from the \code{chosen_cols} and in 70 | #' \code{row_text} write appropriate type of that variable like in the function 71 | #' \code{\link[base]{sprintf}} (for example \code{'\%s'} in case when chosen variable 72 | #' is a character string). 73 | #' @details This function uses \code{\link[shinydetails]{extract_tt_data_row}}. 74 | #' @export 75 | #' 76 | 77 | beam_tooltip <- function(hv, plot_info, plot_data, plot_type, tt_content, tt_range = 5) { 78 | 79 | tt_df <- extract_tt_data_row(hv, plot_info, plot_data, plot_type, tt_range) 80 | 81 | if(nrow(tt_df) != 0) { 82 | tt_pos_adj <- ifelse(hv[["coords_img"]][["x"]]/hv[["range"]][["right"]] < 0.5, 83 | "left", "right") 84 | 85 | tt_pos <- ifelse(hv[["coords_img"]][["x"]]/hv[["range"]][["right"]] < 0.5, 86 | hv[["coords_css"]][["x"]], 87 | hv[["range"]][["right"]]/hv[["img_css_ratio"]][["x"]] - hv[["coords_css"]][["x"]]) 88 | 89 | style <- paste0("position:absolute; z-index:1000; background-color: rgba(245, 245, 245, 1); pointer-events: none;", 90 | tt_pos_adj, ":", tt_pos, 91 | "px; top:", hv[["coords_css"]][["y"]], "px; padding: 0px;") 92 | 93 | if(is.null(tt_content)) { 94 | content <- paste(colnames(tt_df), ": ", t(tt_df ), c(rep("
", ncol(tt_df)-1), "")) 95 | }else { 96 | text <- paste(tt_content[["row_text"]], 97 | c(rep("
", length(tt_content[["row_text"]]) - 1), ""), 98 | sep = "", collapse = "") 99 | content <- do.call(sprintf, c(list(text), lapply(tt_content[["chosen_cols"]], function(i) tt_df[[i]]))) 100 | } 101 | 102 | div(style = style, 103 | p(HTML(content)) 104 | ) 105 | } 106 | } 107 | 108 | -------------------------------------------------------------------------------- /man/beam_plot_panel_SERVER.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/plot_panel.R 3 | \name{beam_plot_panel_SERVER} 4 | \alias{beam_plot_panel_SERVER} 5 | \title{Creating server for a Shiny module with plot and data.} 6 | \usage{ 7 | beam_plot_panel_SERVER( 8 | id, 9 | plot_out, 10 | table_out, 11 | plot_type = "geom_point", 12 | tt_content = NULL, 13 | tt_range = 5, 14 | helpfiles = "helpfiles" 15 | ) 16 | } 17 | \arguments{ 18 | \item{id}{unique Id of tabset panel. The same ID as in the corresponding UI for 19 | a module} 20 | 21 | \item{plot_out}{Plot to display in tab. There will be provided an automatically 22 | generated tooltip compatible with the plot. The items from first mapping will be 23 | connected with tooltip.} 24 | 25 | \item{table_out}{Table to display in tab.} 26 | 27 | \item{plot_type}{Type of plot corresponding to the data from first mapping. 28 | Accepts either \code{'geom_point'}, \code{'geom_segment'} 29 | or \code{'geom_col'}. Default \code{'geom_point'}.} 30 | 31 | \item{tt_content}{Optional. If \code{NULL} in the tooltip will be displayed names of 32 | columns with corresponding values from data. One can customize tooltip content 33 | adding parameter \code{tt_content} here. It should be a list of \code{chosen_cols} 34 | and \code{row_text}. To display some values from the data in the content one 35 | should reference to the relevant column from the \code{chosen_cols} and in 36 | \code{row_text} write appropriate type of that variable like in the function 37 | \code{\link[base]{sprintf}} (for example \code{'\%s'} in case when chosen variable 38 | is a character string).} 39 | 40 | \item{tt_range}{A number denoting maximum distance between hoover and objects on the plot. 41 | The row, whose distance to the hoover is less than \code{tt_range} will be selected from the whole data. Default 5.} 42 | 43 | \item{helpfiles}{A character string denoting directory to save empty help files. 44 | Default \code{'helpfiles'}.} 45 | } 46 | \description{ 47 | Creates module server for tabset panel containing two tabs - with 48 | plot and an elegant table with data. 49 | } 50 | \details{ 51 | Module's server involves a panel with two tabs. The first tab consists of 52 | displayed plot and three download buttons (png, svg and jpeg). There is also a 53 | compatible with plot tooltip obtained via \code{\link[shinydetails]{beam_tooltip}}. 54 | The second tab consists of a table with two download buttons (Excel and CSV). 55 | The table \code{table_out} before displaying is formatted using 56 | \code{\link[shinydetails]{dt_format}}. For both table and plot there are provided 57 | helpers. 58 | } 59 | \examples{ 60 | \dontrun{ 61 | ui <- fluidPage(title = "Example app", 62 | beam_plot_panel_UI("airquality_basic"), 63 | beam_plot_panel_UI("airquality_advanced", 64 | tab_plot = "An advanced plot", 65 | tab_table = "An elegant table for an advanced plot", 66 | helpfiles = "custom_helpfiles")) 67 | 68 | server <- function(input, output, session) { 69 | airquality_basic_plot <- reactive({ 70 | ggplot(airquality, aes(x = Wind, y = Temp, col = as.character(Month))) + 71 | geom_point() 72 | }) 73 | airquality_basic_data <- reactive({ 74 | airquality 75 | }) 76 | beam_plot_panel_SERVER("airquality_basic", 77 | plot_out = airquality_basic_plot(), 78 | table_out = airquality_basic_data()) 79 | 80 | airquality_advanced_data <- reactive({ 81 | df <- data.frame(aggregate(. ~ Month, airquality, function(x) c(mean = mean(x), sd = sd(x)))[, c(1, 5)]) 82 | df[["Month"]] <- month.name[df[["Month"]]] 83 | data.frame(Month = df[["Month"]], 84 | Temp_mean = df$Temp[, 1], 85 | Error = df$Temp[, 2], 86 | Year = 1973)}) 87 | 88 | airquality_advanced_plot <- reactive({ 89 | ggplot(airquality_advanced_data(), aes(y = 0, yend = Temp_mean, x = Month, xend = Month)) + 90 | geom_segment() + 91 | geom_point(mapping = aes(x = Month, y = Temp_mean), size = 3) + 92 | geom_point() + 93 | ylab("average temperature") 94 | }) 95 | beam_plot_panel_SERVER("airquality_advanced", 96 | plot_out = airquality_advanced_plot(), 97 | table_out = airquality_advanced_data(), 98 | plot_type = "geom_segment", 99 | tt_content = list(row_text = c("Date: \%s \%i", 100 | "Average temperature: \%f °F", 101 | "Error: \%f", 102 | "Place: La Guardia Airport"), 103 | chosen_cols = c("Month", 104 | "Year", 105 | "Temp_mean", 106 | "Error")) 107 | ) 108 | 109 | } 110 | } 111 | } 112 | \seealso{ 113 | To build Shiny module within a Shiny app using \code{beam_plot_panel_SERVER} 114 | see \code{\link[shinydetails]{beam_plot_panel_UI}}. 115 | } 116 | -------------------------------------------------------------------------------- /renv/activate.R: -------------------------------------------------------------------------------- 1 | 2 | local({ 3 | 4 | # the requested version of renv 5 | version <- "0.12.3" 6 | 7 | # the project directory 8 | project <- getwd() 9 | 10 | # avoid recursion 11 | if (!is.na(Sys.getenv("RENV_R_INITIALIZING", unset = NA))) 12 | return(invisible(TRUE)) 13 | 14 | # signal that we're loading renv during R startup 15 | Sys.setenv("RENV_R_INITIALIZING" = "true") 16 | on.exit(Sys.unsetenv("RENV_R_INITIALIZING"), add = TRUE) 17 | 18 | # signal that we've consented to use renv 19 | options(renv.consent = TRUE) 20 | 21 | # load the 'utils' package eagerly -- this ensures that renv shims, which 22 | # mask 'utils' packages, will come first on the search path 23 | library(utils, lib.loc = .Library) 24 | 25 | # check to see if renv has already been loaded 26 | if ("renv" %in% loadedNamespaces()) { 27 | 28 | # if renv has already been loaded, and it's the requested version of renv, 29 | # nothing to do 30 | spec <- .getNamespaceInfo(.getNamespace("renv"), "spec") 31 | if (identical(spec[["version"]], version)) 32 | return(invisible(TRUE)) 33 | 34 | # otherwise, unload and attempt to load the correct version of renv 35 | unloadNamespace("renv") 36 | 37 | } 38 | 39 | # load bootstrap tools 40 | bootstrap <- function(version, library) { 41 | 42 | # read repos (respecting override if set) 43 | repos <- Sys.getenv("RENV_CONFIG_REPOS_OVERRIDE", unset = NA) 44 | if (is.na(repos)) 45 | repos <- getOption("repos") 46 | 47 | # fix up repos 48 | on.exit(options(repos = repos), add = TRUE) 49 | repos[repos == "@CRAN@"] <- "https://cloud.r-project.org" 50 | options(repos = repos) 51 | 52 | # attempt to download renv 53 | tarball <- tryCatch(renv_bootstrap_download(version), error = identity) 54 | if (inherits(tarball, "error")) 55 | stop("failed to download renv ", version) 56 | 57 | # now attempt to install 58 | status <- tryCatch(renv_bootstrap_install(version, tarball, library), error = identity) 59 | if (inherits(status, "error")) 60 | stop("failed to install renv ", version) 61 | 62 | } 63 | 64 | renv_bootstrap_download_impl <- function(url, destfile) { 65 | 66 | mode <- "wb" 67 | 68 | # https://bugs.r-project.org/bugzilla/show_bug.cgi?id=17715 69 | fixup <- 70 | Sys.info()[["sysname"]] == "Windows" && 71 | substring(url, 1L, 5L) == "file:" 72 | 73 | if (fixup) 74 | mode <- "w+b" 75 | 76 | download.file( 77 | url = url, 78 | destfile = destfile, 79 | mode = mode, 80 | quiet = TRUE 81 | ) 82 | 83 | } 84 | 85 | renv_bootstrap_download <- function(version) { 86 | 87 | # if the renv version number has 4 components, assume it must 88 | # be retrieved via github 89 | nv <- numeric_version(version) 90 | components <- unclass(nv)[[1]] 91 | 92 | methods <- if (length(components) == 4L) { 93 | list(renv_bootstrap_download_github) 94 | } else { 95 | list( 96 | renv_bootstrap_download_cran_latest, 97 | renv_bootstrap_download_cran_archive 98 | ) 99 | } 100 | 101 | for (method in methods) { 102 | path <- tryCatch(method(version), error = identity) 103 | if (is.character(path) && file.exists(path)) 104 | return(path) 105 | } 106 | 107 | stop("failed to download renv ", version) 108 | 109 | } 110 | 111 | renv_bootstrap_download_cran_latest <- function(version) { 112 | 113 | repos <- renv_bootstrap_download_cran_latest_find(version) 114 | 115 | message("* Downloading renv ", version, " from CRAN ... ", appendLF = FALSE) 116 | 117 | info <- tryCatch( 118 | download.packages("renv", repos = repos, destdir = tempdir(), quiet = TRUE), 119 | condition = identity 120 | ) 121 | 122 | if (inherits(info, "condition")) { 123 | message("FAILED") 124 | return(FALSE) 125 | } 126 | 127 | message("OK") 128 | info[1, 2] 129 | 130 | } 131 | 132 | renv_bootstrap_download_cran_latest_find <- function(version) { 133 | 134 | # check for renv on CRAN matching this version 135 | all <- unique(c( 136 | getOption("repos"), 137 | getOption("renv.bootstrap.repos", default = "https://cloud.r-project.org") 138 | )) 139 | 140 | for (repos in all) { 141 | 142 | db <- tryCatch( 143 | as.data.frame(available.packages(repos = repos), stringsAsFactors = FALSE), 144 | error = identity 145 | ) 146 | 147 | if (inherits(db, "error")) 148 | next 149 | 150 | entry <- db[db$Package %in% "renv" & db$Version %in% version, ] 151 | if (nrow(entry) == 0) 152 | next 153 | 154 | return(repos) 155 | 156 | } 157 | 158 | fmt <- "renv %s is not available from your declared package repositories" 159 | stop(sprintf(fmt, version)) 160 | 161 | } 162 | 163 | renv_bootstrap_download_cran_archive <- function(version) { 164 | 165 | name <- sprintf("renv_%s.tar.gz", version) 166 | repos <- getOption("repos") 167 | urls <- file.path(repos, "src/contrib/Archive/renv", name) 168 | destfile <- file.path(tempdir(), name) 169 | 170 | message("* Downloading renv ", version, " from CRAN archive ... ", appendLF = FALSE) 171 | 172 | for (url in urls) { 173 | 174 | status <- tryCatch( 175 | renv_bootstrap_download_impl(url, destfile), 176 | condition = identity 177 | ) 178 | 179 | if (identical(status, 0L)) { 180 | message("OK") 181 | return(destfile) 182 | } 183 | 184 | } 185 | 186 | message("FAILED") 187 | return(FALSE) 188 | 189 | } 190 | 191 | renv_bootstrap_download_github <- function(version) { 192 | 193 | enabled <- Sys.getenv("RENV_BOOTSTRAP_FROM_GITHUB", unset = "TRUE") 194 | if (!identical(enabled, "TRUE")) 195 | return(FALSE) 196 | 197 | # prepare download options 198 | pat <- Sys.getenv("GITHUB_PAT") 199 | if (nzchar(Sys.which("curl")) && nzchar(pat)) { 200 | fmt <- "--location --fail --header \"Authorization: token %s\"" 201 | extra <- sprintf(fmt, pat) 202 | saved <- options("download.file.method", "download.file.extra") 203 | options(download.file.method = "curl", download.file.extra = extra) 204 | on.exit(do.call(base::options, saved), add = TRUE) 205 | } else if (nzchar(Sys.which("wget")) && nzchar(pat)) { 206 | fmt <- "--header=\"Authorization: token %s\"" 207 | extra <- sprintf(fmt, pat) 208 | saved <- options("download.file.method", "download.file.extra") 209 | options(download.file.method = "wget", download.file.extra = extra) 210 | on.exit(do.call(base::options, saved), add = TRUE) 211 | } 212 | 213 | message("* Downloading renv ", version, " from GitHub ... ", appendLF = FALSE) 214 | 215 | url <- file.path("https://api.github.com/repos/rstudio/renv/tarball", version) 216 | name <- sprintf("renv_%s.tar.gz", version) 217 | destfile <- file.path(tempdir(), name) 218 | 219 | status <- tryCatch( 220 | renv_bootstrap_download_impl(url, destfile), 221 | condition = identity 222 | ) 223 | 224 | if (!identical(status, 0L)) { 225 | message("FAILED") 226 | return(FALSE) 227 | } 228 | 229 | message("Done!") 230 | return(destfile) 231 | 232 | } 233 | 234 | renv_bootstrap_install <- function(version, tarball, library) { 235 | 236 | # attempt to install it into project library 237 | message("* Installing renv ", version, " ... ", appendLF = FALSE) 238 | dir.create(library, showWarnings = FALSE, recursive = TRUE) 239 | 240 | # invoke using system2 so we can capture and report output 241 | bin <- R.home("bin") 242 | exe <- if (Sys.info()[["sysname"]] == "Windows") "R.exe" else "R" 243 | r <- file.path(bin, exe) 244 | args <- c("--vanilla", "CMD", "INSTALL", "-l", shQuote(library), shQuote(tarball)) 245 | output <- system2(r, args, stdout = TRUE, stderr = TRUE) 246 | message("Done!") 247 | 248 | # check for successful install 249 | status <- attr(output, "status") 250 | if (is.numeric(status) && !identical(status, 0L)) { 251 | header <- "Error installing renv:" 252 | lines <- paste(rep.int("=", nchar(header)), collapse = "") 253 | text <- c(header, lines, output) 254 | writeLines(text, con = stderr()) 255 | } 256 | 257 | status 258 | 259 | } 260 | 261 | renv_bootstrap_prefix <- function() { 262 | 263 | # construct version prefix 264 | version <- paste(R.version$major, R.version$minor, sep = ".") 265 | prefix <- paste("R", numeric_version(version)[1, 1:2], sep = "-") 266 | 267 | # include SVN revision for development versions of R 268 | # (to avoid sharing platform-specific artefacts with released versions of R) 269 | devel <- 270 | identical(R.version[["status"]], "Under development (unstable)") || 271 | identical(R.version[["nickname"]], "Unsuffered Consequences") 272 | 273 | if (devel) 274 | prefix <- paste(prefix, R.version[["svn rev"]], sep = "-r") 275 | 276 | # build list of path components 277 | components <- c(prefix, R.version$platform) 278 | 279 | # include prefix if provided by user 280 | prefix <- Sys.getenv("RENV_PATHS_PREFIX") 281 | if (nzchar(prefix)) 282 | components <- c(prefix, components) 283 | 284 | # build prefix 285 | paste(components, collapse = "/") 286 | 287 | } 288 | 289 | renv_bootstrap_library_root <- function(project) { 290 | 291 | path <- Sys.getenv("RENV_PATHS_LIBRARY", unset = NA) 292 | if (!is.na(path)) 293 | return(path) 294 | 295 | path <- Sys.getenv("RENV_PATHS_LIBRARY_ROOT", unset = NA) 296 | if (!is.na(path)) { 297 | id <- substring(renv_bootstrap_hash_text(project), 1L, 8L) 298 | name <- paste(basename(project), id, sep = "-") 299 | return(file.path(path, name)) 300 | } 301 | 302 | file.path(project, "renv/library") 303 | 304 | } 305 | 306 | renv_bootstrap_validate_version <- function(version) { 307 | 308 | loadedversion <- utils::packageDescription("renv", fields = "Version") 309 | if (version == loadedversion) 310 | return(TRUE) 311 | 312 | # assume four-component versions are from GitHub; three-component 313 | # versions are from CRAN 314 | components <- strsplit(loadedversion, "[.-]")[[1]] 315 | remote <- if (length(components) == 4L) 316 | paste("rstudio/renv", loadedversion, sep = "@") 317 | else 318 | paste("renv", loadedversion, sep = "@") 319 | 320 | fmt <- paste( 321 | "renv %1$s was loaded from project library, but this project is configured to use renv %2$s.", 322 | "Use `renv::record(\"%3$s\")` to record renv %1$s in the lockfile.", 323 | "Use `renv::restore(packages = \"renv\")` to install renv %2$s into the project library.", 324 | sep = "\n" 325 | ) 326 | 327 | msg <- sprintf(fmt, loadedversion, version, remote) 328 | warning(msg, call. = FALSE) 329 | 330 | FALSE 331 | 332 | } 333 | 334 | renv_bootstrap_hash_text <- function(text) { 335 | 336 | hashfile <- tempfile("renv-hash-") 337 | on.exit(unlink(hashfile), add = TRUE) 338 | 339 | writeLines(text, con = hashfile) 340 | tools::md5sum(hashfile) 341 | 342 | } 343 | 344 | renv_bootstrap_load <- function(project, libpath, version) { 345 | 346 | # try to load renv from the project library 347 | if (!requireNamespace("renv", lib.loc = libpath, quietly = TRUE)) 348 | return(FALSE) 349 | 350 | # warn if the version of renv loaded does not match 351 | renv_bootstrap_validate_version(version) 352 | 353 | # load the project 354 | renv::load(project) 355 | 356 | TRUE 357 | 358 | } 359 | 360 | # construct path to library root 361 | root <- renv_bootstrap_library_root(project) 362 | 363 | # construct library prefix for platform 364 | prefix <- renv_bootstrap_prefix() 365 | 366 | # construct full libpath 367 | libpath <- file.path(root, prefix) 368 | 369 | # attempt to load 370 | if (renv_bootstrap_load(project, libpath, version)) 371 | return(TRUE) 372 | 373 | # load failed; inform user we're about to bootstrap 374 | prefix <- paste("# Bootstrapping renv", version) 375 | postfix <- paste(rep.int("-", 77L - nchar(prefix)), collapse = "") 376 | header <- paste(prefix, postfix) 377 | message(header) 378 | 379 | # perform bootstrap 380 | bootstrap(version, libpath) 381 | 382 | # exit early if we're just testing bootstrap 383 | if (!is.na(Sys.getenv("RENV_BOOTSTRAP_INSTALL_ONLY", unset = NA))) 384 | return(TRUE) 385 | 386 | # try again to load 387 | if (requireNamespace("renv", lib.loc = libpath, quietly = TRUE)) { 388 | message("* Successfully installed and loaded renv ", version, ".") 389 | return(renv::load()) 390 | } 391 | 392 | # failed to download or load renv; warn the user 393 | msg <- c( 394 | "Failed to find an renv installation: the project will not be loaded.", 395 | "Use `renv::activate()` to re-initialize the project." 396 | ) 397 | 398 | warning(paste(msg, collapse = "\n"), call. = FALSE) 399 | 400 | }) 401 | -------------------------------------------------------------------------------- /R/plot_panel.R: -------------------------------------------------------------------------------- 1 | 2 | #' @title Table widget 3 | #' @description \code{dt_format} is a function for creating a graphical 4 | #' widget containing a table with download buttons (Excel and CSV). 5 | #' @param dat a data object - a matrix or a data frame. 6 | #' @param colnames Names of columns to display in the table. By default it is 7 | #' equal to the names of the columns from the \code{dat}. Parameter \code{colnames} is 8 | #' correspond the argument \code{colnames} from \code{\link[DT]{datatable}}. 9 | #' @details This function uses \code{\link[DT]{datatable}}. 10 | #' 11 | 12 | dt_format <- function(dat, colnames = colnames(dat)) { 13 | datatable(data = dat, 14 | colnames = colnames, 15 | class = "table-bordered table-condensed", 16 | extensions = "Buttons", 17 | options = list(pageLength = 10, 18 | dom = "tBip", 19 | autoWidth = TRUE, 20 | buttons = c("excel", "csv")), 21 | filter = "bottom", 22 | rownames = FALSE) 23 | } 24 | 25 | 26 | #' @title Ggplot_build for flipped plots 27 | #' @description \code{flip_ggplot_build} is a supplementary function for ggplot_build. 28 | #' Changes ggplot_build output in order to make it compatible with the 29 | #' plot when coordinates are flipped. 30 | #' @param ggplot_build_data output of \code{\link[ggplot2]{ggplot_build}} 31 | #' @details \code{data} from the output of \code{\link[ggplot2]{ggplot_build}} has 32 | #' names of columns compatible with the mapping. In case when coordinates are flipped, 33 | #' it is not consistent with the displayed plot. \code{flip_ggplot_build} changes 34 | #' the names so that coordinates from the output of \code{\link[ggplot2]{ggplot_build}} 35 | #' are compatible with the plot and returns it. In case when coordinates are not flipped 36 | #' \code{flip_ggplot_build} returns \code{ggplot_build_data}. 37 | #' @examples 38 | #' \dontrun{ 39 | #' 40 | #' # returns plot info without any change because coordinates are not flipped 41 | #' p <- ggplot(Orange, aes(x = age, y = circumference, col = Tree)) + 42 | #' geom_point() + 43 | #' geom_line() 44 | #' plot_info <- ggplot_build(p) 45 | #' flip_ggplot_build(plot_info) # it is the same as plot_info 46 | #' 47 | #' # returns plot info with data modified for flipped coordinates 48 | #' p <- ggplot(Orange, aes(x = age, y = circumference, col = Tree)) + 49 | #' geom_point() + 50 | #' geom_line() + 51 | #' coord_flip() 52 | #' plot_info <- ggplot_build(p) 53 | #' flip_ggplot_build(plot_info) 54 | #' } 55 | #' 56 | #' @export 57 | 58 | flip_ggplot_build <- function(ggplot_build_data){ 59 | 60 | if("CoordFlip" %in% class(ggplot_build_data$plot$coordinates)) { 61 | 62 | ggplot_build_data[["data"]] <- lapply(ggplot_build_data[["data"]], function(df) { 63 | df_names <- colnames(df) 64 | names(df) <- sapply(df_names, function(name) { 65 | switch(substr(name, 1, 1), 66 | x = { 67 | substr(name, 1, 1) = "y" 68 | }, 69 | y = { 70 | substr(name, 1, 1) = "x" 71 | }) 72 | name 73 | }) 74 | df 75 | }) 76 | } 77 | ggplot_build_data 78 | } 79 | 80 | 81 | #' @title Creating UI for a Shiny module with plot and data 82 | #' @description Creates module's UI for tabset panel containing two tabs - with 83 | #' plot and an elegant table with data. 84 | #' @param id unique ID name of tabset. The same ID as in the corresponding server for 85 | #' a module 86 | #' @param tab_plot Character. Title of tab containing plot. Default to 87 | #' \code{paste(id, "plot")}. 88 | #' @param tab_table Character. Title of tab containing table. Default to 89 | #' \code{paste(id, "data")}. 90 | #' @inheritParams plotOutput_h 91 | #' @details Module's UI involves a panel with two tabs. The first tab consists of 92 | #' displayed plot and three download buttons (png, svg and jpeg). There is also a 93 | #' compatible with the plot tooltip. The second tab consists of a table 94 | #' with two download buttons (Excel and CSV). For both table and plot there are 95 | #' provided helpers. \ 96 | #' For more information see \code{\link[shinydetails]{plotOutput_h}} and 97 | #' \code{\link[shinydetails]{tableOutput_h}} 98 | #' @seealso To build Shiny module within a Shiny app using \code{beam_plot_panel_UI} 99 | #' see \code{\link[shinydetails]{beam_plot_panel_SERVER}}. 100 | #' @examples 101 | #' \dontrun{ 102 | #' ui <- fluidPage(title = "Example app", 103 | #' beam_plot_panel_UI("airquality_basic"), 104 | #' beam_plot_panel_UI("airquality_advanced", 105 | #' tab_plot = "An advanced plot", 106 | #' tab_table = "An elegant table for an advanced plot", 107 | #' helpfiles = "custom_helpfiles")) 108 | #' 109 | #'server <- function(input, output, session) { 110 | #' airquality_basic_plot <- reactive({ 111 | #' ggplot(airquality, aes(x = Wind, y = Temp, col = as.character(Month))) + 112 | #' geom_point() 113 | #' }) 114 | #' airquality_basic_data <- reactive({ 115 | #' airquality 116 | #' }) 117 | #' beam_plot_panel_SERVER("airquality_basic", 118 | #' plot_out = airquality_basic_plot(), 119 | #' table_out = airquality_basic_data()) 120 | #' 121 | #' airquality_advanced_data <- reactive({ 122 | #' df <- data.frame(aggregate(. ~ Month, airquality, function(x) c(mean = mean(x), sd = sd(x)))[, c(1, 5)]) 123 | #' df[["Month"]] <- month.name[df[["Month"]]] 124 | #' data.frame(Month = df[["Month"]], 125 | #' Temp_mean = df$Temp[, 1], 126 | #' Error = df$Temp[, 2], 127 | #' Year = 1973)}) 128 | #' 129 | #' airquality_advanced_plot <- reactive({ 130 | #' ggplot(airquality_advanced_data(), aes(y = 0, yend = Temp_mean, x = Month, xend = Month)) + 131 | #' geom_segment() + 132 | #' geom_point(mapping = aes(x = Month, y = Temp_mean), size = 3) + 133 | #' geom_point() + 134 | #' ylab("average temperature") 135 | #' }) 136 | #' beam_plot_panel_SERVER("airquality_advanced", 137 | #' plot_out = airquality_advanced_plot(), 138 | #' table_out = airquality_advanced_data(), 139 | #' plot_type = "geom_segment", 140 | #' tt_content = list(row_text = c("Date: %s %i", 141 | #' "Average temperature: %f °F", 142 | #' "Error: %f", 143 | #' "Place: La Guardia Airport"), 144 | #' chosen_cols = c("Month", 145 | #' "Year", 146 | #' "Temp_mean", 147 | #' "Error")) 148 | #' ) 149 | #' 150 | #'} 151 | #'} 152 | #' @export 153 | 154 | beam_plot_panel_UI <- function(id, 155 | tab_plot = paste(id, "plot"), 156 | tab_table = paste(id, "data"), 157 | helpfiles = "helpfiles") { 158 | ns <- NS(id) 159 | tagList(tabsetPanel(tabPanel(title = tab_plot, 160 | br(), 161 | div(style = "position:relative", 162 | plotOutput_h(outputId = ns("plot"), 163 | hover = hoverOpts(ns("hover"), 164 | delay = 10, 165 | delayType = "debounce"), 166 | helpfiles = helpfiles), 167 | uiOutput(ns("tooltip")), 168 | downloadButton(ns("download_png"), "Download png"), 169 | downloadButton(ns("download_jpeg"), "Download jpeg"), 170 | downloadButton(ns("download_svg"), "Download svg")) 171 | ), 172 | tabPanel(title = tab_table, 173 | tableOutput_h(outputId = ns("data"), helpfiles = helpfiles)))) 174 | } 175 | 176 | 177 | #' @title Creating server for a Shiny module with plot and data. 178 | #' @description Creates module server for tabset panel containing two tabs - with 179 | #' plot and an elegant table with data. 180 | #' @param id unique Id of tabset panel. The same ID as in the corresponding UI for 181 | #' a module 182 | #' @param plot_out Plot to display in tab. There will be provided an automatically 183 | #' generated tooltip compatible with the plot. The items from first mapping will be 184 | #' connected with tooltip. 185 | #' @param table_out Table to display in tab. 186 | #' @inheritParams extract_tt_data_row 187 | #' @inheritParams plotOutput_h 188 | #' @inheritParams beam_tooltip 189 | #' @details Module's server involves a panel with two tabs. The first tab consists of 190 | #' displayed plot and three download buttons (png, svg and jpeg). There is also a 191 | #' compatible with plot tooltip obtained via \code{\link[shinydetails]{beam_tooltip}}. 192 | #' The second tab consists of a table with two download buttons (Excel and CSV). 193 | #' The table \code{table_out} before displaying is formatted using 194 | #' \code{\link[shinydetails]{dt_format}}. For both table and plot there are provided 195 | #' helpers. 196 | #' @seealso To build Shiny module within a Shiny app using \code{beam_plot_panel_SERVER} 197 | #' see \code{\link[shinydetails]{beam_plot_panel_UI}}. 198 | #' @examples 199 | #' \dontrun{ 200 | #' ui <- fluidPage(title = "Example app", 201 | #' beam_plot_panel_UI("airquality_basic"), 202 | #' beam_plot_panel_UI("airquality_advanced", 203 | #' tab_plot = "An advanced plot", 204 | #' tab_table = "An elegant table for an advanced plot", 205 | #' helpfiles = "custom_helpfiles")) 206 | #' 207 | #'server <- function(input, output, session) { 208 | #' airquality_basic_plot <- reactive({ 209 | #' ggplot(airquality, aes(x = Wind, y = Temp, col = as.character(Month))) + 210 | #' geom_point() 211 | #' }) 212 | #' airquality_basic_data <- reactive({ 213 | #' airquality 214 | #' }) 215 | #' beam_plot_panel_SERVER("airquality_basic", 216 | #' plot_out = airquality_basic_plot(), 217 | #' table_out = airquality_basic_data()) 218 | #' 219 | #' airquality_advanced_data <- reactive({ 220 | #' df <- data.frame(aggregate(. ~ Month, airquality, function(x) c(mean = mean(x), sd = sd(x)))[, c(1, 5)]) 221 | #' df[["Month"]] <- month.name[df[["Month"]]] 222 | #' data.frame(Month = df[["Month"]], 223 | #' Temp_mean = df$Temp[, 1], 224 | #' Error = df$Temp[, 2], 225 | #' Year = 1973)}) 226 | #' 227 | #' airquality_advanced_plot <- reactive({ 228 | #' ggplot(airquality_advanced_data(), aes(y = 0, yend = Temp_mean, x = Month, xend = Month)) + 229 | #' geom_segment() + 230 | #' geom_point(mapping = aes(x = Month, y = Temp_mean), size = 3) + 231 | #' geom_point() + 232 | #' ylab("average temperature") 233 | #' }) 234 | #' beam_plot_panel_SERVER("airquality_advanced", 235 | #' plot_out = airquality_advanced_plot(), 236 | #' table_out = airquality_advanced_data(), 237 | #' plot_type = "geom_segment", 238 | #' tt_content = list(row_text = c("Date: %s %i", 239 | #' "Average temperature: %f °F", 240 | #' "Error: %f", 241 | #' "Place: La Guardia Airport"), 242 | #' chosen_cols = c("Month", 243 | #' "Year", 244 | #' "Temp_mean", 245 | #' "Error")) 246 | #' ) 247 | #' 248 | #'} 249 | #'} 250 | #' @importFrom DT renderDataTable 251 | #' @export 252 | 253 | 254 | beam_plot_panel_SERVER <- function(id, 255 | plot_out, 256 | table_out, 257 | plot_type = "geom_point", 258 | tt_content = NULL, 259 | tt_range = 5, 260 | helpfiles = "helpfiles") { 261 | 262 | match.arg(plot_type, c("geom_col", "geom_point", "geom_segment"), several.ok = FALSE) 263 | 264 | moduleServer(id, function(input, output, session) { 265 | 266 | shinyhelper::observe_helpers(session = shiny::getDefaultReactiveDomain(), 267 | help_dir = helpfiles) 268 | 269 | output[["plot"]] <- renderPlot({plot_out()}) 270 | 271 | plot_info_data <- reactive({ 272 | plot_info <- ggplot_build(plot_out()) 273 | flip_ggplot_build(plot_info)[["data"]][[1]] 274 | }) 275 | 276 | output[["tooltip"]] <- renderUI({ 277 | hv = input[["hover"]] 278 | if(!is.null(hv)) { 279 | beam_tooltip(hv, plot_info_data(), table_out(), plot_type, tt_content, tt_range) 280 | } 281 | }) 282 | 283 | output[["download_png"]] <- beam_downloadButton(id, plot_out(), "png") 284 | output[["download_jpeg"]] <- beam_downloadButton(id, plot_out(), "jpeg") 285 | output[["download_svg"]] <- beam_downloadButton(id, plot_out(), "svg") 286 | 287 | output[["data"]] <- DT::renderDataTable(server = FALSE, { 288 | dt_format(table_out()) 289 | }) 290 | }) 291 | } 292 | -------------------------------------------------------------------------------- /renv.lock: -------------------------------------------------------------------------------- 1 | { 2 | "R": { 3 | "Version": "4.0.4", 4 | "Repositories": [ 5 | { 6 | "Name": "CRAN", 7 | "URL": "https://cran.rstudio.com" 8 | } 9 | ] 10 | }, 11 | "Packages": { 12 | "BH": { 13 | "Package": "BH", 14 | "Version": "1.72.0-3", 15 | "Source": "Repository", 16 | "Repository": "CRAN", 17 | "Hash": "8f9ce74c6417d61f0782cbae5fd2b7b0" 18 | }, 19 | "DT": { 20 | "Package": "DT", 21 | "Version": "0.16", 22 | "Source": "Repository", 23 | "Repository": "CRAN", 24 | "Hash": "acac794cc3e393ca65f916e5ced5c1d2" 25 | }, 26 | "MASS": { 27 | "Package": "MASS", 28 | "Version": "7.3-53", 29 | "Source": "Repository", 30 | "Repository": "CRAN", 31 | "Hash": "d1bc1c8e9c0ace57ec9ffea01021d45f" 32 | }, 33 | "Matrix": { 34 | "Package": "Matrix", 35 | "Version": "1.3-2", 36 | "Source": "Repository", 37 | "Repository": "CRAN", 38 | "Hash": "ff280503079ad8623d3c4b1519b24ea2" 39 | }, 40 | "R6": { 41 | "Package": "R6", 42 | "Version": "2.5.0", 43 | "Source": "Repository", 44 | "Repository": "CRAN", 45 | "Hash": "b203113193e70978a696b2809525649d" 46 | }, 47 | "RColorBrewer": { 48 | "Package": "RColorBrewer", 49 | "Version": "1.1-2", 50 | "Source": "Repository", 51 | "Repository": "CRAN", 52 | "Hash": "e031418365a7f7a766181ab5a41a5716" 53 | }, 54 | "Rcpp": { 55 | "Package": "Rcpp", 56 | "Version": "1.0.5", 57 | "Source": "Repository", 58 | "Repository": "CRAN", 59 | "Hash": "125dc7a0ed375eb68c0ce533b48d291f" 60 | }, 61 | "askpass": { 62 | "Package": "askpass", 63 | "Version": "1.1", 64 | "Source": "Repository", 65 | "Repository": "CRAN", 66 | "Hash": "e8a22846fff485f0be3770c2da758713" 67 | }, 68 | "assertthat": { 69 | "Package": "assertthat", 70 | "Version": "0.2.1", 71 | "Source": "Repository", 72 | "Repository": "CRAN", 73 | "Hash": "50c838a310445e954bc13f26f26a6ecf" 74 | }, 75 | "base64enc": { 76 | "Package": "base64enc", 77 | "Version": "0.1-3", 78 | "Source": "Repository", 79 | "Repository": "CRAN", 80 | "Hash": "543776ae6848fde2f48ff3816d0628bc" 81 | }, 82 | "brio": { 83 | "Package": "brio", 84 | "Version": "1.1.1", 85 | "Source": "Repository", 86 | "Repository": "CRAN", 87 | "Hash": "36758510e65a457efeefa50e1e7f0576" 88 | }, 89 | "cachem": { 90 | "Package": "cachem", 91 | "Version": "1.0.3", 92 | "Source": "Repository", 93 | "Repository": "CRAN", 94 | "Hash": "803b5d36ec15fe3314905749a5619767" 95 | }, 96 | "callr": { 97 | "Package": "callr", 98 | "Version": "3.5.1", 99 | "Source": "Repository", 100 | "Repository": "CRAN", 101 | "Hash": "b7d7f1e926dfcd57c74ce93f5c048e80" 102 | }, 103 | "cli": { 104 | "Package": "cli", 105 | "Version": "2.3.0", 106 | "Source": "Repository", 107 | "Repository": "CRAN", 108 | "Hash": "26fb4f0871c8e5b84d77f6dc22f2ee0a" 109 | }, 110 | "colorspace": { 111 | "Package": "colorspace", 112 | "Version": "1.4-1", 113 | "Source": "Repository", 114 | "Repository": "CRAN", 115 | "Hash": "6b436e95723d1f0e861224dd9b094dfb" 116 | }, 117 | "commonmark": { 118 | "Package": "commonmark", 119 | "Version": "1.7", 120 | "Source": "Repository", 121 | "Repository": "CRAN", 122 | "Hash": "0f22be39ec1d141fd03683c06f3a6e67" 123 | }, 124 | "cpp11": { 125 | "Package": "cpp11", 126 | "Version": "0.2.6", 127 | "Source": "Repository", 128 | "Repository": "CRAN", 129 | "Hash": "f08909ebdad90b19d8d3930da4220564" 130 | }, 131 | "crayon": { 132 | "Package": "crayon", 133 | "Version": "1.4.1", 134 | "Source": "Repository", 135 | "Repository": "CRAN", 136 | "Hash": "e75525c55c70e5f4f78c9960a4b402e9" 137 | }, 138 | "crosstalk": { 139 | "Package": "crosstalk", 140 | "Version": "1.1.0.1", 141 | "Source": "Repository", 142 | "Repository": "CRAN", 143 | "Hash": "ae55f5d7c02f0ab43c58dd050694f2b4" 144 | }, 145 | "curl": { 146 | "Package": "curl", 147 | "Version": "4.3", 148 | "Source": "Repository", 149 | "Repository": "CRAN", 150 | "Hash": "2b7d10581cc730804e9ed178c8374bd6" 151 | }, 152 | "desc": { 153 | "Package": "desc", 154 | "Version": "1.2.0", 155 | "Source": "Repository", 156 | "Repository": "CRAN", 157 | "Hash": "6c8fe8fa26a23b79949375d372c7b395" 158 | }, 159 | "diffobj": { 160 | "Package": "diffobj", 161 | "Version": "0.3.3", 162 | "Source": "Repository", 163 | "Repository": "CRAN", 164 | "Hash": "55fae7ec1418d2a47bd552571673d1af" 165 | }, 166 | "digest": { 167 | "Package": "digest", 168 | "Version": "0.6.27", 169 | "Source": "Repository", 170 | "Repository": "CRAN", 171 | "Hash": "a0cbe758a531d054b537d16dff4d58a1" 172 | }, 173 | "downlit": { 174 | "Package": "downlit", 175 | "Version": "0.2.1", 176 | "Source": "Repository", 177 | "Repository": "CRAN", 178 | "Hash": "f24f1e44320a978c03050b8403a83793" 179 | }, 180 | "ellipsis": { 181 | "Package": "ellipsis", 182 | "Version": "0.3.1", 183 | "Source": "Repository", 184 | "Repository": "CRAN", 185 | "Hash": "fd2844b3a43ae2d27e70ece2df1b4e2a" 186 | }, 187 | "evaluate": { 188 | "Package": "evaluate", 189 | "Version": "0.14", 190 | "Source": "Repository", 191 | "Repository": "CRAN", 192 | "Hash": "ec8ca05cffcc70569eaaad8469d2a3a7" 193 | }, 194 | "fansi": { 195 | "Package": "fansi", 196 | "Version": "0.4.2", 197 | "Source": "Repository", 198 | "Repository": "CRAN", 199 | "Hash": "fea074fb67fe4c25d47ad09087da847d" 200 | }, 201 | "farver": { 202 | "Package": "farver", 203 | "Version": "2.0.3", 204 | "Source": "Repository", 205 | "Repository": "CRAN", 206 | "Hash": "dad6793a5a1f73c8e91f1a1e3e834b05" 207 | }, 208 | "fastmap": { 209 | "Package": "fastmap", 210 | "Version": "1.1.0", 211 | "Source": "Repository", 212 | "Repository": "CRAN", 213 | "Hash": "77bd60a6157420d4ffa93b27cf6a58b8" 214 | }, 215 | "fs": { 216 | "Package": "fs", 217 | "Version": "1.5.0", 218 | "Source": "Repository", 219 | "Repository": "CRAN", 220 | "Hash": "44594a07a42e5f91fac9f93fda6d0109" 221 | }, 222 | "ggplot2": { 223 | "Package": "ggplot2", 224 | "Version": "3.3.2", 225 | "Source": "Repository", 226 | "Repository": "CRAN", 227 | "Hash": "4ded8b439797f7b1693bd3d238d0106b" 228 | }, 229 | "glue": { 230 | "Package": "glue", 231 | "Version": "1.4.2", 232 | "Source": "Repository", 233 | "Repository": "CRAN", 234 | "Hash": "6efd734b14c6471cfe443345f3e35e29" 235 | }, 236 | "gtable": { 237 | "Package": "gtable", 238 | "Version": "0.3.0", 239 | "Source": "Repository", 240 | "Repository": "CRAN", 241 | "Hash": "ac5c6baf7822ce8732b343f14c072c4d" 242 | }, 243 | "highr": { 244 | "Package": "highr", 245 | "Version": "0.8", 246 | "Source": "Repository", 247 | "Repository": "CRAN", 248 | "Hash": "4dc5bb88961e347a0f4d8aad597cbfac" 249 | }, 250 | "htmltools": { 251 | "Package": "htmltools", 252 | "Version": "0.5.1.1", 253 | "Source": "Repository", 254 | "Repository": "CRAN", 255 | "Hash": "af2c2531e55df5cf230c4b5444fc973c" 256 | }, 257 | "htmlwidgets": { 258 | "Package": "htmlwidgets", 259 | "Version": "1.5.2", 260 | "Source": "Repository", 261 | "Repository": "CRAN", 262 | "Hash": "0aaf56b7960bb066646e1868cadcaf07" 263 | }, 264 | "httpuv": { 265 | "Package": "httpuv", 266 | "Version": "1.5.4", 267 | "Source": "Repository", 268 | "Repository": "CRAN", 269 | "Hash": "4e6dabb220b006ccdc3b3b5ff993b205" 270 | }, 271 | "httr": { 272 | "Package": "httr", 273 | "Version": "1.4.2", 274 | "Source": "Repository", 275 | "Repository": "CRAN", 276 | "Hash": "a525aba14184fec243f9eaec62fbed43" 277 | }, 278 | "hunspell": { 279 | "Package": "hunspell", 280 | "Version": "3.0", 281 | "Source": "Repository", 282 | "Repository": "CRAN", 283 | "Hash": "71e7853d60b6b4ba891d62ede21752e9" 284 | }, 285 | "isoband": { 286 | "Package": "isoband", 287 | "Version": "0.2.2", 288 | "Source": "Repository", 289 | "Repository": "CRAN", 290 | "Hash": "6e58bd3d6b3dd82a944cd6f05ade228f" 291 | }, 292 | "jsonlite": { 293 | "Package": "jsonlite", 294 | "Version": "1.7.2", 295 | "Source": "Repository", 296 | "Repository": "CRAN", 297 | "Hash": "98138e0994d41508c7a6b84a0600cfcb" 298 | }, 299 | "knitr": { 300 | "Package": "knitr", 301 | "Version": "1.31", 302 | "Source": "Repository", 303 | "Repository": "CRAN", 304 | "Hash": "c3994c036d19fc22c5e2a209c8298bfb" 305 | }, 306 | "labeling": { 307 | "Package": "labeling", 308 | "Version": "0.3", 309 | "Source": "Repository", 310 | "Repository": "CRAN", 311 | "Hash": "73832978c1de350df58108c745ed0e3e" 312 | }, 313 | "later": { 314 | "Package": "later", 315 | "Version": "1.1.0.1", 316 | "Source": "Repository", 317 | "Repository": "CRAN", 318 | "Hash": "d0a62b247165aabf397fded504660d8a" 319 | }, 320 | "lattice": { 321 | "Package": "lattice", 322 | "Version": "0.20-41", 323 | "Source": "Repository", 324 | "Repository": "CRAN", 325 | "Hash": "fbd9285028b0263d76d18c95ae51a53d" 326 | }, 327 | "lazyeval": { 328 | "Package": "lazyeval", 329 | "Version": "0.2.2", 330 | "Source": "Repository", 331 | "Repository": "CRAN", 332 | "Hash": "d908914ae53b04d4c0c0fd72ecc35370" 333 | }, 334 | "lifecycle": { 335 | "Package": "lifecycle", 336 | "Version": "0.2.0", 337 | "Source": "Repository", 338 | "Repository": "CRAN", 339 | "Hash": "361811f31f71f8a617a9a68bf63f1f42" 340 | }, 341 | "magrittr": { 342 | "Package": "magrittr", 343 | "Version": "2.0.1", 344 | "Source": "Repository", 345 | "Repository": "CRAN", 346 | "Hash": "41287f1ac7d28a92f0a286ed507928d3" 347 | }, 348 | "markdown": { 349 | "Package": "markdown", 350 | "Version": "1.1", 351 | "Source": "Repository", 352 | "Repository": "CRAN", 353 | "Hash": "61e4a10781dd00d7d81dd06ca9b94e95" 354 | }, 355 | "memoise": { 356 | "Package": "memoise", 357 | "Version": "2.0.0", 358 | "Source": "Repository", 359 | "Repository": "CRAN", 360 | "Hash": "a0bc51650201a56d00a4798523cc91b3" 361 | }, 362 | "mgcv": { 363 | "Package": "mgcv", 364 | "Version": "1.8-33", 365 | "Source": "Repository", 366 | "Repository": "CRAN", 367 | "Hash": "eb7b6439bc6d812eed2cddba5edc6be3" 368 | }, 369 | "mime": { 370 | "Package": "mime", 371 | "Version": "0.9", 372 | "Source": "Repository", 373 | "Repository": "CRAN", 374 | "Hash": "e87a35ec73b157552814869f45a63aa3" 375 | }, 376 | "munsell": { 377 | "Package": "munsell", 378 | "Version": "0.5.0", 379 | "Source": "Repository", 380 | "Repository": "CRAN", 381 | "Hash": "6dfe8bf774944bd5595785e3229d8771" 382 | }, 383 | "nlme": { 384 | "Package": "nlme", 385 | "Version": "3.1-149", 386 | "Source": "Repository", 387 | "Repository": "CRAN", 388 | "Hash": "7c24ab3a1e3afe50388eb2d893aab255" 389 | }, 390 | "openssl": { 391 | "Package": "openssl", 392 | "Version": "1.4.3", 393 | "Source": "Repository", 394 | "Repository": "CRAN", 395 | "Hash": "a399e4773075fc2375b71f45fca186c4" 396 | }, 397 | "pillar": { 398 | "Package": "pillar", 399 | "Version": "1.4.7", 400 | "Source": "Repository", 401 | "Repository": "CRAN", 402 | "Hash": "3b3dd89b2ee115a8b54e93a34cd546b4" 403 | }, 404 | "pkgbuild": { 405 | "Package": "pkgbuild", 406 | "Version": "1.1.0", 407 | "Source": "Repository", 408 | "Repository": "CRAN", 409 | "Hash": "404684bc4e3685007f9720adf13b06c1" 410 | }, 411 | "pkgconfig": { 412 | "Package": "pkgconfig", 413 | "Version": "2.0.3", 414 | "Source": "Repository", 415 | "Repository": "CRAN", 416 | "Hash": "01f28d4278f15c76cddbea05899c5d6f" 417 | }, 418 | "pkgdown": { 419 | "Package": "pkgdown", 420 | "Version": "1.6.1", 421 | "Source": "Repository", 422 | "Repository": "CRAN", 423 | "Hash": "8896076540d9e9b556a2ec658c81f916" 424 | }, 425 | "pkgload": { 426 | "Package": "pkgload", 427 | "Version": "1.1.0", 428 | "Source": "Repository", 429 | "Repository": "CRAN", 430 | "Hash": "b6b150cd4709e0c0c9b5d51ac4376282" 431 | }, 432 | "praise": { 433 | "Package": "praise", 434 | "Version": "1.0.0", 435 | "Source": "Repository", 436 | "Repository": "CRAN", 437 | "Hash": "a555924add98c99d2f411e37e7d25e9f" 438 | }, 439 | "prettyunits": { 440 | "Package": "prettyunits", 441 | "Version": "1.1.1", 442 | "Source": "Repository", 443 | "Repository": "CRAN", 444 | "Hash": "95ef9167b75dde9d2ccc3c7528393e7e" 445 | }, 446 | "processx": { 447 | "Package": "processx", 448 | "Version": "3.4.5", 449 | "Source": "Repository", 450 | "Repository": "CRAN", 451 | "Hash": "22aab6098cb14edd0a5973a8438b569b" 452 | }, 453 | "promises": { 454 | "Package": "promises", 455 | "Version": "1.1.1", 456 | "Source": "Repository", 457 | "Repository": "CRAN", 458 | "Hash": "a8730dcbdd19f9047774909f0ec214a4" 459 | }, 460 | "ps": { 461 | "Package": "ps", 462 | "Version": "1.5.0", 463 | "Source": "Repository", 464 | "Repository": "CRAN", 465 | "Hash": "ebaed51a03411fd5cfc1e12d9079b353" 466 | }, 467 | "purrr": { 468 | "Package": "purrr", 469 | "Version": "0.3.4", 470 | "Source": "Repository", 471 | "Repository": "CRAN", 472 | "Hash": "97def703420c8ab10d8f0e6c72101e02" 473 | }, 474 | "ragg": { 475 | "Package": "ragg", 476 | "Version": "0.4.1", 477 | "Source": "Repository", 478 | "Repository": "CRAN", 479 | "Hash": "70bd921f54c3763f3dbec15106118828" 480 | }, 481 | "rematch2": { 482 | "Package": "rematch2", 483 | "Version": "2.1.2", 484 | "Source": "Repository", 485 | "Repository": "CRAN", 486 | "Hash": "76c9e04c712a05848ae7a23d2f170a40" 487 | }, 488 | "renv": { 489 | "Package": "renv", 490 | "Version": "0.12.3", 491 | "Source": "Repository", 492 | "Repository": "CRAN", 493 | "Hash": "b5510c50c7f31d453c385c7b460af2b9" 494 | }, 495 | "rlang": { 496 | "Package": "rlang", 497 | "Version": "0.4.10", 498 | "Source": "Repository", 499 | "Repository": "CRAN", 500 | "Hash": "599df23c40a4fce9c7b4764f28c37857" 501 | }, 502 | "rmarkdown": { 503 | "Package": "rmarkdown", 504 | "Version": "2.6", 505 | "Source": "Repository", 506 | "Repository": "CRAN", 507 | "Hash": "bc4bac38960b446c183957bfd563e763" 508 | }, 509 | "rprojroot": { 510 | "Package": "rprojroot", 511 | "Version": "2.0.2", 512 | "Source": "Repository", 513 | "Repository": "CRAN", 514 | "Hash": "249d8cd1e74a8f6a26194a91b47f21d1" 515 | }, 516 | "rstudioapi": { 517 | "Package": "rstudioapi", 518 | "Version": "0.11", 519 | "Source": "Repository", 520 | "Repository": "CRAN", 521 | "Hash": "33a5b27a03da82ac4b1d43268f80088a" 522 | }, 523 | "scales": { 524 | "Package": "scales", 525 | "Version": "1.1.1", 526 | "Source": "Repository", 527 | "Repository": "CRAN", 528 | "Hash": "6f76f71042411426ec8df6c54f34e6dd" 529 | }, 530 | "shiny": { 531 | "Package": "shiny", 532 | "Version": "1.5.0", 533 | "Source": "Repository", 534 | "Repository": "CRAN", 535 | "Hash": "ee4ed72d7a5047d9e73cf922ad66e9c9" 536 | }, 537 | "shinyhelper": { 538 | "Package": "shinyhelper", 539 | "Version": "0.3.2", 540 | "Source": "Repository", 541 | "Repository": "CRAN", 542 | "Hash": "baef117734d5bd59373a561a15168679" 543 | }, 544 | "sourcetools": { 545 | "Package": "sourcetools", 546 | "Version": "0.1.7", 547 | "Source": "Repository", 548 | "Repository": "CRAN", 549 | "Hash": "947e4e02a79effa5d512473e10f41797" 550 | }, 551 | "spelling": { 552 | "Package": "spelling", 553 | "Version": "2.2", 554 | "Source": "Repository", 555 | "Repository": "CRAN", 556 | "Hash": "b8c899a5c83f0d897286550481c91798" 557 | }, 558 | "stringi": { 559 | "Package": "stringi", 560 | "Version": "1.5.3", 561 | "Source": "Repository", 562 | "Repository": "CRAN", 563 | "Hash": "a063ebea753c92910a4cca7b18bc1f05" 564 | }, 565 | "stringr": { 566 | "Package": "stringr", 567 | "Version": "1.4.0", 568 | "Source": "Repository", 569 | "Repository": "CRAN", 570 | "Hash": "0759e6b6c0957edb1311028a49a35e76" 571 | }, 572 | "sys": { 573 | "Package": "sys", 574 | "Version": "3.4", 575 | "Source": "Repository", 576 | "Repository": "CRAN", 577 | "Hash": "b227d13e29222b4574486cfcbde077fa" 578 | }, 579 | "systemfonts": { 580 | "Package": "systemfonts", 581 | "Version": "1.0.1", 582 | "Source": "Repository", 583 | "Repository": "CRAN", 584 | "Hash": "6e899d7c097698d50ec87b1d8e65f246" 585 | }, 586 | "testthat": { 587 | "Package": "testthat", 588 | "Version": "3.0.2", 589 | "Source": "Repository", 590 | "Repository": "CRAN", 591 | "Hash": "495e0434d9305716b6a87031570ce109" 592 | }, 593 | "textshaping": { 594 | "Package": "textshaping", 595 | "Version": "0.2.1", 596 | "Source": "Repository", 597 | "Repository": "CRAN", 598 | "Hash": "a34d4aa94ca91a52710b1c0c36bcded6" 599 | }, 600 | "tibble": { 601 | "Package": "tibble", 602 | "Version": "3.0.6", 603 | "Source": "Repository", 604 | "Repository": "CRAN", 605 | "Hash": "9c6c10e594f32096ede0c7d373ccbddd" 606 | }, 607 | "tinytex": { 608 | "Package": "tinytex", 609 | "Version": "0.29", 610 | "Source": "Repository", 611 | "Repository": "CRAN", 612 | "Hash": "f0b0ba735febac9a8344253ae6fa93f5" 613 | }, 614 | "utf8": { 615 | "Package": "utf8", 616 | "Version": "1.1.4", 617 | "Source": "Repository", 618 | "Repository": "CRAN", 619 | "Hash": "4a5081acfb7b81a572e4384a7aaf2af1" 620 | }, 621 | "vctrs": { 622 | "Package": "vctrs", 623 | "Version": "0.3.6", 624 | "Source": "Repository", 625 | "Repository": "CRAN", 626 | "Hash": "5cf1957f93076c19fdc81d01409d240b" 627 | }, 628 | "viridisLite": { 629 | "Package": "viridisLite", 630 | "Version": "0.3.0", 631 | "Source": "Repository", 632 | "Repository": "CRAN", 633 | "Hash": "ce4f6271baa94776db692f1cb2055bee" 634 | }, 635 | "waldo": { 636 | "Package": "waldo", 637 | "Version": "0.2.4", 638 | "Source": "Repository", 639 | "Repository": "CRAN", 640 | "Hash": "29df52c781e572c967f90de9713423c4" 641 | }, 642 | "whisker": { 643 | "Package": "whisker", 644 | "Version": "0.4", 645 | "Source": "Repository", 646 | "Repository": "CRAN", 647 | "Hash": "ca970b96d894e90397ed20637a0c1bbe" 648 | }, 649 | "withr": { 650 | "Package": "withr", 651 | "Version": "2.4.1", 652 | "Source": "Repository", 653 | "Repository": "CRAN", 654 | "Hash": "caf4781c674ffa549a4676d2d77b13cc" 655 | }, 656 | "xfun": { 657 | "Package": "xfun", 658 | "Version": "0.20", 659 | "Source": "Repository", 660 | "Repository": "CRAN", 661 | "Hash": "d7222684dc02327871e3b1da0aba7089" 662 | }, 663 | "xml2": { 664 | "Package": "xml2", 665 | "Version": "1.3.2", 666 | "Source": "Repository", 667 | "Repository": "CRAN", 668 | "Hash": "d4d71a75dd3ea9eb5fa28cc21f9585e2" 669 | }, 670 | "xtable": { 671 | "Package": "xtable", 672 | "Version": "1.8-4", 673 | "Source": "Repository", 674 | "Repository": "CRAN", 675 | "Hash": "b8acdf8af494d9ec19ccb2481a9b11c2" 676 | }, 677 | "yaml": { 678 | "Package": "yaml", 679 | "Version": "2.2.1", 680 | "Source": "Repository", 681 | "Repository": "CRAN", 682 | "Hash": "2826c5d9efb0a88f657c7a679c7106db" 683 | } 684 | } 685 | } 686 | --------------------------------------------------------------------------------