From da82baacf245359c6c40585c515de66de8eeb98f Mon Sep 17 00:00:00 2001 From: olivroy <52606734+olivroy@users.noreply.github.com> Date: Thu, 13 Jul 2023 12:27:07 -0400 Subject: [PATCH] Update vignettes to snake_case, and other code quality updates (#682) * Add myself in AUTHORS * Move R/testthat-helpers.R to tests/testthat/helper.R See https://r-pkgs.org/testing-design.html#sec-testing-design-tension * Add pkgdown link to DESCRIPTION and adjust openxlsx.Rproj * Tentative pkgdown function index (to avoid duplication) Note that the alphabetical order will still be displayed in R help pane, no need for it on the website, by topic can be more helpful * Rename vignette so it appears as the Get Started vignette on the `_pkgdown.yml` index * Update dims and snake_case * Update the intro vignette. * Rename packageDoc to `openxlsx2-package`, and add `@keywords internal` * Typo openxlsx -> openxlsx2 * More markdown formatting * Separate options in their own help file and add options to `reference index` * Start working on conditional formatting * Deleting `utils-pipe.R` since not reexporting the pipe. * Move `expect_wrapper()` to tests/testthat/helper.R since it is not part of the exported API and only used for testing. * Revert pipe (since re-exporting after all) * Doc cleanup, add headers, remove useless Roxygen tags, add headers, so functions show in the outline. * Add news bullet. * Typo * Add keywords internal to the deprecated get_sheet_names(), so it doesn't show up on the function index , but link it in the openxlsx2-deprecated page * Change order and tags on the R/dates.R so that exported functions are shown first. * Reorganize `dim_helpers` so the doc is more integrated. * Reorder tags and redocument `read_xlsx` and `wb_read()` Just look at the .Rd, this commit does nothing basically. * Remove quotes on the `fmt_txt()` charset table and add indications on how to use it. The `fmt_txt()` Rd could still be improved imo * Reorder tags and reorganize xl_open and write_xlsx * Rm useless lines * Move `wbColour.Rd` to `wb_color.Rd` * Fix name of wb_get_sheet_name * Put exported functions on top and helpers below in write.R * Comment line in examples. * Comment `fmt_txt()` parameter definition. * Remove `@keywords internal` for un-exported functions. Only adding `@noRd` is sufficient. `@keywords internal` is only meant to be used if 1. A function is exported, but you don't want the documentation to show in the function index 2. A function is not exported, but you still want the .Rd file to be generated. (e.g. similar to package documentation.) * Code coverage is probably not done in `tests/testthat/` Will not generate documentation neither, so no tags needed! * Move `expect_equal_workbooks()` to `tests/testthat/helper.R` * Fix typos * Remove superflous deps from DESCRIPTION * `waldo` is a direct dep of testthat, and only used in tests, no need to declare * roxygen2 is declared with the `RoxygenNote` field. * covr is only used on GHA, and declared in codecov.yml * Add back waldo dep. * Final push * ggplot2 remove `I()` * Add package website to "_PACKAGE" doc * remove testthat requirement in `expect_wrapper()` * Last vignettes check * Convert variable names to snake_case in formulas_manual.Rmd * path correction * Revert bullet in README, and change in download.file * Revert changes to `R/write.R` and document() (now in #683) * Add full link to the PR in NEWS.md * Re-render README. * Move functions to Misc and Helpers (until a better index is found * Put as 80 characters * Add comment about `fmt_txt` parameters * formula correct --- DESCRIPTION | 4 +- NEWS.md | 7 +- R/all-equal.R | 41 --- R/baseXML.R | 1 - R/class-color.R | 3 +- R/class-comment.R | 1 - R/class-hyperlink.R | 1 - R/class-sheet-data.R | 2 - R/class-style_mgr.R | 1 - R/class-workbook-wrappers.R | 15 +- R/class-workbook.R | 2 +- R/class-worksheet.R | 1 - R/conditional_formatting.R | 19 +- R/converters.R | 2 - R/dates.R | 141 ++++----- R/expect-wrapper.R | 244 --------------- R/helperFunctions.R | 38 ++- R/illegal-characters.R | 2 - R/openxlsx2.R | 59 ++-- R/pugixml.R | 8 +- R/readWorkbook.R | 53 ++-- R/standardize.R | 3 - R/utils.R | 124 ++++---- R/wb_functions.R | 8 +- R/write_xlsx.R | 41 +-- R/xl_open.R | 27 +- README.md | 8 +- _pkgdown.yml | 60 +++- inst/AUTHORS | 1 + man/convert_date.Rd | 20 +- man/convert_to_excel_date.Rd | 4 +- man/create_hyperlink.Rd | 8 +- man/dims_helper.Rd | 14 +- man/fmt_txt.Rd | 46 ++- man/openxlsx2-deprecated.Rd | 5 +- man/{openxlsx2.Rd => openxlsx2-package.Rd} | 52 ++-- man/openxlsx2_options.Rd | 21 ++ man/read_sheet_names.Rd | 1 + man/read_xlsx.Rd | 2 +- man/wb_add_formula.Rd | 11 +- man/wb_add_plot.Rd | 2 +- man/{wbColour.Rd => wb_color.Rd} | 0 man/wb_read.Rd | 2 +- man/write_xlsx.Rd | 6 +- man/xl_open.Rd | 4 +- openxlsx2.Rproj | 4 + .../testthat/helper.R | 286 +++++++++++++++++- tests/testthat/test-conditional_formatting.R | 8 +- tests/testthat/test-save.R | 6 +- vignettes/Update-from-openxlsx.Rmd | 61 ++-- vignettes/conditional-formatting.Rmd | 51 ++-- ...enxlsx2_basic_manual.Rmd => openxlsx2.Rmd} | 81 ++--- vignettes/openxlsx2_charts_manual.Rmd | 2 +- vignettes/openxlsx2_formulas_manual.Rmd | 114 +++---- vignettes/openxlsx2_style_manual.Rmd | 42 +-- 55 files changed, 917 insertions(+), 853 deletions(-) delete mode 100644 R/all-equal.R delete mode 100644 R/expect-wrapper.R rename man/{openxlsx2.Rd => openxlsx2-package.Rd} (59%) create mode 100644 man/openxlsx2_options.Rd rename man/{wbColour.Rd => wb_color.Rd} (100%) rename R/testthat-helpers.R => tests/testthat/helper.R (89%) rename vignettes/{openxlsx2_basic_manual.Rmd => openxlsx2.Rmd} (85%) diff --git a/DESCRIPTION b/DESCRIPTION index 533c9b5be..befc45c3d 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -13,7 +13,7 @@ Description: Simplifies the creation of 'xlsx' files by providing a high level interface to writing, styling and editing worksheets. License: MIT + file LICENSE -URL: https://github.com/JanMarvin/openxlsx2 +URL: https://janmarvin.github.io/openxlsx2/, https://github.com/JanMarvin/openxlsx2 BugReports: https://github.com/JanMarvin/openxlsx2/issues Depends: R (>= 3.5.0) @@ -28,12 +28,10 @@ Imports: LinkingTo: Rcpp Suggests: - covr, ggplot2, knitr, mschart (>= 0.4), rmarkdown, - roxygen2, rvg, testthat (>= 3.0.0), waldo diff --git a/NEWS.md b/NEWS.md index 3dabf968b..8ae83022c 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,6 +1,7 @@ # openxlsx2 (development version) -## New features + +## API Change * Function arguments are now defaulting to `snake_case`. For the time being, both arguments are accepted and `camelCase` will be switched to `snake_case` under the hood. Documentation like vignettes and examples are currently still displaying `camelCase` and maybe some `camelCase` function slipped through. [678](https://github.com/JanMarvin/openxlsx2/pull/678) @@ -22,6 +23,10 @@ * make `get_cell_refs()`, `get_date_origin()`, `guess_col_type()`, and `write_file()` internal functions * make classes `styles_mgr()`, `wbSheetData`, `wbWorksheet`, `wbChartsheet`, `wbComment`, `wbHyperlink` internal +## Refactoring + +* Cleanup / revisit documentation and vignettes ([682](https://github.com/JanMarvin/openxlsx2/pull/682), @olivroy) + *************************************************************************** diff --git a/R/all-equal.R b/R/all-equal.R deleted file mode 100644 index 06fe4ba4f..000000000 --- a/R/all-equal.R +++ /dev/null @@ -1,41 +0,0 @@ - -expect_equal_workbooks <- function(object, expected, ..., ignore_fields = NULL) { - # Quick internal expectation function. Easier to ignore fields to be set - - requireNamespace("testthat") - requireNamespace("waldo") - - # object <- as.list(object) - # expected <- as.list(expected) - - assert_workbook(object) - assert_workbook(expected) - - fields <- c(names(wbWorkbook$public_fields), names(wbWorkbook$private_fields)) - bad <- setdiff(ignore_fields, fields) - - if (length(bad)) { - stop("Invalid fields: ", toString(bad)) - } - - for (i in ignore_fields) { - object[[i]] <- NULL - expected[[i]] <- NULL - } - - bad <- waldo::compare( - x = object, - y = expected, - x_arg = "object", - y_arg = "expected", - ... - ) - - if (length(bad)) { - testthat::fail(bad) - return(invisible()) - } - - testthat::succeed() - return(invisible()) -} diff --git a/R/baseXML.R b/R/baseXML.R index d844f1c69..ebb65ce05 100644 --- a/R/baseXML.R +++ b/R/baseXML.R @@ -58,7 +58,6 @@ genClientData <- function(col, row, visible, height, width) { #' @param range range (input cell range) #' @param type type (Checkbox, Radio, Drop) #' @param checked checked (bool) -#' @keywords internal #' @noRd genClientDataFC <- function(left, top, right, bottom, link, range, type, checked) { diff --git a/R/class-color.R b/R/class-color.R index 444764a20..221ad934e 100644 --- a/R/class-color.R +++ b/R/class-color.R @@ -6,7 +6,6 @@ #' @param theme A zero based index referencing a value in the theme. #' @param tint A tint value applied. Range from -1 (dark) to 1 (light). #' @return a `wbColour` object -#' @rdname wbColour #' @export wb_color <- function( name = NULL, @@ -38,7 +37,7 @@ wb_color <- function( } #' @export -#' @rdname wbColour +#' @rdname wb_color #' @usage NULL wb_colour <- wb_color diff --git a/R/class-comment.R b/R/class-comment.R index 08313b586..ef9c5cde3 100644 --- a/R/class-comment.R +++ b/R/class-comment.R @@ -2,7 +2,6 @@ #' #' A comment #' -#' @keywords internal #' @noRd wbComment <- R6::R6Class( "wbComment", diff --git a/R/class-hyperlink.R b/R/class-hyperlink.R index 74f533a4f..4dcad875e 100644 --- a/R/class-hyperlink.R +++ b/R/class-hyperlink.R @@ -2,7 +2,6 @@ #' #' A hyperlink #' -#' @keywords internal #' @noRd wbHyperlink <- R6::R6Class( "wbHyperlink", diff --git a/R/class-sheet-data.R b/R/class-sheet-data.R index 44b561cbf..c16abd9a1 100644 --- a/R/class-sheet-data.R +++ b/R/class-sheet-data.R @@ -3,7 +3,6 @@ #' #' A hyperlink #' -#' @keywords internal #' @noRd wbSheetData <- R6::R6Class( "wbSheetData", @@ -30,7 +29,6 @@ wbSheetData <- R6::R6Class( ## TODO is this even used? #' @rdname wbSheetData -#' @keywords internal #' @noRd wb_sheet_data <- function() { wbSheetData$new() diff --git a/R/class-style_mgr.R b/R/class-style_mgr.R index b03b781f4..d0d25a06a 100644 --- a/R/class-style_mgr.R +++ b/R/class-style_mgr.R @@ -65,7 +65,6 @@ #' wb$set_cell_style("SUM", "C7:C16", wb$styles_mgr$get_xf_id("new_xf")) #' # wb_open(wb) #' -#' @keywords internal #' @noRd style_mgr <- R6::R6Class("wbStylesMgr", { diff --git a/R/class-workbook-wrappers.R b/R/class-workbook-wrappers.R index ca40a5ee6..07be65212 100644 --- a/R/class-workbook-wrappers.R +++ b/R/class-workbook-wrappers.R @@ -312,14 +312,13 @@ wb_add_pivot_table <- function( #' #' @details Currently only the English version of functions are supported. Please don't use the local translation. #' The examples below show a small list of possible formulas: -#' \itemize{ -#' \item{SUM(B2:B4)} -#' \item{AVERAGE(B2:B4)} -#' \item{MIN(B2:B4)} -#' \item{MAX(B2:B4)} -#' \item{...} #' -#' } +#' * SUM(B2:B4) +#' * AVERAGE(B2:B4) +#' * MIN(B2:B4) +#' * MAX(B2:B4) +#' * ... +#' #' @param wb A Workbook object containing a worksheet. #' @param sheet The worksheet to write to. Can be the worksheet index or name. #' @param x A character vector. @@ -880,7 +879,7 @@ wb_remove_row_heights <- function(wb, sheet = current_sheet(), rows) { #' require(ggplot2) #' p1 <- ggplot(mtcars, aes(x = mpg, fill = as.factor(gear))) + #' ggtitle("Distribution of Gas Mileage") + -#' geom_density(alpha = I(.5)) +#' geom_density(alpha = 0.5) #' p2 <- ggplot(Orange, aes(x = age, y = circumference, color = Tree)) + #' geom_point() + geom_line() #' diff --git a/R/class-workbook.R b/R/class-workbook.R index 45c30d5cf..81c6ed372 100644 --- a/R/class-workbook.R +++ b/R/class-workbook.R @@ -6782,7 +6782,7 @@ wbWorkbook <- R6::R6Class( sheet <- as.character(sheet) if (has_illegal_chars(sheet)) { - stop("illegal characters found in sheet. Please remove. See ?openxlsx::clean_worksheet_name") + stop("illegal characters found in sheet. Please remove. See ?openxlsx2::clean_worksheet_name") } if (!nzchar(sheet)) { diff --git a/R/class-worksheet.R b/R/class-worksheet.R index ffd29150f..05fb0980a 100644 --- a/R/class-worksheet.R +++ b/R/class-worksheet.R @@ -5,7 +5,6 @@ #' #' A Worksheet #' -#' @keywords internal #' @noRd wbWorksheet <- R6::R6Class( "wbWorksheet", diff --git a/R/conditional_formatting.R b/R/conditional_formatting.R index 3b1daaa85..de8564bc8 100644 --- a/R/conditional_formatting.R +++ b/R/conditional_formatting.R @@ -2,7 +2,6 @@ #' @name cf_rules #' @param formula formula #' @param values values -#' @keywords internal #' @noRd cf_create_colorscale <- function(formula, values) { @@ -84,11 +83,10 @@ cf_create_colorscale <- function(formula, values) { } #' @rdname cf_rules +#' @details `cf_create_databar()` returns extLst for worksheet #' @param extLst extLst #' @param params params #' @param sqref sqref -#' @keywords internal -#' @details `cf_create_databar()` returns extLst for worksheet #' @noRd cf_create_databar <- function(extLst, formula, params, sqref, values) { if (length(formula) == 2L) { @@ -201,7 +199,6 @@ cf_create_databar <- function(extLst, formula, params, sqref, values) { #' @rdname cf_rules #' @param dxfId dxfId #' @param formula formula -#' @keywords internal #' @noRd cf_create_expression <- function(dxfId, formula) { cf_rule <- sprintf( @@ -218,7 +215,6 @@ cf_create_expression <- function(dxfId, formula) { } #' @rdname cf_rules -#' @keywords internal #' @noRd cf_create_duplicated_values <- function(dxfId) { cf_rule <- sprintf( @@ -231,7 +227,6 @@ cf_create_duplicated_values <- function(dxfId) { } #' @rdname cf_rules -#' @keywords internal #' @noRd cf_create_contains_text <- function(dxfId, sqref, values) { cf_rule <- sprintf( @@ -250,7 +245,6 @@ cf_create_contains_text <- function(dxfId, sqref, values) { } #' @rdname cf_rules -#' @keywords internal #' @noRd cf_create_not_contains_text <- function(dxfId, sqref, values) { cf_rule <- sprintf( @@ -269,7 +263,6 @@ cf_create_not_contains_text <- function(dxfId, sqref, values) { } #' @rdname cf_rules -#' @keywords internal #' @noRd cf_begins_with <- function(dxfId, sqref, values) { cf_rule <- sprintf( @@ -289,7 +282,6 @@ cf_begins_with <- function(dxfId, sqref, values) { } #' @rdname cf_rules -#' @keywords internal #' @noRd cf_ends_with <- function(dxfId, sqref, values) { cf_rule <- sprintf( @@ -309,7 +301,6 @@ cf_ends_with <- function(dxfId, sqref, values) { } #' @rdname cf_rules -#' @keywords internal #' @noRd cf_between <- function(dxfId, formula) { cf_rule <- sprintf( @@ -328,7 +319,6 @@ cf_between <- function(dxfId, formula) { } #' @rdname cf_rules -#' @keywords internal #' @noRd cf_top_n <- function(dxfId, values) { cf_rule <- sprintf( @@ -343,7 +333,6 @@ cf_top_n <- function(dxfId, values) { } #' @rdname cf_rules -#' @keywords internal #' @noRd cf_bottom_n <- function(dxfId, values) { cf_rule <- sprintf( @@ -358,7 +347,6 @@ cf_bottom_n <- function(dxfId, values) { } #' @rdname cf_rules -#' @keywords internal #' @noRd cf_icon_set <- function( values, @@ -423,7 +411,6 @@ cf_icon_set <- function( } #' @rdname cf_rules -#' @keywords internal #' @noRd cf_unique_values <- function(dxfId) { cf_rule <- sprintf( @@ -435,7 +422,6 @@ cf_unique_values <- function(dxfId) { } #' @rdname cf_rules -#' @keywords internal #' @noRd cf_iserror <- function(dxfId, sqref) { cf_rule <- sprintf( @@ -452,7 +438,6 @@ cf_iserror <- function(dxfId, sqref) { } #' @rdname cf_rules -#' @keywords internal #' @noRd cf_isnoerror <- function(dxfId, sqref) { cf_rule <- sprintf( @@ -469,7 +454,6 @@ cf_isnoerror <- function(dxfId, sqref) { } #' @rdname cf_rules -#' @keywords internal #' @noRd cf_isblank <- function(dxfId, sqref) { cf_rule <- sprintf( @@ -486,7 +470,6 @@ cf_isblank <- function(dxfId, sqref) { } #' @rdname cf_rules -#' @keywords internal #' @noRd cf_isnoblank <- function(dxfId, sqref) { cf_rule <- sprintf( diff --git a/R/converters.R b/R/converters.R index 0ca7e2acc..a1d75c840 100644 --- a/R/converters.R +++ b/R/converters.R @@ -59,7 +59,6 @@ col2int <- function(x) { #' # "B1" #' get_cell_refs(data.frame(1:3, 2:4)) #' # "B1" "C2" "D3" -#' @keywords internal #' @noRd get_cell_refs <- function(cellCoords) { assert_class(cellCoords, "data.frame") @@ -79,7 +78,6 @@ get_cell_refs <- function(cellCoords) { #' #' @param base_font the base font name and fontsize #' @param col_width column width -#' @keywords internal #' @examples #' base_font <- wb_get_base_font(wb) #' calc_col_width(base_font, col_width = 10) diff --git a/R/dates.R b/R/dates.R index 36126b5e8..e688559f1 100644 --- a/R/dates.R +++ b/R/dates.R @@ -1,28 +1,33 @@ -#' @name as_POSIXct_utc -#' @title Convert to POSIXct with timezone UTC -#' @param x something as.POSIXct can convert -#' @keywords internal -#' @noRd -as_POSIXct_utc <- function(x) { - z <- as.POSIXct(x, tz = "UTC") - attr(z, "tzone") <- "UTC" - z -} - - -#' @name convert_date -#' @title Convert from excel date, datetime or hms number to R Date type -#' @description Convert from excel date number to R Date type +# `convert_date()` ------------------------------------------------ +#' Convert from Excel date, datetime or hms number to R Date type +#' +#' Convert from Excel date number to R Date type +#' +#' Excel stores dates as number of days from some origin day +#' +#' @seealso [write_data()] #' @param x A vector of integers #' @param origin date. Default value is for Windows Excel 2010 -#' @param ... additional parameters passed to as.Date() -#' @details Excel stores dates as number of days from some origin day -#' @seealso [write_data()] +#' @inheritDotParams base::as.Date +#' @return A date, datetime, or hms. #' @export #' @examples +#' # date -- #' ## 2014 April 21st to 25th #' convert_date(c(41750, 41751, 41752, 41753, 41754, NA)) #' convert_date(c(41750.2, 41751.99, NA, 41753)) +#' +#' # datetime -- +#' ## 2014-07-01, 2014-06-30, 2014-06-29 +#' x <- c(41821.8127314815, 41820.8127314815, NA, 41819, NaN) +#' convert_datetime(x) +#' convert_datetime(x, tz = "Australia/Perth") +#' convert_datetime(x, tz = "UTC") +#' +#' # hms --- +#' ## 12:13:14 +#' x <- 0.50918982 +#' convert_hms(x) convert_date <- function(x, origin = "1900-01-01", ...) { # use as.integer to only get the integer part of a number. @@ -41,12 +46,6 @@ convert_date <- function(x, origin = "1900-01-01", ...) { #' @rdname convert_date #' @export -#' @examples -#' ## 2014-07-01, 2014-06-30, 2014-06-29 -#' x <- c(41821.8127314815, 41820.8127314815, NA, 41819, NaN) -#' convert_datetime(x) -#' convert_datetime(x, tz = "Australia/Perth") -#' convert_datetime(x, tz = "UTC") convert_datetime <- function(x, origin = "1900-01-01", ...) { x <- as.numeric(x) date <- convert_date(x, origin) @@ -69,10 +68,6 @@ convert_datetime <- function(x, origin = "1900-01-01", ...) { #' @rdname convert_date #' @export -#' @examples -#' ## 12:13:14 -#' x <- 0.50918982 -#' convert_hms(x) convert_hms <- function(x) { if (isNamespaceLoaded("hms")) { x <- convert_datetime(x, origin = "1970-01-01", tz = "UTC") @@ -83,18 +78,19 @@ convert_hms <- function(x) { } x } - -#' @name get_date_origin -#' @title Get the date origin an xlsx file is using -#' @description Return the date origin used internally by an xlsx or xlsm file +# `convert_date()` helpers -------------------- +#' Get the date origin an xlsx file is using +#' +#' Return the date origin used internally by an xlsx or xlsm file +#' +#' Excel stores dates as the number of days from either 1904-01-01 or 1900-01-01. This function +#' checks the date origin being used in an Excel file and returns is so it can be used in [convert_date()] +#' #' @param xlsxFile An xlsx or xlsm file or a wbWorkbook object. #' @param origin return the origin instead of the character string. -#' @details Excel stores dates as the number of days from either 1904-01-01 or 1900-01-01. This function -#' checks the date origin being used in an Excel file and returns is so it can be used in [convert_date()] #' @return One of "1900-01-01" or "1904-01-01". #' @seealso [convert_date()] #' @examples -#' #' ## create a file with some dates #' temp <- temp_xlsx() #' write_xlsx(as.Date("2015-01-10") - (0:4), file = temp) @@ -106,7 +102,6 @@ convert_hms <- function(x) { #' #' get_date_origin(wb_workbook()) #' get_date_origin(wb_workbook(), origin = TRUE) -#' @keywords internal #' @noRd get_date_origin <- function(xlsxFile, origin = FALSE) { @@ -135,10 +130,17 @@ parseOffset <- function(tz) { ifelse(is.na(z), 0, z) } - +#' @name as_POSIXct_utc +#' @title Convert to POSIXct with timezone UTC +#' @param x something as.POSIXct can convert +#' @noRd +as_POSIXct_utc <- function(x) { + z <- as.POSIXct(x, tz = "UTC") + attr(z, "tzone") <- "UTC" + z +} #' helper function to convert hms to posix #' @param x a hms object -#' @keywords internal #' @noRd as_POSIXlt_hms <- function(x) { z <- as.POSIXlt("1970-01-01") @@ -146,11 +148,41 @@ as_POSIXlt_hms <- function(x) { z$sec <- as.numeric(x) z } +# `convert_to_excel_date()` --------------------------- +#' convert back to an Excel Date +#' @param df dataframe +#' @param date1904 take different origin +#' @examples +#' xlsxFile <- system.file("extdata", "openxlsx2_example.xlsx", package = "openxlsx2") +#' wb1 <- wb_load(xlsxFile) +#' df <- wb_to_df(wb1) +#' # conversion is done on dataframes only +#' convert_to_excel_date(df = df["Var5"], date1904 = FALSE) +#' @export +convert_to_excel_date <- function(df, date1904 = FALSE) { + + is_date <- vapply( + df, + function(x) { + inherits(x, "Date") || inherits(x, "POSIXct") || inherits(x, "hms") + }, + NA + ) + df[is_date] <- lapply(df[is_date], FUN = conv_to_excel_date, date1904 = date1904) + + df +} +#' @export +#' @rdname convert_to_excel_date +convertToExcelDate <- function(df, date1904 = FALSE) { + .Deprecated(old = "convertToExcelDate", new = "convert_to_excel_date", package = "openxlsx2") + convert_to_excel_date(df = df, date1904 = date1904) +} +# `convert_to_excel_date()` helpers ----------------------------------- #' conversion helper function #' @param x a date, posixct or hms object #' @param date1904 a special time format in openxml -#' @keywords internal #' @noRd conv_to_excel_date <- function(x, date1904 = FALSE) { @@ -203,34 +235,3 @@ conv_to_excel_date <- function(x, date1904 = FALSE) { z } - -#' convert back to ExcelDate -#' @param df dataframe -#' @param date1904 take different origin -#' @examples -#' xlsxFile <- system.file("extdata", "openxlsx2_example.xlsx", package = "openxlsx2") -#' wb1 <- wb_load(xlsxFile) -#' df <- wb_to_df(wb1) -#' # conversion is done on dataframes only -#' convert_to_excel_date(df = df["Var5"], date1904 = FALSE) -#' @export -convert_to_excel_date <- function(df, date1904 = FALSE) { - - is_date <- vapply( - df, - function(x) { - inherits(x, "Date") || inherits(x, "POSIXct") || inherits(x, "hms") - }, - NA - ) - - df[is_date] <- lapply(df[is_date], FUN = conv_to_excel_date, date1904 = date1904) - - df -} -#' @export -#' @rdname convert_to_excel_date -convertToExcelDate <- function(df, date1904 = FALSE) { - .Deprecated(old = "convertToExcelDate", new = "convert_to_excel_date", package = "openxlsx2") - convert_to_excel_date(df = df, date1904 = date1904) -} diff --git a/R/expect-wrapper.R b/R/expect-wrapper.R deleted file mode 100644 index 58080c525..000000000 --- a/R/expect-wrapper.R +++ /dev/null @@ -1,244 +0,0 @@ -#' Expect wrapper -#' -#' Internal tool: see tests/testthat/test-workbook-wrappers.R -#' -#' @description Testing expectations for [wbWorkbook] wrappers. These test that -#' the method and wrappers have the same params, same default values, and -#' return the same value. -#' -#' Requires the `waldo` package, used within `testthat`. -#' -#' @param method The name of the [wbWorkbook] method -#' @param fun The name of the wrapper (probably in R/class-workbook-wrappers) -#' @param wb A `wbWorkbook` object -#' @param params A named list of params. Set to `NULL` to not execute functions -#' @param ignore Names of params to ignore -#' @param ignore_attr Passed to `waldo::compare()` for the result of the -#' executed functions -#' @param ignore_fields Ignore immediate fields by removing them from the -#' objects for comparison -#' @param ignore_wb for pseudo wbWorkbook wrappers such as wb_load() we have -#' to ignore wb -#' @returns Nothing, called for its side-effects -#' @rdname expect_wrapper -#' @keywords internal -#' @noRd -expect_wrapper <- function( - method, - fun = paste0("wb_", method), - wb = wb_workbook(), - params = list(), - ignore = NULL, - ignore_attr = "waldo_opts", - ignore_fields = NULL, - ignore_wb = FALSE -) { - stopifnot( - requireNamespace("waldo", quietly = TRUE), - requireNamespace("testthat", quietly = TRUE), - is.character(method), length(method) == 1L, - is.character(fun), length(fun) == 1L, - is.list(params) || is.null(params) - ) - - method_fun <- get(method, wbWorkbook$public_methods) - fun_fun <- match.fun(fun) - - # these come as pairlist -- we don't really care about that - method_forms <- as.list(formals(method_fun)) - fun_forms <- as.list(formals(fun_fun)) - - method_args <- names(method_forms) - fun_args <- names(fun_forms) - - # remove wb and other ignores - ignore <- c("wb", ignore) - - # remove ignores from fun - m <- match(ignore, fun_args, 0L) - if (!identical(m, 0L)) { - # remove wb from both the args and formals - fun_args <- fun_args[-m] - fun_forms <- fun_forms[-m] - } - - # remove ignores from method - m <- match(ignore, method_args, 0L) - if (!identical(m, 0L)) { - # remove wb from both the args and formals - method_args <- method_args[-m] - method_forms <- method_forms[-m] - } - - method0 <- paste0("wbWorkbook$", method) - - # adjustments for when wrappers don't have any args - if (!length(method_args)) { - method_args <- character() - } - - if (!length(method_forms)) { - method_forms <- structure(list(), names = character()) - } - - # expectation that the names are the same (possibly redundant but quicker to) - bad <- waldo::compare( - x = method_args, - y = setdiff(fun_args, "wb"), - x_arg = method0, - y_arg = fun - ) - - if (length(bad)) { - testthat::fail(bad) - return(invisible()) - } - - # expectation that the default values are the same - bad <- waldo::compare( - x = method_forms, - y = fun_forms, - x_arg = method0, - y_arg = fun - ) - - if (length(bad)) { - testthat::fail(bad) - return(invisible()) - } - - if (!is.null(params)) { - # create now so that it's the same every time - wb_fun <- wb$clone(deep = TRUE) - wb_method <- wb$clone(deep = TRUE) - - # be careful and report when we failed to run these - - - # the style names are generated at random: use matching seeds for both calls - options("openxlsx2_seed" = NULL) - if (ignore_wb) { - res_fun <- try(do.call(fun, c(params)), silent = TRUE) - } else { - res_fun <- try(do.call(fun, c(wb = wb_fun, params)), silent = TRUE) - } - - options("openxlsx2_seed" = NULL) - res_method <- try(do.call(wb_method[[method]], params), silent = TRUE) - - msg <- NULL - - if (inherits(res_fun, "try-error")) { - temp <- file() - writeLines(attr(res_fun, "condition")$message, temp) - bad <- paste0("# > ", readLines(temp)) - close(temp) - expr <- paste0("\n", deparse1(do.call(call, c(fun, c(wb = wb_fun, params))))) - msg <- c(msg, expr, bad) - } - - if (inherits(res_method, "try-error")) { - temp <- file() - writeLines(attr(res_method, "condition")$message, temp) - bad <- paste0("# > ", readLines(temp)) - close(temp) - expr <- paste0("\n", deparse1(do.call(call, c(method0, params)))) - # slight fix because we get those "`" which I don't want to see - expr <- sub(paste0("`", method0, "`"), method0, expr, fixed = TRUE) - msg <- c(msg, expr, bad) - } - - if (!is.null(msg)) { - # browser() - bad <- c("Failed to get results", msg) - testthat::fail(bad) - return(invisible()) - } - - for (i in ignore_fields) { - # remove the fields we don't want to check - res_method[[i]] <- NULL - res_fun[[i]] <- NULL - } - - # expectation that the results are the same - bad <- waldo::compare( - x = res_method, - y = res_fun, - x_arg = method0, - y_arg = fun, - ignore_attr = ignore_attr, - ignore_formula_env = TRUE - ) - - if (length(bad)) { - testthat::fail(bad) - return(invisible()) - } - } - - testthat::succeed() - return(invisible()) -} - -#' @description -#' A trimmed down pseudo wrapper to check internal wrapped functions. -#' @rdname expect_wrapper -#' @keywords internal -#' @noRd -expect_pseudo_wrapper <- function( - method, - fun = paste0("wb_", method) -) { - method_fun <- get(method, wbWorkbook$public_methods) - fun_fun <- match.fun(fun) - - method_forms <- as.list(formals(method_fun)) - fun_forms <- as.list(formals(fun_fun)) - - method_args <- names(method_forms) - fun_args <- names(fun_forms) - - ignore <- "xlsx_file" - - # remove ignores from fun - m <- match(ignore, fun_args, 0L) - if (!identical(m, 0L)) { - # remove wb from both the args and formals - fun_args <- fun_args[-m] - fun_forms <- fun_forms[-m] - } - - # remove ignores from method - m <- match(ignore, method_args, 0L) - if (!identical(m, 0L)) { - # remove wb from both the args and formals - method_args <- method_args[-m] - method_forms <- method_forms[-m] - } - - # expectation that the names are the same (possibly redundant but quicker to) - bad <- waldo::compare( - x = method_args, - y = setdiff(fun_args, "wb") - ) - - if (length(bad)) { - testthat::fail(bad) - return(invisible()) - } - - # expectation that the default values are the same - bad <- waldo::compare( - x = method_forms, - y = fun_forms - ) - - if (length(bad)) { - testthat::fail(bad) - return(invisible()) - } - - testthat::succeed() - return(invisible()) -} diff --git a/R/helperFunctions.R b/R/helperFunctions.R index 733a514f3..dc9d701b8 100644 --- a/R/helperFunctions.R +++ b/R/helperFunctions.R @@ -1,13 +1,14 @@ -#' @name create_hyperlink -#' @title create Excel hyperlink string -#' @description Wrapper to create internal hyperlink string to pass to write_formula(). Either link to external urls or local files or straight to cells of local Excel sheets. +# `create_hyperlink()` --------------------------------------------------------- +#' Create Excel hyperlink string +#' +#' Wrapper to create internal hyperlink string to pass to [write_formula()]. +#' Either link to external URLs or local files or straight to cells of local Excel sheets. +#' #' @param sheet Name of a worksheet #' @param row integer row number for hyperlink to link to #' @param col column number of letter for hyperlink to link to #' @param text display text #' @param file Excel file name to point to. If NULL hyperlink is internal. -#' @seealso [write_formula()] -#' @export create_hyperlink #' @examples #' #' ## Writing internal hyperlinks @@ -80,6 +81,7 @@ #' ## Link to internal file #' x = create_hyperlink(text = "test.png", file = "D:/somepath/somepicture.png") #' write_formula(wb, "Sheet1", startRow = 11, startCol = 1, x = x) +#' @export create_hyperlink <- function(sheet, row = 1, col = 1, text = NULL, file = NULL) { if (missing(sheet)) { if (!missing(row) || !missing(col)) warning("Option for col and/or row found, but no sheet was provided.") @@ -115,12 +117,11 @@ getRId <- function(x) reg_match0(x, '(?<= r:id=")[0-9A-Za-z]+') getId <- function(x) reg_match0(x, '(?<= Id=")[0-9A-Za-z]+') - -#' @name validateColor -#' @description validate the color input +# `validateColor()` ------------------------------------------------------------ +#' Validate the color input +#' #' @param color color #' @param errorMsg Error message -#' @keywords internal #' @noRd validateColor <- function(color, errorMsg = "Invalid color!") { color <- check_valid_color(color) @@ -151,18 +152,17 @@ check_valid_color <- function(color) { FALSE } } - -#' @name col2hex -#' @description convert rgb to hex -#' @param creator my.col -#' @keywords internal +# `col2hex()` ------------------------------------------------------------------ +#' Convert rgb to hex +#' +#' @param my.col my.col #' @noRd col2hex <- function(my.col) { rgb(t(col2rgb(my.col)), maxColorValue = 255) } -## header and footer replacements +## header and footer replacements ---------------------------------------------- headerFooterSub <- function(x) { if (!is.null(x)) { x <- replace_illegal_chars(x) @@ -224,10 +224,9 @@ pxml <- function(x) { # paste(unique(unlist(x)), collapse = "") paste(unlist(x), collapse = "") } - +# `amp_split()` ---------------------------------------------------------------- #' split headerFooter xml into left, center, and right. #' @param x xml string -#' @keywords internal #' @noRd amp_split <- function(x) { if (length(x) == 0) return(NULL) @@ -246,10 +245,9 @@ amp_split <- function(x) { # return the string vector unname(res) } - +# Header footer --------------------------------------------------------------- #' get headerFooter from xml into list with left, center, and right. #' @param x xml string -#' @keywords internal #' @noRd getHeaderFooterNode <- function(x) { @@ -269,7 +267,6 @@ getHeaderFooterNode <- function(x) { #' generate headerFooter xml from left, center, and right characters #' @param x xml string -#' @keywords internal #' @noRd genHeaderFooterNode <- function(x) { @@ -1173,7 +1170,6 @@ write_workbook.xml.rels <- function(x, rm_sheet = NULL) { #' convert objects with attribute labels into strings #' @param x an object to convert -#' @keywords internal #' @noRd to_string <- function(x) { lbls <- attr(x, "labels") diff --git a/R/illegal-characters.R b/R/illegal-characters.R index 62558e040..a626c6559 100644 --- a/R/illegal-characters.R +++ b/R/illegal-characters.R @@ -42,7 +42,6 @@ legal_sub <- function() { c("&", """, "'", "<", ">", "", #' converts & to & #' @param x some xml string -#' @keywords internal #' @noRd replace_legal_chars <- function(x) { x <- as.character(x) @@ -63,7 +62,6 @@ replace_illegal_chars <- function(x, replacement = " ") { #' converts & to & #' @param x some xml string -#' @keywords internal #' @noRd replaceXMLEntities <- function(x) { stringi::stri_replace_all_fixed( diff --git a/R/openxlsx2.R b/R/openxlsx2.R index a3be7726e..173a447ac 100644 --- a/R/openxlsx2.R +++ b/R/openxlsx2.R @@ -6,7 +6,7 @@ #' Based on a powerful XML library and focusing on modern programming flows in pipes #' or chains, `openxlsx2` allows to break many new ground. #' -#' @name openxlsx2 +#' @name openxlsx2-package #' @docType package #' @useDynLib openxlsx2, .registration=TRUE #' @@ -19,34 +19,23 @@ #' @importFrom zip zip #' #' @seealso -#' \itemize{ -#' \item{`vignette(package = "openxlsx2")`} -#' \item{[write_data()]} -#' \item{[write_datatable()]} -#' \item{[write_xlsx()]} -#' \item{[read_xlsx()]} -#' } +#' * `browseVignettes("openxlsx2")` +#' * [write_data()] +#' * [write_datatable()] +#' * [write_xlsx()] +#' * [read_xlsx()] +#' * #' for examples #' #' @details -#' The openxlsx package uses global options to simplify formatting: -#' -#' \itemize{ -#' \item{`options("openxlsx2.borderColor" = "black")`} -#' \item{`options("openxlsx2.borderStyle" = "thin")`} -#' \item{`options("openxlsx2.dateFormat" = "mm/dd/yyyy")`} -#' \item{`options("openxlsx2.datetimeFormat" = "yyyy-mm-dd hh:mm:ss")`} -#' \item{`options("openxlsx2.numFmt" = NULL)`} -#' \item{`options("openxlsx2.paperSize" = 9)`} ## A4 -#' \item{`options("openxlsx2.orientation" = "portrait")`} ## page orientation -#' \item{`options("openxlsx2.sheet.default_name" = "Sheet")`} -#' \item{`options("openxlsx2.rightToLeft" = NULL)`} -#' } -#' By default, openxlsx2 uses the American English word for color (written with 'o' instead of the British English 'ou'). However, both spellings are supported. So where the documentation uses a 'color', the function should also accept a 'color'. However, this is not indicated by the autocompletion. +#' By default, openxlsx2 uses the American English word for color (written with 'o' instead of the British English 'ou'). +#' However, both spellings are supported. +#' So where the documentation uses a 'color', the function should also accept a 'colour'. +#' However, this is not indicated by the autocompletion. #' #' ## Authors and contributions #' -#' For a full list of all authors that have made this package possible and for whom we are greatful, please see: +#' For a full list of all authors that have made this package possible and for whom we are grateful, please see: #' #' ``` r #' system.file("AUTHORS", package = "openxlsx2") @@ -61,9 +50,25 @@ #' ## License #' #' This package is licensed under the MIT license and is based on [`openxlsx`](https://github.com/ycphs/openxlsx) (by Alexander Walker and Philipp Schauberger; COPYRIGHT 2014-2022) and [`pugixml`](https://github.com/zeux/pugixml) (by Arseny Kapoulkine; COPYRIGHT 2006-2022). Both released under the MIT license. +#' @keywords internal +"_PACKAGE" + +#' openxlsx2 Options +#' +#' The openxlsx2 package uses global options to simplify formatting: +#' +#' * `options("openxlsx2.borderColor" = "black")` +#' * `options("openxlsx2.borderStyle" = "thin")` +#' * `options("openxlsx2.dateFormat" = "mm/dd/yyyy")` +#' * `options("openxlsx2.datetimeFormat" = "yyyy-mm-dd hh:mm:ss")` +#' * `options("openxlsx2.numFmt" = NULL)` +#' * `options("openxlsx2.paperSize" = 9)` ## A4 +#' * `options("openxlsx2.orientation" = "portrait")` ## page orientation +#' * `options("openxlsx2.sheet.default_name" = "Sheet")` +#' * `options("openxlsx2.rightToLeft" = NULL)` #' +#' @name openxlsx2_options NULL - # matches enum celltype openxlsx2_celltype <- c( short_date = 0, @@ -85,11 +90,11 @@ openxlsx2_celltype <- c( ) #' Deprecated Functions in Package *openxlsx2* -#' @description -#' These functions are provided for compatibility with older versions of `openxlsx2`, and may be defunct as soon as the next release. #' +#' These functions are provided for compatibility with older versions of `openxlsx2`, and may be defunct as soon as the next release. #' @details -#' `convertToExcelDate()` -> `convert_to_excel_date()` +#' * [convertToExcelDate()] -> [convert_to_excel_date()] +#' * [read_sheet_names()] -> [wb_get_sheet_names()] #' @seealso [.Deprecated] #' @name openxlsx2-deprecated NULL diff --git a/R/pugixml.R b/R/pugixml.R index 6df63a053..8ca5d15ea 100644 --- a/R/pugixml.R +++ b/R/pugixml.R @@ -258,17 +258,19 @@ as_xml <- function(x, ...) { } #' write xml file -#' @description brings the added benefit of xml checking +#' +#' brings the added benefit of xml checking +#' #' @param head head part of xml #' @param body body part of xml #' @param tail tail part of xml #' @param fl file name with full path #' @param escapes bool if characters like "&" should be escaped. The default is #' no escape, assuming that xml to export is already valid. -#' @keywords internal +#' #' @noRd -# TODO needs a unit test write_file <- function(head = "", body = "", tail = "", fl = "", escapes = FALSE) { + # TODO `write_file()` needs a unit test if (getOption("openxlsx2.force_utf8_encoding", default = FALSE)) { from_enc <- getOption("openxlsx2.native_encoding") head <- stringi::stri_encode(head, from = from_enc, to = "UTF-8") diff --git a/R/readWorkbook.R b/R/readWorkbook.R index e87e4d88f..b6e2c76b5 100644 --- a/R/readWorkbook.R +++ b/R/readWorkbook.R @@ -1,6 +1,14 @@ -#' @name read_xlsx -#' @title Read from an Excel file or Workbook object -#' @description Read data from an Excel file or Workbook object into a data.frame +# `read_xlsx()` ----------------------------------------------------------------- +#' Read from an Excel file or Workbook object +#' +#' Read data from an Excel file or Workbook object into a data.frame +#' +#' @details +#' Formulae written using write_formula to a Workbook object will not get picked up by read_xlsx(). +#' This is because only the formula is written and left to be evaluated when the file is opened in Excel. +#' Opening, saving and closing the file with Excel will resolve this. +#' @seealso [wb_get_named_regions()] [wb_to_df()] +#' #' @param xlsx_file An xlsx file, Workbook object or URL to xlsx file. #' @param sheet The name or index of the sheet to read data from. #' @param start_row first row to begin looking for data. @@ -23,12 +31,8 @@ #' @param fill_merged_cells If TRUE, the value in a merged cell is given to all cells within the merge. #' @param skip_empty_cols If `TRUE`, empty columns are skipped. #' @param ... additional arguments passed to `wb_to_df()` -#' @seealso [wb_get_named_regions()] [wb_to_df()] -#' @details Formulae written using write_formula to a Workbook object will not get picked up by read_xlsx(). -#' This is because only the formula is written and left to be evaluated when the file is opened in Excel. -#' Opening, saving and closing the file with Excel will resolve this. -#' @return data.frame -#' @export +#' @return A data.frame +#' #' @examples #' xlsxFile <- system.file("extdata", "openxlsx2_example.xlsx", package = "openxlsx2") #' read_xlsx(xlsxFile = xlsxFile) @@ -79,22 +83,24 @@ read_xlsx <- function( ) } - -#' @name wb_read -#' @title Read from an Excel file or Workbook object -#' @description Read data from an Excel file or Workbook object into a data.frame -#' @inheritParams read_xlsx -#' @details Creates a data.frame of all data in worksheet. -#' @param ... additional arguments passed to `wb_to_df()` +# `wb_read()` ------------------------------------------------------------------ +#' Read from an Excel file or Workbook object +#' +#' Read data from an Excel file or Workbook object into a data.frame +#' +#' @details +#' Creates a data.frame of all data in worksheet. #' @seealso [wb_get_named_regions()] [wb_to_df()] [read_xlsx()] -#' @return data.frame -#' @export +#' +#' @inheritParams read_xlsx +#' @inherit read_xlsx return #' @examples #' xlsxFile <- system.file("extdata", "openxlsx2_example.xlsx", package = "openxlsx2") #' df1 <- wb_read(xlsxFile = xlsxFile, sheet = 1) #' #' xlsxFile <- system.file("extdata", "openxlsx2_example.xlsx", package = "openxlsx2") #' df1 <- wb_read(xlsxFile = xlsxFile, sheet = 1, rows = c(1, 3, 5), cols = 1:3) +#' @export wb_read <- function( xlsx_file, sheet = 1, @@ -137,16 +143,19 @@ wb_read <- function( ) } - -#' @name read_sheet_names -#' @title Get names of worksheets -#' @description Returns the worksheet names within an xlsx file +# `read_sheet_names()` ---------------------------------------------- +#' Get names of worksheets +#' +#' Returns the worksheet names within an xlsx file +#' #' @param file An xlsx or xlsm file. #' @return Character vector of worksheet names. #' @examples #' wb_load(system.file("extdata", "openxlsx2_example.xlsx", package = "openxlsx2"))$get_sheet_names() +#' @keywords internal #' @export read_sheet_names <- function(file) { + # TODO Move `read_sheet_names()` to a file named R/openxlsx2-deprecated.R if (!inherits(file, "wbWorkbook")) { wb <- wb_load(file) } diff --git a/R/standardize.R b/R/standardize.R index ebb39379f..3c422f009 100644 --- a/R/standardize.R +++ b/R/standardize.R @@ -2,7 +2,6 @@ #' takes colour and returns color #' @param ... ... #' @returns void. assigns an object in the parent frame -#' @keywords internal #' @noRd standardize_color_names <- function(..., return = FALSE) { @@ -36,7 +35,6 @@ standardize_color_names <- function(..., return = FALSE) { #' takes camelCase and returns camel_case #' @param ... ... #' @returns void. assigns an object in the parent frame -#' @keywords internal #' @noRd standardize_case_names <- function(..., return = FALSE) { @@ -77,7 +75,6 @@ standardize_case_names <- function(..., return = FALSE) { #' takes camelCase and colour returns camel_case and color #' @param ... ... #' @returns void. assigns an object in the parent frame -#' @keywords internal #' @noRd standardize <- function(...) { diff --git a/R/utils.R b/R/utils.R index 85a24812c..610f3c4b5 100644 --- a/R/utils.R +++ b/R/utils.R @@ -53,8 +53,7 @@ temp_xlsx <- function(name = "temp_xlsx", macros = FALSE) { } #' helper function to create temporary directory for testing purpose -#' @param pattern pattern from `base::tempfile()` -#' @keywords internal +#' @inheritParams base::tempfile pattern #' @noRd temp_dir <- function(pattern = "file") { @@ -142,7 +141,6 @@ as_xml_attr <- function(x) { #' #' @inheritParams stringi::stri_rand_strings #' @param keep_seed logical should the default seed be kept unaltered -#' @keywords internal #' @noRd random_string <- function(n = 1, length = 16, pattern = "[A-Za-z0-9]", keep_seed = TRUE) { # https://github.com/ycphs/openxlsx/issues/183 @@ -171,15 +169,25 @@ random_string <- function(n = 1, length = 16, pattern = "[A-Za-z0-9]", keep_seed return(res) } - -#' dims helpers -#' @description Internal helpers to (de)construct a dims argument from/to a row -#' and column vector. Exported for user convenience. -#' @name dims_helper +# dims helpers ----------------------------------------------------------------- +#' Helper functions to work with `dims` +#' +#' Internal helpers to (de)construct a dims argument from/to a row and column +#' vector. Exported for user convenience. +#' #' @param x a dimension object "A1" or "A1:A1" -#' @param as_integer optional if the output should be returned as integer +#' @param as_integer If the output should be returned as integer, (defaults to string) +#' @param row a numeric vector of rows +#' @param col a numeric or character vector of cols +#' @returns +#' * A `dims` string for `_to_dim` i.e "A1:A1" +#' * A list of rows and columns for `to_rowcol` #' @examples #' dims_to_rowcol("A1:J10") +#' rowcol_to_dims(1:10, 1:10) +#' @name dims_helper +NULL +#' @rdname dims_helper #' @export dims_to_rowcol <- function(x, as_integer = FALSE) { @@ -220,26 +228,7 @@ dims_to_rowcol <- function(x, as_integer = FALSE) { list(cols_out, rows_out) } -#' row and col to dims -#' @param row a numeric vector of rows -#' @param col a numeric or character vector of cols -#' @noRd -rowcol_to_dim <- function(row, col) { - # no assert for col. will output character anyways - # assert_class(row, "numeric") - complains if integer - col_int <- col2int(col) - min_col <- int2col(min(col_int)) - min_row <- min(row) - - # we will always return something like "A1" - stringi::stri_join(min_col, min_row) -} - #' @rdname dims_helper -#' @param row a numeric vector of rows -#' @param col a numeric or character vector of cols -#' @examples -#' rowcol_to_dims(1:10, 1:10) #' @export rowcol_to_dims <- function(row, col) { @@ -258,7 +247,19 @@ rowcol_to_dims <- function(row, col) { stringi::stri_join(min_col, min_row, ":", max_col, max_row) } +#' @rdname dims_helper +#' @noRd +rowcol_to_dim <- function(row, col) { + # no assert for col. will output character anyways + # assert_class(row, "numeric") - complains if integer + col_int <- col2int(col) + min_col <- int2col(min(col_int)) + min_row <- min(row) + # we will always return something like "A1" + stringi::stri_join(min_col, min_row) +} +# Relationship helpers -------------------- #' removes entries from worksheets_rels #' @param x character string #' @noRd @@ -303,7 +304,6 @@ read_xml_files <- function(x) { #' unlist modifies names #' @param x a cf list -#' @keywords internal #' @noRd un_list <- function(x) { @@ -317,12 +317,40 @@ un_list <- function(x) { names(x) <- nams x } - +# `fmt_txt()` ------------------------------------------------------------------ #' format strings independent of the cell style. +#' +#' #' @details #' The result is an xml string. It is possible to paste multiple `fmt_txt()` #' strings together to create a string with differing styles. -#' @param x a string or part of a string +#' +#' Using `fmt_txt(charset = 161)` will give the Greek Character Set +#' +#' | charset| "Character Set" | +#' |--------|----------------------| +#' | 0 | "ANSI_CHARSET" | +#' | 1 | "DEFAULT_CHARSET" | +#' | 2 | "SYMBOL_CHARSET" | +#' | 77 | "MAC_CHARSET" | +#' | 128 | "SHIFTJIS_CHARSET" | +#' | 129 | "HANGUL_CHARSET" | +#' | 130 | "JOHAB_CHARSET" | +#' | 134 | "GB2312_CHARSET" | +#' | 136 | "CHINESEBIG5_CHARSET"| +#' | 161 | "GREEK_CHARSET" | +#' | 162 | "TURKISH_CHARSET" | +#' | 163 | "VIETNAMESE_CHARSET" | +#' | 177 | "HEBREW_CHARSET" | +#' | 178 | "ARABIC_CHARSET" | +#' | 186 | "BALTIC_CHARSET" | +#' | 204 | "RUSSIAN_CHARSET" | +#' | 222 | "THAI_CHARSET" | +#' | 238 | "EASTEUROPE_CHARSET" | +#' | 255 | "OEM_CHARSET" | +#' +# FIXME review the `fmt_txt.Rd` +# #' @param x a string or part of a string #' @param bold bold #' @param italic italic #' @param underline underline @@ -333,31 +361,8 @@ un_list <- function(x) { #' @param charset integer value from the table below #' @param outline TRUE or FALSE #' @param vertAlign baseline, superscript, or subscript -#' @details -#' |"Value" | "Character Set" | -#' |--------|----------------------| -#' |"0" | "ANSI_CHARSET" | -#' |"1" | "DEFAULT_CHARSET" | -#' |"2" | "SYMBOL_CHARSET" | -#' |"77" | "MAC_CHARSET" | -#' |"128" | "SHIFTJIS_CHARSET" | -#' |"129" | "HANGUL_CHARSET" | -#' |"130" | "JOHAB_CHARSET" | -#' |"134" | "GB2312_CHARSET" | -#' |"136" | "CHINESEBIG5_CHARSET"| -#' |"161" | "GREEK_CHARSET" | -#' |"162" | "TURKISH_CHARSET" | -#' |"163" | "VIETNAMESE_CHARSET" | -#' |"177" | "HEBREW_CHARSET" | -#' |"178" | "ARABIC_CHARSET" | -#' |"186" | "BALTIC_CHARSET" | -#' |"204" | "RUSSIAN_CHARSET" | -#' |"222" | "THAI_CHARSET" | -#' |"238" | "EASTEUROPE_CHARSET" | -#' |"255" | "OEM_CHARSET" | #' @examples #' fmt_txt("bar", underline = TRUE) -#' @name fmt_txt #' @export fmt_txt <- function( x, @@ -445,13 +450,12 @@ fmt_txt <- function( out } -#' @rdname fmt_txt #' @method + fmt_txt -#' @param x an openxlsx2 fmt_txt string -#' @param y an openxlsx2 fmt_txt string +#' @param x,y an openxlsx2 fmt_txt string #' @details You can join additional objects into fmt_txt() objects using "+". Though be aware that `fmt_txt("sum:") + (2 + 2)` is different to `fmt_txt("sum:") + 2 + 2`. #' @examples #' fmt_txt("foo ", bold = TRUE) + fmt_txt("bar") +#' @rdname fmt_txt #' @export "+.fmt_txt" <- function(x, y) { @@ -466,7 +470,8 @@ fmt_txt <- function( #' @rdname fmt_txt #' @method as.character fmt_txt -#' @param x an openxlsx2 fmt_txt string +# FIXME review the `fmt_txt.Rd` +# #' @param x an openxlsx2 fmt_txt string #' @param ... unused #' @examples #' as.character(fmt_txt(2)) @@ -477,7 +482,8 @@ as.character.fmt_txt <- function(x, ...) { #' @rdname fmt_txt #' @method print fmt_txt -#' @param x an openxlsx2 fmt_txt string +# FIXME review the `fmt_txt.Rd` +# #' @param x an openxlsx2 fmt_txt string #' @param ... additional arguments for default print #' @export print.fmt_txt <- function(x, ...) { diff --git a/R/wb_functions.R b/R/wb_functions.R index 4099fc96a..883cd329b 100644 --- a/R/wb_functions.R +++ b/R/wb_functions.R @@ -83,7 +83,7 @@ dataframe_to_dims <- function(df) { #' function to estimate the column type. #' 0 = character, 1 = numeric, 2 = date. #' @param tt dataframe produced by wb_to_df() -#' @keywords internal +#' #' @noRd guess_col_type <- function(tt) { @@ -116,7 +116,6 @@ guess_col_type <- function(tt) { #' check if numFmt is date. internal function #' @param numFmt numFmt xml nodes -#' @keywords internal #' @noRd numfmt_is_date <- function(numFmt) { @@ -147,7 +146,6 @@ numfmt_is_date <- function(numFmt) { #' check if numFmt is posix. internal function #' @param numFmt numFmt xml nodes -#' @keywords internal #' @noRd numfmt_is_posix <- function(numFmt) { @@ -180,7 +178,6 @@ numfmt_is_posix <- function(numFmt) { #' check if numFmt is posix. internal function #' @param numFmt numFmt xml nodes -#' @keywords internal #' @noRd numfmt_is_hms <- function(numFmt) { @@ -215,7 +212,6 @@ numfmt_is_hms <- function(numFmt) { #' #' @param cellXfs cellXfs xml nodes #' @param numfmt_date custom numFmtId dates -#' @keywords internal #' @noRd style_is_date <- function(cellXfs, numfmt_date) { @@ -233,7 +229,6 @@ style_is_date <- function(cellXfs, numfmt_date) { #' #' @param cellXfs cellXfs xml nodes #' @param numfmt_date custom numFmtId dates -#' @keywords internal #' @noRd style_is_posix <- function(cellXfs, numfmt_date) { @@ -251,7 +246,6 @@ style_is_posix <- function(cellXfs, numfmt_date) { #' #' @param cellXfs cellXfs xml nodes #' @param numfmt_date custom numFmtId dates -#' @keywords internal #' @noRd style_is_hms <- function(cellXfs, numfmt_date) { diff --git a/R/write_xlsx.R b/R/write_xlsx.R index 506a82661..dd71ccfa9 100644 --- a/R/write_xlsx.R +++ b/R/write_xlsx.R @@ -1,20 +1,11 @@ -#' @name write_xlsx -#' @title write data to an xlsx file -#' @description write a data.frame or list of data.frames to an xlsx file -#' @param x object or a list of objects that can be handled by [write_data()] to write to file -#' @param file xlsx file name -#' @param as_table write using write_datatable as opposed to write_data -#' @param ... optional parameters to pass to functions: -#' \itemize{ -#' \item{[wb_workbook()]} -#' \item{[wb_add_worksheet()]} -#' \item{[wb_add_data()]} -#' \item{[wb_freeze_pane]} -#' \item{[wb_save()]} -#' } +# `write_xlsx()` --------------------------------------------------------------- +#' Write data to an xlsx file #' -#' see details. -#' @details Optional parameters are: +#' Write a data.frame or list of data.frames to an xlsx file +#' +#' @seealso [wb_add_worksheet()], [write_data()] +#' @details +#' Optional parameters are: #' #' **wb_workbook Parameters** #' \itemize{ @@ -61,10 +52,23 @@ #' #' columns of x with class Date or POSIXt are automatically #' styled as dates and datetimes respectively. -#' @seealso [wb_add_worksheet()], [write_data()] +#' +#' @param x object or a list of objects that can be handled by [write_data()] to write to file +#' @param file xlsx file name +#' @param as_table write using write_datatable as opposed to write_data +#' @param ... optional parameters to pass to functions: +#' \itemize{ +#' \item{[wb_workbook()]} +#' \item{[wb_add_worksheet()]} +#' \item{[wb_add_data()]} +#' \item{[wb_freeze_pane]} +#' \item{[wb_save()]} +#' } +#' +#' see details. +#' #' @return A workbook object #' @examples -#' #' ## write to working directory #' write_xlsx(iris, file = temp_xlsx(), colNames = TRUE) #' @@ -87,7 +91,6 @@ #' write_xlsx(l, temp_xlsx(), colWidths = 20) #' write_xlsx(l, temp_xlsx(), colWidths = list(100, 200, 300)) #' write_xlsx(l, temp_xlsx(), colWidths = list(rep(10, 5), rep(8, 11), rep(5, 5))) -#' #' @export write_xlsx <- function(x, file, as_table = FALSE, ...) { diff --git a/R/xl_open.R b/R/xl_open.R index e06e6f9a8..895b844e6 100644 --- a/R/xl_open.R +++ b/R/xl_open.R @@ -1,26 +1,26 @@ #' Open a Microsoft Excel file (xls/xlsx) or an openxlsx2 wbWorkbook #' -#' @description This function tries to open a Microsoft Excel (xls/xlsx) file or -#' an openxlsx2 wbWorkbook with the proper application, in a portable manner. +#' @description +#' This function tries to open a Microsoft Excel (xls/xlsx) file or, +#' an openxlsx2 wbWorkbook with the proper application, in a portable manner. #' -#' In Windows it uses `base::shell.exec()` (Windows only function) to -#' determine the appropriate program. +#' On Windows it uses `base::shell.exec()` (Windows only function) to +#' determine the appropriate program. #' -#' In Mac (c) it uses system default handlers, given the file type. +#' In Mac (c) it uses system default handlers, given the file type. #' -#' In Linux it searches (via `which`) for available xls/xlsx reader -#' applications (unless `options('openxlsx2.excelApp')` is set to the app bin -#' path), and if it finds anything, sets `options('openxlsx2.excelApp')` to the -#' program chosen by the user via a menu (if many are present, otherwise it -#' will set the only available). Currently searched for apps are -#' Libreoffice/Openoffice (`soffice` bin), Gnumeric (`gnumeric`) and Calligra -#' Sheets (`calligrasheets`). +#' In Linux it searches (via `which`) for available xls/xlsx reader +#' applications (unless `options('openxlsx2.excelApp')` is set to the app bin +#' path), and if it finds anything, sets `options('openxlsx2.excelApp')` to the +#' program chosen by the user via a menu (if many are present, otherwise it +#' will set the only available). Currently searched for apps are +#' Libreoffice/Openoffice (`soffice` bin), Gnumeric (`gnumeric`) and Calligra +#' Sheets (`calligrasheets`). #' #' @param x A path to the Excel (xls/xlsx) file or Workbook object. #' @param interactive If `FALSE` will throw a warning and not open the path. #' This can be manually set to `TRUE`, otherwise when `NA` (default) uses the #' value returned from [base::interactive()] -#' @export #' @examples #' \donttest{ #' if (interactive()) { @@ -35,6 +35,7 @@ #' xl_open(wb) #' } #' } +#' @export xl_open <- function(x, interactive = NA) { UseMethod("xl_open") } diff --git a/README.md b/README.md index 511a12d6f..0a2927d67 100644 --- a/README.md +++ b/README.md @@ -107,7 +107,7 @@ read_xlsx(path) #> 6 FALSE 2 NA #NUM! 2 17:24:53 #> 7 FALSE 3 NA 1.56 e #> 8 FALSE 1 NA 1.7 f 2023-03-02 2.7 08:45:58 -#> 9 NA NA NA 2023-04-17 +#> 9 NA NA NA #> 10 FALSE 2 NA 23 h 2023-12-24 25 #> 11 FALSE 3 NA 67.3 i 2023-12-25 3 #> 12 NA 1 NA 123 2023-07-31 122 @@ -118,8 +118,8 @@ wb #> A Workbook object. #> #> Worksheets: -#> Sheets: Sheet1 -#> Write order: 1 +#> Sheets: Sheet1 Sheet2 +#> Write order: 1, 2 # read a data frame wb_to_df(wb) @@ -130,7 +130,7 @@ wb_to_df(wb) #> 6 FALSE 2 NA #NUM! 2 17:24:53 #> 7 FALSE 3 NA 1.56 e #> 8 FALSE 1 NA 1.7 f 2023-03-02 2.7 08:45:58 -#> 9 NA NA NA 2023-04-17 +#> 9 NA NA NA #> 10 FALSE 2 NA 23 h 2023-12-24 25 #> 11 FALSE 3 NA 67.3 i 2023-12-25 3 #> 12 NA 1 NA 123 2023-07-31 122 diff --git a/_pkgdown.yml b/_pkgdown.yml index 7f8264181..802f8cdab 100644 --- a/_pkgdown.yml +++ b/_pkgdown.yml @@ -1,5 +1,13 @@ +url: https://janmarvin.github.io/openxlsx2 + destination: docs +template: + bootstrap: 5 + +development: + mode: auto + reference: - title: Main contents: @@ -25,23 +33,61 @@ reference: - starts_with("wb_get_") - starts_with("wb_set_") +- title: wb Misc + contents: + - starts_with("wb_protect") + - wb_hyperlink + - cleanup + - wb_freeze_pane + - wb_open + - starts_with("wb_clone") + - starts_with("wb_copy") + - wb_color + - wb_data + - wb_grid_lines + - wb_update_table + - wb_copy_cells + - title: create functions contents: - starts_with("create_") - title: XML functions - desc: A curated list of XML functions used in openxlsx2. + desc: > + A curated list of XML functions used in openxlsx2. contents: - read_xml - starts_with("xml_") - as_xml + - starts_with("print") -- title: All functions +- title: R6 Classes contents: - - matches(".*") + - wbWorkbook + - wbChartSheet -template: - bootstrap: 5 +- title: Misc and helpers + contents: + - openxlsx2_options + - int2col + - col2int + - fmt_txt + - starts_with("convert_") + - temp_xlsx + - read_sheet_names + - clean_worksheet_name + - styles_on_sheet + - waivers + - starts_with("ws_") + - xl_open + - dims_helper + - workbook_grouping + - contains("dims") + - starts_with("write_") -development: - mode: auto +- title: Deprecated + contents: + - openxlsx2-deprecated + +redirects: + - ["articles/openxlsx2_basic_manual.html", "articles/openxlsx2.html"] diff --git a/inst/AUTHORS b/inst/AUTHORS index fda5489a8..c2be0866a 100644 --- a/inst/AUTHORS +++ b/inst/AUTHORS @@ -25,6 +25,7 @@ Luke Symes Martins Liberts Mikael Elenius Noam Ross +olivroy Philipp Schauberger Reinhold Kainhofer Renaud diff --git a/man/convert_date.Rd b/man/convert_date.Rd index 5f264ce82..0d28ea602 100644 --- a/man/convert_date.Rd +++ b/man/convert_date.Rd @@ -4,7 +4,7 @@ \alias{convert_date} \alias{convert_datetime} \alias{convert_hms} -\title{Convert from excel date, datetime or hms number to R Date type} +\title{Convert from Excel date, datetime or hms number to R Date type} \usage{ convert_date(x, origin = "1900-01-01", ...) @@ -17,23 +17,35 @@ convert_hms(x) \item{origin}{date. Default value is for Windows Excel 2010} -\item{...}{additional parameters passed to as.Date()} +\item{...}{ + Arguments passed on to \code{\link[base:as.Date]{base::as.Date}} + \describe{ + \item{\code{}}{} + }} +} +\value{ +A date, datetime, or hms. } \description{ -Convert from excel date number to R Date type +Convert from Excel date number to R Date type } \details{ Excel stores dates as number of days from some origin day } \examples{ +# date -- ## 2014 April 21st to 25th convert_date(c(41750, 41751, 41752, 41753, 41754, NA)) convert_date(c(41750.2, 41751.99, NA, 41753)) -## 2014-07-01, 2014-06-30, 2014-06-29 + +# datetime -- +## 2014-07-01, 2014-06-30, 2014-06-29 x <- c(41821.8127314815, 41820.8127314815, NA, 41819, NaN) convert_datetime(x) convert_datetime(x, tz = "Australia/Perth") convert_datetime(x, tz = "UTC") + +# hms --- ## 12:13:14 x <- 0.50918982 convert_hms(x) diff --git a/man/convert_to_excel_date.Rd b/man/convert_to_excel_date.Rd index 9bb89a4d4..ca4ac259f 100644 --- a/man/convert_to_excel_date.Rd +++ b/man/convert_to_excel_date.Rd @@ -3,7 +3,7 @@ \name{convert_to_excel_date} \alias{convert_to_excel_date} \alias{convertToExcelDate} -\title{convert back to ExcelDate} +\title{convert back to an Excel Date} \usage{ convert_to_excel_date(df, date1904 = FALSE) @@ -15,7 +15,7 @@ convertToExcelDate(df, date1904 = FALSE) \item{date1904}{take different origin} } \description{ -convert back to ExcelDate +convert back to an Excel Date } \examples{ xlsxFile <- system.file("extdata", "openxlsx2_example.xlsx", package = "openxlsx2") diff --git a/man/create_hyperlink.Rd b/man/create_hyperlink.Rd index 39a288429..2620c40c1 100644 --- a/man/create_hyperlink.Rd +++ b/man/create_hyperlink.Rd @@ -2,7 +2,7 @@ % Please edit documentation in R/helperFunctions.R \name{create_hyperlink} \alias{create_hyperlink} -\title{create Excel hyperlink string} +\title{Create Excel hyperlink string} \usage{ create_hyperlink(sheet, row = 1, col = 1, text = NULL, file = NULL) } @@ -18,7 +18,8 @@ create_hyperlink(sheet, row = 1, col = 1, text = NULL, file = NULL) \item{file}{Excel file name to point to. If NULL hyperlink is internal.} } \description{ -Wrapper to create internal hyperlink string to pass to write_formula(). Either link to external urls or local files or straight to cells of local Excel sheets. +Wrapper to create internal hyperlink string to pass to \code{\link[=write_formula]{write_formula()}}. +Either link to external URLs or local files or straight to cells of local Excel sheets. } \examples{ @@ -93,6 +94,3 @@ write_formula( x = create_hyperlink(text = "test.png", file = "D:/somepath/somepicture.png") write_formula(wb, "Sheet1", startRow = 11, startCol = 1, x = x) } -\seealso{ -\code{\link[=write_formula]{write_formula()}} -} diff --git a/man/dims_helper.Rd b/man/dims_helper.Rd index b6461dc11..38b16e8c7 100644 --- a/man/dims_helper.Rd +++ b/man/dims_helper.Rd @@ -4,7 +4,7 @@ \alias{dims_helper} \alias{dims_to_rowcol} \alias{rowcol_to_dims} -\title{dims helpers} +\title{Helper functions to work with \code{dims}} \usage{ dims_to_rowcol(x, as_integer = FALSE) @@ -13,15 +13,21 @@ rowcol_to_dims(row, col) \arguments{ \item{x}{a dimension object "A1" or "A1:A1"} -\item{as_integer}{optional if the output should be returned as integer} +\item{as_integer}{If the output should be returned as integer, (defaults to string)} \item{row}{a numeric vector of rows} \item{col}{a numeric or character vector of cols} } +\value{ +\itemize{ +\item A \code{dims} string for \verb{_to_dim} i.e "A1:A1" +\item A list of rows and columns for \code{to_rowcol} +} +} \description{ -Internal helpers to (de)construct a dims argument from/to a row -and column vector. Exported for user convenience. +Internal helpers to (de)construct a dims argument from/to a row and column +vector. Exported for user convenience. } \examples{ dims_to_rowcol("A1:J10") diff --git a/man/fmt_txt.Rd b/man/fmt_txt.Rd index b8a77f93b..3ccae5b18 100644 --- a/man/fmt_txt.Rd +++ b/man/fmt_txt.Rd @@ -28,7 +28,7 @@ fmt_txt( \method{print}{fmt_txt}(x, ...) } \arguments{ -\item{x}{an openxlsx2 fmt_txt string} +\item{x, y}{an openxlsx2 fmt_txt string} \item{bold}{bold} @@ -50,8 +50,6 @@ fmt_txt( \item{vertAlign}{baseline, superscript, or subscript} -\item{y}{an openxlsx2 fmt_txt string} - \item{...}{additional arguments for default print} } \description{ @@ -61,27 +59,27 @@ format strings independent of the cell style. The result is an xml string. It is possible to paste multiple \code{fmt_txt()} strings together to create a string with differing styles. -\tabular{ll}{ - "Value" \tab "Character Set" \cr - "0" \tab "ANSI_CHARSET" \cr - "1" \tab "DEFAULT_CHARSET" \cr - "2" \tab "SYMBOL_CHARSET" \cr - "77" \tab "MAC_CHARSET" \cr - "128" \tab "SHIFTJIS_CHARSET" \cr - "129" \tab "HANGUL_CHARSET" \cr - "130" \tab "JOHAB_CHARSET" \cr - "134" \tab "GB2312_CHARSET" \cr - "136" \tab "CHINESEBIG5_CHARSET" \cr - "161" \tab "GREEK_CHARSET" \cr - "162" \tab "TURKISH_CHARSET" \cr - "163" \tab "VIETNAMESE_CHARSET" \cr - "177" \tab "HEBREW_CHARSET" \cr - "178" \tab "ARABIC_CHARSET" \cr - "186" \tab "BALTIC_CHARSET" \cr - "204" \tab "RUSSIAN_CHARSET" \cr - "222" \tab "THAI_CHARSET" \cr - "238" \tab "EASTEUROPE_CHARSET" \cr - "255" \tab "OEM_CHARSET" \cr +Using \code{fmt_txt(charset = 161)} will give the Greek Character Set\tabular{ll}{ + charset \tab "Character Set" \cr + 0 \tab "ANSI_CHARSET" \cr + 1 \tab "DEFAULT_CHARSET" \cr + 2 \tab "SYMBOL_CHARSET" \cr + 77 \tab "MAC_CHARSET" \cr + 128 \tab "SHIFTJIS_CHARSET" \cr + 129 \tab "HANGUL_CHARSET" \cr + 130 \tab "JOHAB_CHARSET" \cr + 134 \tab "GB2312_CHARSET" \cr + 136 \tab "CHINESEBIG5_CHARSET" \cr + 161 \tab "GREEK_CHARSET" \cr + 162 \tab "TURKISH_CHARSET" \cr + 163 \tab "VIETNAMESE_CHARSET" \cr + 177 \tab "HEBREW_CHARSET" \cr + 178 \tab "ARABIC_CHARSET" \cr + 186 \tab "BALTIC_CHARSET" \cr + 204 \tab "RUSSIAN_CHARSET" \cr + 222 \tab "THAI_CHARSET" \cr + 238 \tab "EASTEUROPE_CHARSET" \cr + 255 \tab "OEM_CHARSET" \cr } You can join additional objects into fmt_txt() objects using "+". Though be aware that \code{fmt_txt("sum:") + (2 + 2)} is different to \code{fmt_txt("sum:") + 2 + 2}. diff --git a/man/openxlsx2-deprecated.Rd b/man/openxlsx2-deprecated.Rd index 7111970ef..facc34f76 100644 --- a/man/openxlsx2-deprecated.Rd +++ b/man/openxlsx2-deprecated.Rd @@ -7,7 +7,10 @@ These functions are provided for compatibility with older versions of \code{openxlsx2}, and may be defunct as soon as the next release. } \details{ -\code{convertToExcelDate()} -> \code{convert_to_excel_date()} +\itemize{ +\item \code{\link[=convertToExcelDate]{convertToExcelDate()}} -> \code{\link[=convert_to_excel_date]{convert_to_excel_date()}} +\item \code{\link[=read_sheet_names]{read_sheet_names()}} -> \code{\link[=wb_get_sheet_names]{wb_get_sheet_names()}} +} } \seealso{ \link{.Deprecated} diff --git a/man/openxlsx2.Rd b/man/openxlsx2-package.Rd similarity index 59% rename from man/openxlsx2.Rd rename to man/openxlsx2-package.Rd index 5ce8d228f..0b775781f 100644 --- a/man/openxlsx2.Rd +++ b/man/openxlsx2-package.Rd @@ -1,8 +1,9 @@ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/openxlsx2.R \docType{package} -\name{openxlsx2} +\name{openxlsx2-package} \alias{openxlsx2} +\alias{openxlsx2-package} \title{xlsx reading, writing and editing.} \description{ This R package is a modern reinterpretation of the widely used popular @@ -12,23 +13,13 @@ Based on a powerful XML library and focusing on modern programming flows in pipe or chains, \code{openxlsx2} allows to break many new ground. } \details{ -The openxlsx package uses global options to simplify formatting: - -\itemize{ -\item{\code{options("openxlsx2.borderColor" = "black")}} -\item{\code{options("openxlsx2.borderStyle" = "thin")}} -\item{\code{options("openxlsx2.dateFormat" = "mm/dd/yyyy")}} -\item{\code{options("openxlsx2.datetimeFormat" = "yyyy-mm-dd hh:mm:ss")}} -\item{\code{options("openxlsx2.numFmt" = NULL)}} -\item{\code{options("openxlsx2.paperSize" = 9)}} ## A4 -\item{\code{options("openxlsx2.orientation" = "portrait")}} ## page orientation -\item{\code{options("openxlsx2.sheet.default_name" = "Sheet")}} -\item{\code{options("openxlsx2.rightToLeft" = NULL)}} -} -By default, openxlsx2 uses the American English word for color (written with 'o' instead of the British English 'ou'). However, both spellings are supported. So where the documentation uses a 'color', the function should also accept a 'color'. However, this is not indicated by the autocompletion. +By default, openxlsx2 uses the American English word for color (written with 'o' instead of the British English 'ou'). +However, both spellings are supported. +So where the documentation uses a 'color', the function should also accept a 'colour'. +However, this is not indicated by the autocompletion. \subsection{Authors and contributions}{ -For a full list of all authors that have made this package possible and for whom we are greatful, please see: +For a full list of all authors that have made this package possible and for whom we are grateful, please see: \if{html}{\out{
}}\preformatted{system.file("AUTHORS", package = "openxlsx2") }\if{html}{\out{
}} @@ -47,11 +38,28 @@ This package is licensed under the MIT license and is based on \href{https://git } \seealso{ \itemize{ -\item{\code{vignette(package = "openxlsx2")}} -\item{\code{\link[=write_data]{write_data()}}} -\item{\code{\link[=write_datatable]{write_datatable()}}} -\item{\code{\link[=write_xlsx]{write_xlsx()}}} -\item{\code{\link[=read_xlsx]{read_xlsx()}}} -} +\item \code{browseVignettes("openxlsx2")} +\item \code{\link[=write_data]{write_data()}} +\item \code{\link[=write_datatable]{write_datatable()}} +\item \code{\link[=write_xlsx]{write_xlsx()}} +\item \code{\link[=read_xlsx]{read_xlsx()}} +\item \url{https://janmarvin.github.io/openxlsx2} for examples } +} +\author{ +\strong{Maintainer}: Jan Marvin Garbuszus \email{jan.garbuszus@ruhr-uni-bochum.de} + +Authors: +\itemize{ + \item Jordan Mark Barbone \email{jmbarbone@gmail.com} (\href{https://orcid.org/0000-0001-9788-3628}{ORCID}) +} + +Other contributors: +\itemize{ + \item openxlsx authors (openxlsx package) [copyright holder] + \item Arseny Kapoulkine (Author of included pugixml code) [contributor, copyright holder] +} + +} +\keyword{internal} diff --git a/man/openxlsx2_options.Rd b/man/openxlsx2_options.Rd new file mode 100644 index 000000000..15e8c26d9 --- /dev/null +++ b/man/openxlsx2_options.Rd @@ -0,0 +1,21 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/openxlsx2.R +\name{openxlsx2_options} +\alias{openxlsx2_options} +\title{openxlsx2 Options} +\description{ +The openxlsx2 package uses global options to simplify formatting: +} +\details{ +\itemize{ +\item \code{options("openxlsx2.borderColor" = "black")} +\item \code{options("openxlsx2.borderStyle" = "thin")} +\item \code{options("openxlsx2.dateFormat" = "mm/dd/yyyy")} +\item \code{options("openxlsx2.datetimeFormat" = "yyyy-mm-dd hh:mm:ss")} +\item \code{options("openxlsx2.numFmt" = NULL)} +\item \code{options("openxlsx2.paperSize" = 9)} ## A4 +\item \code{options("openxlsx2.orientation" = "portrait")} ## page orientation +\item \code{options("openxlsx2.sheet.default_name" = "Sheet")} +\item \code{options("openxlsx2.rightToLeft" = NULL)} +} +} diff --git a/man/read_sheet_names.Rd b/man/read_sheet_names.Rd index 6227bdabb..0af72c1b3 100644 --- a/man/read_sheet_names.Rd +++ b/man/read_sheet_names.Rd @@ -18,3 +18,4 @@ Returns the worksheet names within an xlsx file \examples{ wb_load(system.file("extdata", "openxlsx2_example.xlsx", package = "openxlsx2"))$get_sheet_names() } +\keyword{internal} diff --git a/man/read_xlsx.Rd b/man/read_xlsx.Rd index 1a3bc02ea..09b7c0b0b 100644 --- a/man/read_xlsx.Rd +++ b/man/read_xlsx.Rd @@ -67,7 +67,7 @@ are checked to ensure that they are syntactically valid variable names} \item{...}{additional arguments passed to \code{wb_to_df()}} } \value{ -data.frame +A data.frame } \description{ Read data from an Excel file or Workbook object into a data.frame diff --git a/man/wb_add_formula.Rd b/man/wb_add_formula.Rd index 937c84679..28bd5efa8 100644 --- a/man/wb_add_formula.Rd +++ b/man/wb_add_formula.Rd @@ -48,12 +48,11 @@ Add a character vector containing Excel formula to a worksheet. Currently only the English version of functions are supported. Please don't use the local translation. The examples below show a small list of possible formulas: \itemize{ -\item{SUM(B2:B4)} -\item{AVERAGE(B2:B4)} -\item{MIN(B2:B4)} -\item{MAX(B2:B4)} -\item{...} - +\item SUM(B2:B4) +\item AVERAGE(B2:B4) +\item MIN(B2:B4) +\item MAX(B2:B4) +\item ... } } \seealso{ diff --git a/man/wb_add_plot.Rd b/man/wb_add_plot.Rd index 0c07d419b..4653cd9df 100644 --- a/man/wb_add_plot.Rd +++ b/man/wb_add_plot.Rd @@ -56,7 +56,7 @@ wb$add_worksheet("Sheet 1", gridLines = FALSE) require(ggplot2) p1 <- ggplot(mtcars, aes(x = mpg, fill = as.factor(gear))) + ggtitle("Distribution of Gas Mileage") + - geom_density(alpha = I(.5)) + geom_density(alpha = 0.5) p2 <- ggplot(Orange, aes(x = age, y = circumference, color = Tree)) + geom_point() + geom_line() diff --git a/man/wbColour.Rd b/man/wb_color.Rd similarity index 100% rename from man/wbColour.Rd rename to man/wb_color.Rd diff --git a/man/wb_read.Rd b/man/wb_read.Rd index 24c8fe6f8..0097490de 100644 --- a/man/wb_read.Rd +++ b/man/wb_read.Rd @@ -57,7 +57,7 @@ If NULL, all columns are read.} \item{...}{additional arguments passed to \code{wb_to_df()}} } \value{ -data.frame +A data.frame } \description{ Read data from an Excel file or Workbook object into a data.frame diff --git a/man/write_xlsx.Rd b/man/write_xlsx.Rd index 115201a84..bf4060ff9 100644 --- a/man/write_xlsx.Rd +++ b/man/write_xlsx.Rd @@ -2,7 +2,7 @@ % Please edit documentation in R/write_xlsx.R \name{write_xlsx} \alias{write_xlsx} -\title{write data to an xlsx file} +\title{Write data to an xlsx file} \usage{ write_xlsx(x, file, as_table = FALSE, ...) } @@ -28,7 +28,7 @@ see details.} A workbook object } \description{ -write a data.frame or list of data.frames to an xlsx file +Write a data.frame or list of data.frames to an xlsx file } \details{ Optional parameters are: @@ -78,7 +78,6 @@ columns of x with class Date or POSIXt are automatically styled as dates and datetimes respectively. } \examples{ - ## write to working directory write_xlsx(iris, file = temp_xlsx(), colNames = TRUE) @@ -101,7 +100,6 @@ write_xlsx(l, temp_xlsx(), write_xlsx(l, temp_xlsx(), colWidths = 20) write_xlsx(l, temp_xlsx(), colWidths = list(100, 200, 300)) write_xlsx(l, temp_xlsx(), colWidths = list(rep(10, 5), rep(8, 11), rep(5, 5))) - } \seealso{ \code{\link[=wb_add_worksheet]{wb_add_worksheet()}}, \code{\link[=write_data]{write_data()}} diff --git a/man/xl_open.Rd b/man/xl_open.Rd index 483d29827..17849107f 100644 --- a/man/xl_open.Rd +++ b/man/xl_open.Rd @@ -20,10 +20,10 @@ This can be manually set to \code{TRUE}, otherwise when \code{NA} (default) uses value returned from \code{\link[base:interactive]{base::interactive()}}} } \description{ -This function tries to open a Microsoft Excel (xls/xlsx) file or +This function tries to open a Microsoft Excel (xls/xlsx) file or, an openxlsx2 wbWorkbook with the proper application, in a portable manner. -In Windows it uses \code{base::shell.exec()} (Windows only function) to +On Windows it uses \code{base::shell.exec()} (Windows only function) to determine the appropriate program. In Mac (c) it uses system default handlers, given the file type. diff --git a/openxlsx2.Rproj b/openxlsx2.Rproj index 9e0721e39..9d06b5e0d 100644 --- a/openxlsx2.Rproj +++ b/openxlsx2.Rproj @@ -21,3 +21,7 @@ PackageCleanBeforeInstall: No PackageInstallArgs: --no-multiarch --with-keep.source PackageCheckArgs: --as-cran PackageRoxygenize: rd,collate,namespace,vignette + +UseNativePipeOperator: No + +SpellingDictionary: en_US diff --git a/R/testthat-helpers.R b/tests/testthat/helper.R similarity index 89% rename from R/testthat-helpers.R rename to tests/testthat/helper.R index 8ab6855e3..549a31fc6 100644 --- a/R/testthat-helpers.R +++ b/tests/testthat/helper.R @@ -1,5 +1,282 @@ +#' expect_equal_workbooks() ------------------------------------------ +#' Quick internal expectation function. Easier to ignore fields to be set +expect_equal_workbooks <- function(object, expected, ..., ignore_fields = NULL) { -# Miscellaneous helpers for testthat + # object <- as.list(object) + # expected <- as.list(expected) + requireNamespace("waldo") + assert_workbook(object) + assert_workbook(expected) + + fields <- c(names(wbWorkbook$public_fields), names(wbWorkbook$private_fields)) + bad <- setdiff(ignore_fields, fields) + + if (length(bad)) { + stop("Invalid fields: ", toString(bad)) + } + + for (i in ignore_fields) { + object[[i]] <- NULL + expected[[i]] <- NULL + } + + bad <- waldo::compare( + x = object, + y = expected, + x_arg = "object", + y_arg = "expected", + ... + ) + + if (length(bad)) { + testthat::fail(bad) + return(invisible()) + } + + testthat::succeed() + return(invisible()) +} + +# expect_wrapper helper -------------------- +#' Expect wrapper +#' +#' Internal tool: see tests/testthat/test-workbook-wrappers.R +#' +#' @description Testing expectations for [wbWorkbook] wrappers. These test that +#' the method and wrappers have the same params, same default values, and +#' return the same value. +#' +#' Requires the `waldo` package, used within `testthat`. +#' +#' @param method The name of the [wbWorkbook] method +#' @param fun The name of the wrapper (probably in R/class-workbook-wrappers) +#' @param wb A `wbWorkbook` object +#' @param params A named list of params. Set to `NULL` to not execute functions +#' @param ignore Names of params to ignore +#' @param ignore_attr Passed to `waldo::compare()` for the result of the +#' executed functions +#' @param ignore_fields Ignore immediate fields by removing them from the +#' objects for comparison +#' @param ignore_wb for pseudo wbWorkbook wrappers such as wb_load() we have +#' to ignore wb +#' @returns Nothing, called for its side-effects +expect_wrapper <- function( + method, + fun = paste0("wb_", method), + wb = wb_workbook(), + params = list(), + ignore = NULL, + ignore_attr = "waldo_opts", + ignore_fields = NULL, + ignore_wb = FALSE +) { + stopifnot( + requireNamespace("waldo", quietly = TRUE), + is.character(method), length(method) == 1L, + is.character(fun), length(fun) == 1L, + is.list(params) || is.null(params) + ) + + method_fun <- get(method, wbWorkbook$public_methods) + fun_fun <- match.fun(fun) + + # these come as pairlist -- we don't really care about that + method_forms <- as.list(formals(method_fun)) + fun_forms <- as.list(formals(fun_fun)) + + method_args <- names(method_forms) + fun_args <- names(fun_forms) + + # remove wb and other ignores + ignore <- c("wb", ignore) + + # remove ignores from fun + m <- match(ignore, fun_args, 0L) + if (!identical(m, 0L)) { + # remove wb from both the args and formals + fun_args <- fun_args[-m] + fun_forms <- fun_forms[-m] + } + + # remove ignores from method + m <- match(ignore, method_args, 0L) + if (!identical(m, 0L)) { + # remove wb from both the args and formals + method_args <- method_args[-m] + method_forms <- method_forms[-m] + } + + method0 <- paste0("wbWorkbook$", method) + + # adjustments for when wrappers don't have any args + if (!length(method_args)) { + method_args <- character() + } + + if (!length(method_forms)) { + method_forms <- structure(list(), names = character()) + } + + # expectation that the names are the same (possibly redundant but quicker to) + bad <- waldo::compare( + x = method_args, + y = setdiff(fun_args, "wb"), + x_arg = method0, + y_arg = fun + ) + + if (length(bad)) { + testthat::fail(bad) + return(invisible()) + } + + # expectation that the default values are the same + bad <- waldo::compare( + x = method_forms, + y = fun_forms, + x_arg = method0, + y_arg = fun + ) + + if (length(bad)) { + testthat::fail(bad) + return(invisible()) + } + + if (!is.null(params)) { + # create now so that it's the same every time + wb_fun <- wb$clone(deep = TRUE) + wb_method <- wb$clone(deep = TRUE) + + # be careful and report when we failed to run these + + + # the style names are generated at random: use matching seeds for both calls + options("openxlsx2_seed" = NULL) + if (ignore_wb) { + res_fun <- try(do.call(fun, c(params)), silent = TRUE) + } else { + res_fun <- try(do.call(fun, c(wb = wb_fun, params)), silent = TRUE) + } + + options("openxlsx2_seed" = NULL) + res_method <- try(do.call(wb_method[[method]], params), silent = TRUE) + + msg <- NULL + + if (inherits(res_fun, "try-error")) { + temp <- file() + writeLines(attr(res_fun, "condition")$message, temp) + bad <- paste0("# > ", readLines(temp)) + close(temp) + expr <- paste0("\n", deparse1(do.call(call, c(fun, c(wb = wb_fun, params))))) + msg <- c(msg, expr, bad) + } + + if (inherits(res_method, "try-error")) { + temp <- file() + writeLines(attr(res_method, "condition")$message, temp) + bad <- paste0("# > ", readLines(temp)) + close(temp) + expr <- paste0("\n", deparse1(do.call(call, c(method0, params)))) + # slight fix because we get those "`" which I don't want to see + expr <- sub(paste0("`", method0, "`"), method0, expr, fixed = TRUE) + msg <- c(msg, expr, bad) + } + + if (!is.null(msg)) { + # browser() + bad <- c("Failed to get results", msg) + testthat::fail(bad) + return(invisible()) + } + + for (i in ignore_fields) { + # remove the fields we don't want to check + res_method[[i]] <- NULL + res_fun[[i]] <- NULL + } + + # expectation that the results are the same + bad <- waldo::compare( + x = res_method, + y = res_fun, + x_arg = method0, + y_arg = fun, + ignore_attr = ignore_attr, + ignore_formula_env = TRUE + ) + + if (length(bad)) { + testthat::fail(bad) + return(invisible()) + } + } + + testthat::succeed() + return(invisible()) +} +# `expect_pseudo_wrapper()` ------- +#' A trimmed down pseudo wrapper to check internal wrapped functions. +#' @rdname expect_wrapper +expect_pseudo_wrapper <- function( + method, + fun = paste0("wb_", method) +) { + method_fun <- get(method, wbWorkbook$public_methods) + fun_fun <- match.fun(fun) + + method_forms <- as.list(formals(method_fun)) + fun_forms <- as.list(formals(fun_fun)) + + method_args <- names(method_forms) + fun_args <- names(fun_forms) + + ignore <- "xlsx_file" + + # remove ignores from fun + m <- match(ignore, fun_args, 0L) + if (!identical(m, 0L)) { + # remove wb from both the args and formals + fun_args <- fun_args[-m] + fun_forms <- fun_forms[-m] + } + + # remove ignores from method + m <- match(ignore, method_args, 0L) + if (!identical(m, 0L)) { + # remove wb from both the args and formals + method_args <- method_args[-m] + method_forms <- method_forms[-m] + } + + # expectation that the names are the same (possibly redundant but quicker to) + bad <- waldo::compare( + x = method_args, + y = setdiff(fun_args, "wb") + ) + + if (length(bad)) { + testthat::fail(bad) + return(invisible()) + } + + # expectation that the default values are the same + bad <- waldo::compare( + x = method_forms, + y = fun_forms + ) + + if (length(bad)) { + testthat::fail(bad) + return(invisible()) + } + + testthat::succeed() + return(invisible()) +} + +# Miscellaneous helpers for testthat ----------- expected_shared_strings <- function() { structure(c( @@ -710,11 +987,8 @@ expected_shared_strings <- function() { ), uniqueCount = "2114") } -#nocov start #' initiates testfiles in local testthat folder -#' @keywords internal -#' @noRd download_testfiles <- function() { fls <- c( @@ -774,8 +1048,6 @@ download_testfiles <- function() { #' provides testfile path for testthat #' @param x a file assumed in testfiles folder -#' @keywords internal -#' @noRd testfile_path <- function(x) { # apparently this runs in a different folder fl <- testthat::test_path("testfiles", x) @@ -785,5 +1057,3 @@ testfile_path <- function(x) { return(fl) } } - -#nocov end diff --git a/tests/testthat/test-conditional_formatting.R b/tests/testthat/test-conditional_formatting.R index 7f98d1001..fa41347b1 100644 --- a/tests/testthat/test-conditional_formatting.R +++ b/tests/testthat/test-conditional_formatting.R @@ -607,17 +607,17 @@ test_that("create dxfs style without font family and size", { exp <- "" got <- create_dxfs_style( font_color = wb_colour(hex = "FF9C0006"), - bgFill = wb_colour(hex = "FFFFC7CE") + bg_fill = wb_colour(hex = "FFFFC7CE") ) expect_equal(exp, got) # the fully fletched old default dxfs style exp <- "" got <- create_dxfs_style( - font_name = "Calibri", - font_size = 11, + font_name = "Calibri", + font_size = 11, font_color = wb_colour(hex = "FF9C0006"), - bgFill = wb_colour(hex = "FFFFC7CE") + bg_fill = wb_colour(hex = "FFFFC7CE") ) expect_equal(exp, got) diff --git a/tests/testthat/test-save.R b/tests/testthat/test-save.R index aa97eb4e0..e09c3d7c3 100644 --- a/tests/testthat/test-save.R +++ b/tests/testthat/test-save.R @@ -239,7 +239,7 @@ test_that("writing NA, NaN and Inf", { test_that("write cells without data", { temp <- temp_xlsx() - tmp <- temp_dir() + tmp_dir <- temp_dir() dat <- as.data.frame(matrix(NA, 2, 2)) wb <- wb_workbook()$ @@ -254,7 +254,7 @@ test_that("write cells without data", { wb$save(temp) - unzip(temp, exdir = tmp) + unzip(temp, exdir = tmp_dir) exp <- structure( list( @@ -280,7 +280,7 @@ test_that("write cells without data", { got <- wb$worksheets[[1]]$sheet_data$cc expect_equal(exp, got) - sheet <- paste0(tmp, "/xl/worksheets/sheet1.xml") + sheet <- paste0(tmp_dir, "/xl/worksheets/sheet1.xml") exp <- "" got <- xml_node(sheet, "worksheet", "sheetData") expect_equal(exp, got) diff --git a/vignettes/Update-from-openxlsx.Rmd b/vignettes/Update-from-openxlsx.Rmd index 99a54ecda..e05314ddf 100644 --- a/vignettes/Update-from-openxlsx.Rmd +++ b/vignettes/Update-from-openxlsx.Rmd @@ -15,36 +15,36 @@ library(openxlsx2) ## Basic read and write functions Welcome to the `openxlsx2` update vignette. In this vignette we will take some common code examples from `openxlsx` and show you how similar results can be replicated in `openxlsx2`. Thank you for taking a look, and let's get started. -While previous `openxlsx` functions used the `.` in function calls, as well as camel-case, we have tried to switch to snake-case (this is still a work in progress, there are still function arguments that use camel-case). +While previous `openxlsx` functions used the `.` in function calls, as well as camelCase, we have tried to switch to snake_case (this is still a work in progress, there may still be function arguments that use camelCase). ### Read xlsx or xlsm files The basic read function changed from `read.xlsx` to `read_xlsx`. Using a default xlsx file included in the package: ```{r read} -xlsxFile <- system.file("extdata", "openxlsx2_example.xlsx", package = "openxlsx2") +xlsx_file <- system.file("extdata", "openxlsx2_example.xlsx", package = "openxlsx2") ``` The old syntax looked like this: ```{r old_read, eval = FALSE} # read in openxlsx -openxlsx::read.xlsx(xlsxFile) +openxlsx::read.xlsx(xlsxFile = xlsx_file) ``` This has changed to this: ```{r new_read} # read in openxlsx2 -openxlsx2::read_xlsx(xlsxFile) +openxlsx2::read_xlsx(xlsx_file = xlsx_file) ``` -As you can see, we return the spreadsheet return codes (e.g., `#NUM`) in openxlsx2. Another thing to see above, we return the cell row as rowname for the data frame returned. `openxlsx2` should return a data frame of the selected size, even if it empty. If you preferred `readWorksheet()` this has become `wb_read()`. All of these are wrappers for the newly introduced function `wb_to_df()` which provides the most options. `read_xlsx()` and `wb_read()` were created for backward comparability. +As you can see, we return the spreadsheet return codes (e.g., `#NUM`) in openxlsx2. Another thing to see above, we return the cell row as rowname for the data frame returned. `openxlsx2` should return a data frame of the selected size, even if it empty. If you preferred `openxlsx::readWorkbook()` this has become `wb_read()`. All of these are wrappers for the newly introduced function `wb_to_df()` which provides the most options. `read_xlsx()` and `wb_read()` were created for backward comparability. ## Write xlsx files -Basic writing in `openxlsx2` behaves identical to `openxlsx`. Though be aware that `overwrite` is an optional parameter in `openxlsx2` and just like in other functions like `base::write.csv` if you write onto an existing file name, this file will be replaced. +Basic writing in `openxlsx2` behaves identical to `openxlsx`. Though be aware that `overwrite` is an optional parameter in `openxlsx2` and just like in other functions like `base::write.csv()` if you write onto an existing file name, this file will be replaced. Setting the output to some temporary xlsx file ```{r write} @@ -62,7 +62,7 @@ The new function looks quite similar: ```{r new_write} # write in openxlsx2 -openxlsx2::write_xlsx(iris, file = output, colNames = TRUE) +openxlsx2::write_xlsx(iris, file = output, col_names = TRUE) ``` @@ -75,13 +75,13 @@ Workbook functions have been renamed to begin with `wb_` there are plenty of the A major feature in `openxlsx` are workbooks. Obviously they remain a central piece in `openxlsx2`. Previous you would load them with: ```{r old_workbook, eval = FALSE} -wb <- loadWorkbook(xlsxFile) +wb <- openxlsx::loadWorkbook(file = xlsx_file) ``` In `openxlsx2` loading was changed to: ```{r workbook} -wb <- wb_load(xlsxFile) +wb <- wb_load(file = xlsx_file) ``` There are plenty of functions to interact with workbooks and we will not describe every single one here. A detailed list can be found over at [our references](https://janmarvin.github.io/openxlsx2/reference/index.html) @@ -91,8 +91,9 @@ There are plenty of functions to interact with workbooks and we will not describ One of the biggest user facing change was the removal of the `stylesObject`. In the following section we use code from [addStyle](https://ycphs.github.io/openxlsx/reference/addStyle.html) ```{r old_style, eval = FALSE} +# openxlsx ## Create a new workbook -wb <- createWorkbook("My name here") +wb <- createWorkbook(creator = "My name here") addWorksheet(wb, "Expenditure", gridLines = FALSE) writeData(wb, sheet = 1, USPersonalExpenditure, rowNames = TRUE) @@ -107,10 +108,11 @@ setColWidths(wb, 1, cols = 1, widths = 21) In `openxlsx2` the same code looks something like this: ```{r new_style} +# openxlsx2 chained border_color <- wb_color(hex = "FF4F81BD") -wb <- wb_workbook("My name here")$ - add_worksheet("Expenditure", gridLines = FALSE)$ - add_data(x = USPersonalExpenditure, rowNames = TRUE)$ +wb <- wb_workbook(creator = "My name here")$ + add_worksheet("Expenditure", grid_lines = FALSE)$ + add_data(x = USPersonalExpenditure, row_names = TRUE)$ add_border( # add the outer and inner border dims = "A1:F6", top_border = "thin", top_color = border_color, @@ -120,7 +122,7 @@ wb <- wb_workbook("My name here")$ )$ set_col_widths( # set column width cols = 1:6, - widths = c("20", rep("10", 5)) + widths = c(20, rep(10, 5)) )$ # remove the value in A1 add_data(dims = "A1", x = "") ``` @@ -130,10 +132,11 @@ The code above uses chaining. If you prefer piping, we provide the chained funct With pipes the code from above becomes ```{r new_style_pipes} +# openxlsx2 with pipes border_color <- wb_color(hex = "FF4F81BD") -wb <- wb_workbook("My name here") %>% - wb_add_worksheet("Expenditure", gridLines = FALSE) %>% - wb_add_data(x = USPersonalExpenditure, rowNames = TRUE) %>% +wb <- wb_workbook(creator = "My name here") %>% + wb_add_worksheet(sheet = "Expenditure", grid_lines = FALSE) %>% + wb_add_data(x = USPersonalExpenditure, row_names = TRUE) %>% wb_add_border( # add the outer and inner border dims = "A1:F6", top_border = "thin", top_color = border_color, @@ -143,7 +146,7 @@ wb <- wb_workbook("My name here") %>% ) %>% wb_set_col_widths( # set column width cols = 1:6, - widths = c("20", rep("10", 5)) + widths = c(20, rep(10, 5)) ) %>% # remove the value in A1 wb_add_data(dims = "A1", x = "") ``` @@ -151,6 +154,7 @@ wb <- wb_workbook("My name here") %>% Be aware that chains modify an object in place and pipes do not. ```{r pipe_chain} +# openxlsx2 wbp <- wb_workbook() %>% wb_add_worksheet() wbc <- wb_workbook()$add_worksheet() @@ -168,17 +172,17 @@ Additional examples regarding styles can be found in the styles vignette. Extended examples for conditional formatting can be found in the conditional formatting vignette. A minimal example is the following: ```{r new_cf} -# with chains +# openxlsx2 with chains wb <- wb_workbook()$ add_worksheet("a")$ - add_data(x = 1:4, colNames = FALSE)$ - add_conditional_formatting(cols = 1, rows = 1:4, rule = ">2") + add_data(x = 1:4, col_names = FALSE)$ + add_conditional_formatting(dims = "A1:A4", rule = ">2") -# with pipes +# openxlsx2 with pipes wb <- wb_workbook() %>% wb_add_worksheet("a") %>% - wb_add_data(x = 1:4, colNames = FALSE) %>% - wb_add_conditional_formatting(cols = 1, rows = 1:4, rule = ">2") + wb_add_data(x = 1:4, col_names = FALSE) %>% + wb_add_conditional_formatting(dims = "A1:A4", rule = ">2") ``` ### Data validation @@ -186,6 +190,7 @@ wb <- wb_workbook() %>% Similar data validation has been updated and improved. This `openxlsx` code for data validation ```{r old_dv, eval = FALSE} +# openxlsx wb <- createWorkbook() addWorksheet(wb, "Sheet 1") writeDataTable(wb, 1, x = iris[1:30, ]) @@ -198,21 +203,21 @@ dataValidation(wb, 1, looks in `openxlsx2` something like this: ```{r new_dv} -# with chains +# openxlsx2 with chains wb <- wb_workbook()$ add_worksheet("Sheet 1")$ add_data_table(1, x = iris[1:30, ])$ add_data_validation(1, - col = 1:3, rows = 2:31, type = "whole", + dims = "A2:C31", type = "whole", operator = "between", value = c(1, 9) ) -# with pipes +# openxlsx2 with pipes wb <- wb_workbook() %>% wb_add_worksheet("Sheet 1") %>% wb_add_data_table(1, x = iris[1:30, ]) %>% wb_add_data_validation(1, - col = 1:3, rows = 2:31, type = "whole", + dims = "A2:C31", type = "whole", operator = "between", value = c(1, 9) ) ``` diff --git a/vignettes/conditional-formatting.Rmd b/vignettes/conditional-formatting.Rmd index 449262002..8dae43de2 100644 --- a/vignettes/conditional-formatting.Rmd +++ b/vignettes/conditional-formatting.Rmd @@ -34,11 +34,10 @@ knitr::include_graphics("img/cf_cells.jpg") ```{r} wb$add_worksheet("cellIs") wb$add_data("cellIs", -5:5) -wb$add_data("cellIs", LETTERS[1:11], startCol = 2) +wb$add_data("cellIs", LETTERS[1:11], start_col = 2) wb$add_conditional_formatting( "cellIs", - cols = 1, - rows = 1:11, + dims = "A1:A11", rule = "!=0", style = "negStyle" ) @@ -53,25 +52,23 @@ wb$add_conditional_formatting( ## Highlight row dependent on first cell in row -```{r echo=FALSE, warning=FALSE} +```{r echo = FALSE, warning = FALSE} knitr::include_graphics("img/cf_moving_row.jpg") ``` ```{r} wb$add_worksheet("Moving Row") wb$add_data("Moving Row", -5:5) -wb$add_data("Moving Row", LETTERS[1:11], startCol = 2) +wb$add_data("Moving Row", LETTERS[1:11], start_col = 2) wb$add_conditional_formatting( "Moving Row", - cols = 1:2, - rows = 1:11, + dims = "A1:B11", rule = "$A1<0", style = "negStyle" ) wb$add_conditional_formatting( "Moving Row", - cols = 1:2, - rows = 1:11, + dims = "A1:B11", rule = "$A1>0", style = "posStyle" ) @@ -86,11 +83,10 @@ knitr::include_graphics("img/cf_moving_col.jpg") ```{r} wb$add_worksheet("Moving Col") wb$add_data("Moving Col", -5:5) -wb$add_data("Moving Col", LETTERS[1:11], startCol = 2) +wb$add_data("Moving Col", LETTERS[1:11], start_col = 2) wb$add_conditional_formatting( "Moving Col", - cols = 1:2, - rows = 1:11, + dims = "A1:B11", rule = "A$1<0", style = "negStyle" ) @@ -105,18 +101,17 @@ wb$add_conditional_formatting( ## Highlight entire range cols X rows dependent only on cell A1 -```{r echo=FALSE, warning=FALSE} +```{r echo = FALSE, warning = FALSE} knitr::include_graphics("img/cf_dependent_on.jpg") ``` ```{r} wb$add_worksheet("Dependent on") wb$add_data("Dependent on", -5:5) -wb$add_data("Dependent on", LETTERS[1:11], startCol = 2) +wb$add_data("Dependent on", LETTERS[1:11], start_col = 2) wb$add_conditional_formatting( "Dependent on", - cols = 1:2, - rows = 1:11, + dims = "A1:B11", rule = "$A$1 < 0", style = "negStyle" ) @@ -279,21 +274,19 @@ knitr::include_graphics("img/cf_databar.jpg") ```{r} wb$add_worksheet("databar") ## Databars -wb$add_data("databar", -5:5, startCol = 1) +wb$add_data("databar", -5:5, start_col = 1) wb <- wb_add_conditional_formatting( wb, "databar", - cols = 1, - rows = 1:11, + dims = "A1:A11", type = "dataBar" ) ## Default colors -wb$add_data("databar", -5:5, startCol = 3) +wb$add_data("databar", -5:5, start_col = 3) wb <- wb_add_conditional_formatting( wb, "databar", - cols = 3, - rows = 1:11, + dims = "C1:C11", type = "dataBar", params = list( showValue = FALSE, @@ -301,23 +294,21 @@ wb <- wb_add_conditional_formatting( ) ) ## Default colors -wb$add_data("databar", -5:5, startCol = 5) +wb$add_data("databar", -5:5, start_col = 5) wb <- wb_add_conditional_formatting( wb, "databar", - cols = 5, - rows = 1:11, + dims = "E1:E11", type = "dataBar", style = c("#a6a6a6"), params = list(showValue = FALSE) ) -wb$add_data("databar", -5:5, startCol = 7) +wb$add_data("databar", -5:5, start_col = 7) wb <- wb_add_conditional_formatting( wb, "databar", - cols = 7, - rows = 1:11, + dims = "G1:G11", type = "dataBar", style = c("red"), params = list( @@ -327,7 +318,7 @@ wb <- wb_add_conditional_formatting( ) # custom color -wb$add_data("databar", -5:5, startCol = 9) +wb$add_data("databar", -5:5, start_col = 9) wb <- wb_add_conditional_formatting( wb, "databar", @@ -339,7 +330,7 @@ wb <- wb_add_conditional_formatting( ) # with rule -wb$add_data(x = -5:5, startCol = 11) +wb$add_data(x = -5:5, start_col = 11) wb <- wb_add_conditional_formatting( wb, "databar", diff --git a/vignettes/openxlsx2_basic_manual.Rmd b/vignettes/openxlsx2.Rmd similarity index 85% rename from vignettes/openxlsx2_basic_manual.Rmd rename to vignettes/openxlsx2.Rmd index 155db95b5..2bf247541 100644 --- a/vignettes/openxlsx2_basic_manual.Rmd +++ b/vignettes/openxlsx2.Rmd @@ -30,107 +30,108 @@ For this example we will use example data provided by the package. You can locat ### Basic import We begin with the `openxlsx2_example.xlsx` file by telling R where to find this file on our system ```{r} -xlsxFile <- system.file("extdata", "openxlsx2_example.xlsx", package = "openxlsx2") +xlsx_file <- system.file("extdata", "openxlsx2_example.xlsx", package = "openxlsx2") ``` The object contains a path to the xlsx file and we pass this file to our function to read the workbook into R ```{r} # import workbook -wb_to_df(xlsxFile) +library(openxlsx2) +wb_to_df(xlsx_file) ``` The output is created as a data frame and contains data types date, logical, numeric and character. The function to import the file to R, `wb_to_df()` provides similar options as the `openxlsx` functions `read.xlsx()` and `readWorkbook()` and a few new functions we will go through the options. As you might have noticed, we return the column of the xlsx file as the row name of the data frame returned. Per default the first sheet in the workbook is imported. If you want to switch this, either provide the `sheet` parameter with the correct index or provide the sheet name. -### colNames - first row as column name +### `col_names` - first row as column name In the previous example the first imported row was used as column name for the data frame. This is the default behavior, but not always wanted or expected. Therefore this behavior can be disabled by the user. ```{r} -# do not convert first row to colNames -wb_to_df(xlsxFile, colNames = FALSE) +# do not convert first row to column names +wb_to_df(xlsx_file, col_names = FALSE) ``` -### detectDates - convert cells to R dates +### `detect_dates` - convert cells to R dates The creators of the openxml standard are well known for mistakenly treating something as a date and `openxlsx2` has built in ways to identify a cell as a date and will try to convert the value for you, but unfortunately this is not always a trivial task and might fail. In such a case we provide an option to disable the date conversion entirely. In this case the underlying numerical value will be returned. ```{r} # do not try to identify dates in the data -wb_to_df(xlsxFile, detectDates = FALSE) +wb_to_df(xlsx_file, detect_dates = FALSE) ``` -### showFormula - show formulas instead of results -Sometimes things might feel off. This can be because the openxml files are not updating formula results in the sheets unless they are opened in software that provides such functionality as certain tabular calculation software. Therefore the user might be interested in the underlying functions to see what is going on in the sheet. Using `showFormula` this is possible +### `show_formula` - show formulas instead of results +Sometimes things might feel off. This can be because the openxml files are not updating formula results in the sheets unless they are opened in software that provides such functionality as certain tabular calculation software. Therefore the user might be interested in the underlying functions to see what is going on in the sheet. Using `show_formula` this is possible ```{r} # return the underlying Excel formula instead of their values -wb_to_df(xlsxFile, showFormula = TRUE) +wb_to_df(xlsx_file, show_formula = TRUE) ``` -### dims - read specific dimension +### `dims` - read specific dimension Sometimes the entire worksheet contains to much data, in such case we provide functions to read only a selected dimension range. Such a range consists of either a specific cell like "A1" or a cell range in the notion used in the openxml standard ```{r} -# read dimension withot colNames -wb_to_df(xlsxFile, dims = "A2:C5", colNames = FALSE) +# read dimension withot column names +wb_to_df(xlsx_file, dims = "A2:C5", col_names = FALSE) ``` -### cols - read selected columns +### `cols` - read selected columns If you do not want to read a specific cell, but a cell range you can use the column attribute. This attribute takes a numeric vector as argument ```{r} # read selected cols -wb_to_df(xlsxFile, cols = c("A:B", "G")) +wb_to_df(xlsx_file, cols = c("A:B", "G")) ``` -### rows - read selected rows +### `rows` - read selected rows The same goes with rows. You can select them using numeric vectors ```{r} # read selected rows -wb_to_df(xlsxFile, rows = c(2, 4, 6)) +wb_to_df(xlsx_file, rows = c(2, 4, 6)) ``` -### convert - convert input to guessed type +### `convert` - convert input to guessed type In xml exists no difference between value types. All values are per default characters. To provide these as numerics, logicals or dates, `openxlsx2` and every other software dealing with xlsx files has to make assumptions about the cell type. This is especially tricky due to the notion of worksheets. Unlike in a data frame, a worksheet can have a wild mix of all types of data. Even though the conversion process from character to date or numeric is rather solid, sometimes the user might want to see the data without any conversion applied. This might be useful in cases where something unexpected happened or the import created warnings. In such a case you can look at the raw input data. If you want to disable date detection as well, please see the entry above. ```{r} # convert characters to numerics and date (logical too?) -wb_to_df(xlsxFile, convert = FALSE) +wb_to_df(xlsx_file, convert = FALSE) ``` -### skipEmptyRows - remove empty rows +### `skip_empty_rows` - remove empty rows Even though `openxlsx2` imports everything as requested, sometimes it might be helpful to remove empty lines from the data. These might be either left empty intentional or empty because they are were formatted, but the cell value was removed afterwards. This was added mostly for backward comparability, but the default has been changed to `FALSE`. The behavior has changed a bit as well. Previously empty cells were removed prior to the conversion to R data frames, now they are removed after the conversion and are removed only if they are completely empty ```{r} -# erase empty Rows from dataset -wb_to_df(xlsxFile, sheet = 1, skipEmptyRows = TRUE) |> tail() +# erase empty rows from dataset +wb_to_df(xlsx_file, sheet = 1, skip_empty_rows = TRUE) |> tail() ``` -### skipEmptyCols - remove empty columns +### `skip_empty_cols` - remove empty columns The same for columns ```{r} -# erase empty Cols from dataset -wb_to_df(xlsxFile, skipEmptyCols = TRUE) +# erase empty cols from dataset +wb_to_df(xlsx_file, skip_empty_cols = TRUE) ``` -### rowNames - keep rownames from input +### `row_names` - keep rownames from input Sometimes the data source might provide rownames as well. In such a case you can `openxlsx2` to treat the first column as rowname ```{r} # convert first row to rownames -wb_to_df(xlsxFile, sheet = 2, dims = "C6:G9", rowNames = TRUE) +wb_to_df(xlsx_file, sheet = 2, dims = "C6:G9", row_names = TRUE) ``` -### types - convert column to specific type +### `types` - convert column to specific type If the user know better than the software what type to expect in a worksheet, this can be provided via types. This parameter takes a named numeric. `0` is character, `1` is numeric and `2` is date ```{r} # define type of the data.frame -wb_to_df(xlsxFile, cols = c(2, 5), types = c("Var1" = 0, "Var3" = 1)) +wb_to_df(xlsx_file, cols = c(2, 5), types = c("Var1" = 0, "Var3" = 1)) ``` -### startRow - where to begin -Often the creator of the worksheet has used a lot of creativity and the data does not begin in the first row, instead it begins somewhere else. To define the row where to begin reading, define it via the `startRow` parameter +### `start_row` - where to begin +Often the creator of the worksheet has used a lot of creativity and the data does not begin in the first row, instead it begins somewhere else. To define the row where to begin reading, define it via the `start_row` parameter ```{r} # start in row 5 -wb_to_df(xlsxFile, startRow = 5, colNames = FALSE) +wb_to_df(xlsx_file, start_row = 5, col_names = FALSE) ``` -### na.strings - define missing values +### `na.strings` - define missing values There is the "#N/A" string, but often the user will be faced with custom missing values and other values we are not interested. Such strings can be passed as character vector via `na.strings` ```{r} -# na string -wb_to_df(xlsxFile, na.strings = "") +# na strings +wb_to_df(xlsx_file, na.strings = "") ``` ### Importing as workbook @@ -140,9 +141,9 @@ In addition to importing directly from xlsx or xlsm files, `openxlsx2` provides Importing a file into a workbook looks like this: ```{r} # the file we are going to load -xlsxFile <- system.file("extdata", "openxlsx2_example.xlsx", package = "openxlsx2") +xlsx_file <- system.file("extdata", "openxlsx2_example.xlsx", package = "openxlsx2") # loading the file into the workbook -wb <- wb_load(file = xlsxFile) +wb <- wb_load(file = xlsx_file) ``` The additional options `wb_load()` provides are for internal use: `sheet` loads only a selected sheet from the workbook and `data_only` reads only the data parts from a workbook and ignores any additional graphics or pivot tables. Both functions create workbook objects that can only be used to read data, and we do not recommend end users to use them. Especially not if they intend to re-export the workbook afterwards. @@ -156,10 +157,10 @@ Once a workbook is imported, we provide several functions to interact with and m If you want to export a data frame from R, you can use `write_xlsx()` which will create an xlsx file. This file can be tweaked further. The man page provides various options (further explanation and examples will follow). ```{r, eval = FALSE} -write_xlsx(mtcars, "mtcars.xlsx") +write_xlsx(x = mtcars, file = "mtcars.xlsx") ``` -### Exporting `wbWorkbooks` +### Exporting a `wbWorkbook` Imported workbooks can be saved as xlsx or xlsm files with the wrapper `wb_save()` or with `wb$save()`. Both functions take the filename and an optional `Overwrite` option. If the latter is set, an optional guard is provided to check if the file you want to write already exists. But be careful, this is optional. The default is to save the file and replace an existing file. Of course, in Windows, files that are locked (for example, if they were opened by another process) will not be replaced. @@ -167,7 +168,7 @@ Imported workbooks can be saved as xlsx or xlsm files with the wrapper `wb_save( # replace the existing file wb$save("mtcars.xlsx") -# do not overwrite the exisisting file +# do not overwrite the existing file try(wb$save("mtcars.xlsx", overwrite = FALSE)) ``` diff --git a/vignettes/openxlsx2_charts_manual.Rmd b/vignettes/openxlsx2_charts_manual.Rmd index 4561e158a..67a0e3626 100644 --- a/vignettes/openxlsx2_charts_manual.Rmd +++ b/vignettes/openxlsx2_charts_manual.Rmd @@ -53,7 +53,7 @@ library(ggplot2) print(ggplot(mtcars, aes(x = mpg, fill = as.factor(gear))) + ggtitle("Distribution of Gas Mileage") + - geom_density(alpha = I(.5))) + geom_density(alpha = 0.5)) # Add ggplot to the workbook wb$add_worksheet("add_plot")$ diff --git a/vignettes/openxlsx2_formulas_manual.Rmd b/vignettes/openxlsx2_formulas_manual.Rmd index ce82f26ac..b8d30bc52 100644 --- a/vignettes/openxlsx2_formulas_manual.Rmd +++ b/vignettes/openxlsx2_formulas_manual.Rmd @@ -25,13 +25,13 @@ This can be shown in a simple example: We have a spreadsheet with a formula `A1 ```{r} # Create artificial xlsx file -wb <- wb_workbook()$add_worksheet()$add_data(x = t(c(1, 1)), colNames = FALSE)$ +wb <- wb_workbook()$add_worksheet()$add_data(x = t(c(1, 1)), col_names = FALSE)$ add_formula(dims = "C1", x = "A1 + B1") # Users should never modify cc as shown here wb$worksheets[[1]]$sheet_data$cc$v[3] <- 2 # we expect a value of 2 -wb_to_df(wb, colNames = FALSE) +wb_to_df(wb, col_names = FALSE) ``` Now, lets assume we modify the data in cell `A1`. @@ -39,7 +39,7 @@ Now, lets assume we modify the data in cell `A1`. wb$add_data(x = 2) # we expect 3 -wb_to_df(wb, colNames = FALSE) +wb_to_df(wb, col_names = FALSE) ``` What happened? Even though we see cells `A1` and `B1` show a value of `2` and `1` our formula in `C1` was not updated. It still shows a value of `2`. This is because `openxlsx2` does not evaluate formulas and workbooks on a more general scale. In the open xml style the cell looks something like this: @@ -54,7 +54,7 @@ What happened? Even though we see cells `A1` and `B1` show a value of `2` and `1 And when we read from this cell, we always return the value of `v`. In this case it is obvious, but still wrong and it is a good idea to check if underlying fields contain formulas. ```{r} -wb_to_df(wb, colNames = FALSE, showFormula = TRUE) +wb_to_df(wb, col_names = FALSE, show_formula = TRUE) ``` If `openxlsx2` writes formulas, as shown in the examples below, the fields will be entirely blank. These fields will only be evaluated and filled, once the output file is opened in spreadsheet software. @@ -66,8 +66,8 @@ The only way to avoid surprises is to be aware of this all the time and similar, ```{r} wb <- wb_workbook()$add_worksheet()$ add_data(x = head(cars))$ - add_formula(dims = "D2", x = "SUM(A2, B2)")$ - add_formula(dims = "D3", x = "A2 + B2") + add_formula(x = "SUM(A2, B2)", dims = "D2")$ + add_formula(x = "A2 + B2", dims = "D3") # wb$open() ``` @@ -76,7 +76,7 @@ wb <- wb_workbook()$add_worksheet()$ ```{r} wb <- wb_workbook()$add_worksheet()$ add_data(x = head(cars))$ - add_formula(dims = "C2:C7", x = "A2:A7 * B2:B7", array = TRUE) + add_formula(x = "A2:A7 * B2:B7", dims = "C2:C7", array = TRUE) # wb$open() ``` @@ -91,7 +91,7 @@ m2 <- matrix(7:12, nrow = 2) wb <- wb_workbook()$add_worksheet()$ add_data(x = m1, startCol = 1)$ add_data(x = m2, startCol = 4)$ - add_formula(dims = "H2:J4", x = "MMULT(A2:B4, D2:F3)", array = TRUE) + add_formula(x = "MMULT(A2:B4, D2:F3)", dims = "H2:J4", array = TRUE) # wb$open() ``` @@ -101,18 +101,18 @@ Similar a the coefficients of a linear regression coef(lm(head(cars))) wb <- wb_workbook()$add_worksheet()$ add_data(x = head(cars))$ - add_formula(dims = "D2:E2", x = "LINEST(A2:A7, B2:B7, TRUE)", array = TRUE) + add_formula(x = "LINEST(A2:A7, B2:B7, TRUE)", dims = "D2:E2", array = TRUE) # wb$open() ``` -# cm formulas +# cells metadata (cm) formulas -Similar to array formulas, these cell metadata formulas hide to the user that they are array formulas. Using these is implemented in `openxlsx2` > 0.6.1: +Similar to array formulas, these cell metadata (cm) formulas hide to the user that they are array formulas. Using these is implemented in `openxlsx2` > 0.6.1: ```{r} wb <- wb_workbook()$add_worksheet()$ add_data(x = head(cars))$ - add_formula(dims = "D2", x = 'SUM(ABS(A2:A7))', cm = TRUE) + add_formula(x = "SUM(ABS(A2:A7))", dims = "D2", cm = TRUE) # wb$open() ``` @@ -121,51 +121,51 @@ wb <- wb_workbook()$add_worksheet()$ #### `dataTable` formula differences #### | | A | B | C | |---|-------------|------|---------------| -| 1 | SalesPrice | COGS | SalesQuantity | +| 1 | sales_price | COGS | sales_quantity| | 2 | 20 | 5 | 1 | | 3 | 30 | 11 | 2 | | 4 | 40 | 13 | 3 | -Given a basic table like the above, a similarly basic formula for "Total_Sales" would be "=A2 * C2" with the row value changing at each row. +Given a basic table like the above, a similarly basic formula for `total_sales` would be "= A2 * C2" with the row value changing at each row. -An implementation for this formula using `wb_add_formula()` would look this (taken from current documentation) lets say we've read in the data and assigned it to the table "company_sales" +An implementation for this formula using `wb_add_formula()` would look this (taken from current documentation) lets say we've read in the data and assigned it to the table `company_sales` ```{r} ## creating example data -example_data <- data.frame( - SalesPrice = c(20, 30, 40), +company_sales <- data.frame( + sales_price = c(20, 30, 40), COGS = c(5, 11, 13), - SalesQuantity = c(1, 2, 3) + sales_quantity = c(1, 2, 3) ) ## write in the formula -example_data$Total_Sales <- paste(paste0("A", 1:3 + 1L), paste0("C", 1:3 + 1L), sep = " + ") +company_sales$total_sales <- paste(paste0("A", 1:3 + 1L), paste0("C", 1:3 + 1L), sep = " * ") ## add the formula class -class(example_data$Total_Sales) <- c(class(example_data$Total_Sales), "formula") +class(company_sales$total_sales) <- c(class(company_sales$total_sales), "formula") ## write a workbook wb <- wb_workbook()$ add_worksheet("Total Sales")$ - add_data_table(x = example_data) + add_data_table(x = company_sales) ``` Then we create the workbook, worksheet, and use `wb_add_data_table()`. One of the advantages of the open xml `dataTable` syntax is that we don't have to specify row numbers or columns as letters. The table also grows dynamically, adding new rows as new data is appended and extending formulas to the new rows. These `dataTable` have named columns that we can use instead of letters. -When writing the formulas within the `dataTable` we would use the following syntax `[@[column_name]]` to reference the current row. So the "Total_Sales" formula written in open xml in `dataTable` would look like this; `=[@[SalesPrice]] * [@[SalesQuantity]]` +When writing the formulas within the `dataTable` we would use the following syntax `[@[column_name]]` to reference the current row. So the "total_sales" formula written in open xml in `dataTable` would look like this; `=[@[sales_price]] * [@[sales_quantity]]` -If we are writing the formula outside of the `dataTable` we have to reference the table name. In this case lets say the table name is 'daily_sales' `=daily_sales[@[SalesPrice]] * daily_sales[@[SalesQuantity]]` +If we are writing the formula outside of the `dataTable` we have to reference the table name. In this case lets say the table name is 'daily_sales' `=daily_sales[@[sales_price]] * daily_sales[@[sales_quantity]]` However, if we were to pass this as the text for the formula to be written it would cause an error because the syntax that open xml requires for selecting the current row is different. In open xml the `dataTable` formula looks like this: ``` - daily_sales[[#This Row],[SalesPrice]]*daily_sales[[#ThisRow],[SalesQuantity]] + daily_sales[[#This Row],[sales_price]]*daily_sales[[#ThisRow],[sales_quantity]] ``` -Now we can see that open xml replaces `[@[SalesPrice]]` with `daily_sales[[#This Row],[SalesPrice]]` We must then use this syntax when writing formulas for `dataTable` +Now we can see that open xml replaces `[@[sales_price]]` with `daily_sales[[#This Row],[sales_price]]` We must then use this syntax when writing formulas for `dataTable` ```{r} ## Because we want the `dataTable` formula to propagate down the entire column of the data @@ -174,30 +174,30 @@ Now we can see that open xml replaces `[@[SalesPrice]]` with `daily_sales[[#This ## creating example data example_data <- data.frame( - SalesPrice = c(20, 30, 40), + sales_price = c(20, 30, 40), COGS = c(5, 11, 13), - SalesQuantity = c(1, 2, 3) + sales_quantity = c(1, 2, 3) ) ## base R method -example_data$GrossProfit <- "daily_sales[[#This Row],[SalesPrice]] - daily_sales[[#This Row],[COGS]]" -example_data$Total_COGS <- "daily_sales[[#This Row],[COGS]] * daily_sales[[#This Row],[SalesQuantity]]" -example_data$Total_Sales <- "daily_sales[[#This Row],[SalesPrice]] * daily_sales[[#This Row],[SalesQuantity]]" -example_data$Total_GrossProfit <- "daily_sales[[#This Row],[Total_Sales]] - daily_sales[[#This Row],[Total_COGS]]" - -class(example_data$GrossProfit) <- c(class(example_data$GrossProfit), "formula") -class(example_data$Total_COGS) <- c(class(example_data$Total_COGS), "formula") -class(example_data$Total_Sales) <- c(class(example_data$Total_Sales), "formula") -class(example_data$Total_GrossProfit) <- c(class(example_data$Total_GrossProfit), "formula") +example_data$gross_profit <- "daily_sales[[#This Row],[sales_price]] - daily_sales[[#This Row],[COGS]]" +example_data$total_COGS <- "daily_sales[[#This Row],[COGS]] * daily_sales[[#This Row],[sales_quantity]]" +example_data$total_sales <- "daily_sales[[#This Row],[sales_price]] * daily_sales[[#This Row],[sales_quantity]]" +example_data$total_gross_profit <- "daily_sales[[#This Row],[total_sales]] - daily_sales[[#This Row],[total_COGS]]" + +class(example_data$gross_profit) <- c(class(example_data$gross_profit), "formula") +class(example_data$total_COGS) <- c(class(example_data$total_COGS), "formula") +class(example_data$total_sales) <- c(class(example_data$total_sales), "formula") +class(example_data$total_gross_profit) <- c(class(example_data$total_gross_profit), "formula") ``` ```{r} wb$ - add_worksheet('Daily Sales')$ + add_worksheet("Daily Sales")$ add_data_table( - x = example_data, - tableStyle = "TableStyleMedium2", - tableName = 'daily_sales' + x = example_data, + table_style = "TableStyleMedium2", + table_name = "daily_sales" ) ``` @@ -205,7 +205,7 @@ And if we open the workbook to view the table we created we can see that the for | | A | B | C |D|E|F|G| |---|-------------|------|---------------|-|-|-|-| -| 1 | SalesPrice | COGS | SalesQuantity |GrossProfit| Total_COGS| Total_Sales| Total_GrossProfit| +| 1 | sales_price | COGS | sales_quantity|gross_profit| total_COGS| total_sales| total_gross_profit| | 2 | 20 | 5 | 1 |15| 5| 20| 15| | 3 | 30 | 11 | 2 |19| 22| 60| 38| | 4 | 40 | 13 | 3 |27| 39| 120| 81| @@ -214,32 +214,32 @@ We can also see that it has replaced `[#This Row]` with `@`. | | A | B | C | D | E | F | G | |---|-------------|------|---------------|-------------------------|-------------------------------|-------------------------------------|------------------------------------| -| 1 | SalesPrice | COGS | SalesQuantity | GrossProfit | Total_COGS | Total_Sales | Total_GrossProfit | -| 2 | 20 | 5 | 1 |=[@SalesPrice] - [@COGS] | =[@COGS] \* [@SalesQuantity] | =[@SalesPrice] \* [@SalesQuantity] | =[@[Total\_Sales]] - [@[Total\_COGS]]| -| 3 | 30 | 11 | 2 |=[@SalesPrice] - [@COGS] | =[@COGS] \* [@SalesQuantity] | =[@SalesPrice] \* [@SalesQuantity] | =[@[Total\_Sales]] - [@[Total\_COGS]]| -| 4 | 40 | 13 | 3 |=[@SalesPrice] - [@COGS] | =[@COGS] \* [@SalesQuantity] | =[@SalesPrice] \* [@SalesQuantity] | =[@[Total\_Sales]] - [@[Total\_COGS]]| +| 1 | sales_price | COGS | sales_quantity | gross_profit | total_COGS | total_sales | total_gross_profit | +| 2 | 20 | 5 | 1 |=[@sales_price] - [@COGS] | =[@COGS] \* [@sales_quantity] | =[@sales_price] \* [@sales_quantity] | =[@[total\_sales]] - [@[total\_COGS]]| +| 3 | 30 | 11 | 2 |=[@sales_price] - [@COGS] | =[@COGS] \* [@sales_quantity] | =[@sales_price] \* [@sales_quantity] | =[@[total\_sales]] - [@[total\_COGS]]| +| 4 | 40 | 13 | 3 |=[@sales_price] - [@COGS] | =[@COGS] \* [@sales_quantity] | =[@sales_price] \* [@sales_quantity] | =[@[total\_sales]] - [@[total\_COGS]]| For completion, the formula as we wrote it appears as; | D | E | F | G | |-------------------------|-------------------------------|-------------------------------------|------------------------------------| -| GrossProfit | Total_COGS | Total_Sales | Total_GrossProfit | -|=grossprofit[[#This Row],[SalesPrice]] - grossprofit[[#This Row],[COGS]] | =grossprofit[[#This Row],[COGS]] \* grossprofit[[#This Row],[SalesQuantity]] | =grossprofit[[#This Row],[SalesPrice]] \* grossprofit[[#This Row],[SalesQuantity]] | =grossprofit[[#This Row],[Total\_Sales]] - grossprofit[[#This Row],[Total\_COGS]]| -|=grossprofit[[#This Row],[SalesPrice]] - grossprofit[[#This Row],[COGS]] | =grossprofit[[#This Row],[COGS]] \* grossprofit[[#This Row],[SalesQuantity]] | =grossprofit[[#This Row],[SalesPrice]] \* grossprofit[[#This Row],[SalesQuantity]] | =grossprofit[[#This Row],[Total\_Sales]] - grossprofit[[#This Row],[Total\_COGS]]| -|=grossprofit[[#This Row],[SalesPrice]] - grossprofit[[#This Row],[COGS]] | =grossprofit[[#This Row],[COGS]] \* grossprofit[[#This Row],[SalesQuantity]] | =grossprofit[[#This Row],[SalesPrice]] \* grossprofit[[#This Row],[SalesQuantity]] | =grossprofit[[#This Row],[Total\_Sales]] - grossprofit[[#This Row],[Total\_COGS]]| +| gross_profit | total_COGS | total_sales | total_gross_profit | +|=gross_profit[[#This Row],[sales_price]] - gross_profit[[#This Row],[COGS]] | =gross_profit[[#This Row],[COGS]] \* gross_profit[[#This Row],[sales_quantity]] | =gross_profit[[#This Row],[sales_price]] \* gross_profit[[#This Row],[sales_quantity]] | =gross_profit[[#This Row],[total\_sales]] - gross_profit[[#This Row],[total\_COGS]]| +|=gross_profit[[#This Row],[sales_price]] - gross_profit[[#This Row],[COGS]] | =gross_profit[[#This Row],[COGS]] \* gross_profit[[#This Row],[sales_quantity]] | =gross_profit[[#This Row],[sales_price]] \* gross_profit[[#This Row],[sales_quantity]] | =gross_profit[[#This Row],[total\_sales]] - gross_profit[[#This Row],[total\_COGS]]| +|=gross_profit[[#This Row],[sales_price]] - gross_profit[[#This Row],[COGS]] | =gross_profit[[#This Row],[COGS]] \* gross_profit[[#This Row],[sales_quantity]] | =gross_profit[[#This Row],[sales_price]] \* gross_profit[[#This Row],[sales_quantity]] | =gross_profit[[#This Row],[total\_sales]] - gross_profit[[#This Row],[total\_COGS]]| ```{r} #### sum dataTable examples -wb$add_worksheet('sum_examples') +wb$add_worksheet("sum_examples") ### Note: dataTable formula do not need to be used inside of dataTables. dataTable formula are for referencing the data within the dataTable. sum_examples <- data.frame( - description = c("sum_SalesPrice", "sum_product_Price_Quantity"), + description = c("sum_sales_price", "sum_product_Price_Quantity"), formula = c( - "sum(daily_sales[[#Data],[SalesPrice]])", - "sum(daily_sales[[#Data],[SalesPrice]] * daily_sales[[#Data],[SalesQuantity]])" + "sum(daily_sales[[#Data],[sales_price]])", + "sum(daily_sales[[#Data],[sales_price]] * daily_sales[[#Data],[sales_quantity]])" ) ) class(sum_examples$formula) <- c(class(sum_examples$formula), "formula") @@ -247,17 +247,17 @@ class(sum_examples$formula) <- c(class(sum_examples$formula), "formula") wb$add_data(x = sum_examples) #### dataTable referencing -wb$add_worksheet('dt_references') +wb$add_worksheet("dt_references") ### Adding the headers by themselves. wb$add_formula( - x = "daily_sales[[#Headers],[SalesPrice]:[Total_GrossProfit]]", + x = "daily_sales[[#Headers],[sales_price]:[total_gross_profit]]", ) ### Adding the raw data by reference and selecting them directly. wb$add_formula( - x = "daily_sales[[#Data],[SalesPrice]:[Total_GrossProfit]]", - startRow = 2 + x = "daily_sales[[#Data],[sales_price]:[total_gross_profit]]", + start_row = 2 ) # wb$open() ``` diff --git a/vignettes/openxlsx2_style_manual.Rmd b/vignettes/openxlsx2_style_manual.Rmd index ac7d79bf4..a9b2698de 100644 --- a/vignettes/openxlsx2_style_manual.Rmd +++ b/vignettes/openxlsx2_style_manual.Rmd @@ -101,12 +101,12 @@ wb$styles_mgr$add(new_font, "new_font") # create a new cell style, that uses the fill, the font and the border style new_cellxfs <- create_cell_style( - numFmtId = 0, + num_fmt_id = 0, horizontal = "center", - textRotation = 45, - fillId = wb$styles_mgr$get_fill_id("new_fill"), - fontId = wb$styles_mgr$get_font_id("new_font"), - borderId = wb$styles_mgr$get_border_id("new_border") + text_rotation = 45, + fill_id = wb$styles_mgr$get_fill_id("new_fill"), + font_id = wb$styles_mgr$get_font_id("new_font"), + border_id = wb$styles_mgr$get_border_id("new_border") ) # assign this style to the workbook wb$styles_mgr$add(new_cellxfs, "new_styles") @@ -126,7 +126,7 @@ x <- c( ) # create styles -new_cellxfs <- create_cell_style(numFmtId = x, horizontal = "center") +new_cellxfs <- create_cell_style(num_fmt_id = x, horizontal = "center") # assign the styles to the workbook for (i in seq_along(x)) { @@ -242,14 +242,14 @@ wb <- wb %>% wb_set_col_widths(cols = cols, widths = "auto") ```{r} wb <- wb_workbook() # full inner grid -wb$add_worksheet("S1", gridLines = FALSE)$add_data(x = mtcars) +wb$add_worksheet("S1", grid_lines = FALSE)$add_data(x = mtcars) wb$add_border( dims = "A2:K33", inner_hgrid = "thin", inner_hcolor = wb_color(hex = "FF808080"), inner_vgrid = "thin", inner_vcolor = wb_color(hex = "FF808080") ) # only horizontal grid -wb$add_worksheet("S2", gridLines = FALSE)$add_data(x = mtcars) +wb$add_worksheet("S2", grid_lines = FALSE)$add_data(x = mtcars) wb$add_border(dims = "A2:K33", inner_hgrid = "thin", inner_hcolor = wb_color(hex = "FF808080")) # only vertical grid wb$add_worksheet("S3", gridLines = FALSE)$add_data(x = mtcars) @@ -276,7 +276,7 @@ colnames(mat) <- make.names(seq_len(ncol(mat))) wb <- wb_workbook() %>% wb_add_worksheet("test") %>% - wb_add_data(x = mat, colNames = TRUE, startCol = 2, startRow = 2) %>% + wb_add_data(x = mat, col_names = TRUE, start_col = 2, start_row = 2) %>% # center first row wb_add_cell_style(dims = "B2:C2", horizontal = "center") %>% # add border for first row @@ -474,7 +474,7 @@ dx8 <- create_dxfs_style( wb <- wb_workbook() %>% - wb_add_worksheet(gridLines = FALSE) + wb_add_worksheet(grid_lines = FALSE) wb$add_style(dx0) wb$add_style(dx1) @@ -488,16 +488,16 @@ wb$add_style(dx8) # finally create the table xml <- create_tablestyle( - name = "red_table", - wholeTable = wb$styles_mgr$get_dxf_id("dx8"), - headerRow = wb$styles_mgr$get_dxf_id("dx7"), - totalRow = wb$styles_mgr$get_dxf_id("dx6"), - firstColumn = wb$styles_mgr$get_dxf_id("dx5"), - lastColumn = wb$styles_mgr$get_dxf_id("dx4"), - firstRowStripe = wb$styles_mgr$get_dxf_id("dx3"), - secondRowStripe = wb$styles_mgr$get_dxf_id("dx2"), - firstColumnStripe = wb$styles_mgr$get_dxf_id("dx1"), - secondColumnStripe = wb$styles_mgr$get_dxf_id("dx0") + name = "red_table", + whole_table = wb$styles_mgr$get_dxf_id("dx8"), + header_row = wb$styles_mgr$get_dxf_id("dx7"), + total_row = wb$styles_mgr$get_dxf_id("dx6"), + first_column = wb$styles_mgr$get_dxf_id("dx5"), + last_column = wb$styles_mgr$get_dxf_id("dx4"), + first_row_stripe = wb$styles_mgr$get_dxf_id("dx3"), + second_row_stripe = wb$styles_mgr$get_dxf_id("dx2"), + first_column_stripe = wb$styles_mgr$get_dxf_id("dx1"), + second_column_stripe = wb$styles_mgr$get_dxf_id("dx0") ) @@ -505,5 +505,5 @@ wb$add_style(xml) # create a table and apply the custom style wb <- wb %>% - wb_add_data_table(x = mtcars, tableStyle = "red_table") + wb_add_data_table(x = mtcars, table_style = "red_table") ```