diff --git a/DESCRIPTION b/DESCRIPTION index 163b6f0..63936f8 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: shinywqbench Title: R Shiny App to Calculates Aquatic Life Benchmarks -Version: 0.1.0.9000 +Version: 0.2.0 Authors@R: c( person("Ayla", "Pearson", , "ayla@poissonconsulting.ca", role = "aut", comment = c(ORCID = "0000-0001-7388-1222")), @@ -16,8 +16,9 @@ Description: This package is the user interface to the wqbench R package compute the aquatic life water quality benchmark for a compound. License: Apache License (== 2) Depends: - R (>= 2.10) + R (>= 4.1) Imports: + chk, dplyr, DT, ggplot2, @@ -30,6 +31,7 @@ Imports: shiny, shinyjs, stringr, + tidyr, utils, waiter, wqbench, diff --git a/NEWS.md b/NEWS.md index edea934..5836fea 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,8 +1,24 @@ - + -# shinywqbench (development version) +# shinywqbench 0.2.0 (2023-12-07) -- Updating title, adding instructions to data tab, updating user and about tabs +### New feature + +- Ability to add your own data by uploading a file. + +### Major changes + +- Updated data in app to the Ecotox Sept 2023 data set. +- Number of bootstrap samples is 1000 (for SSD method). + +### Minor improvements and bug fixes + +- Added number of bootstrap samples to tab 2.2 and pdf report when the method is SSD. +- Column order changes in tab 1.1 (displayed and download table). +- Switched block/stop on generating guideline to second tab when the chemical already has a BC wqg. +- Updated naming to be Review instead of Raw. +- Added hyperlink to write up in about and user guide tab. +- BC gov style added. # shinywqbench 0.1.0 diff --git a/R/app-ui.R b/R/app-ui.R index 2fc3139..b118774 100644 --- a/R/app-ui.R +++ b/R/app-ui.R @@ -20,7 +20,10 @@ app_ui <- function() { shinyjs::useShinyjs(), waiter::useWaiter(), navbarPage( - title = "Emergent Contaminant Aquatic Life Benchmarks - DRAFT", + title = div( + img(src = "../images/gov3_bc_logo.png", style = "padding-right: 20px;"), + "Emerging Contaminant Aquatic Life Benchmarks - DRAFT" + ), selected = "tab1", id = "navbarID", tabPanel( @@ -51,6 +54,10 @@ app_ui <- function() { title = "User Guide", mod_user_ui("mod_user_ui") ) + ), + div( + class = "footer", + includeHTML("www/footer.html") ) ) } diff --git a/R/css.R b/R/css.R index a9d7532..ffdef22 100644 --- a/R/css.R +++ b/R/css.R @@ -14,7 +14,7 @@ add_external_resources <- function() { addResourcePath("www", system.file("app/www", package = "shinywqbench")) - tagList(tags$link(rel = "stylesheet", type = "text/css", href = "www/style.css")) + tagList(tags$link(rel = "stylesheet", type = "text/css", href = "www/bcgov.css")) } css_styling <- function() { @@ -29,6 +29,17 @@ css_styling <- function() { padding: 0.3em; padding-right: 1em; } + + .container-fluid { + margin-top: 10px; + } + + .navbar-nav { + float: right; + margin-bottom: 0; + margin-right: 20px !important; + } + " tags$style(css_text, type = "text/css") } diff --git a/R/functions.R b/R/functions.R index 950ce9b..b961fef 100644 --- a/R/functions.R +++ b/R/functions.R @@ -150,12 +150,26 @@ filter_data_raw_dl <- function(data) { data <- data |> dplyr::select( - "chemical_name", "cas", - "latin_name", "common_name", "endpoint", "effect", "effect_conc_mg.L", - "lifestage", "duration_hrs", "duration_class", "effect_conc_std_mg.L", - "acr", "media_type", "trophic_group", "ecological_group", + "chemical_name", + "cas", + "common_name", + "latin_name", + "endpoint", + "effect", + "lifestage", + "effect_conc_mg.L", + "effect_conc_std_mg.L", + "trophic_group", + "ecological_group", "species_present_in_bc", - "author", "title", "source", "publication_year", + "duration_hrs", + "duration_class", + "acr", + "media_type", + "author", + "title", + "source", + "publication_year", "ecotox_download_date" = "download_date", "ecotox_version" = "version" ) @@ -174,3 +188,30 @@ filter_data_agg_dl <- function(data) { ) data } + +# Upload Data ----- +is_try_error <- function(x) inherits(x, "try-error") + +check_modal <- function(check, title = "Please fix the following issue ...") { + msg <- stringr::str_replace(check[1], "^Error\\s*.*[:]", "") + msg <- gsub("Error : ", "", msg) + modalDialog( + paste(msg), + title = title, + footer = modalButton("Got it") + ) +} + +check_upload <- function(x, ext = "csv") { + if (is.null(x)) { + chk::abort_chk("A file needs to be uploaded before it can be added.") + } + if (!any(stringr::str_detect(x, ext))) { + ext <- paste0(ext, collapse = " or ") + chk::abort_chk( + "We're not sure what to do with that file type. Please upload a ", + ext, + " file." + ) + } +} diff --git a/R/mod-bench.R b/R/mod-bench.R index a1a997b..6df5dfc 100644 --- a/R/mod-bench.R +++ b/R/mod-bench.R @@ -48,6 +48,7 @@ mod_bench_ui <- function(id, label = "bench") { h5(uiOutput(ns("ui_text_2"))), uiOutput(ns("ui_table_trophic_groups")), uiOutput(ns("ui_text_3")), + uiOutput(ns("ui_text_3_1")), br(), uiOutput(ns("ui_text_4")), uiOutput(ns("ui_table_bench")), @@ -80,6 +81,7 @@ mod_bench_server <- function(id, ext) { cas = NULL, fit = NULL, bench = NULL, + nboot = 1000, gp_results = NULL, bench_display = NULL, raw = NULL, @@ -93,6 +95,36 @@ mod_bench_server <- function(id, ext) { w <- waiter_data("Running model for selected chemical ...") observeEvent(input$benchmark, { + # Don't allow value to be generated if already present + guideline_present <- cname |> + dplyr::filter(.data$cas_number == ext$chem_check) |> + dplyr::select("present_in_bc_wqg") |> + dplyr::pull() + + if (guideline_present) { + chem_msg <- ext$chem_check + + return( + showModal( + modalDialog( + div( + paste( + cname$chemical_name[cname$cas_number == chem_msg], + "has a guideline present. To look up this guideline go to the" + ), + tags$a( + "BC Water Quality Guideline Look-up App", + target = "_blank", + href = "https://www2.gov.bc.ca/gov/content/environment/air-land-water/water/water-quality/water-quality-guidelines/approved-water-quality-guidelines", + target = "_blank" + ) + ), + footer = modalButton("Got it") + ) + ) + ) + } + w$show() rv$raw <- ext$data rv$selected <- ext$selected @@ -115,7 +147,11 @@ mod_bench_server <- function(id, ext) { rv$gp_results <- wqbench::wqb_plot_det(rv$agg_af) } else { rv$fit <- wqbench::wqb_ssd_fit(rv$agg_af) - rv$bench <- wqbench::wqb_method_ssd(rv$agg_af, rv$fit) + rv$bench <- wqbench::wqb_method_ssd( + rv$agg_af, + rv$fit, + nboot = rv$nboot + ) rv$gp_results <- wqbench::wqb_plot_ssd(rv$agg_af, rv$fit) } @@ -211,6 +247,22 @@ mod_bench_server <- function(id, ext) { text_output(ns("text_3")) }) + output$text_3_1 <- renderText({ + req(rv$method) + if (rv$method == "SSD") { + paste( + "Number of bootstrap samples: ", rv$nboot + ) + } else { + paste("") + } + }) + + output$ui_text_3_1 <- renderUI({ + req(rv$bench) + htmlOutput(ns("text_3_1")) + }) + output$text_4 <- renderText({ paste("Critical Toxicity Value (HC5 if method is SSD):") }) @@ -281,7 +333,7 @@ mod_bench_server <- function(id, ext) { req(rv$bench) htmlOutput(ns("text_8")) }) - + output$download_data_bench <- renderUI({ req(rv$cas, rv$bench, rv$af_table) download_button(ns("dl_data_bench")) diff --git a/R/mod-data.R b/R/mod-data.R index 132fec0..f634813 100644 --- a/R/mod-data.R +++ b/R/mod-data.R @@ -56,16 +56,40 @@ mod_data_ui <- function(id, label = "data") { p("1. To clear a selection, hit the backspace button in the input field."), p("2. If you are unable to find the chemical by name try the CAS number."), p( - "3. You can use the", - a("CompTox Chemicals Dashboard", href = "https://comptox.epa.gov/dashboard/"), - "maintained by the US EPA to look up a CAS number." + "3. You can use the", + a( + "CAS Common Chemistry lookup tool", + href = "https://commonchemistry.cas.org/", + target = "_blank" + ), + "maintained by the American Chemical Society to look up the CAS number." ), p( - "4. The", - a("CompTox Chemicals Dashboard", href = "https://comptox.epa.gov/dashboard/"), + "4. The", + a( + "CompTox Chemicals Dashboard", + href = "https://comptox.epa.gov/dashboard/", + target = "_blank" + ), "is also helpful to look up synonyms. Many chemicals have multiple names." ), p("Once a chemical has been selected, hit the Run button."), + ), + wellPanel( + p("To add your own data."), + p("1. Download and fill in template. Check the User Guide tab for descriptions of each column."), + uiOutput(ns("download_add")), + br(), + p("2. Upload the completed template."), + fileInput( + ns("file_add"), + "", + multiple = FALSE, + accept = c(".csv") + ), + p("3. Click the Add button to add the uploaded data."), + actionButton(ns("add_button"), "Add"), + br() ) ), column( @@ -106,92 +130,7 @@ mod_data_ui <- function(id, label = "data") { ) ) ) - - ) - - - # sidebarLayout( - # sidebarPanel( - # - # fluidRow( - # column( - # width = 1 - # tagList( - # radioButtons( - # ns("chem_type"), - # label = "Select chemical by", - # choices = c("Name", "CAS Registry Number (without dashes)"), - # selected = "Name", - # inline = TRUE - # ), - # shinyjs::hidden( - # div( - # id = ns("div_name"), - # selectizeInput( - # ns("select_chem_name"), - # label = "", - # choices = NULL - # ), - # ) - # ), - # shinyjs::hidden( - # div( - # id = ns("div_cas"), - # selectizeInput( - # ns("select_cas_num"), - # label = "", - # choices = NULL, - # selected = NULL - # ) - # ) - # ) - # ), - # actionButton(ns("run"), "Run"), - # ), - # column( - # tabPanel("Instructions here"), - # ), - # ), - # ), - # - #mainPanel( - # tabsetPanel( - # tabPanel( - # title = "1.1 Data Review", - # well_panel( - # inline(uiOutput(ns("download_raw"))), - # inline(uiOutput(ns("button_select"))), - # br(), - # h3(uiOutput(ns("ui_text_1"))), - # br(), - # br(), - # uiOutput(ns("ui_table_selected")) - # ) - # ), - # tabPanel( - # title = "1.2 View Plot", - # well_panel( - # uiOutput(ns("download_plot")), - # br(), - # h3(uiOutput(ns("ui_text_2"))), - # br(), - # br(), - # uiOutput(ns("ui_plot")) - # ) - # ), - # tabPanel( - # title = "1.3 Aggregated Data", - # well_panel( - # uiOutput(ns("download_aggregated")), - # br(), - # h3(uiOutput(ns("ui_text_3"))), - # br(), - # br(), - # uiOutput(ns("ui_table_aggregated")) - # ) - # ) - # ) - # ) + ) ) } @@ -299,57 +238,24 @@ mod_data_server <- function(id) { if (input$chem_type == "Name") { cas_number <- cname |> dplyr::filter(.data$chemical_name == input$select_chem_name) |> - dplyr::select(cas_number) |> + dplyr::select("cas_number") |> dplyr::pull() rv$chem_check <- cas_number } else { rv$chem_check <- input$select_cas_num } - guideline_present <- cname |> - dplyr::filter(cas_number == rv$chem_check) |> - dplyr::select("present_in_bc_wqg") |> - dplyr::pull() - - # when chemical already present in wqg - if (guideline_present) { - chem_msg <- rv$chem_check - rv$data <- NULL - rv$aggregated <- NULL - rv$selected <- NULL - rv$gp <- NULL - rv$name <- NULL - rv$chem_check <- NULL - rv$chem <- NULL - rv$chem_pick <- NULL - rv$data_table_agg <- NULL - rv$clear_id <- 1 + rv$clear_id - return( - showModal( - modalDialog( - div( - paste( - cname$chemical_name[cname$cas_number == chem_msg], - "has a guideline present. To look up this guideline go to the" - ), - tags$a( - "BC Water Quality Guideline Look-up App", - target = "_blank", - href = "https://www2.gov.bc.ca/gov/content/environment/air-land-water/water/water-quality/water-quality-guidelines/approved-water-quality-guidelines" - ) - ), - footer = modalButton("Got it") - ) - ) - ) - } else { - rv$chem <- rv$chem_check - } - w$show() - + rv$chem <- rv$chem_check rv$data <- wqbench::wqb_filter_chemical(ecotox_data, rv$chem) rv$data$remove_row <- FALSE + rv$data <- dplyr::relocate( + rv$data, + "latin_name", "endpoint", "effect", "lifestage", "effect_conc_mg.L", + "effect_conc_std_mg.L", "trophic_group", "ecological_group", + "species_present_in_bc", + .after = "cas", + ) rv$name <- unique(rv$data$chemical_name) rv$selected <- rv$data rv$selected <- wqbench::wqb_benchmark_method(rv$selected) @@ -363,12 +269,110 @@ mod_data_server <- function(id) { rv$aggregated <- wqbench::wqb_aggregate(rv$selected) w$hide() }) - + # Clear Tab 2 when data is edited or chemical re selected observeEvent(rv$chem_pick, { rv$clear_id <- 1 + rv$clear_id }) + + ## Add Data ---- + output$download_add <- renderUI({ + download_button(ns("dl_add")) + }) + + output$dl_add <- downloadHandler( + filename = function() paste0("template-wqbench.csv"), + content = function(file) { + readr::write_csv(wqbench::template[0, -1], file) + } + ) + + # Add data + observeEvent(input$add_button, { + # Check that data already present + if (is.null(rv$data)) { + return( + showModal( + modalDialog( + title = "Please fix the following issue ...", + div("You must select a chemical and click run before adding your data."), + footer = modalButton("Got it") + ) + ) + ) + } + + check_uploaded_1 <- try( + check_upload(input$file_add$datapath, ext = "csv"), + silent = TRUE + ) + if (is_try_error(check_uploaded_1)) { + return(showModal(check_modal(check_uploaded_1))) + } + + add_tbl_1 <- readr::read_csv( + input$file_add$datapath, + show_col_types = FALSE + ) + + if (nrow(add_tbl_1) == 0) { + return( + showModal( + modalDialog( + title = "Please fix the following issue ...", + paste("There are no rows of data in the uploaded data.", + "Please fill out the template and try again."), + footer = modalButton("Got it") + ) + ) + ) + } + + add_tbl_1 <- try( + wqbench::wqb_check_add_data(add_tbl_1, wqbench::template), + silent = TRUE + ) + if (is_try_error(add_tbl_1)) { + return(showModal(check_modal(add_tbl_1))) + } + + species_match <- rv$data |> + dplyr::select("species_number", "latin_name") |> + dplyr::distinct() + + add_tbl_1 <- add_tbl_1 |> + dplyr::left_join( + species_match, + by = "latin_name", + multiple = "first" + ) |> + dplyr::mutate( + species_number = dplyr::if_else( + is.na(.data$species_number), + (max(rv$data$species_number):(max(rv$data$species_number) + nrow(add_tbl_1)))[-1], + .data$species_number + ), + trophic_group = factor( + .data$trophic_group, + levels = levels(rv$data$trophic_group) + ), + ecological_group = factor( + .data$ecological_group, + levels = levels(rv$data$ecological_group) + ), + remove_row = FALSE + ) + + # 3. Add to data set + rv$data <- + rv$data |> + dplyr::bind_rows(add_tbl_1) |> + tidyr::fill("chemical_name", "cas") + ## not sure where this can go or how the other parts may need to be adjusted + rv$selected <- wqbench::wqb_benchmark_method(rv$data) + rv$aggregated <- wqbench::wqb_aggregate(rv$selected) + }) # Tab 1.1 ---- output$text_1 <- renderText({ @@ -390,7 +394,7 @@ mod_data_server <- function(id) { output$dl_raw <- downloadHandler( filename = function() { - file_name_dl("data-raw", rv$chem, "csv") + file_name_dl("data-review", rv$chem, "csv") }, content = function(file) { if (is.null(rv$selected)) { @@ -398,13 +402,13 @@ mod_data_server <- function(id) { } else { data <- filter_data_raw_dl(rv$selected) } - readr::write_csv(data, file) + readr::write_csv(data, file, na = "") } ) observeEvent(input$select, { rv$clear_id <- 1 + rv$clear_id - + rv$data <- rv$data |> dplyr::mutate( @@ -529,7 +533,7 @@ mod_data_server <- function(id) { } else { data <- filter_data_agg_dl(rv$aggregated) } - readr::write_csv(data, file) + readr::write_csv(data, file, na = "") } ) diff --git a/R/mod-summary.R b/R/mod-summary.R index e2379fc..48d04fb 100644 --- a/R/mod-summary.R +++ b/R/mod-summary.R @@ -57,6 +57,7 @@ mod_summary_server <- function(id, ext1, ext2) { trophic_sp_table = ext2$trophic_sp_table, trophic_grp_table = ext2$trophic_grp_table, method = ext2$method, + nboot = ext2$nboot, benchmark = ext2$bench, gp_result = ext2$gp_results ) @@ -70,6 +71,7 @@ mod_summary_server <- function(id, ext1, ext2) { trophic_sp_table = NULL, trophic_grp_table = NULL, method = "", + nboot = "", benchmark = data.frame(ctv_est_mg.L = NA_real_), gp_result = NULL ) @@ -97,7 +99,7 @@ mod_summary_server <- function(id, ext1, ext2) { ) } else { sheets <- list( - raw = filter_data_raw_dl(ext2$raw), + review = filter_data_raw_dl(ext2$raw), selected = filter_data_raw_dl(ext2$selected), aggregate_data = filter_data_agg_dl(ext2$agg), assessment_factor = ext2$af_table, diff --git a/R/sysdata.rda b/R/sysdata.rda index dc6d8f4..65f826b 100644 Binary files a/R/sysdata.rda and b/R/sysdata.rda differ diff --git a/inst/app/server.R b/inst/app/server.R index 94f9a0f..d0de761 100644 --- a/inst/app/server.R +++ b/inst/app/server.R @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -shinywqbench:::app_server \ No newline at end of file +shinywqbench:::app_server diff --git a/inst/app/ui.R b/inst/app/ui.R index ff13e01..4bede41 100644 --- a/inst/app/ui.R +++ b/inst/app/ui.R @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -shinywqbench:::app_ui() \ No newline at end of file +shinywqbench:::app_ui() diff --git a/inst/app/www/bcgov.css b/inst/app/www/bcgov.css new file mode 100644 index 0000000..8dd1bf1 --- /dev/null +++ b/inst/app/www/bcgov.css @@ -0,0 +1,272 @@ +/* +# Copyright 2023 Province of British Columbia +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +*/ + +@font-face { + font-family: 'Myriad Pro'; +} + +html { + position: relative; + min-height: 100%; +} + +body { + /* Margin bottom by footer height */ + margin-top: 0; + margin-bottom: 100px; +} + +body { + font-family: "Myriad Pro", Calibri, Arial, 'sans serif'; + color: #494949; +} + +.navbar { + position: relative; + top: 0; + width: 100%; + min-height: 60px; +} + +.navbar-default { + background-color: #036; + border-bottom: 3px solid #fcba19; + color: #fff; +} + +.navbar-default .navbar-nav>li>a { + color: #fff; +} + +.navbar-nav>li>a { + line-height: 30px; + font-size: 15px; +} + +.navbar-default .navbar-nav>li>a:focus, .navbar-default .navbar-nav>li>a:hover { + color: #f0f0f0; + text-decoration: underline; +} + +.navbar-default .navbar-brand, .navbar-default .navbar-brand:hover { + color: #fff; + color: #fff; + /*background: transparent url("../images/gov3_bc_logo.png") no-repeat center center;*/ + padding-right: 150px; + padding-bottom: 0px; + padding-top: 0px; + min-width: 150px; +} + +.dropdown-menu { + background-color: #38598a; + border: none; +} +.dropdown-menu>li>a { + color: #fff; +} + +.navbar-default .navbar-nav>.active>a, .navbar-default .navbar-nav>.active>a:focus, .navbar-default .navbar-nav>.active>a:hover { + color: #fff; + background-color: #38598a; + text-decoration: underline; + font-size: 15px; +} + +.dropdown-menu>li>a, .navbar-default .navbar-nav>.open>a, .navbar-default .navbar-nav>li>a { + font-size: 15px; +} + +.dropdown-menu>li>a:focus, .dropdown-menu>li>a:hover, .navbar-default .navbar-nav>.open>a, .navbar-default .navbar-nav>.open>a:focus, +.navbar-default .navbar-nav>.open>a:hover, .navbar-default .navbar-nav>li>a:focus, .navbar-default .navbar-nav>li>a:hover { + color: #fff; + text-decoration: underline; + background-color: #38598a; + font-size: 15px; +} + +.nav-tabs { + margin: 20px 0; +} + +.tab-content p { + padding: 0 15px 0 0; +} + +hr { + border-top: 1px solid #ccc; +} + +.container .jumbotron, .container-fluid .jumbotron h1 { + color: #e6e6e6; + margin-bottom: 50px; + text-align: center; + text-shadow: #363636 2px 2px 5px, -2px -2px 5px #363636; +} + +.container-fluid .jumbotron .quick-fact-container { + margin-bottom: 65px; + padding: 10px 0; + /*border: 1px solid #cfcfcf;*/ +} + +.container-fluid .jumbotron .quick-fact { + background-color: rgba(255, 255, 255, 0.85); + font-size: 18px; + padding: 15px 40px; +} + +.splash-icon { + display: inline-block; + font-size: 36px; + width: 52px; + height: 52px; + color: #505050; + vertical-align: top; +} + +.splash-text { + display: inline-block; + /*width: 80%;*/ + margin-bottom: 20px; +} + +.splash-text .fa { + margin-right: 7px; +} + +#splash-intro { + margin: 15px 0 30px; + font-size: 14px; +} + +#splash-intro-credit { + font-size: 11px; +} + +.alert { + background-color: #f5f5f5; + color: #393939; + border: 1px solid #e3e3e3; +} + +.tooltip-inner { + text-align: left; + background-color: #393939; + padding: 10px 15px; +} + +.tooltip.right .tooltip-arrow { + border-right-color: #393939; +} + +.btn-bcgov { + background-color: #385988; + border-color: #357ebd; + color: #fff; + text-decoration: none; +} + +.btn-bcgov:hover { + background-color: #5475a7; + color: #fff; +} + + + +/* BCGOV guidelines */ +#footer #footerWrapper { + width: 100%; + bottom: 0; +} + +#footer { + background-color: #003366; + border-top: 2px solid #fcba19; + position: absolute; + bottom: 0; + left: 0; + width: 100%; + height: 50px; +} + +#footerAdminSection { + background-color: #003366; + width: 0px; + margin-left: 20px; +} + +#footerAdminLinks { + clear: both; +} + +#footerAdminSection ul { + clear: both; + padding: 10px 0; +} + +ul.inline { + list-style-type: none; + margin: 0; + overflow: hidden; + padding: 0; + text-align: left; +} + +ul.inline li { + display: inline-block; + padding: 2px 10px; + position: relative; +} + +img.back-to-top.footer-overlap { + position: absolute; + top: -63px; +} + +img.back-to-top { + position: fixed; + right: 10px; + bottom: 10px; + opacity: 0.75; + filter: alpha(opacity=75); + z-index: 1100; + cursor: pointer; + display: none; + vertical-align: middle; + border: 0; +} + +#footer a, #footer h2 { + color: #fff; +} + +a { + color: #1a5a96; +} + +ul.inline li a:link, nav ul.inline li a:visited { + color: white; + display: block; + text-align: center; +} + +/* Mobility sunburst title */ +#mobility_sunburst_title { + font-size: 14px; + text-align: center; + font-weight: bold; +} diff --git a/inst/app/www/images/back-to-top.png b/inst/app/www/images/back-to-top.png new file mode 100644 index 0000000..398e60d Binary files /dev/null and b/inst/app/www/images/back-to-top.png differ diff --git a/inst/app/www/images/favicon.ico b/inst/app/www/images/favicon.ico new file mode 100644 index 0000000..1841396 Binary files /dev/null and b/inst/app/www/images/favicon.ico differ diff --git a/inst/app/www/images/gov3_bc_logo.png b/inst/app/www/images/gov3_bc_logo.png new file mode 100644 index 0000000..68fd36c Binary files /dev/null and b/inst/app/www/images/gov3_bc_logo.png differ diff --git a/inst/app/www/style.css b/inst/app/www/style.css deleted file mode 100644 index 316166f..0000000 --- a/inst/app/www/style.css +++ /dev/null @@ -1,219 +0,0 @@ -/* -# Copyright 2023 Province of British Columbia -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -*/ - -input[type="number"] { - max-width: 80%; -} - -div.outer { - position: fixed; - top: 41px; - left: 0; - right: 0; - bottom: 0; - overflow: hidden; - padding: 0; -} - -body{ - font-family: Myriad-Pro, Calibri, Arial, 'sans serif'; - color: #494949; - font-size: 13px; -} - -#codes{ - background-color:#EEEEEE; - font-family:Consolas,Monaco,Lucida Console,Liberation Mono,DejaVu Sans Mono,Bitstream Vera Sans Mono,Courier New; - font-size: 12px; - font-weight: 200; -} - -#feedbackForm{ - max-width: 500px; -} - -#titleHead { - background-color: #003366; - color: #fff; - text-align: center; - font-weight: 100; - font-size: 10px; -} - -#note { - padding: 15px; -} - - - #information {background-color: white; - padding: 15px; - text-align: center; - color: #2B4777; - } - - #feedback { - background-color: white; - text-align: center; - color: #2B4777; - } - - .msw-button { - font-size: 11px; - padding: 5px; - border: 0; - text-decoration: underline; - margin-bottom: 2px; - display: inline-block; - -} - -.div-link { - font-size: 11px; - text-align: right; - display: inline-block; -} - -/* Customize fonts */ - body, label, input, button, select { - font-family: Myriad-Pro, Calibri, Arial, 'sans serif'; - font-weight: 100; - color: #494949; - font-size: 13px; - - - /*color: #F0F0F0;*/ - } -h1, h2, h3, h4 { font-weight: 100; } - h5 { - font-weight: 200; - color: #5475A7; - font-size: 13px; - } - - a { - font-weight: 200; - color: #5475A7; - font-size: 13px; - } - -#demoData { - font-size: 13px; -} - -.wellpanel { - overflow-x:scroll; - max-height: 700px; -} - -.container-fluid { - margin-top: 10px; -} - -/*********************** navbar css ****************************/ -.navbar .navbar-nav {float: right} - -.navbar-header { - padding: 0px 20px 0px 30px; -} - -.navbar.navbar-default.navbar-static-top{ - padding:0; - margin-bottom: 0px; - background: rgba(44,62,80, 1); -} -.navbar-default { - box-shadow: 0 4px 4px -2px rgba(0,0,0,.2); -} -.navbar-default { - background-color: #101010; - border-color: transparent; -} -.navbar-default .navbar-brand { - color: #E0E0E0; -} -.navbar-default .navbar-brand:hover, -.navbar-default .navbar-brand:focus { - color: #E0E0E0; - background-color: transparent; -} -.navbar-default .navbar-text { - color: #E0E0E0; -} -.navbar-default .navbar-nav > li > a { - color: #E0E0E0; -} -.navbar-default .navbar-nav > li > a:hover, -.navbar-default .navbar-nav > li > a:focus { - color: #37CBA2; - background-color: transparent; -} -.navbar-default .navbar-nav > .active > a, -.navbar-default .navbar-nav > .active > a:hover, -.navbar-default .navbar-nav > .active > a:focus { - color: #37CBA2; - background-color: transparent; -} -.navbar-default .navbar-nav > .disabled > a, -.navbar-default .navbar-nav > .disabled > a:hover, -.navbar-default .navbar-nav > .disabled > a:focus { - color: #101010; - background-color: transparent; -} -.navbar-default .navbar-toggle { - border-color: #101010; -} -.navbar-default .navbar-toggle:hover, -.navbar-default .navbar-toggle:focus { - background-color: #37CBA2; -} -.navbar-default .navbar-toggle .icon-bar { - background-color: #E0E0E0; -} -.navbar-default .navbar-collapse, -.navbar-default .navbar-form { - border-color: transparent; -} -.navbar-default .navbar-nav > .open > a, -.navbar-default .navbar-nav > .open > a:hover, -.navbar-default .navbar-nav > .open > a:focus { - background-color: #101010; - color:#37CBA2; -} -@media (max-width: 767px) { - .navbar-default .navbar-nav .open .dropdown-menu > li > a { - color: #E0E0E0; - } - .navbar-default .navbar-nav .open .dropdown-menu > li > a:hover, - .navbar-default .navbar-nav .open .dropdown-menu > li > a:focus { - color: #101010; - background-color: transparent; - } - .navbar-default .navbar-nav .open .dropdown-menu > .active > a, - .navbar-default .navbar-nav .open .dropdown-menu > .active > a:hover, - .navbar-default .navbar-nav .open .dropdown-menu > .active > a:focus { - color: #E0E0E0; - background-color: #101010; - } - .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a, - .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:hover, - .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:focus { - color: #cccccc; - background-color: transparent; - } -} -.navbar-default .btn-link { - color: #E0E0E0; -} diff --git a/inst/extdata/about.md b/inst/extdata/about.md index 3b2883c..3274cd6 100644 --- a/inst/extdata/about.md +++ b/inst/extdata/about.md @@ -14,12 +14,12 @@ # limitations under the License. --> -The purpose of this app is to allow the user to calculate aquatic life benchmarks for emergent contaminants when no water quality guidelines are available. +The purpose of this app is to allow the user to calculate aquatic life benchmarks for emerging contaminants when no water quality guidelines are available. Although these benchmarks follow methods similar to those outlined in the [BC WQG derivation protocol](https://www2.gov.bc.ca/assets/gov/environment/air-land-water/water/waterquality/water-quality-guidelines/derivation-protocol/bc_wqg_aquatic_life_derivation_protocol.pdf), many steps have been omitted including data quality screening and expert review and therefore these benchmarks are not equivalent to water quality guidelines. Rather the purpose of the benchmarks is to support the assessment of monitoring data and the potential for a chemical to impact the aquatic environment. If you have any feedback or comments on this app, please email them to Angeline.Tillmanns@gov.bc.ca For further information on this app, please see the draft overview: -Tillmanns, A.R. and Pearson, A. 2023. DRAFT wqbench: A Tool for Calculating Emergent Contaminant Aquatic Life Benchmarks. Ministry of Water, Land and Resource Stewardship. Province of British Columbia, Victoria. +[Tillmanns, A.R. and Pearson, A. 2023. DRAFT wqbench: A Tool for Calculating Emerging Contaminant Aquatic Life Benchmarks. Ministry of Water, Land and Resource Stewardship. Province of British Columbia, Victoria.](https://www2.gov.bc.ca/assets/gov/environment/air-land-water/water/waterquality/water-quality-guidelines/approved-wqgs/benchmarks_for_emerging_contaminants_overview_draft_august_2023.pdf) @@ -33,7 +33,7 @@ The app automatically completes the following steps: - Step 5: Data are aggregated and the most sensitive endpoint for the most sensitive life stage is selected for each species. - Step 6: Assessment factors are applied to account for uncertainty related to the number of species, representation of ecologically important groups and representation of B.C. species. -A full description of the steps can be found in the accompanying word document, “An overview of the aquatic life water quality benchmark generator” which will eventually be published. +A full description of the steps can be found in the accompanying document, "An overview of the aquatic life water quality benchmark generator" which will eventually be published. Please do not cite this app at this point. diff --git a/inst/extdata/data.R b/inst/extdata/data.R index c872313..c7509f6 100644 --- a/inst/extdata/data.R +++ b/inst/extdata/data.R @@ -25,7 +25,6 @@ cname <- data_set |> dplyr::distinct() ecotox_data <- data_set |> - dplyr::filter(!present_in_bc_wqg) |> dplyr::select(-present_in_bc_wqg) rm(data_set) diff --git a/inst/extdata/summary-report.Rmd b/inst/extdata/summary-report.Rmd index a9cbced..403faa6 100644 --- a/inst/extdata/summary-report.Rmd +++ b/inst/extdata/summary-report.Rmd @@ -9,6 +9,7 @@ params: trophic_sp_table: data.frame(x = 1) trophic_grp_table: data.frame(x = 1) method: "" + nboot: "" benchmark: data.frame(ctv_est_mg.L = 1) gp_result: NULL --- @@ -43,6 +44,8 @@ knitr::kable( Benchmark derivation method selected: `r params$method` +`r if (params$method == "SSD") paste("Number of bootstrap samples: ", params$nboot)` + Critical Toxicity Value (HC5 if method is SSD): ```{r, echo=FALSE} diff --git a/inst/extdata/user.md b/inst/extdata/user.md index a53f9d3..10260bc 100644 --- a/inst/extdata/user.md +++ b/inst/extdata/user.md @@ -27,13 +27,19 @@ The app is built from the R package [wqbench](https://github.com/bcgov/wqbench), - Due to the large number of chemicals present, the input field can only display a thousand values at a time. Type the value (name or CAS number) to narrow down the choices. - To clear a selection, hit the backspace button in the input field. - If you are unable to find the chemical by name try the CAS number. - - You can use the [CompTox Chemicals Dashboard](https://comptox.epa.gov/dashboard/) maintained by the US EPA to look up a CAS number. - - The [CompTox Chemicals Dashboard](https://comptox.epa.gov/dashboard/) is also helpful to look up synonyms. Many chemicals have multiple names. + - You can use the [CompTox Chemicals Dashboard](https://comptox.epa.gov/dashboard/) maintained by the US EPA to look up a CAS number. + - The [CompTox Chemicals Dashboard](https://comptox.epa.gov/dashboard/) is also helpful to look up synonyms. Many chemicals have multiple names. - Once a chemical has been selected, hit the Run button. - A loading screen may appear telling you the app is processing your request. - Chemicals with more data will take longer to load, be patient. -- If the chemical has an approved BC Water Quality Guideline associated with it, a pop up box will appear and provide a link to the [BC Water Quality Guideline Look-up App](https://www2.gov.bc.ca/gov/content/environment/air-land-water/water/water-quality/water-quality-guidelines/approved-water-quality-guidelines). - If the chemical is not found in the data set, a pop up box will appear and say "The chemical you selected cannot be found in the database." +- If required you can add your own data to the app. + - Download the template. + - Fill in the template with your data. + - See the [Data Definitions](#data-definitions) section for descriptions of the columns. + - Hit the Add button. + - If the data is in the wrong format a pop up box providing information on why the data was not accepted will appear. + - Correct the data and try again. ### Step 2: Edit Data @@ -72,9 +78,10 @@ The data on Tab 1.1 Review Data can be edited by removing specific rows. **Tab 2.1 Plot & 2.2 Report** - Go to Tab 2 Benchmark and click Generate Benchmark on the left panel. -- Either an SSD analysis or deterministic method is used to generate the critical toxicity and benchmark value as per the steps in (LINK TO PDF DOC). +- Either an SSD analysis or deterministic method is used to generate the critical toxicity and benchmark value as per the steps in "[An overview of the aquatic life water quality benchmark generator](https://www2.gov.bc.ca/assets/gov/environment/air-land-water/water/waterquality/water-quality-guidelines/approved-wqgs/benchmarks_for_emerging_contaminants_overview_draft_august_2023.pdf)". - Download the plot as a png on Tab 2.1 Plot - Download the tables as an excel file on Tab 2.2 Report +- If the chemical has an approved BC Water Quality Guideline associated with it, a pop up box will appear and provide a link to the [BC Water Quality Guideline Look-up App](https://www2.gov.bc.ca/gov/content/environment/air-land-water/water/water-quality/water-quality-guidelines/approved-water-quality-guidelines). **SSD Method** The SSD method used in the app uses ssdtools `ssd_hc_bcanz()` with 10000 bootstrap samples. @@ -106,21 +113,21 @@ critical toxicity value, and benchmark value. | ----------- | ----------- | ------ | | chemical_name | chemical name | ECOTOX | | cas | chemical registry number | ECOTOX | -| latin_name | species Latin name | ECOTOX | | common_name | species common name | ECOTOX | +| latin_name | species Latin name | ECOTOX | | endpoint | the statistic or hypothesis generated from the test results (e.g. EC10, NOEC) | ECOTOX | | effect | a measurable biological change | ECOTOX | -| effect_conc_mg.L | contaminant concentration that corresponds to the endpoint| ECOTOX | | lifestage | lifestage description | ECOTOX | -| duration_hrs | study duration, standardized to hours | ECOTOX | -| duration_class | Values are classified as acute or chronic based on rules/step 2 | Calculated variable | +| effect_conc_mg.L | contaminant concentration that corresponds to the endpoint| ECOTOX | | effect_conc_std_mg.L | effect concentration standardized to include the acute to chronic ratio to extrapolate acute and/or effect concentrations to chronic and/or no-effect concentrations | Calculated variable based on Okonski et al. 2021 | -| sp_aggre_conc_mg.L | standardized effect concentration aggregated for each species | Calculated variable | -| acr | acute to chronic ratio; either 10, 5 or 1 depending on the duration and endpoint reported | Okonski et al. 2021 | -| media_type | Media type of tests | ECOTOX | | trophic_group | Trophic group of species: fish, amphibian, invertebrate, algae and plant. | Based on ECOTOX | | ecological_group | Identification of salmonids and planktonic invertebrates. If neither of these, listed as "other". | B.C. ENV 2009 | | species_present_in_bc | Species is present in British Columbia if entry = TRUE | Based on B.C. ENV 2019 | +| duration_hrs | study duration, standardized to hours | ECOTOX | +| duration_class | Values are classified as acute or chronic based on rules/step 2 | Calculated variable | +| acr | acute to chronic ratio; either 10, 5 or 1 depending on the duration and endpoint reported | Okonski et al. 2021 | +| sp_aggre_conc_mg.L | standardized effect concentration aggregated for each species | Calculated variable | +| media_type | Media type of tests | ECOTOX | | author | Author of reference | ECOTOX | | title | Title of reference | ECOTOX | | source | Journal name or other | ECOTOX | diff --git a/rsconnect/shinyapps.io/poissonconsulting/shinywqbench.dcf b/rsconnect/shinyapps.io/poissonconsulting/shinywqbench.dcf deleted file mode 100644 index 7444dc7..0000000 --- a/rsconnect/shinyapps.io/poissonconsulting/shinywqbench.dcf +++ /dev/null @@ -1,11 +0,0 @@ -name: shinywqbench -title: -username: -account: poissonconsulting -server: shinyapps.io -hostUrl: https://api.shinyapps.io/v1 -appId: 8452407 -bundleId: 7454584 -url: https://poissonconsulting.shinyapps.io/shinywqbench/ -when: 1689290624.50421 -lastSyncTime: 1689290624.50422