From 9145cbf697d0aa2318a96cef273938c75adfb511 Mon Sep 17 00:00:00 2001 From: martens73 <60771411+martens73@users.noreply.github.com> Date: Thu, 29 Oct 2020 12:17:50 +0100 Subject: [PATCH 1/3] Update app.R --- app.R | 402 +++++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 274 insertions(+), 128 deletions(-) diff --git a/app.R b/app.R index fb87829..9c44571 100644 --- a/app.R +++ b/app.R @@ -1,8 +1,9 @@ library(shiny) library(shinydashboard) -library(shinyFiles) library(shinyWidgets) library(seacarb) +library(ggplot2) +library(plotly) library(readr) library(dplyr) library(DT) @@ -14,10 +15,6 @@ ui <- dashboardPage( sidebarMenu(id = "tabs", menuItem("About", tabName = "about", icon = icon("info")), menuItem("Bjerrum plot", tabName = "bjerrum", icon = icon("chart-area")), - menuItem("Working Directory", tabname = "wd", icon = icon("cog"), - menuSubItem("Directory to data storage", tabName = "wd_sub"), - shinyDirButton("dir", "Choose", "Upload", icon=icon("folder-plus")), - verbatimTextOutput("path", placeholder = TRUE)), menuItem("Carbonate chemistry", tabName = "carb", icon = icon("flask"), menuSubItem("manual input", tabName = "man", icon = icon("hand-pointer")), menuSubItem("batch input", tabName = "batch", icon = icon("folder-open"))), @@ -34,13 +31,12 @@ ui <- dashboardPage( br(), br(), p("ScarFace", align = "center", style="color: #7da2d1; font-size: 48px"), - p(em("version 1.2.0"), align="center"), + p(em("web version 1.3.0"), align="center"), p("This application is designed to calculate the carbonate system chemistry of seawater based on the 'seacarb' package using a graphical user interface", align="center"), p("Its name stands for ",tags$b("s"),"ea",tags$b("car"),"b calculations with R Shiny user inter",tags$b("face"),".",align="center"), p("'ScarFace' was written in 'R' and embedded in an interactive web app using the 'Shiny' package. Shiny combines the computational power of R with the interactivity of the modern web.", align="center"), p("Shiny uses reactive elements, i.e. the user interacts via the 'ui' (user interface) with the actual R code running in the background called 'server'. Whenever the user make input changes, this will automatically affect all dependent elements (e.g. plots or data tables).", align="center"), p("Even though the code can be accessed and modified, there is no need for the user to dig into R programming. So 'ScarFace' is extremely user-friendly and makes the usage of 'seacarb' work like a charm.", align="center"), - p("The Shiny package as a whole is distributed under GPL-3 (GNU GENERAL PUBLIC LICENSE version 3). R as a package is licensed under GPL-2 and GPL-3.", align="center"), br(), br(), p("Authors: Markus Raitzsch and Jean-Pierre Gattuso", align="center"), @@ -51,20 +47,28 @@ ui <- dashboardPage( tabItem(tabName = "bjerrum", fluidRow( box(width = 3, status = "primary", solidHeader = F, title="Set physical parameters", collapsible=T, - uiOutput("T"), div(class='row', - div(style="float: left; display:inline-block; margin-left: 15px; width: 25%", - numericInput("T", value=25, min=-10, label=""))), + div(style="float: left; display:inline-block; margin-left: 15px; width: 90%", + sliderInput('temp', 'Temperature (°C)', + min = 0, max = 60, value=25, step=0.1)), + div(style="float: left; display:inline-block; margin-left: 15px; width: 45%", + numericInput("T", value=25, min=-10, step=0.1, label=""))), br(), uiOutput("S"), div(class='row', - div(style="float: left; display:inline-block; margin-left: 15px; width: 25%", - numericInput("S", value=35, min=0, label=""))), + div(style="float: left; display:inline-block; margin-left: 15px; width: 90%", + sliderInput('sal', 'Salinity (psu scale)', + min = 0, max = 50, value=35, step=0.1)), + div(style="float: left; display:inline-block; margin-left: 15px; width: 45%", + numericInput("S", value=35, min=0, step=0.1, label=""))), br(), uiOutput("P"), div(class='row', - div(style="float: left; display:inline-block; margin-left: 15px; width: 25%", - numericInput("P", value=0, min=0, label=""))), + div(style="float: left; display:inline-block; margin-left: 15px; width: 90%", + sliderInput('pres', 'Pressure (bar) | P=0 at surface', + min = 0, max = 1200, value=0, step=1)), + div(style="float: left; display:inline-block; margin-left: 15px; width: 45%", + numericInput("P", value=0, min=0, step=1, label=""))), hr(), div(class='row', div(style="float: left; display:inline-block; margin-left: 15px; width: 90%", @@ -77,7 +81,8 @@ ui <- dashboardPage( )) ), box(width = 9, status = "primary", solidHeader = F, title="Bjerrum plot", collapsible=T, - plotOutput(outputId = "plot1", width = "100%", height = "600px") + p("The grey lines are reference carbon speciations at T = 25 °C, S = 35 (psu), and P = 0 bar", align="left"), + plotlyOutput(outputId = "plot1", width = "100%", height = "600px") ) )), @@ -193,7 +198,7 @@ ui <- dashboardPage( div(style = 'overflow-x: auto', DTOutput('CollectedData')), hr(), shinyUI(bootstrapPage( - shinySaveButton('coll','Save collected data as csv table','Save as "filename"_coll', filetype=list(csv='csv'), icon=icon("save")) + downloadButton("coll", "Save collected data as csv table") )), actionButton('delete', label = tags$div(HTML('   Delete selected rows')), style="color: #000; background-color: #F0BD18; border-color: #E0E0E0")) @@ -205,8 +210,10 @@ ui <- dashboardPage( box(width = 12, status = "primary", solidHeader = F, title="Table with input data", collapsible=T, div(class='row', div(style="float: left; display:inline-block; margin-left: 15px; width: 25%", - p(tags$b("Choose CSV file to upload")), - shinyFilesButton('batch', 'File select', icon=icon("file-upload"), 'Please select a file', FALSE)), + fileInput("batch", "Choose CSV file to upload", + multiple = FALSE, + accept = c(".csv")) + ), div(style="float: left; display:inline-block; margin-left: 15px; width: 15%", selectInput("sep", "Choose separator type", c("Comma-separated" = ",", @@ -246,15 +253,22 @@ ui <- dashboardPage( selectInput("secondb", "Select Variable 2", choices = NULL))), hr(), div(class='row', - div(style="float: left; display:inline-block; margin-left: 15px; width: 90%", + div(style="float: left; display:inline-block; margin-left: 15px; width: 43.2%", selectInput("tempb", "Select Temperature", choices = NULL)), - div(style="float: left; display:inline-block; margin-left: 15px; width: 90%", - selectInput("salb", "Select Salinity", choices = NULL))), + div(style="float: left; display:inline-block; margin-left: 15px; width: 43.2%", + numericInput("tempbm", "or enter generic value", value = "", min = 0, max = 50))), + div(class='row', + div(style="float: left; display:inline-block; margin-left: 15px; width: 43.2%", + selectInput("salb", "Select Salinity", choices = NULL)), + div(style="float: left; display:inline-block; margin-left: 15px; width: 43.2%", + numericInput("salbm", "or enter generic value", value = "", min = 0, max = 50))), div(class='row', div(style="float: left; display:inline-block; margin-left: 15px; width: 43.2%", selectInput("presb", "Select Pressure or Depth", choices = NULL)), - div(style="float: left; display:inline-block; margin-left: 15px; width: 43.2%", - radioButtons("PorD", "What is given?", choices = c("Pressure" = 1, "Depth" = 9.9548), inline = TRUE))) + div(style="float: left; display:inline-block; margin-left: 15px; width: 20%", + numericInput("presbm", "or generic", value = "", min = 0, max = 12000)), + div(style="float: left; display:inline-block; margin-left: 15px; width: 20%", + radioButtons("PorD", "What is given?", choices = c("Pressure" = 1, "Depth" = 9.9548), inline = F))) ), box(width = 3, status = "primary", solidHeader = F, title="Additional choices [optional]", collapsible=T, p("Leave silicate and phosphate concentrations at zero if unknown"), @@ -294,8 +308,6 @@ ui <- dashboardPage( box(width = 3, status = "primary", solidHeader = F, title = "Include additional columns [optional]", collapsible = T, pickerInput("incol", "Select columns from source table to be included in output table", choices = "", multiple = T, options = list('actions-box' = T))), - # checkboxGroupInput("incol", - # "Select columns from source table to be included in output table")), box(width = 3, status = "primary", solidHeader = F, title=tags$div(HTML('   Flags')), collapsible=T, collapsed = T, p("1 = pH and CO2", br(), "2 = CO2 and HCO3", br(), @@ -323,7 +335,7 @@ ui <- dashboardPage( div(style = 'overflow-x: auto', tableOutput('table2')), hr(), shinyUI(bootstrapPage( - shinySaveButton('batch_end','Save batch data as csv table','Save as "filename"_calc', filetype=list(csv='csv'), icon=icon("save")) + downloadButton("batch_end", "Save results as csv file") )), actionButton('gotoerr', label = 'OR continue here for error propagation', style="color: #000; background-color: #F0BD18; border-color: #E0E0E0") @@ -337,30 +349,32 @@ ui <- dashboardPage( p("either from the data source or by entering manually", align="left"), p("NOTE: 'Manual' will override 'Data Source'", align="left"), hr(), - p(tags$b("Variable 1 uncertainty:"), align="left"), + htmlOutput("var1e_text"), + br(), div(class='row', div(style="float: left; display:inline-block; margin-left: 15px; width: 43.2%", selectInput("firste", "Data source", choices = NULL)), div(style="float: left; display:inline-block; margin-left: 15px; width: 43.2%", - numericInput("firstem", min=0, value="", label="Manual"))), - p(tags$b("Variable 2 uncertainty:"), align="left"), + numericInput("firstem", min=0, value="", label="or enter generic value"))), + htmlOutput("var2e_text"), + br(), div(class='row', div(style="float: left; display:inline-block; margin-left: 15px; width: 43.2%", selectInput("seconde", "Data source", choices = NULL)), div(style="float: left; display:inline-block; margin-left: 15px; width: 43.2%", - numericInput("secondm", min=0, value="", label="Manual"))), + numericInput("secondm", min=0, value="", label="or enter generic value"))), p(tags$b("Temperature uncertainty:"), align="left"), div(class='row', div(style="float: left; display:inline-block; margin-left: 15px; width: 43.2%", selectInput("tempe", "Data source", choices = NULL)), div(style="float: left; display:inline-block; margin-left: 15px; width: 43.2%", - numericInput("tempm", min=0, step=0.1, value="", label="Manual"))), + numericInput("tempm", min=0, step=0.1, value="", label="or enter generic value"))), p(tags$b("Salinity uncertainty:"), align="left"), div(class='row', div(style="float: left; display:inline-block; margin-left: 15px; width: 43.2%", selectInput("sale", "Data source", choices = NULL)), div(style="float: left; display:inline-block; margin-left: 15px; width: 43.2%", - numericInput("salm", min=0, step=0.1, value="", label="Manual"))), + numericInput("salm", min=0, step=0.1, value="", label="or enter generic value"))), ), box(width = 3, status = "primary", solidHeader = F, title="Additional choices [optional]", collapsible=T, p("Leave silicate and phosphate uncertainties at zero if unknown"), @@ -403,7 +417,8 @@ ui <- dashboardPage( checkboxInput(inputId="comb", label = "Should input data be included?", value = FALSE, width = NULL)), div(style="float: left; display:inline-block; margin-left: 15px", shinyUI(bootstrapPage( - shinySaveButton('batch_err','Save uncertainties as csv table','Save as "filename"_err', filetype=list(csv='csv'), icon=icon("save")))))) + downloadButton("batch_err", "Save uncertainties as csv table") + )))) )) ), @@ -413,7 +428,7 @@ ui <- dashboardPage( br(), br(), p("ScarFace", align = "center", style="color: #7da2d1; font-size: 48px"), - p(em("version 1.2.0"), align="center"), + p(em("web version 1.3.0"), align="center"), p("When you use 'ScarFace' for your published research, please cite the following two references:", align="center"), br(), p("Raitzsch, M. and Gattuso, J.-P., 2020. ScarFace - seacarb calculations with R Shiny user interface. https://doi.org/10.5281/zenodo.3662139.", align="center"), @@ -426,30 +441,25 @@ ui <- dashboardPage( ##### Server ##### server <- function(input, output, session) { #### Bjerrum plot #### - # Render plot # - output$plot1 <- renderPlot({ - bjerrum(K1=K1(T=25,S=35,P=0), K2=K2(T=25,S=35,P=0), K3=NULL, phmin=2, phmax=12, by=0.1, conc=1, - type="l", col="black", ylab="Relative concentration", lwd=2) - bjerrum(K1=K1(T=input$temp,S=input$sal,P=input$pres), K2=K2(T=input$temp,S=input$sal,P=input$pres), K3=NULL, phmin=2, phmax=12, by=0.1, conc=1, - type="l", col="red", add=TRUE) - legend("right",lty=1:3,legend=c(expression(CO[2]),expression(HCO[3]^"-"), - expression(CO[3]^"2-"))) - legend("left",lty=1, col="black", legend="T=25, S=35, P=0\npK1=5.847, pK2=8.966") - }) - - # Slider and numeric inputs # - output$T <- renderUI({ - sliderInput('temp', 'Temperature (°C)', - min = 0, max = 60, value=input$T, step=0.5) - }) - output$S <- renderUI({ - sliderInput('sal', 'Salinity (psu scale)', - min = 0, max = 50, value=input$S, step=0.5) - }) - output$P <- renderUI({ - sliderInput('pres', 'Pressure (bar) | P=0 at surface', - min = 0, max = 1000, value=input$P, step=1) - }) + # Dynamic Slider and numeric inputs # + observeEvent(input$T, { + updateSliderInput(session, "temp", value = input$T) + }) + observeEvent(input$temp, { + updateNumericInput(session, "T", value = input$temp) + }) + observeEvent(input$S, { + updateSliderInput(session, "sal", value = input$S) + }) + observeEvent(input$sal, { + updateNumericInput(session, "S", value = input$sal) + }) + observeEvent(input$P, { + updateSliderInput(session, "pres", value = input$P) + }) + observeEvent(input$pres, { + updateNumericInput(session, "P", value = input$pres) + }) # Text output of calculated K1 and K2 # output$pK1 <- renderText({ @@ -467,30 +477,79 @@ server <- function(input, output, session) { paste("Second dissociation constant pK2 =", pK2) }) - #### Set working directory #### - shinyDirChoose(input, 'dir', roots = c(Home = fs::path_home(), getVolumes()()), session=session) + # Render plot + output$plot1 <- renderPlotly({ + + pH <- seq(2, 12, 0.1) + pH <- as.data.frame(pH) + + K10 <- as.numeric(K1(S=35, T=25, P=0, pHscale="T")) + K20 <- as.numeric(K2(S=35, T=25, P=0, pHscale="T")) + res0 <- speciation(K1=K10, K2=K20, K3=NULL, pH, conc=1) + res0 <- as.data.frame(res0) + df0 <- bind_cols(pH, res0) %>% + rename(c(CO2 = pH1, HCO3 = pH.1, CO3 = pH.2)) + + K1 <- as.numeric(K1(S=input$sal, T=input$temp, P=input$pres, pHscale="T")) + K2 <- as.numeric(K2(S=input$sal, T=input$temp, P=input$pres, pHscale="T")) + res <- speciation(K1=K1, K2=K2, K3=NULL, pH, conc=1) + res <- as.data.frame(res) + df <- bind_cols(pH, res) %>% + rename(c(CO2 = pH1, HCO3 = pH.1, CO3 = pH.2)) + + ggplot(df0) + + geom_line(aes(pH, CO2), linetype = "solid", color = "grey", size = 0.5) + + geom_line(aes(pH, HCO3), linetype = "dashed", color = "grey", size = 0.5) + + geom_line(aes(pH, CO3), linetype = "dotted", color = "grey", size = 0.5) + + theme(axis.line = element_line(size=0.3), + axis.text = element_text(size=8, colour="black"), + axis.ticks.length = unit(0.15,"cm"), + axis.ticks = element_line(colour = "black", size = 0.3), + axis.title = element_text(size=8), + panel.grid = element_blank(), + panel.background = element_blank()) + + scale_y_continuous(name=bquote("Relative concentration"), breaks=seq(0, 1, 0.2), sec.axis=dup_axis(label=NULL, name=NULL)) + + scale_x_continuous(name=bquote("pH(tot)"), breaks=seq(2, 12, 0.5), expand = c(0,0), sec.axis=dup_axis(label=NULL, name=NULL)) + + geom_line(df, mapping = aes(pH, CO2), linetype = "solid", color = "darkred", size = 0.5) + + geom_line(df, mapping = aes(pH, HCO3), linetype = "dashed", color = "darkred", size = 0.5) + + geom_line(df, mapping = aes(pH, CO3), linetype = "dotted", color = "darkred", size = 0.5) + }) - global <- reactiveValues(datapath = getwd()) - - dir <- reactive(input$dir) + #### Carbonate system parameters (manual) #### + # Some code for dynamic labels # + observeEvent(input$pair, { + x <- if (input$pair==1 || input$pair==6 || input$pair==7 || input$pair==8 || input$pair==9){ + "pH"} + else if (input$pair==2 || input$pair==3 || input$pair==4 || input$pair==5){ + "CO2 (µmol/kg)"} + else if (input$pair==10 || input$pair==11 || input$pair==12){ + "HCO3 (µmol/kg)"} + else if (input$pair==13 || input$pair==14){ + "CO3 (µmol/kg)"} + else if (input$pair==15){ + "ALK (µmol/kg)"} + else + "pCO2 (µatm)" + + y <- if (input$pair==21){ + "pH"} + else if (input$pair==1){ + "CO2 (µmol/kg)"} + else if (input$pair==3 || input$pair==7 || input$pair==10 || input$pair==23){ + "CO3 (µmol/kg)"} + else if (input$pair==2 || input$pair==6 || input$pair==22){ + "HCO3 (µmol/kg)"} + else if (input$pair==4 || input$pair==8 || input$pair==11 || input$pair==13 || input$pair==24){ + "ALK (µmol/kg)"} + else + "DIC (µmol/kg)" - wd <- output$path <- renderText({ - global$datapath + updateNumericInput(session, "first", + label = paste(x)) + updateNumericInput(session, "second", + label = paste(y)) }) - observeEvent(ignoreNULL = TRUE, - eventExpr = { - input$dir - }, - handlerExpr = { - if (!"path" %in% names(dir())) - return() - home <- normalizePath("~") - global$datapath <- - file.path(home, paste(unlist(dir()$path[-1]), collapse = .Platform$file.sep)) - }) - - #### Carbonate system parameters (manual) #### # Carbonate system calculation based on parameter inputs # carb_man <- reactive({ if (input$pair == "2" || input$pair == "3" || input$pair == "4" || input$pair == "5" || input$pair == "10" || input$pair == "11" || input$pair == "12" || input$pair == "13" || input$pair == "14" || input$pair == "15") { @@ -611,36 +670,27 @@ server <- function(input, output, session) { } }) - # Save data as csv # - observe({ - volumes <- c('Working Directory' = wd(), Home = fs::path_home(), getVolumes()()) - shinyFileSave(input,'coll', roots=volumes, session = session) - fileinfo <- parseSavePath(volumes, input$coll) - if (nrow(fileinfo) > 0) { - write_csv(isolate(values$df), fileinfo$datapath, append = FALSE) - } - }) + # Save data as csv + output$coll <- downloadHandler( + filename = "Results_collected_data.csv", + content = function(file) { + write.csv(isolate(values$df), file, row.names = FALSE) + } + ) #### Carbonate system parameters (batch) #### # Upload data as csv # - observe ({ - volumes <- c('Working Directory' = wd(), Home = fs::path_home(), getVolumes()()) - shinyFileChoose(input, 'batch', roots=volumes, filetypes=c('', 'csv'), session=session) - }) - tbl1 <- reactive({ - inFile <- parseFilePaths(roots=c('Working Directory' = wd(), Home = fs::path_home(), getVolumes()()), input$batch) - if(NROW(inFile)) { - tbl1 <- read_delim(inFile$datapath, delim = input$sep, col_names = TRUE, col_types = NULL, na = c("", "NA"), quoted_na = TRUE, quote = "\"", comment = "", trim_ws = TRUE, progress = show_progress(), skip_empty_rows = TRUE) - } - }) + req(input$batch) + tbl1 <- read_delim(input$batch$datapath, delim = input$sep, col_names = TRUE, col_types = NULL, na = c("", "NA"), quoted_na = TRUE, quote = "\"", comment = "", trim_ws = TRUE, progress = show_progress(), skip_empty_rows = TRUE) + }) # Render uploaded table # output$table1 <- renderTable({ tbl1() }, align='c', digits=2) - # Read column names and render for dropdown menu # + # Read column names and render for drop-down menu # observeEvent(tbl1(), { updateSelectInput(session, "firstb", choices = names(tbl1())) updateSelectInput(session, "secondb", choices = names(tbl1())) @@ -649,7 +699,7 @@ server <- function(input, output, session) { updateSelectInput(session, "presb", choices = names(tbl1())) }) - # Read column names and create checkbox list # + # Read column names and create check-box list # observe({ req(input$batch) dnames <- names(tbl1()) @@ -661,45 +711,107 @@ server <- function(input, output, session) { selected = "") }) + # Some code for dynamic labels for input variables # + observeEvent(input$pairb, { + x <- if (input$pairb==1 || input$pairb==6 || input$pairb==7 || input$pairb==8 || input$pairb==9){ + "pH"} + else if (input$pairb==2 || input$pairb==3 || input$pairb==4 || input$pairb==5){ + "CO2 (µmol/kg)"} + else if (input$pairb==10 || input$pairb==11 || input$pairb==12){ + "HCO3 (µmol/kg)"} + else if (input$pairb==13 || input$pairb==14){ + "CO3 (µmol/kg)"} + else if (input$pairb==15){ + "ALK (µmol/kg)"} + else + "pCO2 (µatm)" + + y <- if (input$pairb==21){ + "pH"} + else if (input$pairb==1){ + "CO2 (µmol/kg)"} + else if (input$pairb==3 || input$pairb==7 || input$pairb==10 || input$pairb==23){ + "CO3 (µmol/kg)"} + else if (input$pairb==2 || input$pairb==6 || input$pairb==22){ + "HCO3 (µmol/kg)"} + else if (input$pairb==4 || input$pairb==8 || input$pairb==11 || input$pairb==13 || input$pairb==24){ + "ALK (µmol/kg)"} + else + "DIC (µmol/kg)" + + updateNumericInput(session, "firstb", + label = paste("Select ", x)) + updateNumericInput(session, "secondb", + label = paste("Select ", y)) + }) + + # Define T, S, and P in case they are not available from the source table # + tx <- reactive({ + req(input$batch) + if (isTruthy(input$tempbm)) { + as.numeric(input$tempbm) + } else { + tbl1()[[input$tempb]] + } + }) + + sx <- reactive({ + req(input$batch) + if (isTruthy(input$salbm)) { + as.numeric(input$salbm) + } else { + tbl1()[[input$salb]] + } + }) + + px <- reactive({ + req(input$batch) + if (isTruthy(input$presbm)) { + as.numeric(input$presbm)/as.numeric(input$PorD) + } else { + tbl1()[[input$presb]]/as.numeric(input$PorD) + } + }) + # Carbonate system calculation based on parameter inputs # carb_batch <- reactive({ if (input$pairb == "2" || input$pairb == "3" || input$pairb == "4" || input$pairb == "5" || input$pairb == "10" || input$pairb == "11" || input$pairb == "12" || input$pairb == "13" || input$pairb == "14" || input$pairb == "15") { if (!input$pHscaleb == "NBS") { - carb(flag=as.numeric(input$pairb), var1=tbl1()[[input$firstb]]/1000000, var2=tbl1()[[input$secondb]]/1000000, S=tbl1()[[input$salb]], T=tbl1()[[input$tempb]], Patm=1, P=tbl1()[[input$presb]]/as.numeric(input$PorD), Pt=input$phob/1000000, Sit=input$silb/1000000, + carb(flag=as.numeric(input$pairb), var1=tbl1()[[input$firstb]]/1000000, var2=tbl1()[[input$secondb]]/1000000, S=sx(), T=tx(), Patm=1, P=px(), Pt=input$phob/1000000, Sit=input$silb/1000000, k1k2=input$k1k2b, kf="x", ks="d", pHscale=input$pHscaleb, b=input$bb, gas=input$gasb, warn="y", eos="eos80", long=1.e20, lat=1.e20) } else { - carb(flag=as.numeric(input$pairb), var1=tbl1()[[input$firstb]]/1000000, var2=tbl1()[[input$secondb]]/1000000, S=tbl1()[[input$salb]], T=tbl1()[[input$tempb]], Patm=1, P=tbl1()[[input$presb]]/as.numeric(input$PorD), Pt=input$phob/1000000, Sit=input$silb/1000000, + carb(flag=as.numeric(input$pairb), var1=tbl1()[[input$firstb]]/1000000, var2=tbl1()[[input$secondb]]/1000000, S=sx(), T=tx(), Patm=1, P=px(), Pt=input$phob/1000000, Sit=input$silb/1000000, k1k2=input$k1k2b, kf="x", ks="d", pHscale="SWS", b=input$bb, gas=input$gasb, warn="y", eos="eos80", long=1.e20, lat=1.e20) } } else if (input$pairb == "22" || input$pairb == "23" || input$pairb == "24" || input$pairb == "25") { if (!input$pHscaleb == "NBS") { - carb(flag=as.numeric(input$pairb), tbl1()[[input$firstb]], var2=tbl1()[[input$secondb]]/1000000, S=tbl1()[[input$salb]], T=tbl1()[[input$tempb]], Patm=1, P=tbl1()[[input$presb]]/as.numeric(input$PorD), Pt=input$phob/1000000, Sit=input$silb/1000000, + carb(flag=as.numeric(input$pairb), tbl1()[[input$firstb]], var2=tbl1()[[input$secondb]]/1000000, S=sx(), T=tx(), Patm=1, P=px(), Pt=input$phob/1000000, Sit=input$silb/1000000, k1k2=input$k1k2b, kf="x", ks="d", pHscale=input$pHscaleb, b=input$bb, gas=input$gasb, warn="y", eos="eos80", long=1.e20, lat=1.e20) } else { - carb(flag=as.numeric(input$pairb), tbl1()[[input$firstb]], var2=tbl1()[[input$secondb]]/1000000, S=tbl1()[[input$salb]], T=tbl1()[[input$tempb]], Patm=1, P=tbl1()[[input$presb]]/as.numeric(input$PorD), Pt=input$phob/1000000, Sit=input$silb/1000000, + carb(flag=as.numeric(input$pairb), tbl1()[[input$firstb]], var2=tbl1()[[input$secondb]]/1000000, S=sx(), T=tx(), Patm=1, P=px(), Pt=input$phob/1000000, Sit=input$silb/1000000, k1k2=input$k1k2b, kf="x", ks="d", pHscale="SWS", b=input$bb, gas=input$gasb, warn="y", eos="eos80", long=1.e20, lat=1.e20) } } else if (input$pairb == "21") { if (!input$pHscaleb == "NBS") { - carb(flag=as.numeric(input$pairb), tbl1()[[input$firstb]], var2=tbl1()[[input$secondb]], S=tbl1()[[input$salb]], T=tbl1()[[input$tempb]], Patm=1, P=tbl1()[[input$presb]]/as.numeric(input$PorD), Pt=input$phob/1000000, Sit=input$silb/1000000, + carb(flag=as.numeric(input$pairb), tbl1()[[input$firstb]], var2=tbl1()[[input$secondb]], S=sx(), T=tx(), Patm=1, P=px(), Pt=input$phob/1000000, Sit=input$silb/1000000, k1k2=input$k1k2b, kf="x", ks="d", pHscale=input$pHscaleb, b=input$bb, gas=input$gasb, warn="y", eos="eos80", long=1.e20, lat=1.e20) } else { - carb(flag=as.numeric(input$pairb), tbl1()[[input$firstb]], var2=tbl1()[[input$secondb]]+log10(1.2948 - 2.036e-3*(tbl1()[[input$tempb]]+273.15) + (4.607e-4 - 1.475e-6*(tbl1()[[input$tempb]]+273.15))*tbl1()[[input$salb]]^2), S=tbl1()[[input$salb]], T=tbl1()[[input$tempb]], Patm=1, P=tbl1()[[input$presb]]/as.numeric(input$PorD), Pt=input$phob/1000000, Sit=input$silb/1000000, + carb(flag=as.numeric(input$pairb), tbl1()[[input$firstb]], var2=tbl1()[[input$secondb]]+log10(1.2948 - 2.036e-3*(tx()+273.15) + (4.607e-4 - 1.475e-6*(tx()+273.15))*sx()^2), S=sx(), T=tx(), Patm=1, P=px(), Pt=input$phob/1000000, Sit=input$silb/1000000, k1k2=input$k1k2b, kf="x", ks="d", pHscale="SWS", b=input$bb, gas=input$gasb, warn="y", eos="eos80", long=1.e20, lat=1.e20) } } else { if (input$pHscaleb == "NBS") { - carb(flag=as.numeric(input$pairb), var1=tbl1()[[input$firstb]]+log10(1.2948 - 2.036e-3*(tbl1()[[input$tempb]]+273.15) + (4.607e-4 - 1.475e-6*(tbl1()[[input$tempb]]+273.15))*tbl1()[[input$salb]]^2), var2=tbl1()[[input$secondb]]/1000000, S=tbl1()[[input$salb]], T=tbl1()[[input$tempb]], Patm=1, P=tbl1()[[input$presb]]/as.numeric(input$PorD), Pt=input$phob/1000000, Sit=input$silb/1000000, + carb(flag=as.numeric(input$pairb), var1=tbl1()[[input$firstb]]+log10(1.2948 - 2.036e-3*(tx()+273.15) + (4.607e-4 - 1.475e-6*(tx()+273.15))*tbl1()[[input$salb]]^2), var2=tbl1()[[input$secondb]]/1000000, S=sx(), T=tx(), Patm=1, P=px(), Pt=input$phob/1000000, Sit=input$silb/1000000, k1k2=input$k1k2b, kf="x", ks="d", pHscale="SWS", b=input$bb, gas=input$gasb, warn="y", eos="eos80", long=1.e20, lat=1.e20) } else { - carb(flag=as.numeric(input$pairb), var1=tbl1()[[input$firstb]], var2=tbl1()[[input$secondb]]/1000000, S=tbl1()[[input$salb]], T=tbl1()[[input$tempb]], Patm=1, P=tbl1()[[input$presb]]/as.numeric(input$PorD), Pt=input$phob/1000000, Sit=input$silb/1000000, + carb(flag=as.numeric(input$pairb), var1=tbl1()[[input$firstb]], var2=tbl1()[[input$secondb]]/1000000, S=sx(), T=tx(), Patm=1, P=px(), Pt=input$phob/1000000, Sit=input$silb/1000000, k1k2=input$k1k2b, kf="x", ks="d", pHscale=input$pHscaleb, b=input$bb, gas=input$gasb, warn="y", eos="eos80", long=1.e20, lat=1.e20) } @@ -708,8 +820,7 @@ server <- function(input, output, session) { # Render output table and (if needed) combine with selected columns from uploaded table # dat <- reactive({ - if(is.null(input$batch)) - return() + req(input$batch) if (is.null(input$incol)) return() tbl1()[, input$incol] @@ -738,21 +849,20 @@ server <- function(input, output, session) { } }) - output$table2 <- renderTable({ req(input$batch) tbl_final() }, align='c', digits=2) - # Save data as csv # - observe({ - volumes <- c('Working Directory' = wd(), Home = fs::path_home(), getVolumes()()) - shinyFileSave(input,'batch_end', roots=volumes) - fileinfo <- parseSavePath(volumes, input$batch_end) - if (nrow(fileinfo) > 0) { - write_csv(isolate(tbl_final()), fileinfo$datapath, append = FALSE) - } - }) + # Save data as csv + output$batch_end <- downloadHandler( + filename = function() { + paste("Results", input$batch, sep = "_") + }, + content = function(file) { + write.csv(isolate(tbl_final()), file, row.names = FALSE) + } + ) #### Error propagation #### # On click switch to other tab # @@ -761,6 +871,42 @@ server <- function(input, output, session) { updateTabItems(session, "tabs", newtab) }) + # Dynamically change labels when input parameters are changed # + x <- reactive( + if (input$pairb==1 || input$pairb==6 || input$pairb==7 || input$pairb==8 || input$pairb==9){ + "pH"} + else if (input$pairb==2 || input$pairb==3 || input$pairb==4 || input$pairb==5){ + "CO2 (µmol/kg)"} + else if (input$pairb==10 || input$pairb==11 || input$pairb==12){ + "HCO3 (µmol/kg)"} + else if (input$pairb==13 || input$pairb==14){ + "CO3 (µmol/kg)"} + else if (input$pairb==15){ + "ALK (µmol/kg)"} + else + "pCO2 (µatm)" + ) + + output$var1e_text <- renderText({paste("", x(), " uncertainty")}) + + y <- reactive( + if (input$pairb==21){ + "pH"} + else if (input$pairb==1){ + "CO2 (µmol/kg)"} + else if (input$pairb==3 || input$pairb==7 || input$pairb==10 || input$pairb==23){ + "CO3 (µmol/kg)"} + else if (input$pairb==2 || input$pairb==6 || input$pairb==22){ + "HCO3 (µmol/kg)"} + else if (input$pairb==4 || input$pairb==8 || input$pairb==11 || input$pairb==13 || input$pairb==24){ + "ALK (µmol/kg)"} + else + "DIC (µmol/kg)" + ) + + output$var2e_text <- renderText({paste("", y(), " uncertainty")}) + + # Select errors from uploaded table or enter manually # observeEvent(tbl1(), { updateSelectInput(session, "firste", choices = names(tbl1())) @@ -864,15 +1010,15 @@ server <- function(input, output, session) { tbl5() }, align='c', digits=2) - # Save data as csv # - observe({ - volumes <- c('Working Directory' = wd(), Home = fs::path_home(), getVolumes()()) - shinyFileSave(input,'batch_err', roots=volumes) - fileinfo <- parseSavePath(volumes, input$batch_err) - if (nrow(fileinfo) > 0) { - write_csv(isolate(tbl5()), fileinfo$datapath, append = FALSE) - } - }) + # Save data as csv + output$batch_err <- downloadHandler( + filename = function() { + paste("Results_err", input$batch, sep = "_") + }, + content = function(file) { + write.csv(isolate(tbl5()), file, row.names = FALSE) + } + ) } # Run the application # From dd7abd3621f8bdef257483d2c75c0a9aa1f6b00d Mon Sep 17 00:00:00 2001 From: martens73 <60771411+martens73@users.noreply.github.com> Date: Thu, 29 Oct 2020 12:18:51 +0100 Subject: [PATCH 2/3] Update MANUAL.Rmd --- MANUAL.Rmd | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/MANUAL.Rmd b/MANUAL.Rmd index 45bdf5a..527fb72 100644 --- a/MANUAL.Rmd +++ b/MANUAL.Rmd @@ -1,5 +1,5 @@ --- -title: "'ScarFace' (v1.2.0) Manual" +title: "'ScarFace' (v1.3.0) Manual" author: "Markus Raitzsch and Jean-Pierre Gattuso" date: "October 2020" output: html_document @@ -30,7 +30,7 @@ R -e "shiny::runApp('~/app.R')" In both cases, '~/app.R' must be completed with the full path to the location of 'app.R'. ## Bjerrum plot -The Bjerrum plot displays the relative concentrations of carbonate species, with respect to DIC, as a function of pH, when the solution is at equilibrium. The black lines represent the speciation at T=25 °C, S=35, and P=0 bar (at sea surface). By using the sliders or manual inputs, the effects of temperature, salinity and pressure on the dissociation constants *p*K1 and *p*K2 of carbonic acid can be visualized. In the rightmost box the dissociation constants are displayed as numeric values. +The Bjerrum plot displays the relative concentrations of carbonate species, with respect to DIC, as a function of pH, when the solution is at equilibrium. The grey lines represent the speciation at T=25 °C, S=35, and P=0 bar (at sea surface). By using the sliders or manual inputs, the effects of temperature, salinity and pressure on the dissociation constants *p*K1 and *p*K2 of carbonic acid can be visualized. The graph is interactive, i.e. it can be zoomed in or data can be read on mouse over. ## Working Directory The working directory, i.e. the path to where the input files are stored and where output files should be saved, can be defined here by pushing 'Choose' and selecting the destination folder from the dialog window. @@ -48,7 +48,7 @@ First the input parameters must be entered in the upper left box by choosing the Once the desired choices were selected, the output values in the following table can be collected in an extra table. This facilitates the comparison of computed values from different input variables. There you can delete single or multiple rows by mouse selection and pressing 'Delete selected rows'. The content of 'Collected output data' can be saved to the destination path as a csv file. ### batch input -The input data can also be read from an uploaded csv file (here you may choose between comma-, semicolon- or tab-separation). An example is given with 'Batch_example_comma.csv'. In the box 'Carbonate system parameters [INPUT]', define the pair of known carbonate system variables. Then define the input parameters by choosing the corresponding columns of the source table from the dropdown menu. For the pressure, use the radio buttons to select whether pressure or water depth is given in the source data.

+The input data can also be read from an uploaded csv file (here you may choose between comma-, semicolon- or tab-separation). An example is given with 'Batch_example_comma.csv'. In the box 'Carbonate system parameters [INPUT]', define the pair of known carbonate system variables. Then define the input parameters by choosing the corresponding columns of the source table from the dropdown menu or by entering generic values. For the pressure, use the radio buttons to select whether pressure or water depth is given in the source data.

The usage of 'Additional choices' is equivalent to the 'manual input' (see above).

The calculated variables are shown in the table 'Carbonate system parameters [OUTPUT]'. Before continuing, it might be helpful to include additional columns from the source table (e.g. sample name, age, etc.). This can be done by using the checkboxes in the box 'Include additional columns [optional]'.

Once all information is included in the output table, it can be saved to the destination path as a csv file, or proceed with 'Error propagation'. From 3bab8be9bc7056ea04082bf3a200212f7d2e1da6 Mon Sep 17 00:00:00 2001 From: martens73 <60771411+martens73@users.noreply.github.com> Date: Thu, 29 Oct 2020 12:21:03 +0100 Subject: [PATCH 3/3] Update MANUAL.md --- MANUAL.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MANUAL.md b/MANUAL.md index 265ad2c..8c98560 100644 --- a/MANUAL.md +++ b/MANUAL.md @@ -25,7 +25,7 @@ R -e "shiny::runApp('~/app.R')" In both cases, '~/app.R' must be completed with the full path to the location of 'app.R'. ## Bjerrum plot -The Bjerrum plot displays the relative concentrations of carbonate species, with respect to DIC, as a function of pH, when the solution is at equilibrium. The black lines represent the speciation at T=25 °C, S=35, and P=0 bar (at sea surface). By using the sliders or manual inputs, the effects of temperature, salinity and pressure on the dissociation constants *p*K1 and *p*K2 of carbonic acid can be visualized. In the rightmost box the dissociation constants are displayed as numeric values. +The Bjerrum plot displays the relative concentrations of carbonate species, with respect to DIC, as a function of pH, when the solution is at equilibrium. The grey lines represent the speciation at T=25 °C, S=35, and P=0 bar (at sea surface). By using the sliders or manual inputs, the effects of temperature, salinity and pressure on the dissociation constants *p*K1 and *p*K2 of carbonic acid can be visualized. The graph is interactive, i.e. it can be zoomed in or data can be read on mouse over. ## Working Directory The working directory, i.e. the path to where the input files are stored and where output files should be saved, can be defined here by pushing 'Choose' and selecting the destination folder from the dialog window. @@ -43,7 +43,7 @@ First the input parameters must be entered in the upper left box by choosing the Once the desired choices were selected, the output values in the following table can be collected in an extra table. This facilitates the comparison of computed values from different input variables. There you can delete single or multiple rows by mouse selection and pressing 'Delete selected rows'. The content of 'Collected output data' can be saved to the destination path as a csv file. ### batch input -The input data can also be read from an uploaded csv file (here you may choose between comma-, semicolon- or tab-separation). An example is given with 'Batch_example_comma.csv'. In the box 'Carbonate system parameters [INPUT]', define the pair of known carbonate system variables. Then define the input parameters by choosing the corresponding columns of the source table from the dropdown menu. For the pressure, use the radio buttons to select whether pressure or water depth is given in the source data.

+The input data can also be read from an uploaded csv file (here you may choose between comma-, semicolon- or tab-separation). An example is given with 'Batch_example_comma.csv'. In the box 'Carbonate system parameters [INPUT]', define the pair of known carbonate system variables. Then define the input parameters by choosing the corresponding columns of the source table from the dropdown menu or by entering generic values. For the pressure, use the radio buttons to select whether pressure or water depth is given in the source data.

The usage of 'Additional choices' is equivalent to the 'manual input' (see above).

The calculated variables are shown in the table 'Carbonate system parameters [OUTPUT]'. Before continuing, it might be helpful to include additional columns from the source table (e.g. sample name, age, etc.). This can be done by using the checkboxes in the box 'Include additional columns [optional]'.

Once all information is included in the output table, it can be saved to the destination path as a csv file, or proceed with 'Error propagation'.