Nothing
library(shiny)
library(shinyWidgets)
library(shinydashboard)
library(MtreeRing)
library(testthat)
library(magrittr)
library(png)
library(jpeg)
library(tiff)
library(bmp)
library(magick)
library(imager)
library(dplR)
library(spatstat.geom)
library(measuRing)
library(dplyr)
# define common CSS styles
style1 = ';font-weight:bolder;font-family:"Times New Roman"'
style1 = ';font-family:"Times New Roman"'
# Run the application
createUI <- function()
{
shiny.title <- dashboardHeader(
title = div(style = paste0('font-size:2vw;font-weight:bolder;',
style1), 'MtreeRing'),
tags$li(
tags$style(".main-header {min-height: 0vw}"),
tags$style(".main-header .logo {height: 4vw; line-height:4vw;}"),
tags$style(".sidebar-toggle {height: 4vw; min-height:0vw}"),
tags$style(".main-header .sidebar-toggle {font-size:1.5vw;
padding:0.8vw 1.5vw 0.8vw 1.5vw}"),
tags$style(".navbar {height:4vw}"),
tags$style(".main-header .navbar {min-height:0vw}"),
tags$style(".main-header .navbar-custom-menu {min-height:0vw}"),
tags$style(".main-header .navbar-custom-menu .navbar-nav
{min-height:0vw}"),
div(
style = 'padding:1.3vw;height:4vw;content-align:center',
a(
div(
style = paste0(
'font-weight:bolder;font-size:1.4vw;color:white;line-height:0vw',
style1),
span(icon('fas fa-question-circle fa-fw'), 'User Manual')),
href = paste0("https://ropensci.github.io/MtreeRing/",
"articles/app-MtreeRing.html"),
target = "_blank"
)
),
class = "dropdown"
),
titleWidth = '15vw'
)
shiny.sider <- dashboardSidebar(
width = '15vw',
tags$style(".left-side, .main-sidebar {padding-top: 4vw}"),
sidebarMenu(
menuItem(
div(style = paste0('font-size:1.4vw', style1),
span(icon('fas fa-folder-open fa-fw'), 'Image Loading')),
tabName = 'input_pre', selected = TRUE),
menuItem(
tabName = 'mea_arg',
div(style = paste0('font-size:1.4vw;', style1),
span(icon('fas fa-gear fa-fw'), 'Measurement'))
)
)
)
page1 <- fluidRow(
box(
title = div(style = paste0('font-size:1.5vw;font-weight:bolder',
style1), 'Image Preview'),
width = 12, status = 'primary', solidHeader = T, collapsible = T,
plotOutput(outputId = 'pre.img', height = "25vw",
brush = brushOpts(id = "plot1_brush", opacity = 0.25, resetOnNew = TRUE)
)
),
tags$li(
tags$style(".progress {height:18px;margin-bottom: 0px}"),
tags$style(".progress-bar {line-height:18px; font-size: 15px}")
),
box(
title = div(style = paste0('font-size:1.5vw;font-weight:bolder',
style1), 'Image Upload'),
width = 4, status = 'primary', solidHeader = T, collapsible = T,
conditionalPanel(
condition = '!input.inmethod',
div(
style = paste0('font-size:1.5vw', style1),
fileInput(
inputId = 'selectfile', width = '80%',
label = 'Choose an image file'
)
)
),
div(
style = paste0('font-size:1.2vw', style1),
prettySwitch(
inputId = "magick.switch", value = TRUE, status = "success",
label = div(style = 'font-weight:bolder', "Magick ON"))
),
helpText('The maximum file size is 100 MB. Supported',
' formats include png, jpg, tif and bmp.',
style = paste0(
'font-size:1.2vw;color:black;font-weight:bolder', style1)),
div(
style = paste0('font-size:1.3vw', style1),
prettyCheckbox(
inputId = "inmethod", shape = "curve", value = F,
status = "success",
label = div(style = 'font-weight:bolder', 'Image Path'))
),
conditionalPanel(
condition = 'input.inmethod',
textInput(
inputId = 'enter.path', value = '',
label = div(
style = paste0('font-size:1.3vw', style1), 'File Path')
),
helpText('For example: C:/Users/shiny/img01.png',
style = paste0('font-size:1.2vw;color:black;font-weight:bolder;',
style1)),
hr()
),
div(
style = paste0('font-size:1.3vw;', style1),
prettyCheckbox(
inputId = "wh_ratio",
label = div(style = 'font-weight:bolder', 'Original Aspect Ratio'),
shape = "curve", value = F, status = "success")
),
actionButton(
'buttoninputimage', 'Load ',
class = "btn btn-primary btn-md",
icon = icon('upload', "fa-1x"),
style = 'color:#FFFFFF;text-align:center;font-family:"Times New Roman";
font-weight: bolder;font-size:1.4vw;'),
useSweetAlert()
),
box(
title = div(style = paste0('font-size:1.5vw;font-weight:bolder',
style1), 'Image Rotation'),
width = 3, status = 'primary', solidHeader = T, collapsible = T,
div(
style = paste0('font-size:1.3vw', style1),
prettyRadioButtons(
inputId = "rotatede", label = "",
choices = c("0 degrees" = "rotate0",
"90 degrees" = "rotate90",
"180 degrees" = "rotate180",
"270 degrees" = "rotate270"),
shape = "curve", status = "success",
fill = TRUE, inline = TRUE
)
),
helpText(
"Rotation angle in degrees. The bark ",
"side should be placed at the left side of the ",
"graphics window and the pith side at the right.",
style = paste0(
'font-size:1.2vw;color:black;text-align:justify;font-weight:bolder;',
style1)),
actionButton(
'buttonrotate', 'Rotate',
class = "btn btn-primary btn-md",
icon = icon('repeat',"fa-1x"),
style = 'color:#FFFFFF;text-align:center;font-family:"Times New Roman";
font-weight: bolder;font-size:1.4vw;')
),
box(
title = div(style = paste0('font-size:1.5vw;font-weight:bolder',
style1), 'Image Cropping'),
width = 3, status = 'primary', solidHeader = T, collapsible = T,
helpText(
"To remove unwanted cores and irrelevant objects, ",
"move the mouse to the core you wish to measure and",
"create a rectangle by brushing, see details below.",
style = paste0(
'font-size:1.2vw;color:black;text-align:justify;font-weight:bolder;',
style1)),
div(
style = paste0('font-size:1.3vw', style1),
prettyRadioButtons(
inputId = "cropcondition", label = "",
choiceNames = 'UNCROPPED', choiceValues = list('a'),
status = "danger", shape = "square",
fill = FALSE, inline = FALSE)),
div(
style = paste0('font-size:1.3vw', style1),
prettyCheckbox(
inputId = "showcropp",
label = div(style = 'color:black;font-weight: bolder;', 'Show Help'),
shape = "curve", value = F, status = "success")),
conditionalPanel(
condition = 'input.showcropp',
helpText(
"The operation \"brush\" allows users to create a transparent ",
"rectangle on the image and drag it around. For cores scanned ",
"side by side, the user can choose a core of interest by brushing.",
style = paste0(
'font-size:1.2vw;color:black;text-align:justify;
font-weight:bolder;', style1)),
helpText(
"After brushing, click on the button \"Crop\" to create a",
" cropped area. The measurement will be performed within",
" this area, rather than the whole (uncropped) image.",
style = paste0(
'font-size:1.2vw;color:black;text-align:justify;
font-weight:bolder;', style1)),
helpText(
"To cancel this operation, click on the button \"Cancel\".",
" If the transparent rectangle exists, the user should first ",
"click on the outer region of the rectangle (this will make the",
" rectangle disappear) and then click on the button \"Cancel\".",
style = paste0(
'font-size:1.2vw;color:black;text-align:justify;
font-weight:bolder;', style1))
),
hr(),
actionButton(
'buttoncrop', 'Crop',
class = "btn btn-primary btn-md",
icon = icon('crop',"fa-1x"),
style = 'color:#FFFFFF;text-align:center;font-family:"Times New Roman";
font-weight: bolder;font-size:1.4vw;')
)
)
page2.1 <- fluidRow(
box(
title = div(style = paste0('font-size:1.4vw;font-weight:bolder',
style1), 'Path Options'),
width = 4, status = 'primary', solidHeader = T, collapsible = T,
div(
style = paste0('font-size:1.2vw;color:black;', style1),
textInput('tuid', 'Series ID', '', width = '75%'),
textInput('dpi', 'DPI', '', '75%'),
textInput('sample_yr', 'Sampling year', '', '75%'),
pickerInput(
inputId = "sel_sin_mul", label = 'Path Mode', width = '87%',
choices = c("Single Segment", "Multi Segments"),
options = list(
style = "btn-primary"))
),
# textInput('m_line', 'Y-coordinate of path', '', '75%'),
conditionalPanel(
condition = 'input.sel_sin_mul == "Single Segment"',
div(
style = paste0('font-size:1.2vw;color:black;', style1),
prettyCheckbox(
inputId = "hor_path",
label = div(style = 'font-weight:bolder', 'Horizontal path'),
shape = "curve", value = T, status = "success"
))
),
numericInput(
inputId = 'num_seg',
div(style = paste0('font-size:1.2vw;color:black;', style1),
'Number of segments'),
value = 1, min = 1, max = 1, step = 1, width = "75%"),
conditionalPanel(
condition = 'input.hor_path',
div(
style = paste0('font-size:1.2vw', style1),
prettyCheckbox(
inputId = "incline",
label = div(
style = 'color:black;font-weight: bolder',
'Inclined tree rings'),
shape = "curve", value = F, status = "success")),
conditionalPanel(
condition = 'input.incline',
div(
style = paste0('font-size:1.2vw', style1),
numericInput('h.dis', 'Distance between paths (mm)',
1, 0.1, 30, 0.1, width = '75%'))
)
)
),
box(
title = div(style = paste0('font-size:1.4vw;font-weight:bolder',
style1), 'Label Options'),
width = 4, status = 'primary', solidHeader = T, collapsible = T,
div(
style = paste0('font-size:1.2vw;color:black;', style1),
sliderInput('linelwd', 'Path width', 0.1, 3, 1, 0.1, width = '80%'),
sliderInput('label.cex', 'Magnification for labels',
0.1, 3, 1.5, 0.1, width = '80%'),
radioGroupButtons(
inputId = "pch",
label = 'Symbol for borders', status = "btn btn-primary btn-md",
size = 'sm',
choiceNames = list(
div(style = 'color:#FFFFFF;font-weight: bolder;',
icon('circle', 'fa-lg')),
div(style = 'color:#FFFFFF;font-weight: bolder;',
icon('circle', 'fa-1x')),
div(style = 'color:#FFFFFF;font-weight: bolder;',
icon('circle-o', 'fa-1x')),
div(style = 'color:#FFFFFF;font-weight: bolder;',
icon('times', 'fa-1x')),
div(style = 'color:#FFFFFF;font-weight: bolder;',
icon('plus', 'fa-1x'))
),
selected = '20',
choiceValues = list('19', '20', '1', '4', '3'),
width = '100%'
),
colorSelectorInput(
inputId = "border.color", label = "Color for borders",
choices = c("black", "gray", "white", "red", "#FF6000",
"#FFBF00", "#DFFF00", "#80FF00", "#20FF00",
"#00FF40", "#00FF9F", "cyan", "#009FFF", "#0040FF",
"#2000FF", "#8000FF", "#DF00FF", "#FF00BF"),
selected = '#20FF00', mode = "radio", display_label = FALSE, ncol = 9
),
colorSelectorInput(
inputId = "label.color", label = "Color for labels",
choices = c("black", "gray", "white", "red", "#FF6000",
"#FFBF00", "#DFFF00", "#80FF00", "#20FF00",
"#00FF40", "#00FF9F", "cyan", "#009FFF", "#0040FF",
"#2000FF", "#8000FF", "#DF00FF", "#FF00BF"),
selected = 'black', mode = "radio", display_label = FALSE, ncol = 9
))
),
box(
title = div(
style = paste0('font-size:1.4vw;font-weight:bolder', style1),
'Detection Options'),
width = 4, status = 'primary', solidHeader = T, collapsible = T,
div(
style = paste0('font-size:1.2vw', style1),
prettyCheckbox(
inputId = "isrgb",
label = div(
style = 'color:black;font-size:90%;font-weight:bolder;',
"Default RGB"),
shape = "curve", value = T, status = "success"
)),
conditionalPanel(
condition = '!input.isrgb',
div(
style = paste0('font-size:1.2vw;color:black;', style1),
textInput('customRGB', 'Custom RGB', '0.299,0.587,0.114')),
helpText(
'Note:The three numbers correspond to',
'R, G and B components,respectively.',
style = paste0(
'font-size:1.1vw;color:black;text-align:justify;
font-weight:bolder;', style1)),
hr()
),
div(
style = paste0('font-size:1.2vw;color:black;', style1),
radioGroupButtons(
inputId = "method", label = 'Ring detection method', size = 'normal',
status = "btn btn-primary btn-md", selected = 'canny',
choiceNames = list(
div(style = 'color:#FFFFFF;font-weight: bolder;font-size:1vw',
'Watershed'),
div(style = 'color:#FFFFFF;font-weight: bolder;font-size:1vw',
'Canny'),
div(style = 'color:#FFFFFF;font-weight: bolder;font-size:1vw',
'measuRing')
),
choiceValues = list('watershed', 'canny', 'lineardetect'),
width = '100%'
)),
conditionalPanel(
condition = 'input.method=="watershed"',
div(
style = paste0('font-size:1.2vw;color:black;', style1),
selectInput('watershed.threshold',
'Otsu threshold',
c('Auto (Recommended)' = 'auto',
'Custom' = 'custom.waterthr'),
width = '75%')),
conditionalPanel(
condition = 'input["watershed.threshold"]=="auto"',
div(
style = paste0('font-size:1.2vw;color:black;', style1),
sliderInput('watershed.adjust',
'Threshold adjusment factor',
0.5, 1.5, 0.8, 0.05, width = '85%'))
),
conditionalPanel(
condition = 'input["watershed.threshold"]=="custom.waterthr"',
div(
style = paste0('font-size:1.2vw;color:black;', style1),
textInput(
'watershed.threshold2',
'Threshold value', '', width = '75%')),
helpText(
'A value of the form XX% (e.g. 98%)',
style = paste0(
'font-size:1.1vw;color:black;text-align:justify;
font-weight:bolder;', style1)),
br(),
br()
)
),
conditionalPanel(
condition = 'input.method=="canny"',
div(
style = paste0('font-size:1.2vw;color:black;', style1),
prettyCheckbox(
inputId = "defaultcanny",
label = div(style = 'color:black;font-weight:bolder;',
"Auto threshold (Recommanded)"),
shape = "curve", value = T, status = "success")),
conditionalPanel(
condition = 'input.defaultcanny',
div(
style = paste0('font-size:1.2vw;color:black;', style1),
sliderInput(
'canny.adjust', 'Threshold adjusment factor',
0.8, 1.8, 1.4, 0.05, width = '85%'))
),
conditionalPanel(
condition = '!input.defaultcanny',
div(
style = paste0('font-size:1.2vw;color:black;', style1),
textInput('canny.t2', 'Threshold for strong edges', '', '85%'),
textInput('canny.t1', 'Threshold for weak edges', '', '85%'))
),
div(
style = paste0('font-size:1.2vw;color:black;', style1),
sliderInput('canny.smoothing', 'Degree of smoothing',
0, 5, 2, 1, width = '85%'))
# numericInput('canny.smoothing', 'Degree of smoothing',
# 1, 0, 4, 1, width = '75%')
),
conditionalPanel(
condition = 'input.method!="lineardetect"',
div(
style = paste0('font-size:1.2vw;color:black;', style1),
prettyCheckbox(
inputId = "defaultse",
label = div(style = 'font-weight:bolder',
"Default structuring elements"),
shape = "curve", value = T, status = "success")),
conditionalPanel(
condition = '!input.defaultse',
div(
style = paste0('font-size:1.2vw;color:black;', style1),
numericInput('struc.ele1', 'First structuring element',
3, 1, 100, 1, "75%"),
numericInput('struc.ele2', 'First structuring element',
9, 1, 100, 1, "75%"))
),
hr()
),
conditionalPanel(
condition = 'input.method=="lineardetect"',
div(
style = paste0('font-size:1.2vw;color:black;', style1),
textInput('origin', ' Origin in smoothed gray', '0', '75%')),
helpText(
'In this mode, don\'t tick the checkbox "Inclined tree rings".',
style = paste0(
'font-size:1.1vw;color:black;text-align:justify;
font-weight:bolder;', style1)),
hr()
),
helpText(
# div(
# style =
# paste0('font-size:1.1vw;color:red;text-align:justify;', style1),
# ''
# ),
div(
style =
paste0('font-size:1.1vw;color:black;font-weight:bolder;', style1),
'Automatic detection may take a few seconds'
)
)
),
box(
title = div(style = paste0('font-size:1.4vw;font-weight:bolder',
style1), 'Main Window'),
width = 12, status = 'primary', solidHeader = T, collapsible = T,
# height = '60vw',
div(
style = paste0('font-size:1.25vw', style1),
radioGroupButtons(inputId = "sel_mode", status = "primary",
label =
div(style = 'color:black;font-weight:bolder',
'Working mode selector'),
choiceNames = list(
div(style = 'font-size:1.1vw;font-weight:bolder', 'Path Creation'),
div(style = 'font-size:1.1vw;font-weight:bolder', 'Ring Detection'),
div(style = 'font-size:1.1vw;font-weight:bolder', 'Ring Editing')
),
choiceValues = list('sel_path', 'sel_det', 'sel_edit')
)
),
conditionalPanel(
condition = "input.sel_mode == 'sel_path'",
actionButton(
'rm_last', 'Remove Last',
class = "btn btn-warning btn-md", icon = icon('reply'),
style = 'color:#FFFFFF;text-align:center;
font-family:"Times New Roman";font-weight:bolder;font-size:1.2vw;'
),
useSweetAlert(),
actionButton(
'rm_all', 'Remove All',
class = "btn btn-danger btn-md", icon = icon('trash'),
style = 'color:#FFFFFF;text-align:center;
font-family:"Times New Roman";font-weight:bolder;font-size:1.2vw;'
),
useSweetAlert(),
br(),
br(),
div(
style = paste0('font-size:1.2vw', style1),
prettyCheckbox(
inputId = "pre_path",
label = div(style = 'color:black;font-weight: bolder;',
'Show the preview path'),
shape = "curve", value = F, status = "success", inline = T))
),
conditionalPanel(
condition = "input.sel_mode == 'sel_det'",
actionButton(
'button_run_auto', 'Run Detection',
class = "btn btn-success btn-md", icon = icon('play'),
style = 'color:#FFFFFF;text-align:center;
font-family:"Times New Roman";font-weight:bolder;font-size:1.2vw;'
),
useSweetAlert(),
br(),
br()
),
conditionalPanel(
condition = "input.sel_mode == 'sel_edit'",
actionButton(
'buttonzoomdel', 'Delete Border',
class = "btn btn-warning btn-md",
icon = icon('eraser'),
style = 'color:#FFFFFF;text-align:center;
font-family:"Times New Roman";font-weight:bolder;font-size:1.2vw;'
),
useSweetAlert(),
actionButton(
'rm_all_border', 'Remove All',
class = "btn btn-danger btn-md", icon = icon('trash'),
style = 'color:#FFFFFF;text-align:center;
font-family:"Times New Roman";font-weight:bolder;font-size:1.2vw;'
),
useSweetAlert(),
br(),
br()
),
div(
style = paste0('font-size:1.2vw', style1),
prettyCheckbox(
inputId = "wh_ratio2",
label = div(style = 'color:black;font-weight: bolder;',
'Original Aspect Ratio'),
shape = "curve", value = F, status = "success")),
hr(),
fluidPage(
fluidRow(
column(
width = 11,
plotOutput(
'ring_edit', height = "20vw",
dblclick = "plot2_dblclick",
brush = brushOpts(
id = "plot2_brush", resetOnNew = TRUE
),
hover = hoverOpts(
id = "plot2_hover", delay = 300,
delayType = "debounce"
)
)
),
column(width = 1,
br(), br(),
noUiSliderInput(
width = "100px", height = "13vw",
inputId = "img_ver", label = NULL, tooltips = F,
min = 0, max = 1000, step = 10,
value = c(0, 1000), margin = 10,
orientation = "vertical", behaviour = "drag"
)
)
),
br(),
fluidRow(
column(
width = 11, offset = 0,
sliderInput(
inputId = "img_hor", label = NULL,
min = 0, max = 100, value = c(0, 100), step = 1,
round = T, ticks = F, dragRange = T, post = "%"
)
)
)
)
)
)
page2.2 <- fluidRow(
column(width = 12,
conditionalPanel(
condition = '!input.tuheader',
box(
title = div(
style = paste0('font-size:1.4vw;font-weight:bolder', style1),
'Delete Borders'),
width = 3, status = 'primary', solidHeader = T, collapsible = T,
conditionalPanel(
condition = 'input.incline',
div(
style = paste0('font-size:1.2vw;color:black;', style1),
textInput('del.u', 'Border number in the upper portion',
'', '75%'),
textInput('del.l', 'Border number in the lower portion',
'', '75%'))
),
conditionalPanel(
condition = '!input.incline',
div(
style = paste0('font-size:1.2vw;color:black;', style1),
textInput('del', 'Border number', '', '75%'))
),
helpText(
"To perform a mass deletion of ring borders, use commas ",
"to separate border numbers, e.g. 1, 2, 3, 4",
style = paste0(
'font-size:1.1vw;color:black;text-align:justify;
font-weight:bolder;', style1)
),
br(),
br(),
actionButton(
'button_del', 'Delete Border',
class = "btn btn-danger btn-md", icon = icon('eraser'),
style = 'color:#FFFFFF;text-align:center;font-size:1.2vw;
font-family:"Times New Roman";font-weight: bolder;'
)
)
),
tabBox(
#title = tagList(shiny::icon("gear"), 'Output'),
title = div(style = paste0('font-size:1.4vw;color:black;
font-weight:bolder;', style1),
icon('cog', class = 'fa-spin', lib = 'font-awesome'), 'Output'),
width = 6,
tabPanel(
div(style = paste0('font-size:1.2vw;color:black;
font-weight:bolder;', style1),
icon('list-ol', 'fa-1x'), ' Results'),
#HTML("<p style = 'color:black;'><b>Results</b></p>"),
actionButton(
'button_results', 'Generate Series',
class = "btn btn-primary btn-md",
style = 'color:#FFFFFF;text-align:center;font-size:1.2vw;
font-family:"Times New Roman";font-weight:bolder;'
),
useSweetAlert(),
actionButton(
'button_hide', 'Hide Series',
class = "btn btn-primary btn-md",
style = 'color:#FFFFFF;text-align:center;font-size:1.2vw;
font-family:"Times New Roman";font-weight:bolder;'
),
useSweetAlert(),
br(),
tableOutput('results')
),
tabPanel(
div(style = paste0('font-size:1.2vw;color:black;
font-weight:bolder;', style1),
icon('arrow-down', 'fa-1x'), ' CSV'
),
div(
style = paste0('font-size:1.2vw;color:black;', style1),
textInput('csv.name', 'Name of the csv file', '', width = '50%')),
helpText(
'The filename extension is not required. ',
'Leave blank to use the current series ID.',
style = paste0(
'font-size:1.1vw;color:black;text-align:justify;
font-weight:bolder;', style1)
),
helpText(
'Attention: if running the app within an RStudio window',
', the rename operation doesn\'t work. Please run the app',
' within a browser.',
style = paste0(
'font-size:1.1vw;color:black;text-align:justify;
font-weight:bolder;', style1)
),
hr(),
#HTML("<p style = 'color:black;'><b>CSV</b></p>"),
downloadButton(
'RingWidth.csv', 'Download CSV',
class = "btn btn-primary btn-md",
style = 'color:#FFFFFF;text-align:center;font-size:1.2vw;
font-family:"Times New Roman";font-weight:bolder;'
)
),
tabPanel(
div(style = paste0('font-size:1.2vw;color:black;
font-weight:bolder;', style1),
icon('arrow-down', 'fa-1x'), ' RWL'),
div(
style = paste0('font-size:1.2vw;color:black;', style1),
textInput('rwl.name', 'Name of the rwl file', '', width = '50%')),
helpText(
'The filename extension is not required. ',
' Leave blank to use the current series ID.',
style = paste0(
'font-size:1.1vw;color:black;text-align:justify;
font-weight:bolder;', style1)),
helpText(
'Attention: if running the app within an RStudio window',
', the rename operation doesn\'t work. Please run the app',
' within a browser.',
style = paste0(
'font-size:1.1vw;color:black;text-align:justify;
font-weight:bolder;', style1)),
hr(),
div(
style = paste0('font-size:1.2vw;color:black;', style1),
selectInput('tuprec', 'Precision of the rwl file',
c('0.01' = '0.01', '0.001' = '0.001'),
selected = '0.01', width = '50%')),
helpText(
'Units are in mm.',
style = paste0(
'font-size:1.1vw;color:black;text-align:justify;
font-weight:bolder;', style1)),
hr(),
div(
style = paste0('font-size:1.2vw;color:black;', style1),
checkboxInput('tuheader', 'Header of the File', F)),
conditionalPanel(
condition = 'input.tuheader',
actionButton(
'reset.hdr', 'Reset Header',
class = "btn btn-danger btn-md",
icon = icon('trash'),
style = 'color:#FFFFFF;text-align:center;font-size:1.2vw;
font-family:"Times New Roman";font-weight:bolder;'
)
),
helpText(
'For more details about the header, please',
'read reference manual of the R package dplR.',
'The output file is Tucson format.',
style = paste0(
'font-size:1.1vw;color:black;text-align:justify;
font-weight:bolder;', style1)),
hr(),
#HTML("<p style = 'color:black;'><b>RWL</b></p>"),
downloadButton(
'RingWidth.rwl', 'Download RWL',
class = "btn btn-primary btn-md",
style = 'color:#FFFFFF;text-align:center;font-size:1.2vw;
font-family:"Times New Roman";font-weight:bolder;'
)
)
),
conditionalPanel(
condition = 'input.tuheader',
div(
style = paste0('font-size:1.2vw;color:black;', style1),
box(
title = 'Header',width = 3,
status = 'primary', solidHeader = T, collapsible = T,
textInput('tuhdr1', 'Site ID', ''),
textInput('tuhdr2', 'Site Name', ''),
textInput('tuhdr3', 'Species Code', ''),
textInput('tuhdr4', 'State or Country', ''),
textInput('tuhdr5', 'Species', ''),
textInput('tuhdr6', 'Elevation', '')
)
)
),
conditionalPanel(
condition = 'input.tuheader',
div(
style = paste0('font-size:1.2vw;color:black;', style1),
box(
title = 'Header',width = 3,
status = 'primary', solidHeader = T, collapsible = T,
textInput('tuhdr7', 'Latitude', ''),
textInput('tuhdr8', 'Longitude', ''),
textInput('tuhdr9', 'First Year', ''),
textInput('tuhdr10', 'Last Year', ''),
textInput('tuhdr11', 'Lead Investigator', ''),
textInput('tuhdr12', 'Completion Date', '')
)
)
)
)
)
shiny.body <- dashboardBody(
tabItems(
tabItem(tabName = 'input_pre', page1),
tabItem(tabName = 'mea_arg', page2.1, page2.2)
)
)
ui <- dashboardPage(
shiny.title,
shiny.sider,
shiny.body
)
return(ui)
}
createServer <- function(input, output, session)
{
f.morphological <- function(seg.data, struc.ele1, struc.ele2, x.dpi) {
cim <- as.cimg(seg.data)
cim2 <- erode_rect(cim, sx = struc.ele1[1], sy = struc.ele1[2], sz = 1L)
cim2 <- dilate_rect(cim2, sx = struc.ele1[1], sy = struc.ele1[2], sz = 1L)
cim2 <- dilate_rect(cim2, sx = struc.ele1[1], sy = struc.ele1[2], sz = 1L)
cim2 <- erode_rect(cim2, sx = struc.ele1[1], sy = struc.ele1[2], sz = 1L)
cim2 <- erode_rect(cim2, sx = struc.ele2[1], sy = struc.ele2[2], sz = 1L)
cim2 <- dilate_rect(cim2, sx = struc.ele2[1], sy = struc.ele2[2], sz = 1L)
return(cim2)
}
hat <- function(seg.mor, x.dpi, watershed.threshold, watershed.adjust) {
black.hat <- mclosing_square(seg.mor, size = round(x.dpi / 10))
black.hat <- black.hat - seg.mor
black.hat <- threshold(black.hat, thr = watershed.threshold,
approx = FALSE, adjust = watershed.adjust)
black.hat <- 1 - black.hat
black.hat.mat <- black.hat[, , 1, 1]
return(black.hat.mat)
}
normalize <- function(x) {
return((x - min(x))/(max(x) - min(x)))
}
correct.color <- function(water.c2) {
color.adj <- function(i, water.c2, diff.m) {
color.position <- which(water.c2 == i, arr.ind = T)
row.range <- range(color.position[, 1])
row.range <- row.range[1]:row.range[2]
color.adjacent <- integer()
for (j in row.range) {
row.p <- which(color.position[, 1] == j)
min.column <- color.position[row.p, 2] %>% min
color.diff <- which(diff.m[, j] != 0)
color.pre.p <- color.diff[which(color.diff == min.column) - 1] - 1
color.pre <- water.c2[j, color.pre.p]
color.adjacent <- c(color.adjacent, color.pre)
}
max(color.adjacent)
}
water.c3 <- cbind(matrix(-1, nrow(water.c2), 1),
matrix(0, nrow(water.c2), 1),
water.c2)
diff.m <- apply(water.c3, 1, function(x) c(0, diff(x)))
color.max <- max(water.c2)
df.color <- data.frame(color = c(1:color.max),
adj = rep(NA, times = color.max))
for (i in 1:color.max) {
test.c <- color.adj(i, water.c3, diff.m)
df.color[i, 2] <- test.c
}
for (i in -1:color.max) {
adj.c <- which(df.color[, 2] == i)
if (length(adj.c) >= 2) {
max.c <- max(df.color[adj.c, 1])
covered.c <- sort(df.color[adj.c, 1])
covered.c <- covered.c[-length(covered.c)]
for (j in covered.c) {
cl <- which(water.c3 == j, arr.ind = T)
water.c3[cl] <- max.c
df.color[which(df.color == j, arr.ind = T)] <- max.c
}
}
}
return(water.c3[, -c(1, 2)])
}
water.im <- function(black.hat, correct) {
water.c <- connected(im(black.hat), background = 0, method = "C")
water.c2 <- apply(water.c$v, 2, function(x){
x[is.na(x)]<- 0
return(x)
})
if (correct)
water.c2 <- correct.color(water.c2)
return(water.c2)
}
watershed.im <- function(water.seg, seg.data) {
normalize <- function(x) return((x - min(x))/(max(x) - min(x)))
imgra <- imgradient(as.cimg(seg.data), axes = "y", scheme = 2)
watershed.seg <- watershed(as.cimg(water.seg), imgra, fill_lines = F)
# watershed.seg <- normalize(watershed.seg[, , 1, 1])
return(watershed.seg[,, 1, 1])
}
f.sort <- function(bor_xy, dp) {
filter.col <- diff(bor_xy$x) >= dp/10
filter.col <- c(TRUE, filter.col)
bor_xy <- bor_xy[filter.col,]
return(bor_xy)
}
plot.marker <- function(path.info, hover.xy, sample_yr, l.w, pch,
bor.color, lab.color, label.cex)
{
if(is.null(path.info$x))
return()
p.max <- path.info$max
p.x <- path.info$x - crop.offset.xy$x
p.y <- path.info$y - crop.offset.xy$y
p.type <- path.info$type
p.hor <- path.info$horizontal
incline <- path.info$incline
h.dis <- path.info$h
dpi <- path.info$dpi
len <- length(p.x)
# plot path
if (len == 1)
points(p.x, p.y, pch = 16, col = lab.color)
if (len >= 2 & !incline)
points(p.x, p.y, type = 'l', col = lab.color, lty = 1, lwd = l.w)
if(incline){
dp <- dpi/25.4
d <- h.dis*dp/2
points(p.x, p.y + d, type = 'l', col = lab.color, lty = 1, lwd = l.w)
points(p.x, p.y - d, type = 'l', col = lab.color, lty = 1, lwd = l.w)
if(len == 2) {
points(p.x, p.y, type = 'l', col = lab.color, lty = 2, lwd = l.w)
points(c(p.x[1], p.x[1]), c(p.y[1] + d, p.y[1] - d),
type = 'l', col = lab.color, lty = 2, lwd = l.w)
points(c(p.x[len], p.x[len]), c(p.y[len] + d, p.y[len] - d),
type = 'l', col = lab.color, lty = 2, lwd = l.w)
}
}
if(input$sel_mode == 'sel_path' & len < p.max & len >= 1 & input$pre_path){
y <- ifelse(p.hor, p.y[len], hover.xy$y)
points(c(p.x[len], hover.xy$x), c(p.y[len], y),
type = 'l', col = lab.color, lty = 2, lwd = l.w)
}
# plot border point
if(is.null(df.loc$data))
return()
df.loc <- df.loc$data
if (nrow(df.loc) >= 1) {
bx <- df.loc$x - crop.offset.xy$x
by <- df.loc$y - crop.offset.xy$y
bz <- df.loc$z
bz <- bz[order(bx)]
by <- by[order(bx)]
bx <- sort(bx)
if (incline) {
up <- which(bz == 'u')
lenup <- length(up)
if (lenup >= 1) {
points(bx[up], by[up], col = bor.color, type = "p",
pch = pch, cex = label.cex * 0.75)
year.u <- c(sample_yr:(sample_yr - lenup + 1))
text(bx[up], by[up], year.u, adj = c(-0.5, 0.5),
srt = 90, col = lab.color, cex = label.cex)
border.num <- 1:lenup
text(bx[up], by[up], border.num, adj = c(0.5, 2.25),
col = lab.color, cex = label.cex)
}
lower <- which(bz == 'l')
lenlo <- length(lower)
if (lenlo >= 1) {
points(bx[lower], by[lower], col = bor.color, type = "p",
pch = pch, cex = label.cex * 0.75)
year.l <- c(sample_yr:(sample_yr - lenlo + 1))
text(bx[lower], by[lower], year.l, adj = c(1.5, 0.5),
srt = 90, col = lab.color, cex = label.cex)
border.num <- 1:lenlo
text(bx[lower], by[lower], border.num, adj = c(0.5, -1.25),
col = lab.color, cex = label.cex)
}
} else {
if (length(bx) >= 1) {
lenbx <- length(bx)
points(bx, by, col = bor.color, type = "p",
pch = pch, cex = label.cex * 0.75)
year.u <- c(sample_yr:(sample_yr - length(by) + 1))
text(bx, by, year.u, adj = c(1.5, 0.5),
srt = 90, col = lab.color, cex = label.cex)
border.num <- 1:lenbx
text(bx, by, border.num, adj = c(0.5, -1.25),
col = lab.color, cex = label.cex)
}
}
}
}
f.rw <- function(outfile, sample_yr, incline, dpi, h.dis) {
df.loc <- outfile
bx <- df.loc$x
by <- df.loc$y
bz <- df.loc$z
by <- by[order(bx)]
bz <- bz[order(bx)]
bx <- sort(bx)
dp <- dpi/25.4
if (!incline) {
lenbx <- length(bx)
dx <- diff(bx)
dy <- diff(by)
d <- sqrt(dx^2 + dy^2)
rw <- c(NA, round(d / dp, 2))
years <- c(sample_yr:(sample_yr - lenbx + 1))
df.rw <- data.frame(year = years, x = bx, y = by, ring.width = rw)
} else {
up <- which(bz == 'u')
lenup <- length(up)
bx.up <- bx[up]
diff.col.num.up <- diff(bx.up)
rw.up <- round(diff.col.num.up/dp, 2)
lower <- which(bz == 'l')
lenlo <- length(lower)
bx.lower <- bx[lower]
diff.col.num.lower <- diff(bx.lower)
rw.lower <- round(diff.col.num.lower/dp, 2)
years <- c(sample_yr:(sample_yr - lenup + 1))
mean.bor <- (diff.col.num.lower + diff.col.num.up)/2
x.cor <- abs(bx.lower - bx.up)
x.cor <- x.cor[-length(x.cor)]
correct.rw <- mean.bor * cos(atan(x.cor/(dp * h.dis)))
correct.rw <- c(NA, correct.rw)
correct.rw <- round(correct.rw / dp, 2)
df.rw <- data.frame(year = years,
original = round(c(NA, mean.bor)/dp, 2),
corrected = correct.rw)
}
return(df.rw)
}
calc.se <- function(se, dpi, order) {
if (is.null(se)) {
if(order == 1)
se1 <- dpi/400
if(order == 2)
se1 <- dpi/80
se <- c(se1, se1) %>% round
}
return(se)
}
# 0804
automatic.det <- function(
img, incline, method, h.dis, dpi, RGB, px, py, path.hor, path.df,
watershed.threshold, watershed.adjust, struc.ele1, struc.ele2,
default.canny, canny.t1, canny.t2, canny.adjust, canny.smoothing, origin
)
{
dp <- dpi/25.4
dimt <- image_info(img) %>% '['(1, 2:3) %>% as.numeric
dimcol <- dimt[1]
dimrow <- dimt[2]
struc.ele1 <- calc.se(struc.ele1, dpi, 1)
struc.ele2 <- calc.se(struc.ele2, dpi, 2)
# X direction
pxmin <- min(px) - round(1.5 * struc.ele2[1])
if (pxmin <= 0)
pxmin <- 0
pxmax <- max(px) + round(1.5 * struc.ele2[1])
if (pxmax >= dimcol)
pxmax <- dimcol
# Y direction
pymin <- min(py) - 2 * struc.ele2[1]
if (incline & path.hor)
pymin <- pymin - round(h.dis * dp / 2)
if (pymin <= 0)
pymin <- 0
pymax <- max(py) + 2 * struc.ele2[1]
if (incline & path.hor)
pymax <- pymax + round(h.dis * dp / 2)
if (pymax >= dimrow)
pymax <- dimrow
# crop an image
img.range <- paste0(as.character(pxmax - pxmin), 'x',
as.character(pymax - pymin), '+',
as.character(pxmin), '+',
as.character(dimrow - pymax))
img <- image_crop(img, img.range)
rd.martix <- img[[1]]
hex2dec <- function(rd.martix) apply(rd.martix, 1, as.numeric)
rd.channel <- dim(rd.martix)[1]
if (rd.channel == 1) {
rd.m.array <- hex2dec(rd.martix[1, , ])
} else {
rd.m.array <- array(0, dim = rev(dim(rd.martix)))
for (i in 1:rd.channel) {
rd.m.array[, , i] <- hex2dec(rd.martix[i, , ])
}
}
rd.m.array <- rd.m.array/255
if (rd.channel == 1)
seg.data <- rd.m.array[, ]
if (rd.channel == 2)
seg.data <- rd.m.array[, , 1]
if (rd.channel >= 3)
seg.data <- apply(rd.m.array[, , 1:3], 1, function(x) x %*% RGB) %>% t
tdata <- seg.data
if (method == 'watershed') {
seg.mor <- f.morphological(seg.data, struc.ele1, struc.ele2, dpi)
black.hat <- hat(seg.mor, dpi, watershed.threshold, watershed.adjust)
marker.img <- water.im(black.hat, T)
seg.data <- watershed.im(marker.img, seg.mor)
s2 <- seg.data[, -1]
s2 <- cbind(s2, matrix(max(s2), ncol = 1, nrow = nrow(s2)))
seg.data <- as.cimg(s2 - seg.data)
}
if (method == 'canny') {
seg.mor <- f.morphological(seg.data, struc.ele1, struc.ele2, dpi)
if (default.canny) {
seg.data <- cannyEdges(as.cimg(seg.mor), alpha = canny.adjust,
sigma = canny.smoothing)
} else {
seg.data <- cannyEdges(as.cimg(seg.mor), t1=canny.t1, t2=canny.t2,
alpha = canny.adjust, sigma = canny.smoothing)
}
# seg.data <- canny.seg[, , 1, 1]
}
# intersection operations
if (method != 'lineardetect') {
bor_xy <- where(seg.data == TRUE)
bor_xy <- bor_xy[, c(2, 1)]
colnames(bor_xy) <- c('x', 'y')
bor_xy$x <- bor_xy$x + pxmin - 1
bor_xy$y <- nrow(seg.data) - bor_xy$y + pymin
if (path.hor & incline) {
df.upper <- path.df
df.lower <- path.df
df.upper$y <- df.upper$y + round(h.dis * dp / 2)
df.lower$y <- df.lower$y - round(h.dis * dp / 2)
bor_xy_u <- intersect(bor_xy, df.upper)
bor_xy_u <- f.sort(bor_xy_u, dp)
bor_xy_u$z <- 'u'
bor_xy_l <- intersect(bor_xy, df.lower)
bor_xy_l <- f.sort(bor_xy_l, dp)
bor_xy_l$z <- 'l'
bor_xy <- rbind(bor_xy_u, bor_xy_l)
} else {
bor_xy <- intersect(bor_xy, path.df)
bor_xy <- f.sort(bor_xy, dp)
bor_xy$z <- 'u'
}
# filter falsely identified borders
filter_edge <- function(bor_xy, tdata, pxmin, pymin, dp) {
bor_row <- nrow(tdata) - bor_xy$y + pymin
bor_col <- bor_xy$x - pxmin
num_dp <- dp * 0.2
num_dp <- ifelse(num_dp %% 2 ==0, num_dp + 1, num_dp)
mat <- matrix(c(bor_row, bor_col - (num_dp - 1) / 2), ncol = 2)
pixel_mat <- matrix(nrow = length(bor_row), ncol = 0)
# calculate slope
for(i in 1:num_dp) {
pixel_mat <- cbind(pixel_mat, tdata[mat])
mat[,2] <- mat[,2] + 1
}
calc_slope <- function(x){
lm(x ~ c(1:num_dp)) %>% coef %>% as.numeric
}
slope <- apply(pixel_mat, 1, calc_slope)
bor_xy <- bor_xy[slope[2,] < 0,]
}
bor_xy <- filter_edge(bor_xy, tdata, pxmin, pymin, dp)
}
if (method == 'lineardetect') {
attributes(seg.data)['image'] <- 'img'
smoothed <- graySmoothed(seg.data, ppi = dpi, rgb = RGB)
borders <- linearDetect(smoothed, origin = origin)
borders <- borders + pxmin
bor_xy <- data.frame(x = borders, y = py[1], z = 'u')
}
return(bor_xy)
}
readImg <- function(img, img.name, magick.switch = TRUE) {
img.size <- file.size(img)/1024^2
options(warn = -1)
if(img.size <= 10 | !magick.switch){
if (grepl("\\.tif", img))
tree.data <- readTIFF(img, native = FALSE, info = TRUE)
if (grepl("\\.png", img))
tree.data <- readPNG(img, native = FALSE, info = TRUE)
if (grepl("\\.jpg", img) | grepl("\\.jpeg", img))
tree.data <- readJPEG(img, native = FALSE)
if (grepl("\\.bmp", img)) {
tree.data <- read.bmp(img)
tree.data <- tree.data/255
}
td.dim <- dim(tree.data)
if (!is.matrix(tree.data)) {
if(any(td.dim[3]== c(2,4)))
tree.data <- tree.data[, , -td.dim[3]]
}
if(is.matrix(tree.data)){
tdata <- as.raster(tree.data) %>%
image_read %>%
image_convert(colorspace = 'gray')
} else {
tdata <- image_read(tree.data)
}
rm(tree.data)
gc()
} else {
tdata <- image_read(img)
}
options(warn = 0)
dim.tdata <- image_info(tdata) %>% '['(1, 2:3) %>% as.numeric
attributes(tdata) <- c(attributes(tdata),
list(img.name = img.name, dimt = dim.tdata))
return(tdata)
}
imgInput <- function(tdata, tdata.copy, plot1_rangesx, plot1_rangesy) {
img.name <- attributes(tdata)$img.name
dim.tdata <- image_info(tdata.copy) %>% '['(1,2:3) %>% as.numeric
xleft <- 0
ybottom <- 0
xright <- dim.tdata[1]
ytop <- dim.tdata[2]
par(mar = c(2.5, 2, 2, 0))
# 0729
if(input$wh_ratio){
plot(tdata.copy, xlim = c(xleft, xright), ylim = c(ybottom, ytop),
main = img.name, xlab = "", ylab = "", cex.main = 1.2)
} else {
plot(x = c(xleft, xright), y = c(ybottom, ytop),
xlim = c(xleft, xright), ylim = c(ybottom, ytop),
main = img.name, xlab = "", ylab = "",
type = "n", axes = F, cex.main = 1.2)
rasterImage(as.raster(tdata.copy), xleft, ybottom,
xright, ytop, interpolate = FALSE)
}
axis(1, col = "grey", cex.axis = 1)
axis(2, col = "grey", cex.axis = 1)
if (!is.null(plot1_rangesx)) {
xmin <- plot1_rangesx[1]
xmax <- plot1_rangesx[2]
ymin <- plot1_rangesy[1]
ymax <- plot1_rangesy[2]
dimt <- image_info(tdata) %>% '['(1, 2:3) %>% as.numeric
if (dimt[1] * dimt[2] >= 1.2e+07) {
xmin <- xmin/4
xmax <- xmax/4
ymin <- ymin/4
ymax <- ymax/4
}
x <- c(xmin, xmax, xmax, xmin, xmin)
y <- c(ymin, ymin, ymax, ymax, ymin)
points(x, y, type = 'l', lty = 2, lwd = 1.5)
}
}
imgInput_crop <- function(tdata, ver, hor) {
# crop an image based on slider info
dim.tdata <- image_info(tdata) %>% '['(1, 2:3) %>% as.numeric
dimcol <- dim.tdata[1]
dimrow <- dim.tdata[2]
crop.x <- round(diff(hor)*dimcol/100)
crop.y <- round(diff(ver)*dimrow/1000)
ini.x <- round(hor[1]*dimcol/100)
ini.y <- round(ver[1]*dimrow/1000)
img.range <- paste0(as.character(crop.x), 'x',
as.character(crop.y), '+',
as.character(ini.x), '+',
as.character(ini.y))
tdata <- image_crop(tdata, img.range)
# new dimension
dim.tdata <- image_info(tdata) %>% '['(1, 2:3) %>% as.numeric
xleft <- 0
ybottom <- 0
xright <- dim.tdata[1]
ytop <- dim.tdata[2]
par(mar = c(0, 0, 0, 0), mai = c(0, 0, 0, 0))
# 0730
if(input$wh_ratio2) {
plot(tdata, xlim = c(xleft, xright), ylim = c(ybottom, ytop),
main = '', xlab = "", ylab = "", cex.main = 1.2)
} else {
plot(x = c(xleft, xright), y = c(ybottom, ytop),
xlim = c(xleft, xright), ylim = c(ybottom, ytop),
main = '', xlab = "", ylab = "",
type = "n", axes = F, cex.main = 1.2)
rasterImage(as.raster(tdata), xleft, ybottom,
xright, ytop, interpolate = FALSE)
}
return(tdata)
}
rotateImg <- function(tdata, degree) {
tdata <- image_rotate(tdata, degree)
dim.tdata <- image_info(tdata) %>% '['(1, 2:3) %>% as.numeric
attributes(tdata) <- c(attributes(tdata), list(dimt = dim.tdata))
return(tdata)
}
# Functions listed above are used for shiny app
options(shiny.maxRequestSize = 100*(1024^2))
img.file <- reactiveValues(data = NULL)
img.file.crop <- reactiveValues(data = NULL)
img.file.copy <- reactiveValues(data = NULL)
observeEvent(input$inmethod, {
img.file$data <- NULL
img.file.copy$data <- NULL
img.file.crop$data <- NULL
df.loc$data <- NULL
df.loc$ID <- NULL
plot1_ranges$x <- NULL
plot1_ranges$y <- NULL
plot2_ranges$x <- NULL
plot2_ranges$y <- NULL
path.info$x <- NULL
path.info$y <- NULL
path.info$type <- NULL
path.info$ID <- NULL
path.info$horizontal <- NULL
path.info$incline <- NULL
path.info$h <- NULL
path.info$dpi <- NULL
path.info$max <- NULL
path.info$df <- NULL
rw.dataframe$data <- NULL
updatePrettyRadioButtons(
session = session, inputId = "cropcondition",
choiceNames = 'UNCROPPED', choiceValues = list('a'),
prettyOptions = list(shape = "curve", status = "danger",
fill = F, inline = F)
)
updateActionButton(session, "buttoncrop", label = "Crop")
updatePrettyRadioButtons(
session = session, inputId = "rotatede",
label = "Clockwise Rotation",
choices = c("0 degrees" = "rotate0",
"90 degrees" = "rotate90",
"180 degrees" = "rotate180",
"270 degrees" = "rotate270"),
prettyOptions = list(shape = "curve", status = "success",
fill = F, inline = F)
)
})
observeEvent(input$buttonrotate, {
if (!input$inmethod)
img <- input$selectfile["datapath"] %>% as.character
if (input$inmethod)
img <- input$enter.path
img.check1 <- ifelse(length(img) >= 1, TRUE, FALSE)
img.check2 <- FALSE
if (img.check1)
img.check2 <- ifelse(nchar(img) > 1, TRUE, FALSE)
if (any(!img.check1, !img.check2, is.null(img.file$data))) {
et <- paste('The preview image has not been generated')
sendSweetAlert(
session = session, title = "Error", text = et, type = "error"
)
return()
}
degree <- input$rotatede %>% substring(7) %>% as.numeric
img.file$data <- rotateImg(img.file$data, degree)
img.file.crop$data <- img.file$data
img.file.copy$data <- rotateImg(img.file.copy$data, degree)
# new.dimt <- attributes(img.file$data)[["dimt"]]
# attributes(img.file.copy$data)[["dimt"]] <- new.dimt
plot1_ranges$x <- NULL
plot1_ranges$y <- NULL
plot2_ranges$x <- NULL
plot2_ranges$y <- NULL
df.loc$data <- NULL
df.loc$ID <- NULL
# path
path.info$x <- NULL
path.info$y <- NULL
path.info$type <- NULL
path.info$ID <- NULL
path.info$horizontal <- NULL
path.info$incline <- NULL
path.info$h <- NULL
path.info$dpi <- NULL
path.info$max <- NULL
path.info$df <- NULL
rw.dataframe$data <- NULL
updateTextInput(session, "m_line", value = '',
label = 'Y-coordinate of the path')
updatePrettyRadioButtons(
session = session, inputId = "cropcondition",
choiceNames = 'UNCROPPED', choiceValues = list('a'),
prettyOptions = list(shape = "curve", status = "danger",
fill = F, inline = F)
)
updateActionButton(session, "buttoncrop", label = "Crop")
})
observeEvent(input$magick.switch, {
if(input$magick.switch){
updatePrettySwitch(session, inputId = 'magick.switch',
label = 'Magick ON', value = TRUE)
} else {
updatePrettySwitch(session, inputId = 'magick.switch',
label = 'Magick OFF', value = FALSE)
}
})
observeEvent(input$buttoninputimage, {
magick.switch <- input$magick.switch
if (!input$inmethod) {
imgf <- input$selectfile
if (is.null(imgf)) {
et <- paste('The image file has not been uploaded')
sendSweetAlert(
session = session, title = "Error", text = et, type = "error"
)
return()
}
img <- as.character(imgf["datapath"])
img.name <- as.character(imgf["name"])
}
if (input$inmethod) {
img <- input$enter.path
if (img == '') {
et <- paste('The file path has not been entered')
sendSweetAlert(
session = session, title = "Error", text = et, type = "error"
)
return()
}
img.name <- basename(img)
}
updatePrettyRadioButtons(
session = session, inputId = "rotatede",
label = "Clockwise Rotation",
choices = c("0 degrees" = "rotate0",
"90 degrees" = "rotate90",
"180 degrees" = "rotate180",
"270 degrees" = "rotate270"),
prettyOptions = list(shape = "curve", status = "success",
fill = F, inline = F)
)
plot1_ranges$x <- NULL
plot1_ranges$y <- NULL
plot2_ranges$x <- NULL
plot2_ranges$y <- NULL
df.loc$data <- NULL
df.loc$ID <- NULL
# path
path.info$x <- NULL
path.info$y <- NULL
path.info$type <- NULL
path.info$ID <- NULL
path.info$horizontal <- NULL
path.info$incline <- NULL
path.info$h <- NULL
path.info$dpi <- NULL
path.info$max <- NULL
path.info$df <- NULL
rw.dataframe$data <- NULL
#cur.time <- as.character(Sys.time())
updateTextInput(session, "tuid", value = '',
label = 'Series ID')
updateTextInput(session, "sample_yr", value = '',
label = 'Sampling year')
updateTextInput(session, "dpi", value = '',
label = 'DPI of the image')
updatePrettyRadioButtons(
session = session, inputId = "cropcondition",
choiceNames = 'UNCROPPED', choiceValues = list('a'),
prettyOptions = list(shape = "curve", status = "danger",
fill = F, inline = F)
)
updateActionButton(session, "buttoncrop", label = "Crop")
img.file$data <- readImg(img, img.name, magick.switch)
img.file.crop$data <- img.file$data
#img.file.crop.copy$data <- as.raster(img.file$data)
dim.tdata <- attributes(img.file$data)[["dimt"]]
dimcol <- dim.tdata[1]
dimrow <- dim.tdata[2]
if ((dimcol*dimrow) >= 1.2e+07) {
resize.ratio <- 0.25
resize.str <- paste0(round(dimcol*resize.ratio), 'x',
round(dimrow*resize.ratio))
img.file.copy$data <- image_resize(img.file$data, resize.str)
} else {
img.file.copy$data <- img.file$data
}
})
plot1_ranges <- reactiveValues(x = NULL, y = NULL)
observeEvent(input$buttoncrop, {
if(is.null(img.file$data)){
et <- paste('The preview image have not been generated')
sendSweetAlert(
session = session, title = "Error", text = et, type = "error"
)
return()
}
plot1_brush <- input$plot1_brush
plot1_ranges$x <- NULL
plot1_ranges$y <- NULL
plot2_ranges$x <- NULL
plot2_ranges$y <- NULL
df.loc$data <- NULL
df.loc$ID <- NULL
# path
path.info$x <- NULL
path.info$y <- NULL
path.info$type <- NULL
path.info$ID <- NULL
path.info$horizontal <- NULL
path.info$incline <- NULL
path.info$h <- NULL
path.info$dpi <- NULL
path.info$max <- NULL
path.info$df <- NULL
rw.dataframe$data <- NULL
updateTextInput(session, "tuid", value = '', label = 'Series ID')
if (!is.null(plot1_brush)) {
plot1_ranges$x <- c(round(plot1_brush$xmin), round(plot1_brush$xmax))
plot1_ranges$y <- c(round(plot1_brush$ymin), round(plot1_brush$ymax))
#0730
dimt <- attributes(img.file$data)[["dimt"]]
dimcol <- dimt[1]
dimrow <- dimt[2]
if (dimcol * dimrow >= 1.2e+07) {
plot1_ranges$x <- plot1_ranges$x * 4
plot1_ranges$y <- plot1_ranges$y * 4
}
if (plot1_ranges$x[1] <= 0) plot1_ranges$x[1] <- 0
if (plot1_ranges$y[1] <= 0) plot1_ranges$y[1] <- 0
if (plot1_ranges$x[2] >= dimcol) plot1_ranges$x[2] <- dimcol
if (plot1_ranges$y[2] >= dimrow) plot1_ranges$y[2] <- dimrow
xmin <- plot1_ranges$x[1]
ymin <- plot1_ranges$y[1]
xmax <- plot1_ranges$x[2]
ymax <- plot1_ranges$y[2]
img.range <- paste0(as.character(xmax-xmin), 'x',
as.character(ymax-ymin), '+',
as.character(xmin), '+',
as.character(dimrow-ymax))
img.file.crop$data <- image_crop(img.file$data, img.range)
updateActionButton(session, "buttoncrop", label = "Cancel")
updatePrettyRadioButtons(
session = session, inputId = "cropcondition",
choiceNames = 'CROPPED', choiceValues = list('a'),
prettyOptions = list(shape = "curve", status = "success",
fill = F, inline = F)
)
} else {
img.file.crop$data <- img.file$data
updateActionButton(session, "buttoncrop", label = "Crop")
updatePrettyRadioButtons(
session = session, inputId = "cropcondition",
choiceNames = 'UNCROPPED', choiceValues = list('a'),
prettyOptions = list(shape = "curve", status = "danger",
fill = F, inline = F)
)
}
})
output$pre.img <- renderPlot({
if (is.null(img.file$data)) return()
imgInput(img.file$data, img.file.copy$data, plot1_ranges$x, plot1_ranges$y)
})
plot2_ranges <- reactiveValues(x = NULL, y = NULL)
df.loc <- reactiveValues(data = NULL, ID = NULL)
# update path options
observeEvent(input$sel_sin_mul, {
if(input$sel_sin_mul == "Single Segment") {
updateNumericInput(session = session, inputId = 'num_seg',
value = 1, min = 1, max = 1, step = 1)
updatePrettyCheckbox(
session = session, inputId = "hor_path", value = TRUE)
updatePrettyCheckbox(
session = session, inputId = "incline", value = FALSE)
} else {
updateNumericInput(session = session, inputId = 'num_seg',
value = 2, min = 1, max = 10, step = 1)
updatePrettyCheckbox(
session = session, inputId = "hor_path", value = FALSE)
updatePrettyCheckbox(
session = session, inputId = "incline", value = FALSE)
}
})
# 0803 delete a segment
observeEvent(input$rm_last, {
if(is.null(path.info$x)) {
et <- 'The path to be removed does not exist.'
sendSweetAlert(
session = session, title = "Error", text = et, type = "error"
)
return()
}
if(length(path.info$x) == 1) {
path.info$x <- NULL
path.info$y <- NULL
path.info$type <- NULL
path.info$ID <- NULL
path.info$horizontal <- NULL
path.info$incline <- NULL
path.info$h <- NULL
path.info$dpi <- NULL
path.info$max <- NULL
et <- 'The path has been removed. You need to recreate a path.'
sendSweetAlert(
session = session, "Success", et, "success"
)
return()
}
if(length(path.info$x) >= 2) {
path.info$x <- path.info$x[-length(path.info$x)]
path.info$y <- path.info$y[-length(path.info$y)]
et <- 'The last endpoint added has been removed.'
sendSweetAlert(
session = session, "Success", et, "success"
)
return()
}
})
# 0803 delete all segments
observeEvent(input$rm_all, {
if(is.null(path.info$x)) {
et <- 'The path to be removed does not exist.'
sendSweetAlert(
session = session, title = "Error", text = et, type = "error"
)
return()
}
if(length(path.info$x) >= 1) {
path.info$x <- NULL
path.info$y <- NULL
path.info$type <- NULL
path.info$ID <- NULL
path.info$horizontal <- NULL
path.info$incline <- NULL
path.info$h <- NULL
path.info$dpi <- NULL
path.info$max <- NULL
df.loc$data <- NULL
df.loc$ID <- NULL
plot2_ranges$x <- NULL
plot2_ranges$y <- NULL
et <- 'The path has been removed. You need to recreate a path.'
sendSweetAlert(
session = session, "Success", et, "success"
)
return()
}
})
# del border points
observeEvent(input$rm_all_border, {
if(is.null(df.loc$data)) {
et <- 'Ring borders were not found'
sendSweetAlert(
session = session, title = "Error", text = et, type = "error"
)
return()
}
df.loc$data <- NULL
et <- 'All ring borders have been removed'
sendSweetAlert(
session = session, "Success", et, "success"
)
return()
})
# record slider info
crop.offset.xy <- reactiveValues(x = NULL, y = NULL)
observeEvent(input$img_ver, {
if (is.null(img.file.crop$data))
return()
dimt <- image_info(img.file.crop$data) %>% '['(1, 2:3) %>% as.numeric
dimrow <- dimt[2]
crop.offset.xy$y <- dimrow - round(input$img_ver[2]*dimrow/1000)
})
observeEvent(input$img_hor, {
if (is.null(img.file.crop$data))
return()
dimt <- image_info(img.file.crop$data) %>% '['(1, 2:3) %>% as.numeric
dimcol <- dimt[1]
crop.offset.xy$x <- input$img_hor[1]*dimcol/100 %>% round
})
observeEvent(img.file.crop$data, {
if (is.null(img.file.crop$data))
return()
dimt <- image_info(img.file.crop$data) %>% '['(1, 2:3) %>% as.numeric
dimcol <- dimt[1]
dimrow <- dimt[2]
crop.offset.xy$x <- input$img_hor[1]*dimcol/100 %>% round
crop.offset.xy$y <- dimrow - round(input$img_ver[2]*dimrow/1000)
})
# record mouse position to generate a preview path
hover.xy <- reactiveValues(x = NULL, y = NULL)
observeEvent(input$plot2_hover, {
hover.xy$x <- input$plot2_hover$x
hover.xy$y <- input$plot2_hover$y
})
# turn off ring width correction when switching to another mode
observeEvent(input$hor_path, {
updatePrettyCheckbox(
session = session, inputId = "incline",
value = FALSE)
})
observeEvent(input$sel_sin_mul, {
updatePrettyCheckbox(
session = session, inputId = "incline",
value = FALSE)
})
## create path with mouse clicks
path.info <- reactiveValues(x = NULL, y = NULL, type = NULL, ID = NULL,
horizontal = NULL, incline = NULL, h = NULL,
dpi = NULL, max = NULL, df = NULL)
observeEvent(input$plot2_dblclick,
{
if(input$sel_mode != "sel_path")
return()
if (is.null(img.file.crop$data)) {
et <- 'Path creation fails because the image has not been plotted'
sendSweetAlert(
session = session, title = "Error", text = et, type = "error"
)
return()
}
dpi <- as.numeric(input$dpi)
if (is.na(dpi)) {
et <- 'Please enter the DPI of the image'
sendSweetAlert(
session = session, title = "Error", text = et, type = "error"
)
return()
}
seriesID <- input$tuid
if (seriesID == '') {
et <- 'Please enter a series ID'
sendSweetAlert(
session = session, title = "Error", text = et, type = "error"
)
return()
}
dimt <- image_info(img.file.crop$data) %>% '['(1, 2:3) %>% as.numeric
dimrow <- dimt[2]
dimcol <- dimt[1]
if (!is.null(path.info$max)) {
if(length(path.info$x) >= path.info$max) {
et <- paste('You have already created a path')
sendSweetAlert(
session = session, title = "Error", text = et, type = "error"
)
return()
}
}
if(length(path.info$x) >= 1) {
cur.p.x <- round(input$plot2_dblclick$x + crop.offset.xy$x)
last.point <- path.info$x[length(path.info$x)]
if(last.point >= cur.p.x) {
et <- paste('The x-position of the current point must be greater',
'than the x-position of the previous point')
sendSweetAlert(
session = session, title = "Error", text = et, type = "error"
)
return()
}
}
px <- round(input$plot2_dblclick$x + crop.offset.xy$x)
if (px <= 0 | px >= dimcol) {
et <- paste('The X-coordinate of the endpoint is out of',
'range. Please click on the image.')
sendSweetAlert(
session = session, title = "Error", text = et, type = "error"
)
return()
}
crop.h <- round(diff(input$img_ver)*dimrow/1000)
if (input$plot2_dblclick$y >= crop.h | input$plot2_dblclick$y <= 0) {
et <- paste('The Y-coordinate of the endpoint is out of',
'range. Please click on the image.')
sendSweetAlert(
session = session, title = "Error", text = et, type = "error"
)
return()
}
py <- round(input$plot2_dblclick$y + crop.offset.xy$y)
dp <- dpi/25.4
h.dis <- as.numeric(input$h.dis)
d <- h.dis*dp/2
incline <- input$incline
hor <- input$hor_path
if (hor & incline) {
if(py + d >= dimrow) {
et <- paste('The Y-coordinate of the upper path is out of range.',
'Please decrease the distance between paths')
sendSweetAlert(
session = session, title = "Error", text = et, type = "error"
)
return()
}
if(py - d <= 0) {
et <- paste('The Y-coordinate of the lower path is out of range.',
'Please decrease the distance between paths')
sendSweetAlert(
session = session, title = "Error", text = et, type = "error"
)
return()
}
}
if(length(path.info$x) >= 1) {
if (path.info$horizontal) {
py <- path.info$y[1]
}
}
path.info$x <- c(path.info$x, px)
path.info$y <- c(path.info$y, py)
if(length(path.info$x) == 1) {
rt <- paste('The beginning point of the path have been created.')
sendSweetAlert(
session = session, title = "Success", text = rt, type = "success"
)
# record path info only the first time you click
path.info$type <- input$sel_sin_mul
path.info$ID <- seriesID
path.info$horizontal <- input$hor_path
path.info$incline <- input$incline
path.info$h <- as.numeric(input$h.dis)
path.info$dpi <- dpi
path.info$max <- input$num_seg + 1
df.loc$ID <- input$tuid
}
# record xy-coordinates of the path
if(length(path.info$x) == path.info$max) {
rt <- paste('The ending point of the path have been created.',
'Please switch to another working mode.')
sendSweetAlert(
session = session, title = "Success", text = rt, type = "success"
)
px <- path.info$x
py <- path.info$y
path.df <- as.data.frame(matrix(ncol = 2, nrow = 0))
colnames(path.df) <- c('x', 'y')
len <- length(path.info$x) - 1
for (i in 1:len) {
p1 <- px[i]
p2 <- px[i+1]
lm1 <- lm(py[c(i, i + 1)] ~ c(p1, p2))
cf1 <- coef(lm1)
x1 <- p1:p2
y1 <- cf1[1] + cf1[2] * x1
c1 <- data.frame(x = x1, y = y1)
path.df <- rbind(path.df, c1)
}
path.df$y <- round(path.df$y)
path.info$df <- path.df
}
})
## run auto detection
observeEvent(input$button_run_auto, {
if (is.null(path.info$df)) {
et <- 'A path has not been created.'
sendSweetAlert(
session = session, title = "Error", text = et, type = "error"
)
return()
}
isrgb <- input$isrgb
if (isrgb) {
RGB <- c(0.299, 0.587, 0.114)
} else {
RGB <- strsplit(input$customRGB, ',')[[1]] %>% as.numeric
}
dpi <- path.info$dpi
dp <- dpi/25.4
incline <- path.info$incline
h.dis <- path.info$h
ph <- path.info$horizontal
path.df <- path.info$df
px <- path.info$x
py <- path.info$y
defaultse <- input$defaultse
if (defaultse) {
struc.ele1 <- NULL
struc.ele2 <- NULL
} else {
struc.ele1 <- c(input$struc.ele1, input$struc.ele1) %>% as.numeric
struc.ele2 <- c(input$struc.ele2, input$struc.ele2) %>% as.numeric
}
img <- img.file.crop$data
method <- input$method
if(input$watershed.threshold == 'custom.waterthr'){
watershed.threshold <- input$watershed.threshold2
} else {
watershed.threshold <- input$watershed.threshold
}
watershed.adjust <- input$watershed.adjust
progressSweetAlert(
session = session, id = "detect_progress",
title = "Detection in progress",
display_pct = F, value = 0
)
if (method == 'watershed') {
df.loc$data <- automatic.det(
img, incline, method, h.dis, dpi, RGB, px, py, ph, path.df,
watershed.threshold, watershed.adjust, struc.ele1, struc.ele2
)
}
if (method == "canny") {
default.canny <- input$defaultcanny
canny.t1 <- as.numeric(input$canny.t1)
canny.t2 <- as.numeric(input$canny.t2)
canny.adjust <- input$canny.adjust
canny.smoothing <- input$canny.smoothing
df.loc$data <- automatic.det(
img, incline, method, h.dis, dpi, RGB, px, py, ph, path.df,
watershed.threshold, watershed.adjust, struc.ele1, struc.ele2,
default.canny, canny.t1, canny.t2, canny.adjust, canny.smoothing
)
}
if (method == "lineardetect") {
if (incline | path.info$type == "Multi Segments" | !ph) {
rt <- paste('The linear detection supports only Single Segment',
'mode (without ring width correction). Please recreate',
'a horizontal single-segment path.')
sendSweetAlert(
session = session, title = "ERROR", text = rt, type = "warning"
)
return()
}
origin <- as.numeric(input$origin)
f.df.loc <- automatic.det(
img, incline, method, h.dis, dpi, RGB, px, py, ph, path.df,
struc.ele1 = struc.ele1, struc.ele2 = struc.ele2, origin = origin
)
df.loc$data <- f.df.loc
}
number.border <- nrow(df.loc$data)
if (number.border == 0) {
rt <- 'Ring border was NOT detected'
closeSweetAlert(session = session)
sendSweetAlert(
session = session, title = "Error", text = rt, type = "error"
)
} else {
rt <- paste(number.border, 'borders were detected')
closeSweetAlert(session = session)
sendSweetAlert(
session = session, title = "Finished", text = rt, type = "success"
)
}
})
## Ring editing mode
observeEvent(input$plot2_dblclick, {
if(input$sel_mode == "sel_det"){
et <- paste('If you want to add new ring borders by double-clicking,',
'please switch to the "Ring Editing" mode')
sendSweetAlert(
session = session, title = "Error", text = et, type = "error"
)
return()
}
})
# add a point by double clicking
observeEvent(input$plot2_dblclick, {
if(input$sel_mode != "sel_edit")
return()
if (is.null(img.file.crop$data)) {
et <- paste('Adding new ring borders fails',
'because the image has not been plotted')
sendSweetAlert(
session = session, title = "Error", text = et, type = "error"
)
return()
}
if (is.null(path.info$df)) {
et <- paste('Adding new ring borders fails',
'because a path has not been created')
sendSweetAlert(
session = session, title = "Error", text = et, type = "error"
)
return()
}
if (is.null(df.loc$data)) {
bor.df <- matrix(nrow = 0, ncol = 3) %>% as.data.frame
colnames(bor.df) <- c('x', 'y', 'z')
} else {
bor.df <- df.loc$data
}
dimt <- image_info(img.file.crop$data) %>% '['(1, 2:3) %>% as.numeric
dimrow <- dimt[2]
dimcol <- dimt[1]
# mouse position info
bor <- input$plot2_dblclick
px <- round(bor$x + crop.offset.xy$x)
y_cor <- round(bor$y + crop.offset.xy$y)
if (px <= path.info$x[1] | px >= path.info$x[length(path.info$x)]) {
et <- paste('The X-coordinate of the point you click is',
'out of range. Please click on the path')
sendSweetAlert(
session = session, title = "Error", text = et, type = "error"
)
return()
}
# check y-coordinates
crop.h <- round(diff(input$img_ver)*dimrow/1000)
if (input$plot2_dblclick$y >= crop.h | input$plot2_dblclick$y <= 0) {
et <- paste('The Y-coordinate of the point you click is',
'out of range. Please click on the path')
sendSweetAlert(
session = session, title = "Error", text = et, type = "error"
)
return()
}
path.df <- path.info$df
if (path.info$horizontal & path.info$incline) {
dpi <- path.info$dpi
dp <- dpi/25.4
h.dis <- path.info$h
py <- path.df$y[path.df$x == px]
py <- ifelse(y_cor > path.info$y[1],
py + round(h.dis * dp / 2),
py - round(h.dis * dp / 2))
pz <- ifelse(y_cor > path.info$y[1], 'u', 'l')
temp.df <- data.frame(x = px, y = py, z = pz)
} else {
py <- path.df$y[path.df$x == px]
temp.df <- data.frame(x = px, y = py, z = 'u')
}
df.loc$data <- rbind(bor.df, temp.df)
})
# delete points with a brush
observeEvent(input$buttonzoomdel, {
if (is.null(input$plot2_brush$xmin)) {
err.text <- 'You have not selected ring borders with a brush'
sendSweetAlert(
session = session, title = "Error", text = err.text, type = "error"
)
return()
}
if (is.null(path.info$df)) {
err.text <- 'A path has not been created'
sendSweetAlert(
session = session, title = "Error", text = err.text, type = "error"
)
return()
}
if (is.null(df.loc$data)) {
remove.text <- 'Ring border was NOT found along the path'
sendSweetAlert(
session = session, title = "Error", text = remove.text, type = "error"
)
return()
}
xmin <- round(input$plot2_brush$xmin + crop.offset.xy$x)
xmax <- round(input$plot2_brush$xmax + crop.offset.xy$x)
ymin <- round(input$plot2_brush$ymin + crop.offset.xy$y)
ymax <- round(input$plot2_brush$ymax + crop.offset.xy$y)
x.ranges <- df.loc$data$x
delete.bor <- x.ranges >= xmin & x.ranges <= xmax
y.ranges <- df.loc$data$y
is.contain <- ymin <= y.ranges & ymax >= y.ranges
delete.bor <- delete.bor & is.contain
if (any(delete.bor)) {
df.loc$data <- df.loc$data[!delete.bor,]
} else {
err.text <- 'Ring border was NOT found in the area you selected'
sendSweetAlert(
session = session, title = "Error", text = err.text, type = "error"
)
}
})
output$ring_edit <- renderPlot({
if (is.null(img.file$data)) return()
imgInput_crop(img.file.crop$data, input$img_ver, input$img_hor)
sample_yr <- as.numeric(input$sample_yr)
if (is.na(sample_yr)) return()
pch <- as.numeric(input$pch)
bor.color <- input$border.color
lab.color <- input$label.color
l.w <- as.numeric(input$linelwd)
label.cex <- as.numeric(input$label.cex)*0.7
plot.marker(path.info, hover.xy, sample_yr, l.w, pch,
bor.color, lab.color, label.cex)
})
observeEvent(input$button_del, {
if (is.null(path.info$df)) {
rt <- paste('You can not remove ring borders because',
'the path has not been created.')
sendSweetAlert(
session = session, title = "Error", text = rt, type = "error"
)
return()
}
if (is.null(df.loc$data)) {
rt <- paste('Ring borders were not found')
sendSweetAlert(
session = session, title = "Error", text = rt, type = "error"
)
return()
}
incline <- path.info$incline
bx <- df.loc$data$x
by <- df.loc$data$y
bz <- df.loc$data$z
bz <- bz[order(bx)]
by <- by[order(bx)]
bx <- sort(bx)
if (incline) {
if (input$del.u == '' & input$del.l == '') {
rt <- 'Please enter border numbers'
sendSweetAlert(
session = session, title = "Error", text = rt, type = "error"
)
return()
}
del.u <- input$del.u
del.l <- input$del.l
if (del.u != '')
del.u <- strsplit(del.u, ",")[[1]] %>% as.numeric
if(del.l != '')
del.l <- strsplit(del.l, ",")[[1]] %>% as.numeric
# ndf <- length(del.u) + length(del.l)
up <- which(bz == 'u')
lenup <- length(up)
bx.u <- bx[up]
by.u <- by[up]
if (lenup >= 1 & input$del.u != '') {
if (max(del.u) <= lenup) {
bx.u <- bx.u[-del.u]
by.u <- by.u[-del.u]
} else {
rt <- 'The border number you entered did not exist'
sendSweetAlert(
session = session, title = "Error", text = rt, type = "error"
)
return()
}
}
lower <- which(bz == 'l')
lenlo <- length(lower)
bx.l <- bx[lower]
by.l <- by[lower]
if (lenlo >= 1 & input$del.l != '') {
if (max(del.l) <= lenlo) {
bx.l <- bx.l[-del.l]
by.l <- by.l[-del.l]
} else {
rt <- 'The border number you entered did not exist'
sendSweetAlert(
session = session, title = "Error", text = rt, type = "error"
)
return()
}
}
df.u <- data.frame(x = bx.u, y = by.u, z = 'u')
df.l <- data.frame(x = bx.l, y = by.l, z = 'l')
df.loc$data <- rbind(df.u, df.l)
updateTextInput(session, "del.u",
label = 'Border number in the upper portion',
value = '')
updateTextInput(session, "del.l",
label = 'Border number in the lower portion',
value = '')
} else {
if (input$del == '') {
rt <- 'You have not entered any border number'
sendSweetAlert(
session = session, title = "Error", text = rt, type = "error"
)
return()
}
del <- strsplit(input$del, ",")[[1]] %>% as.numeric
if (max(del) <= length(bx)) {
bx <- bx[-del]
by <- by[-del]
df.loc$data <- data.frame(x = bx, y = by, z = 'u')
updateTextInput(session, "del", label = 'Border number', value = '')
} else {
rt <- 'The border number you entered did not exist'
sendSweetAlert(
session = session, title = "Error", text = rt, type = "error"
)
return()
}
}
})
rw.dataframe <- reactiveValues(data = NULL)
observeEvent(input$button_results, {
if (is.null(df.loc$data)) {
error.text <- 'Ring border was not found along the path'
sendSweetAlert(
session = session, title = "Error", text = error.text, type = "error"
)
return()
}
if (nrow(df.loc$data) <= 1) {
error.text <- paste('A minimum of two ring borders on each path',
'was required to generate a ring-width series')
sendSweetAlert(
session = session, title = "Error", text = error.text, type = "error"
)
return()
}
sample_yr <- as.numeric(input$sample_yr)
if (is.na(sample_yr)) {
error.text <- paste('Please check the argument \'Sampling year\' ')
sendSweetAlert(
session = session, title = "Error", text = error.text, type = "error"
)
return()
}
dpi <- path.info$dpi
dp <- dpi/25.4
incline <- path.info$incline
h.dis <- path.info$h
ph <- path.info$horizontal
path.df <- path.info$df
px <- path.info$x
py <- path.info$y
if (incline) {
incline.cond <- df.loc$data$z %>% table %>% as.numeric
if (length(incline.cond) == 1) {
rt <- paste('A minimum of two ring borders on each path',
'was required to generate a ring-width series')
sendSweetAlert(
session = session, title = "Error", text = rt, type = "error"
)
return()
}
if (all(incline.cond >= 2) & incline.cond[1] == incline.cond[2]) {
rw.dataframe$data <- f.rw(df.loc$data, sample_yr,
incline, dpi, h.dis)
} else {
if (any(incline.cond < 2)) {
et <- paste('A minimum of two ring borders on each path',
'was required to generate a ring-width series')
sendSweetAlert(
session = session, title = "Error", text = et, type = "error"
)
} else {
et <- paste("If you tick the checkbox \"Inclined tree",
"rings\", the upper and lower paths should",
"have the same number of ring borders.")
sendSweetAlert(
session = session, title = "Error", text = et, type = "error"
)
}
}
} else {
rw.dataframe$data <- f.rw(df.loc$data, sample_yr,
incline, dpi, h.dis)
}
})
output$results <- renderTable({
if (is.null(rw.dataframe$data)) {
return()
} else {
return(rw.dataframe$data)
}
})
observeEvent(input$button_hide, {
if (is.null(rw.dataframe$data)) {
rt <- 'The data frame to be deleted does not exist'
sendSweetAlert(
session = session, title = "Error", text = rt, type = "error"
)
} else {
rw.dataframe$data <- NULL
}
})
output$RingWidth.csv <- downloadHandler(
filename = function() {
if (is.null(img.file$data)) {
img.name <- 'Download Fail'
return(paste0(img.name, '.csv'))
} else {
img.name <- input$tuid
}
if (input$csv.name != '')
img.name <- input$csv.name
return(paste0(img.name, '.csv'))
},
content = function(filename) {
if (is.null(df.loc$data)) {
error.text <- 'Ring border was not found along the path'
sendSweetAlert(
session = session, title = "Error", text = error.text, type = "error"
)
return()
}
if (nrow(df.loc$data) <= 1) {
error.text <- paste('A minimum of two ring borders on each path',
'was required to generate a ring-width series')
sendSweetAlert(
session = session, title = "Error", text = error.text, type = "error"
)
return()
}
sample_yr <- as.numeric(input$sample_yr)
if (is.na(sample_yr)) {
error.text <- paste('Please check the argument \'Sampling year\' ')
sendSweetAlert(
session = session, title = "Error", text = error.text, type = "error"
)
return()
}
dpi <- path.info$dpi
dp <- dpi/25.4
incline <- path.info$incline
h.dis <- path.info$h
if (incline) {
incline.cond <- df.loc$data$z %>% table %>% as.numeric
if (length(incline.cond) == 1) {
rt <- paste('A minimum of two ring borders on each path',
'was required to generate a ring-width series')
sendSweetAlert(
session = session, title = "Error", text = rt, type = "error"
)
return()
}
if (all(incline.cond >= 2) & incline.cond[1] == incline.cond[2]) {
df.rw <- f.rw(df.loc$data, sample_yr, incline, dpi, h.dis)
write.csv(df.rw, filename, quote = FALSE, na = '--')
} else {
if (any(incline.cond < 2)) {
rt <- paste('A minimum of two ring borders on each path ',
'was required to generate a ring-width series')
sendSweetAlert(
session = session, title = "Error", text = rt, type = "error"
)
return()
} else {
rt <- paste("If you tick the checkbox \"Inclined tree",
"rings\", the upper and lower paths should",
"have the same number of ring borders.")
sendSweetAlert(
session = session, title = "Error", text = rt, type = "error"
)
return()
}
}
} else {
df.rw <- f.rw(df.loc$data, sample_yr, incline, dpi, h.dis)
write.csv(df.rw, filename, quote = FALSE, na = '--')
}
},
contentType = 'csv'
)
observeEvent(input$reset.hdr,{
updateTextInput(session, "tuhdr1",label = 'Site ID',value = '')
updateTextInput(session, "tuhdr2",label = 'Site Name',value = '')
updateTextInput(session, "tuhdr3",label = 'Species Code',value = '')
updateTextInput(session, "tuhdr4",label = 'State or Country',value = '')
updateTextInput(session, "tuhdr5",label = 'Species',value = '')
updateTextInput(session, "tuhdr6",label = 'Elevation',value = '')
updateTextInput(session, "tuhdr7",label = 'Latitude',value = '')
updateTextInput(session, "tuhdr8",label = 'Longitude',value = '')
updateTextInput(session, "tuhdr9",label = 'First Year',value = '')
updateTextInput(session, "tuhdr10",label = 'Last Year',value = '')
updateTextInput(session, "tuhdr11",label = 'Lead Investigator',value = '')
updateTextInput(session, "tuhdr12",label = 'Completion Date',value = '')
})
output$RingWidth.rwl <- downloadHandler(
filename = function() {
if (is.null(df.loc$data)) {
img.name <- 'Download Unavailable'
return(paste0(img.name, '.rwl'))
} else {
img.name <- input$tuid
}
if (input$rwl.name != '')
img.name <- input$rwl.name
return(paste0(img.name, '.rwl'))
},
content = function(filename) {
seriesID <- df.loc$ID
miss.id1 <- seriesID == ''
if (miss.id1) {
rt <- 'Please enter a series ID'
sendSweetAlert(
session = session, title = "Error", text = rt, type = "error"
)
return()
}
if (is.null(df.loc$data)) {
error.text <- 'Ring border was not found along the path'
sendSweetAlert(
session = session, title = "Error", text = error.text, type = "error"
)
return()
}
if (nrow(df.loc$data) <= 1) {
error.text <- paste('A minimum of two ring borders on each path',
'was required to generate a ring-width series')
sendSweetAlert(
session = session, title = "Error", text = error.text, type = "error"
)
return()
}
sample_yr <- as.numeric(input$sample_yr)
if (is.na(sample_yr)) {
error.text <- paste('Please check the argument \'Sampling year\' ')
sendSweetAlert(
session = session, title = "Error", text = error.text, type = "error"
)
return()
}
dpi <- path.info$dpi
dp <- dpi/25.4
incline <- path.info$incline
h.dis <- path.info$h
df.rw <- NULL
if (incline) {
incline.cond <- df.loc$data$z %>% table %>% as.numeric
if (length(incline.cond) == 1) {
rt <- paste('A minimum of two ring borders on each path',
'was required to generate a ring-width series')
sendSweetAlert(
session = session, title = "Error", text = rt, type = "error"
)
return()
}
if (all(incline.cond >= 2) & incline.cond[1] == incline.cond[2]) {
df.rw <- f.rw(df.loc$data, sample_yr, incline, dpi, h.dis)
} else {
if (any(incline.cond < 2)) {
rt <- paste('A minimum of two ring borders on each path',
'was required to generate a ring-width series')
sendSweetAlert(
session = session, title = "Error", text = rt, type = "error"
)
return()
} else {
rt <- paste("If incline = TRUE, the upper and lower paths",
"should have the same number of ring borders")
sendSweetAlert(
session = session, title = "Error", text = rt, type = "error"
)
return()
}
}
} else {
df.rw <- f.rw(df.loc$data, sample_yr, incline, dpi, h.dis)
}
df.rwl <- data.frame(df.rw$ring.width, row.names = df.rw$year)
tuprec <- as.numeric(input$tuprec)
tuheader <- input$tuheader
tuhdr1 <- input$tuhdr1
tuhdr2<- input$tuhdr2
tuhdr3 <- input$tuhdr3
tuhdr4 <- input$tuhdr4
tuhdr5 <- input$tuhdr5
tuhdr6 <- input$tuhdr6
tuhdr7 <- input$tuhdr7
tuhdr8 <- input$tuhdr8
tuhdr9 <- input$tuhdr9
tuhdr10 <- input$tuhdr10
tuhdr11 <- input$tuhdr11
tuhdr12 <- input$tuhdr12
colnames(df.rwl) <- seriesID
hdr.list<- NULL
if (tuheader) {
hdr <- c(tuhdr1, tuhdr2, tuhdr3, tuhdr4, tuhdr5, tuhdr6,
tuhdr7, tuhdr8, tuhdr9, tuhdr10, tuhdr11, tuhdr12)
hdr.name <- c('site.id','site.name', 'spp.code', 'state.country',
'spp','elev', 'lat', 'long', 'first.yr', 'last.yr',
'lead.invs', 'comp.date')
which.not.empty <- hdr != ''
if (any(which.not.empty)) {
hdr.list <- lapply(hdr, function(x) x)
names(hdr.list) <- hdr.name
}
}
write.rwl(rwl.df = df.rwl, fname = filename,
format = "tucson", header = hdr.list,
append = FALSE, prec = tuprec)
}, contentType = "rwl"
)
}
shinyApp(ui = createUI(), server = createServer)
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.