diff --git a/DESCRIPTION b/DESCRIPTION index d09fd30..f9b5fcb 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: kwb.umberto Title: R package supporting UMERTO LCA at KWB -Version: 0.2.0 +Version: 0.2.0.9000 Authors@R: c( person("Michael", "Rustler", , "michael.rustler@kompetenz-wasser.de", role = c("aut", "cre"), comment = c(ORCID = "0000-0003-0647-7726")), @@ -20,11 +20,14 @@ Imports: ggforce, ggplot2, janitor, + jsonlite, + kwb.utils, magrittr, openxlsx, readr, tidyr, - tidyselect + tidyselect, + writexl Suggests: covr, knitr, @@ -32,8 +35,10 @@ Suggests: testthat (>= 3.0.0) VignetteBuilder: knitr +Remotes: + github::kwb-r/kwb.utils ByteCompile: true Encoding: UTF-8 LazyData: true -RoxygenNote: 7.2.2 +RoxygenNote: 7.3.1 Config/testthat/edition: 3 diff --git a/NAMESPACE b/NAMESPACE index c52aa8c..9138b7c 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -3,7 +3,9 @@ export("%>%") export(create_pivot_list) export(group_data) +export(import_json_files_to_excel) export(import_rawdata) +export(import_rawdata_json) export(pivot_data) export(plot_results) export(write_xlsx) @@ -18,6 +20,10 @@ importFrom(dplyr,select) importFrom(dplyr,summarise_at) importFrom(ggforce,facet_wrap_paginate) importFrom(janitor,clean_names) +importFrom(kwb.utils,hsOpenWindowsExplorer) +importFrom(kwb.utils,selectColumns) +importFrom(kwb.utils,stopFormatted) +importFrom(kwb.utils,substSpecialChars) importFrom(magrittr,"%>%") importFrom(openxlsx,write.xlsx) importFrom(readr,read_csv) @@ -25,3 +31,4 @@ importFrom(readr,read_csv2) importFrom(stats,setNames) importFrom(tidyr,spread) importFrom(tidyselect,all_of) +importFrom(writexl,write_xlsx) diff --git a/R/data_aggregation.R b/R/data_aggregation.R index 67851e1..e9ce955 100644 --- a/R/data_aggregation.R +++ b/R/data_aggregation.R @@ -25,22 +25,29 @@ #' umberto10_rawdata <- kwb.umberto::import_rawdata(csv_dir = umberto10_csv_dir) #' umberto10_data_grouped <- kwb.umberto::group_data(umberto10_rawdata) #' head(umberto10_data_grouped) -group_data <- function(raw_data, - grouping_paras = c("lci_method", "model", "process", "unit"), - grouping_function = "sum", - summarise_col = "quantity") { - +group_data <- function( + raw_data, + grouping_paras = c("lci_method", "model", "process", "unit"), + grouping_function = "sum", + summarise_col = "quantity" +) +{ summarise_col_fun <- function(summarise_col) { sprintf("%s_%s", summarise_col, grouping_function) } raw_data %>% - dplyr::group_by(dplyr::across(tidyselect::all_of(grouping_paras))) %>% - dplyr::rename_with(.fn = summarise_col_fun, - .cols = summarise_col) %>% - dplyr::summarise_at(.vars = summarise_col_fun(summarise_col), - .funs = grouping_function) - + dplyr::group_by( + dplyr::across(tidyselect::all_of(grouping_paras)) + ) %>% + dplyr::rename_with( + .fn = summarise_col_fun, + .cols = summarise_col + ) %>% + dplyr::summarise_at( + .vars = summarise_col_fun(summarise_col), + .funs = grouping_function + ) } @@ -75,15 +82,19 @@ group_data <- function(raw_data, #' umberto10_data_pivot <- kwb.umberto::pivot_data(umberto10_data_grouped) #' head(umberto10_data_pivot) #' -pivot_data <- function(rawdata_grouped, - cols_to_ignore = "unit", - key_col = "model", - value_col = "quantity_sum") { - +pivot_data <- function( + rawdata_grouped, + cols_to_ignore = "unit", + key_col = "model", + value_col = "quantity_sum" +) +{ rawdata_grouped %>% - dplyr::select(tidyselect::all_of(setdiff(names(rawdata_grouped), - cols_to_ignore)) - ) %>% + dplyr::select( + tidyselect::all_of( + setdiff(names(rawdata_grouped), cols_to_ignore) + ) + ) %>% tidyr::spread(key = key_col, value = value_col) } @@ -91,9 +102,13 @@ pivot_data <- function(rawdata_grouped, #' #' @param pivot_data privot data as retrieved from function pivot_data() #' @param arrange_cols columns used for arranging the data (default: "process") +#' @param method_col name of the column containing the method +#' (default: "lci_method"). Depending on your Umberto version you may need to +#' set method_col to "lcia_method". #' @return a list of results, where each element contains the result table for #' one lci_method #' @importFrom dplyr right_join arrange +#' @importFrom kwb.utils selectColumns #' @export #' @examples #' @@ -115,26 +130,37 @@ pivot_data <- function(rawdata_grouped, #' umberto10_data_pivot_list <- kwb.umberto::create_pivot_list(umberto10_data_pivot) #' head(umberto10_data_pivot_list) #' -create_pivot_list <- function(pivot_data, - arrange_cols = "process") { +create_pivot_list <- function( + pivot_data, + arrange_cols = "process", + method_col = "lci_method" +) +{ + method_vector <- kwb.utils::selectColumns(pivot_data, method_col) - myList <- list() - lci_methods <- unique(pivot_data$lci_method) - for (i in seq_along(lci_methods)) { - - selected_lci_method <- unique(pivot_data$lci_method)[i] - - processes <- data.frame(lci_method = selected_lci_method, - process = unique(pivot_data$process), - stringsAsFactors = FALSE) - - - tmp_data <- pivot_data[pivot_data$lci_method == selected_lci_method,] %>% - dplyr::right_join(processes) %>% - dplyr::arrange_(arrange_cols) - - myList[[i]] <- tmp_data - } - names(myList) <- sprintf("lci_method%d", seq_along(lci_methods)) - return(myList) -} \ No newline at end of file + methods <- unique(method_vector) + + indices <- seq_along(methods) + + lapply( + X = indices, + FUN = function(i) { + + selected_lci_method <- methods[i] + + processes <- data.frame( + METHOD = selected_lci_method, + process = unique(kwb.utils::selectColumns(pivot_data, "process")), + stringsAsFactors = FALSE + ) %>% + kwb.utils::renameColumns(list( + METHOD = method_col + )) + + pivot_data[method_vector == selected_lci_method, ] %>% + dplyr::right_join(processes) %>% + dplyr::arrange(arrange_cols) + } + ) %>% + stats::setNames(sprintf("%s%d", method_col, indices)) +} diff --git a/R/excel_export.R b/R/excel_export.R index c8afa40..eee1ec8 100644 --- a/R/excel_export.R +++ b/R/excel_export.R @@ -1,4 +1,5 @@ #' Write results to EXCEL +#' #' @param data_pivot_list a list as retrieved by function create_pivot_list() #' @param path relative or full path to be used for exporting the results to #' EXCEL (default: "results.xlsx") @@ -27,10 +28,7 @@ #' export_path <- file.path(getwd(), "umberto10_results.xlsx") #' print(sprintf("Exporting aggregated results to %s", export_path)) #' write_xlsx(umberto10_data_pivot_list, path = export_path) -write_xlsx <- function(data_pivot_list, - path = "results.xlsx") { - - openxlsx::write.xlsx(data_pivot_list, - file = path) - -} \ No newline at end of file +write_xlsx <- function(data_pivot_list, path = "results.xlsx") +{ + openxlsx::write.xlsx(data_pivot_list, file = path) +} diff --git a/R/flatten.R b/R/flatten.R new file mode 100644 index 0000000..59cbed7 --- /dev/null +++ b/R/flatten.R @@ -0,0 +1,102 @@ +if (FALSE) +{ + xx <- kwb.umberto:::read_json_files("~/../Downloads/S/support/fabian/R-Umberto/Umberto11//") + library(magrittr) + + is_list <- sapply(xx[[1]], is.list) + + results <- lapply(xx[[1]][is_list], flatten) + + r2 <- fhpredict:::flatten_recursive_list(xx[[1]]$products) +} + +# flatten ---------------------------------------------------------------------- +flatten <- function(x, name = NULL, sep = "|") +{ + # x must be a list + check_for_list(x) + + # If the list is empty, return NULL + if (length(x) == 0L) { + return(NULL) + } + + # Are the list entries lists themselves? + is_list <- sapply(x, is.list) + + # Are the list elements named? + is_named <- !is.null(names(x)) + + # If no element is a list and all elements are of length one we return x, + # converted to a data frame + if (!any(is_list) && all(lengths(x) == 1L)) { + + # If the elements are named, each element becomes a column + if (is_named) { + return(do.call(kwb.utils::noFactorDataFrame, x)) + } + + # Otherwise, the "name" argument must be given. It is used as column name + # of the returned data frame + stopifnot(!is.null(name)) + + # List elements are concatenated with a separator to one string value + result <- kwb.utils::noFactorDataFrame(do.call(paste, c(x, sep = sep))) + + # Name the (one and only) column + return(stats::setNames(result, name)) + } + + # If the elements are not named, flatten and row-bind them + if (!is_named) { + + stopifnot(all(sapply(x, is.list))) + stopifnot(all_have_identical_names(x)) + return(do.call(rbind, lapply(x, flatten, name = name, sep = sep))) + } + + # Get the part that is already flat (get_flat_part(x)) + part_1 <- do.call( + data.frame, + replace_null_with_na(x[!is_list]) + ) + + # Names of the other elements (that are lists) + elements <- names(which(is_list)) + + # Loop through these elements, flatten them + part_2_tables <- elements %>% + lapply(function(name) flatten(x[[name]], name = name, sep = sep)) %>% + stats::setNames(elements) + + n_tables <- length(part_2_tables) + + # and row-bind them + part_2 <- if (n_tables > 1L) { + + #do.call(rbind, part_2_tables) + + # Find a column name that does not yet exist + name_column <- kwb.utils::hsSafeName( + paste(elements, collapse = "_"), + names(part_2_tables[[1L]]) + ) + + kwb.utils::rbindAll(part_2_tables, name_column) + + } else if (n_tables == 1L) { + + part_2_tables[[1L]] + + } # else NULL + + if (is.null(part_2)) { + return(part_1) + } + + # We expect part_1 to have one row + check_for_exactly_one_row(part_1) + + # Consider that part_2 may have no rows! + cbind(part_1[rep.int(1L, nrow(part_2)), , drop = FALSE], part_2) +} diff --git a/R/helpers.R b/R/helpers.R new file mode 100644 index 0000000..cec6263 --- /dev/null +++ b/R/helpers.R @@ -0,0 +1,11 @@ +# remove_xid ------------------------------------------------------------------- +remove_xid <- function(df) +{ + kwb.utils::removeColumns(df, "X.id") +} + +# remove_uuid ------------------------------------------------------------------ +remove_uuid <- function(df) +{ + kwb.utils::removeColumns(df, "uuid") +} diff --git a/R/import_json_files_to_excel.R b/R/import_json_files_to_excel.R new file mode 100644 index 0000000..ada519c --- /dev/null +++ b/R/import_json_files_to_excel.R @@ -0,0 +1,134 @@ +# import_json_files_to_excel --------------------------------------------------- + +#' Import JSON files to Excel File +#' +#' @param json_dir path to directory containing .json files +#' @param file path to Excel file to be created. Default: +#' \code{"umberto-results.xlsx"} within \code{json_dir} +#' @param overwrite whether or not to overwrite the Excel \code{file} if it +#' exists. Default: \code{FALSE}. +#' @param open logical indicating whether or not to open the created Excel file +#' @param expand_keys If this argument is not \code{NULL} but a vector of (key) +#' column names, all sheets are expanded to the same number of rows. All +#' possible combinations of values in these key columns are then given in each +#' sheet even though there are no values for these key value combinations. +#' Default: \code{c("indicator", "process", "place", "exchange")} +#' @return path to created Excel file +#' @importFrom kwb.utils hsOpenWindowsExplorer substSpecialChars +#' @importFrom writexl write_xlsx +#' @export +import_json_files_to_excel <- function( + json_dir, + file = file.path(json_dir, "umberto-results.xlsx"), + overwrite = FALSE, + open = TRUE, + expand_keys = c("process", "place", "exchange") +) +{ + #kwb.utils::assignPackageObjects("kwb.umberto");`%>%` <- magrittr::`%>%` + + sheets <- json_dir %>% + import_rawdata_json(add_place = TRUE, old_format = FALSE) %>% + get_core_data() %>% + core_data_to_wide() %>% + split_by_columns("indicator") + + names(sheets) <- sprintf("m%02d", seq_along(sheets)) + + if (!is.null(expand_keys)) { + sheets <- expand_to_all_key_combinations(sheets, keys = expand_keys) + } + + file_exists <- file.exists(file) + quoted_file <- dQuote(file, '"') + + if (file_exists && !overwrite) { + stop( + "The Excel file exists:\n ", + quoted_file, + "\nPlease choose another file name or set overwrite = TRUE.", + call. = FALSE + ) + } + + kwb.utils::catAndRun( + paste( + ifelse(file_exists, "Overwriting", "Writing"), + "Excel file", + quoted_file + ), + writexl::write_xlsx(sheets, file) + ) + + if (open) { + try(kwb.utils::hsOpenWindowsExplorer(path.expand(file))) + } + + file +} + +# get_core_data ---------------------------------------------------------------- +get_core_data <- function(data) +{ + result <- kwb.utils::renameAndSelect(data, list( + model = "model", + process_name = "process", + place_name = "place", + entry_exchange = "exchange", + indicator_name = "indicator", + product_quantity = "quantity", + product_unit = "unit" + )) + + result <- result[!grepl("^Connection", result$place), ] + + duplicates <- kwb.utils::findPartialDuplicates( + result, setdiff(names(result), "quantity") + ) + + stopifnot(is.null(duplicates)) + + result +} + +# core_data_to_wide ------------------------------------------------------------ +core_data_to_wide <- function(data) +{ + data %>% + tidyr::pivot_wider( + id_cols = c( + "indicator", + "process", + "place", + "exchange", + "unit" + ), + names_from = "model", + values_from = "quantity" + ) %>% + kwb.utils::orderBy(c( + "indicator", + "process", + "place", + "exchange" + )) +} + +# expand_to_all_key_combinations ----------------------------------------------- +expand_to_all_key_combinations <- function(sheets, keys) +{ + level_combis <- unique(do.call(rbind, lapply( + sheets, + FUN = function(sheet) unique(kwb.utils::selectColumns(sheet, keys)) + ))) + + lapply(sheets, function(y) { + indicator <- unique(kwb.utils::selectColumns(y, "indicator")) + stopifnot(length(indicator) == 1L) + dplyr::left_join( + x = data.frame(indicator = indicator, level_combis), + y = y, + by = c("indicator", keys) + ) + }) +} diff --git a/R/import_rawdata.R b/R/import_rawdata.R index 4b06a40..0a2ae19 100644 --- a/R/import_rawdata.R +++ b/R/import_rawdata.R @@ -81,25 +81,29 @@ stop_on_differing_names <- function(x) stopifnot(is.list(x), all(sapply(x, is.data.frame))) # Return if there are not at least two data frames - if (length(x) < 2) { - + if (length(x) < 2L) { return() } # Get the column names of the first data frame of the list - names_1 <- names(x[[1]]) + columns_of_first <- names(x[[1L]]) + + # Names of data frames in list x + df_names <- names(x) + is_empty <- df_names == "" + df_names[is_empty] <- sprintf("", which(is_empty)) # Compare with the column names of the other data frames - for (i in seq_along(x)[-1]) { + for (i in seq_along(df_names)[-1L]) { - names_i <- names(x[[i]]) + columns_of_current <- names(x[[i]]) - if (! identical(names_1, names_i)) { - + if (!identical(columns_of_first, columns_of_current)) { + pasted <- function(x) paste(x, collapse = ", ") stop_( - "There are differing column names:\n", - " ", names(x)[1], ": ", paste(names_1, collapse = ", "), - "\n ", names(x)[i], ": ", paste(names_i, collapse = ", ") + "There are differing column names:", + "\n ", df_names[1L], ": ", pasted(columns_of_first), + "\n ", df_names[i], ": ", pasted(columns_of_current) ) } } diff --git a/R/import_rawdata_json.R b/R/import_rawdata_json.R new file mode 100644 index 0000000..bc7c155 --- /dev/null +++ b/R/import_rawdata_json.R @@ -0,0 +1,119 @@ +if (FALSE) +{ + #remotes::install_github("kwb-r/kwb.umberto@dev") + + json_dir <- "~/../Downloads/S/support/fabian/R-Umberto/Umberto11" + json_dir <- "~/../Downloads/S/support/lea/umberto" + json_dir <- "Y:/WWT_Department/Projects/Ultimate/Data_Work-packages/WP2-assessments/CS9_Kalundborg/LCAumberto11" + + result_file <- kwb.umberto:::import_json_files_to_excel(json_dir, file = tempfile(fileext = ".xlsx")) + + files <- dir(json_dir, "\\.json$", full.names = TRUE) + + result_old_with_place <- kwb.umberto:::import_rawdata_json( + json_dir, + add_place = TRUE + ) + + results <- lapply(files, FUN = function(file) { + kwb.umberto:::import_rawdata_json(files = file, add_place = TRUE) + }) + + contents <- kwb.umberto:::read_json_files(json_dir) + + #jsTree::jsTree +} + +# import_rawdata_json ---------------------------------------------------------- + +#' Import Umberto results from .json files +#' +#' @param json_dir path to directory containing .json files. All .json files +#' will be read. +#' @param old_format if TRUE (the default) the same columns are provided that +#' are provided by \code{\link{import_rawdata}} that imports .csv files +#' @param add_place With add_place = TRUE, the "place" is contained in the +#' result even if old_format = TRUE +#' @param files optional. If given and not \code{NULL} this is expected to be a +#' vector of character with the full paths to the \code{.json} files to be +#' read. +#' @return data frame +#' @export +import_rawdata_json <- function( + json_dir, + old_format = TRUE, + add_place = FALSE, + files = NULL +) +{ + #kwb.utils::assignPackageObjects("kwb.umberto");files = NULL + contents <- read_json_files(json_dir, files = files) + + result_tables <- lapply(contents, to_tables) + + data_frames <- lapply(result_tables, merge_json_tables) + + result <- kwb.utils::rbindAll(data_frames, nameColumn = "model") + + if (!old_format) { + return(result) + } + + fetch <- kwb.utils::createAccessor(result) + + result <- data.frame( + project = "not-used", + model = fetch("model"), + net = "not-used", + timestamp = fetch("timestamp"), + product = "not-used", + product_name = fetch("ref_flow_exchange"), + product_arrow = fetch("product_arrow"), + product_flow_amount = fetch("product_amount"), + lcia_method = fetch("indicator_name"), + phase = "not-used", + process = fetch("process_name"), + material_type = fetch("entry_materialType"), + material = "not-used", + quantity = fetch("product_quantity"), + unit = fetch("product_unit"), + scenario = fetch("scenario_name") + ) + + if (add_place) { + result <- cbind(result, place = fetch("place_name")) + } + + result +} + +# read_json_files -------------------------------------------------------------- +read_json_files <- function(json_dir, files = NULL) +{ + if (is.null(files)) { + files <- list_json_files_or_stop(json_dir) + } + + files %>% + lapply(jsonlite::read_json) %>% + stats::setNames(basename(files)) +} + +# list_json_files_or_stop ------------------------------------------------------ +#' @importFrom kwb.utils stopFormatted +list_json_files_or_stop <- function(json_dir) +{ + json_files <- list.files( + json_dir, + pattern = "\\.json$", + full.names = TRUE + ) + + if (length(json_files) < 1L) { + kwb.utils::stopFormatted( + "No result files (*.json) in folder '%s/'", json_dir + ) + } + + json_files +} diff --git a/R/merge_json_tables.R b/R/merge_json_tables.R new file mode 100644 index 0000000..ef98842 --- /dev/null +++ b/R/merge_json_tables.R @@ -0,0 +1,70 @@ +# merge_json_tables ------------------------------------------------------------ +merge_json_tables <- function(tables) +{ + fetch <- kwb.utils::createAccessor(tables) + + fetch("products") %>% + dplyr::left_join( + kwb.utils::selectColumns(fetch("entries"), c( + "entry_id", + "entry_exchange", + "entry_unit" + )), + by = c(product_entryId = "entry_id") + ) %>% + kwb.utils::renameColumns(list( + entry_exchange = "ref_flow_exchange", + entry_unit = "ref_flow_unit" + )) %>% + dplyr::left_join( + fetch("entries"), + by = c(product_lciaEntryId = "entry_id") + ) %>% + dplyr::left_join( + fetch("scenarios"), + by = c(product_scenarioId = "scenario_id") + ) %>% + dplyr::left_join( + fetch("indicators"), + by = c(product_indicatorId = "indicator_id") + ) %>% + dplyr::left_join( + fetch("processes"), + by = c(product_processId = "process_id") + ) %>% + dplyr::left_join( + fetch("places"), + by = c(product_placeId = "place_id") + ) %>% + kwb.utils::moveColumnsToFront(c( + "scenario_name" + , "ref_flow_exchange" + , "product_amount" + , "ref_flow_unit" + , "product_arrow" + , "indicator_indicatorPath" + , "indicator_name" + , "process_name" + , "place_name" + , "entry_exchange" + , "entry_exchangeContext" + , "product_quantity" + , "product_unit" + , "entry_materialType" + , "product_side" + , "entry_costItemGroup" + , "entry_exchangeBoundary" + )) %>% + cbind(timestamp = kwb.utils::getAttribute(tables, "timestamp")) %>% + move_id_columns_right() +} + +# move_id_columns_right -------------------------------------------------------- +move_id_columns_right <- function(df) +{ + columns <- names(df) + + is_id <- grepl("(Id|Index)$", columns) + + df[, c(columns[!is_id], columns[is_id]), drop = FALSE] +} diff --git a/R/to_tables.R b/R/to_tables.R new file mode 100644 index 0000000..734dec0 --- /dev/null +++ b/R/to_tables.R @@ -0,0 +1,100 @@ +# to_tables -------------------------------------------------------------------- +to_tables <- function(content) +{ + #content <- contents[[1L]] + + # Try this general function for the list-type elements + # kwb.umberto:::flatten(content$products) + # kwb.umberto:::flatten(content$entries) + # kwb.umberto:::flatten(content$lifeCycleStages) + # ... + + fetch <- kwb.utils::createAccessor(content) + + products <- fetch("products") %>% + convert_and_bind(to_product) %>% + prefix_columns("product_") + + # products2 <- fetch("products") %>% + # flatten() %>% + # ... + # check_identity(products, products2) + + entries <- fetch("entries") %>% + flatten() %>% + kwb.utils::removeColumns(pattern = "(\\.i|I)d$") %>% + kwb.utils::removeColumns("exchangeFullName") %>% + prefix_columns("entry_") + + processes <- fetch("processes") %>% + flatten() %>% + remove_xid() %>% + prefix_columns("process_") + + places <- fetch("places") %>% + flatten() %>% + remove_xid() %>% + prefix_columns("place_") + + indicators <- fetch("indicators") %>% + flatten(sep = "->") %>% + remove_uuid() %>% + kwb.utils::renameColumns(list(path = "indicatorPath")) %>% + prefix_columns("indicator_") + + scenarios <- fetch("scenarios") %>% + flatten() %>% + remove_xid() %>% + prefix_columns("scenario_") + + evaluationMethods <- fetch("evaluationMethods") %>% + flatten() %>% + remove_xid() %>% + remove_uuid() %>% + prefix_columns("evaluationMethod_") + + result <- list( + products = products, + entries = entries, + processes = processes, + places = places, + indicators = indicators, + scenarios = scenarios, + evaluationMethods = evaluationMethods + ) + + structure( + result, + timestamp = fetch("timestamp") + ) +} + +# to_product ------------------------------------------------------------------- +to_product <- function(x) +{ + #x <- contents[[1]]$products[[1]] + + flat <- get_flat_part(x) + + lcia_list <- get_remaining(x, flat) %>% + remove_zero_length_entries() %>% + kwb.utils::selectElements("lcia") + + #str(lcia_list) + + lcia <- lcia_list %>% + flatten() %>% + kwb.utils::renameColumns(list( + entryId = "lciaEntryId", + inputs_outputs_internals = "side" + )) + + lcia$side <- gsub("s$", "", lcia$side) + + part_1 <- remove_uuid(flat) + + # We expect part_1 to have one row + check_for_exactly_one_row(part_1) + + cbind(part_1[rep.int(1L, nrow(lcia)), , drop = FALSE], lcia) +} diff --git a/R/utils.R b/R/utils.R new file mode 100644 index 0000000..b6eb494 --- /dev/null +++ b/R/utils.R @@ -0,0 +1,98 @@ +# all_have_identical_names ----------------------------------------------------- +all_have_identical_names <- function(x) +{ + suppressMessages(kwb.utils::allAreIdentical(lapply(x, names))) +} + +# check_for_data_frame --------------------------------------------------------- +check_for_data_frame <- function(x) +{ + stopifnot(is.data.frame(x)) +} + +# check_for_exactly_one_row ---------------------------------------------------- +check_for_exactly_one_row <- function(date) +{ + stopifnot(nrow(date) == 1L) +} + +# check_for_list --------------------------------------------------------------- +check_for_list <- function(x) +{ + stopifnot(is.list(x)) +} + +# check_identity --------------------------------------------------------------- +check_identity <- function(x, y) +{ + is_identical <- identical(x, y) + + kwb.utils::printIf(!is_identical, x, caption = deparse(substitute(x))) + kwb.utils::printIf(!is_identical, y, caption = deparse(substitute(y))) + + stopifnot(is_identical) +} + +# convert_and_bind ------------------------------------------------------------- +convert_and_bind <- function(x_list, converter) +{ + lapply(x_list, converter) %>% + kwb.utils::safeRowBindAll() +} + +# get_flat_part ---------------------------------------------------------------- +get_flat_part <- function(x) +{ + check_for_list(x) + + is_flat <- lengths(x) == 1L & !sapply(x, is.list) + + if (!any(is_flat)) { + return(NULL) + } + + as.data.frame(x[is_flat]) +} + +# get_remaining ---------------------------------------------------------------- +get_remaining <- function(x, flat_part) +{ + check_for_list(x) + check_for_data_frame(flat_part) + + x[setdiff(names(x), names(flat_part))] +} + +# prefix_columns --------------------------------------------------------------- +prefix_columns <- function(df, prefix = deparse(substitute(df))) +{ + check_for_data_frame(df) + + stats::setNames(df, paste0(prefix, names(df))) +} + +# remove_zero_length_entries --------------------------------------------------- +remove_zero_length_entries <- function(x) +{ + check_for_list(x) + + x[lengths(x) > 0L] +} + +# replace_null_with_na --------------------------------------------------------- +replace_null_with_na <- function(x) +{ + stopifnot(is.list(x)) + + is_null <- sapply(x, is.null) + + x[is_null] <- as.list(rep(NA, sum(is_null))) + + x +} + +# split_by_columns ------------------------------------------------------------- +split_by_columns <- function(data, columns) +{ + split(x = data, f = kwb.utils::selectColumns(data, columns)) +} diff --git a/man/create_pivot_list.Rd b/man/create_pivot_list.Rd index 8249f8d..c116c0c 100644 --- a/man/create_pivot_list.Rd +++ b/man/create_pivot_list.Rd @@ -4,12 +4,20 @@ \alias{create_pivot_list} \title{Create pivot list} \usage{ -create_pivot_list(pivot_data, arrange_cols = "process") +create_pivot_list( + pivot_data, + arrange_cols = "process", + method_col = "lci_method" +) } \arguments{ \item{pivot_data}{privot data as retrieved from function pivot_data()} \item{arrange_cols}{columns used for arranging the data (default: "process")} + +\item{method_col}{name of the column containing the method +(default: "lci_method"). Depending on your Umberto version you may need to +set method_col to "lcia_method".} } \value{ a list of results, where each element contains the result table for diff --git a/man/import_json_files_to_excel.Rd b/man/import_json_files_to_excel.Rd new file mode 100644 index 0000000..02e0f95 --- /dev/null +++ b/man/import_json_files_to_excel.Rd @@ -0,0 +1,37 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/import_json_files_to_excel.R +\name{import_json_files_to_excel} +\alias{import_json_files_to_excel} +\title{Import JSON files to Excel File} +\usage{ +import_json_files_to_excel( + json_dir, + file = file.path(json_dir, "umberto-results.xlsx"), + overwrite = FALSE, + open = TRUE, + expand_keys = c("process", "place", "exchange") +) +} +\arguments{ +\item{json_dir}{path to directory containing .json files} + +\item{file}{path to Excel file to be created. Default: +\code{"umberto-results.xlsx"} within \code{json_dir}} + +\item{overwrite}{whether or not to overwrite the Excel \code{file} if it +exists. Default: \code{FALSE}.} + +\item{open}{logical indicating whether or not to open the created Excel file} + +\item{expand_keys}{If this argument is not \code{NULL} but a vector of (key) +column names, all sheets are expanded to the same number of rows. All +possible combinations of values in these key columns are then given in each +sheet even though there are no values for these key value combinations. +Default: \code{c("indicator", "process", "place", "exchange")}} +} +\value{ +path to created Excel file +} +\description{ +Import JSON files to Excel File +} diff --git a/man/import_rawdata_json.Rd b/man/import_rawdata_json.Rd new file mode 100644 index 0000000..0fd8e21 --- /dev/null +++ b/man/import_rawdata_json.Rd @@ -0,0 +1,33 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/import_rawdata_json.R +\name{import_rawdata_json} +\alias{import_rawdata_json} +\title{Import Umberto results from .json files} +\usage{ +import_rawdata_json( + json_dir, + old_format = TRUE, + add_place = FALSE, + files = NULL +) +} +\arguments{ +\item{json_dir}{path to directory containing .json files. All .json files +will be read.} + +\item{old_format}{if TRUE (the default) the same columns are provided that +are provided by \code{\link{import_rawdata}} that imports .csv files} + +\item{add_place}{With add_place = TRUE, the "place" is contained in the +result even if old_format = TRUE} + +\item{files}{optional. If given and not \code{NULL} this is expected to be a +vector of character with the full paths to the \code{.json} files to be +read.} +} +\value{ +data frame +} +\description{ +Import Umberto results from .json files +} diff --git a/tests/testthat/test-function-stop_on_differing_names.R b/tests/testthat/test-function-stop_on_differing_names.R index dda10de..aa6ac09 100644 --- a/tests/testthat/test-function-stop_on_differing_names.R +++ b/tests/testthat/test-function-stop_on_differing_names.R @@ -1,16 +1,19 @@ -# -# This test file has been generated by kwb.test::create_test_files() -# launched by user mrustl on 2022-11-18 13:49:45. -# Your are strongly encouraged to modify the dummy functions -# so that real cases are tested. You should then delete this comment. -# +#library(testthat) test_that("stop_on_differing_names() works", { - expect_error( - kwb.umberto:::stop_on_differing_names() - # argument "x" is missing, with no default - ) + f <- kwb.umberto:::stop_on_differing_names + + expect_error(f()) + dfs <- list( + df1 = data.frame(a = 1, b = 2), + df2 = data.frame(a = 1, b = 2, c = 3), + data.frame(a = 2, b = 3) + ) + + expect_error(f(dfs)) + expect_error(f(dfs[-1L]), "") + + expect_silent(f(dfs[-2L])) }) -