Nothing
#' datacleanr server function
#' @param input,output,session standard \code{shiny} boilerplate
#' @param dataset data.frame, tibble or data.table that needs cleaning
#' @param df_name character, name of dataset or file_path passed into shiny app
#' @param is_on_disk logical, whether df was read from file
#'
#' @importFrom rlang .data
#'
datacleanr_server <- function(input, output, session, dataset, df_name, is_on_disk) {
ns <- session$ns
# old_tz <- Sys.getenv("TZ")
# Sys.setenv(TZ = "UTC")
# suppress plotly warnings, etc.
# options(warn = -1)
# DIAGNOSTICS ----------------------
#
# AllInputs <- shiny::reactive({
# x <- unlist(shiny::reactiveValuesToList(input))
# paste(names(x),
# x)
#
#
# })
#
# output$show_inputs <- shiny::renderText({
# AllInputs()
# })
# Set-up ------------------------------------------------------------------
# hide all tabs until go button is clicked
# shiny::hideTab(inputId = "nav", target = "tabFiltering")
# shiny::hideTab(inputId = "nav", target = "tabVisualization")
# shiny::hideTab(inputId = "nav", target = "tabExtraction")
#
# shiny::observeEvent(input$gobutton,
# {
#
# shiny::showTab(inputId = "nav", target = "tabFiltering")
# shiny::showTab(inputId = "nav", target = "tabVisualization")
# shiny::showTab(inputId = "nav", target = "tabExtraction")
#
# })
# handle initialization
dataset$.dcrkey <- seq_len(nrow(dataset))
dataset <- dplyr::mutate_if(dataset,
.predicate = ~ rlang::inherits_any(.x, "POSIXt"),
.funs = ~ lubridate::force_tz(.x, "UTC")
)
# stores data used in app
datareactive <- shiny::reactiveVal()
# stores original data after hitting start button
recover_data <- shiny::reactiveVal()
# tracks which version of data to pass to datareactive
action_tracking <- shiny::reactiveValues(
plot_start = NULL,
controls = NULL
)
# stores recent data selection (used when filtering is reset)
selected_data_recovery <- shiny::reactiveVal()
# used for extraction tab
# filter_string <- shiny::reactiveVal()
filter_strings <- shiny::reactiveValues()
# holds plotly selection data
selected_data <- shiny::reactiveValues(
df = data.frame(
keys = integer(0),
selection_count = integer(0),
.annotation = character(0),
stringsAsFactors = FALSE
)
)
# max_id_original_traces <- shiny::reactive({dplyr::n_groups(datareactive()) - 1})
max_id_original_traces <- shiny::reactive({
dplyr::n_groups(datareactive())
})
# // ----------------------------------------------------------------------
# GROUPING ---------------------------
# get grouping
gvar <- shiny::callModule(module_server_group_select,
id = "group",
dframe = dataset
)
output$gvar <- shiny::reactive({
gvar()
})
# check-box for grouping
grouping_check <- shiny::callModule(
module = module_server_checkbox,
"grouptick",
text = "Use grouping for summary"
)
shiny::outputOptions(output, "gvar", suspendWhenHidden = FALSE)
# START + SUMMARY -------------------
# summary-button
# output$gosummarybutton <- shiny::renderUI({
#
# # shiny::observeEvent(selected_data, {
# shiny::validate(shiny::need(input[["gobutton"]],
# label = "",
# message = ""))
#
# shiny::tagList(shiny::actionButton(inputId = "gosummary",
# label = "Generate Summary",
# icon = shiny::icon("rocket"),
# class = "btn-info"))
#
# })
gobutton_reactive <- shiny::reactive({
input$gobutton
})
# handle summary operations when go button is hit
shiny::observeEvent(input$gobutton,
{
dframe <- apply_data_set_up(df = dplyr::ungroup(dataset), gvar())
dframe <- dplyr::mutate(dframe,
.dcrindex = dplyr::cur_group_id()
)
datareactive(dframe)
recover_data(dframe)
},
priority = 100
)
# shiny::observeEvent(input$gobutton, {
# shiny::observe({
shiny::callModule(module_server_summary,
"summary",
dframe = datareactive,
group_var_check = grouping_check,
#
# df = {if(!is.null(datareactive()) &&
# !grouping_check()){
#
# dplyr::ungroup(datareactive())
#
# } else if(!is.null(datareactive()) &&
# grouping_check()){
#
# datareactive()
# }},
df_label = df_name,
start_clicked = gobutton_reactive
)
# })
# // ----------------------------------------------------------------------
# FILTER STATEMENTS ------------------
# CREATE EMPTY DATAFRAME
add.filter <- shiny::reactiveValues()
add.filter$df <- dplyr::tibble(
filter = character(0),
grouping = list()
)
btn <- shiny::reactiveValues(value = 0)
# ADD VARIABLES
shiny::observeEvent(input$addbutton, {
shiny::validate(shiny::need(input$gobutton > 0, label = "Press go first!"))
btn$value <- btn$value + 1
btn.tmp <- btn$value
# isolate prevents 'apply filter' from re-firing
shiny::callModule(module_server_filter_str,
btn.tmp,
dframe = shiny::isolate(datareactive())
)
shiny::insertUI(
selector = paste0("#", "placeholder"),
where = "beforeEnd",
ui = module_ui_filter_str(btn.tmp)
)
# save data into df
shiny::observeEvent(
{
input[[shiny::NS(btn.tmp, "groupdropdown")]]
input[[shiny::NS(btn.tmp, "filter")]]
},
{
add.filter$df[btn.tmp, 1] <- input[[shiny::NS(btn.tmp, "filter")]]
add.filter$df[btn.tmp, "grouping"][[1]] <- list(input[[shiny::NS(btn.tmp, "groupdropdown")]])
}
)
# Remove filters
shiny::observeEvent(input$removebutton, {
shiny::validate(shiny::need(input$gobutton > 0, label = "Press go first!"))
# drop lines and ui
add.filter$df <- add.filter$df[-btn$value, , drop = FALSE]
shiny::removeUI(
selector = paste0("#", btn$value, "-filt")
)
# manage buttons
if (btn$value > 1) {
btn$value <- btn$value - 1
} else {
btn$value <- 0
}
})
# # diagnostic df
# output$outDF <- shiny::renderPrint({
# })
})
# FILTER PREVIEW STRING ---------------------------------------------------
#
tmp_filter <- shiny::reactiveVal()
shiny::observe({
shiny::validate(shiny::need(add.filter,
label = "add filter"
))
# shiny::validate(shiny::need(input$gobutton,
# label = "StartButton"))
filt_out <- shiny::callModule(
module = module_server_df_filter,
id = "check",
dframe = shiny::isolate(recover_data()),
condition_df = add.filter$df
)
shiny::isolate(tmp_filter(filt_out))
})
# FILTER Apply/Undo -------------------------------------------------------
filter_statements_lgl <- shiny::reactiveVal()
filter_df <- shiny::reactiveVal(data.frame())
# apply
shiny::observeEvent(input$apply_filter, {
shiny::validate(shiny::need(add.filter,
label = "add filter"
))
shiny::validate(shiny::need(input$gobutton,
label = "StartButton"
))
shiny::isolate(datareactive(shiny::isolate(tmp_filter()$df)))
filter_statements_lgl(tmp_filter()$statements_lgl)
filter_df(add.filter$df)
## Logic to handle removal of selected data in plotly
# id points in selection now missing in data
if (nrow(selected_data$df) > 0) {
absent_selection <- selected_data$df$keys %nin% datareactive()$.dcrkey
if (!is.null(selected_data_recovery())) {
selected_data_recovery(rbind(selected_data$df[absent_selection, ], selected_data_recovery()))
} else {
selected_data_recovery(selected_data$df[absent_selection, ])
}
# adjust selection
selected_data$df <- selected_data$df[!absent_selection, ]
}
# force replotting of data
if (!is.null(selector_vals$startscatter)) {
selector_vals$startscatter <- selector_vals$startscatter + 1
}
})
# reset filtering
shiny::observeEvent(
{
input$reset_filter
},
{
shiny::validate(shiny::need(add.filter,
label = "add filter"
))
shiny::validate(shiny::need(input$gobutton,
label = "StartButton"
))
datareactive(recover_data())
filter_statements_lgl(NULL)
# reset filters
add.filter$df <- add.filter$df[0, , drop = FALSE]
sapply(
seq_len(btn$value),
function(i) {
shiny::removeUI(
## pass in appropriate div id
selector = paste0("#", i, "-filt")
)
}
)
btn$value <- 0
filter_strings <- shiny::reactiveValues()
# reset selected data
if (!is.null(selected_data_recovery())) {
# adjust selection
selected_data$df <- rbind(
selected_data$df,
selected_data_recovery()
)
}
## Logic to handle removal of selected data in plotly
selected_data_recovery(NULL)
# force replotting of data
if (!is.null(selector_vals$startscatter)) {
selector_vals$startscatter <- selector_vals$startscatter + 1
}
}
)
# FILTER UPDATE GROUP SELECTION -------------------------------------------
shiny::observeEvent(input$gobutton,
{
if (btn$value > 0) {
sapply(
seq_len(btn$value),
function(i) {
shinyWidgets::updatePickerInput(
session = session,
inputId = shiny::NS(i, "groupdropdown"),
choices = unique(datareactive()$.dcrindex)
)
}
)
}
},
priority = 0
)
# // ----------------------------------------------------------------------
# GROUPTABLES --------------------------------------------------------------
shiny::observe({
if (!is.null(datareactive())) {
# on filter tab
shiny::callModule(module_server_group_selector_table,
id = "df-filter-tab",
df = datareactive,
df_label = df_name,
selection = "none",
options = list(scrollX = TRUE)
)
# on viz tab
shiny::callModule(module_server_group_selector_table,
id = "df",
df = datareactive,
df_label = df_name,
selection = "multiple",
options = list(scrollX = TRUE)
)
}
})
# selected_table_rows <- shiny::reactive({!is.null(input$`df-grouptable_rows_selected`)})
# GROUP TABLE RELAYOUT BTNS---------------------
shiny::callModule(module_server_group_relayout_buttons,
id = "grp_relayout",
startscatter = shiny::reactive(selector_vals$startscatter)
)
# GROUPTABLE PLOT LIMITS --------------------------------------------------
selected_table_rows <- shiny::reactiveVal()
shiny::observeEvent(input[["grp_relayout-update"]], {
shiny::validate(shiny::need(datareactive, label = "datareactive"))
shiny::validate(shiny::need(input[["selectors-startscatter"]], label = "PlotStartbutton"))
shiny::validate(shiny::need(action_tracking$plot_start, label = "plot_start actiontracking"))
shiny::validate(shiny::need(input[["plot-tracemap"]],
label = "need tracepam"
))
selected_table_rows(input$`df-grouptable_rows_selected`)
trace_map <- matrix(input[["plot-tracemap"]], ncol = 2, byrow = TRUE)
handle_restyle_traces(
source_id = "plot-scatterselect",
session = session,
dframe = datareactive(),
scaling = 0.1,
xvar = as.character(selector_vals$xvar),
yvar = as.character(selector_vals$yvar),
max_id_group_trace = max_id_original_traces(),
trace_map = trace_map,
# input_sel_rows = input$`df-grouptable_rows_selected`,
input_sel_rows = selected_table_rows(),
flush = TRUE
)
})
shiny::observeEvent(input[["grp_relayout-clear"]], {
shiny::validate(shiny::need(datareactive, label = "datareactive"))
shiny::validate(shiny::need(input[["selectors-startscatter"]], label = "PlotStartbutton"))
shiny::validate(shiny::need(action_tracking$plot_start, label = "plot_start actiontracking"))
shiny::validate(shiny::need(input[["plot-tracemap"]],
label = "need tracepam"
))
dtpr <- DT::dataTableProxy(
outputId = "df-grouptable",
deferUntilFlush = FALSE
)
DT::selectRows(
proxy = dtpr,
selected = NULL
)
selected_table_rows(NULL)
trace_map <- matrix(input[["plot-tracemap"]], ncol = 2, byrow = TRUE)
handle_restyle_traces(
source_id = "plot-scatterselect",
session = session,
dframe = datareactive(),
scaling = 0.1,
xvar = as.character(selector_vals$xvar),
yvar = as.character(selector_vals$yvar),
trace_map = trace_map,
max_id_group_trace = max_id_original_traces(),
# input_sel_rows = input$`df-grouptable_rows_selected`,
input_sel_rows = selected_table_rows(),
flush = TRUE
)
})
# // ----------------------------------------------------------------------
selector_vals <- shiny::reactiveValues()
# PLOT CONTROLS --------------
# handle data for plotting after gobutton + filtering
shiny::observeEvent(
{
input$gobutton
},
{
shiny::validate(shiny::need(datareactive,
label = "datareactive"
))
shiny::callModule(
module_server_plot_selectorcontrols,
"selectors",
shiny::isolate(datareactive())
)
}
)
# set up disabling of selection when using x/y/z vars
shiny::observe({
selector_vals$xvar <- input$`selectors-xvar`
selector_vals$yvar <- input$`selectors-yvar`
selector_vals$zvar <- input$`selectors-zvar`
selector_vals$startscatter <- input$`selectors-startscatter`
})
# disable selecting when clicked on x/y/z var for plot (need to replot)
shiny::observeEvent(
{
selector_vals$xvar
selector_vals$yvar
selector_vals$zvar
},
{
shiny::validate(shiny::need(shiny::isolate(selector_vals),
label = "control vals"
))
action_tracking$plot_start <- FALSE
action_tracking$controls <- TRUE
}
)
# disable selecting when clicked on different map style (need to replot)
# shiny::observeEvent(input[['lwrcontrol-mapstyle']],{
#
# shiny::validate(shiny::need(shiny::isolate(selector_vals),
# label = "control vals"))
#
# # shiny::validate(shiny::need(input[["selectors-startscatter"]],
# # label = "PlotStartbutton"))
#
# action_tracking$plot_start <- FALSE
# action_tracking$controls <- TRUE
#
# }
# )
## PLOTTING -----------------
shiny::observeEvent(selector_vals$startscatter, {
action_tracking$plot_start <- TRUE
action_tracking$controls <- FALSE
shiny::validate(shiny::need(datareactive, label = "datareactive"))
shiny::validate(shiny::need(input[["selectors-startscatter"]], label = "PlotStartbutton"))
shiny::validate(shiny::need(action_tracking$plot_start, label = "plot_start actiontracking"))
#
# if(selected_table_rows()){
#
# dtpr <- DT::dataTableProxy(
# outputId = 'df-grouptable',
# deferUntilFlush = TRUE
# )
#
# DT::selectRows(proxy = dtpr,
# selected = NULL)
# }
shiny::callModule(module_server_plot_selectable,
id = "plot",
df = datareactive,
selector_inputs = shiny::isolate(selector_vals),
sel_points = shiny::isolate(selected_data),
mapstyle = shiny::isolate(input[["lwrcontrol-mapstyle"]])
)
# if(selected_table_rows()){
#
#
#
# handle_restyle_traces(
# source_id = "plot-scatterselect",
# session = session,
# dframe = datareactive(),
# scaling = 0.075,
# xvar = as.character(selector_vals$xvar),
# yvar = as.character(selector_vals$yvar),
# max_id_group_trace = max_id_original_traces(),
# input_sel_rows = input[['df-grouptable_rows_selected']],
# flush = FALSE)
#
#
#
#
#
# }
}) # /observe
# selected_data <- shiny::reactiveValues(
# df = data.frame(keys = integer(0),
# selection_count = integer(0),
# .annotation = character(0),
# stringsAsFactors = FALSE)
# )
# force replotting in plot observer
# there must be a better way of achieving this
# likely with plotly::restyle or relayout
# shiny::observeEvent(input[['lwrcontrol-mapstyle']],
# {
# shiny::isolate({selector_vals$startscatter <- selector_vals$startscatter + 1})
# }
# )
# PLOT DATA SELECTION ---------------
# handle clicks
# handle selections
shiny::observeEvent(
{
plotly::event_data("plotly_selected", priority = "event", source = "scatterselect")
},
{
# print("selected!")
shiny::validate(shiny::need(action_tracking$plot_start,
label = "PlotStarter"
))
selected <- plotly::event_data("plotly_selected",
source = "scatterselect",
priority = "event"
)
selected_data$df <- handle_sel_outliers(
sel_old_df = selected_data$df,
sel_new = selected
)
}
)
shiny::observeEvent(
{
plotly::event_data("plotly_click", priority = "event", source = "scatterselect")
},
{
# print("clicked!")
shiny::validate(shiny::need(action_tracking$plot_start,
label = "PlotStarter"
))
clicked <- plotly::event_data("plotly_click",
source = "scatterselect",
priority = "event"
)
selected_data$df <- handle_sel_outliers(
sel_old_df = selected_data$df,
sel_new = clicked
)
}
)
# # handle clicks
# shiny::observeEvent({plotly::event_data("plotly_click", priority = "event", source = "scatterselect")}, {
#
# # shiny::req(input[["selectors-startscatter"]])
#
# # shiny::validate(shiny::need(input[["selectors-startscatter"]],
# # label = "PlotStarter"))
# shiny::validate(shiny::need(action_tracking$plot_start,
# label = "PlotStarter"))
#
# clicked <- plotly::event_data("plotly_click",
# source = "scatterselect",
# priority = "event")
#
# if(nrow(selected_data$df) > 0 & nrow(clicked) > 0){
# new <- data.frame(keys = as.integer(clicked$customdata),
# selection_count = max(selected_data$df$selection_count) + 1,
# .annotation = "",
# stringsAsFactors = FALSE)
#
# if(any(new$keys %in% selected_data$df$keys)){
# new <- new[!{new$keys %in% selected_data$df$keys}, ]
# }
#
# selected_data$df <- rbind(selected_data$df, new)
#
# } else {
# new <- data.frame(keys = as.integer(clicked$customdata),
# selection_count = 1,
# .annotation = "",
# stringsAsFactors = FALSE)
# selected_data$df <- new
# }
# })
#
#
# # handle selections
# shiny::observeEvent({plotly::event_data("plotly_selected", priority = "event", source = "scatterselect")}, {
#
# # shiny::validate(shiny::need(input[["selectors-startscatter"]],
# # label = "PlotStarter"))
# shiny::validate(shiny::need(action_tracking$plot_start,
# label = "PlotStarter"))
#
#
# # selected <- shiny::reactiveVal()
# selected <- plotly::event_data("plotly_selected",
# source = "scatterselect",
# priority = "event")
#
# if(length(selected)>0){
#
# if(nrow(selected_data$df) > 0 & nrow(selected) > 0){
# new <- data.frame(keys = as.integer(selected$customdata),
# selection_count = max(selected_data$df$selection_count) + 1,
# .annotation = "",
# stringsAsFactors = FALSE)
#
# if(any(new$keys %in% selected_data$df$keys)){
# new <- new[!{new$keys %in% selected_data$df$keys}, ]
# }
# selected_data$df <- rbind(selected_data$df, new)
# } else {
# new <- data.frame(keys = as.integer(selected$customdata),
# selection_count = 1,
# .annotation = "",
# stringsAsFactors = FALSE)
# selected_data$df <- new
# }
#
# }
#
# })
#
# undo on button
shiny::observeEvent(
input[["lwrcontrol-undoselection"]],
{
shiny::validate(shiny::need(nrow(selected_data$df) > 0,
label = "need selected data"
))
# print("data cleared on button click")
drop_ind <- which(selected_data$df$selection_count == max(selected_data$df$selection_count, na.rm = TRUE))
if (length(drop_ind) == nrow(selected_data$df)) {
selected_data$df <- data.frame(
keys = integer(0),
selection_count = integer(0),
.annotation = character(0),
stringsAsFactors = FALSE
)
}
selected_data$df <- selected_data$df[-drop_ind, ]
},
priority = 1000
)
# clear on dbl click
# shiny::observeEvent(
# plotly::event_data("plotly_deselect", source = "scatterselect", priority = "event")
# , {
#
#
# shiny::validate(shiny::need(nrow(selected_data$df) > 0,
# label = "need selected data"))
#
# drop_ind <- which(selected_data$df$selection_count == max(selected_data$df$selection_count, na.rm = TRUE))
#
# if(length(drop_ind) == nrow(selected_data$df)){
#
# selected_data$df <- data.frame(keys = integer(0),
# selection_count = integer(0),
# .annotation = character(0),
# stringsAsFactors = FALSE)
#
# }
# selected_data$df <- selected_data$df[ -drop_ind, ]
# })
#
shiny::observeEvent(
input[["lwrcontrol-clearselection"]],
{
shiny::validate(shiny::need(nrow(selected_data$df) > 0,
label = "need selected data"
))
selected_data$df <- data.frame(
keys = integer(0),
selection_count = integer(0),
.annotation = character(0),
stringsAsFactors = FALSE
)
}
)
# PLOT ADD TRACES ---------------------------------------------------------
max_trace <- shiny::reactive({
shiny::validate(shiny::need(input[["plot-tracemap"]],
label = "need tracepam"
))
mt <- max(as.numeric(matrix(input[["plot-tracemap"]], ncol = 2, byrow = TRUE)[, 2]))
return(mt)
})
old_keys <- shiny::reactiveVal()
# max_id_original_traces <- shiny::reactive({dplyr::n_groups(datareactive()) - 1})
shiny::observeEvent(plotly::event_data("plotly_click",
source = "scatterselect",
priority = "event"
), {
ok <- handle_add_outlier_trace(
sp = selected_data,
dframe = recover_data,
ok = old_keys,
selectors = selector_vals,
trace_map = shiny::isolate(matrix(input[["plot-tracemap"]], ncol = 2, byrow = TRUE)),
source = "plot-scatterselect",
session = session
)
old_keys(ok())
})
shiny::observeEvent(plotly::event_data("plotly_selected",
source = "scatterselect",
priority = "event"
), {
ok <- handle_add_outlier_trace(
sp = selected_data,
dframe = recover_data,
ok = old_keys,
selectors = selector_vals,
source = "plot-scatterselect",
trace_map = shiny::isolate(matrix(input[["plot-tracemap"]], ncol = 2, byrow = TRUE)),
session = session
)
old_keys(ok())
})
# shiny::observeEvent(plotly::event_data(c("plotly_deselect"),
# source = "scatterselect",
# priority = "event"),
# {
# shiny::validate(shiny::need(input[[ns("plot-tracemap")]],
# label = "need tracepam"))
#
# traces <- matrix(input[[ns("plot-tracemap")]], ncol = 2, byrow = TRUE)
# indices <- as.integer(traces[ as.integer(traces[, 2]) > max_id_original_traces(), 2])
#
#
# if(length(indices)>0){
# plotly::plotlyProxy(ns("plot-scatterselect"), session) %>%
# plotly::plotlyProxyInvoke(
# "deleteTraces",
# max(indices)
# )
# }
# old_keys(NULL)
# })
# PLOT DELETE / MAP CHOICE Control ----------------------------------------
# undo buttons
# shiny::observe({
# shiny::observeEvent(input[["selectors-startscatter"]], {
shiny::observeEvent(
ignoreInit = TRUE,
ignoreNULL = TRUE,
action_tracking$plot_start,
{
# shiny::validate(shiny::need(input[["selectors-startscatter"]], label = "PlotStartbutton"))
# if(shiny::req(shiny::isolate(action_tracking$plot_start))){
# if(shiny::req(shiny::isolate(action_tracking$plot_start))){
shiny::callModule(module_server_lowercontrol_btn,
id = "lwrcontrol",
selector_inputs = shiny::isolate(selector_vals),
action_track = action_tracking
)
# }
}
)
# PLOT DELETE TRACES ---------------------------------------------------------
# undo last selection with button
shiny::observeEvent(
{
input$`lwrcontrol-undoselection`
},
{
shiny::validate(shiny::need(input[["plot-tracemap"]],
label = "need tracepam"
))
is_spatial_plot <- identical(
c(
as.character(selector_vals$xvar),
as.character(selector_vals$yvar)
),
c("lon", "lat")
)
traces <- matrix(input[["plot-tracemap"]], ncol = 2, byrow = TRUE)
# indices <- as.integer(traces[ as.integer(traces[, 2]) > max_id_original_traces(), 2])
indices <- as.integer(traces[traces[, 1] == "O", 2])
if (length(indices) > 0) {
pproxy <- plotly::plotlyProxy("plot-scatterselect", session)
plotly::plotlyProxyInvoke(
pproxy,
"deleteTraces",
max(indices)
)
# z <- zvar_toggle(selector_vals$zvar, df = recover_data()[ selected_data$df$keys, ])
add_points <- recover_data()[selected_data$df$keys, ]
# handle plotly - only adds trace for array > 2L
if (nrow(add_points) == 1) {
add_points <- rbind(add_points, add_points)
}
if (is_spatial_plot) {
add_list <-
list(
lon = add_points[, as.character(selector_vals$xvar), drop = TRUE],
lat = add_points[, as.character(selector_vals$yvar), drop = TRUE],
customdata = add_points[, ".dcrkey", drop = TRUE],
text = add_points[, ".dcrkey", drop = TRUE],
type = "scattermapbox",
mode = "markers",
name = "O",
opacity = 1,
marker = list(
symbol = "hospital",
size = 12,
allowoverlap = TRUE,
color = "black",
opacity = 1
),
selected = list(marker = list(opacity = 1)),
unselected = list(marker = list(opacity = 1)),
showlegend = list(TRUE)
)
} else {
add_list <- list(
x = add_points[, as.character(selector_vals$xvar), drop = TRUE],
y = add_points[, as.character(selector_vals$yvar), drop = TRUE],
# size = z,
# sizes = c(25,100),
type = "scattergl",
mode = "markers",
name = "O",
customdata = add_points[, ".dcrkey", drop = TRUE],
text = add_points[, ".dcrkey", drop = TRUE],
marker = list(
symbol = ifelse(is_spatial_plot,
"hospital",
"x"
),
size = 12,
color = "black",
opacity = 1
),
unselected = list(marker = list(opacity = 1)),
selected = list(marker = list(opacity = 1)),
showlegend = TRUE
)
}
plotly::plotlyProxyInvoke(
pproxy,
"addTraces",
add_list
)
}
old_keys(NULL)
},
priority = 0
)
# undo last selection with click
# shiny::observeEvent({
# plotly::event_data(c("plotly_deselect"),
# source = "scatterselect",
# priority = "event")},
# {
#
# shiny::validate(shiny::need(input[["plot-tracemap"]],
# label = "need tracepam"))
#
# traces <- matrix(input[["plot-tracemap"]], ncol = 2, byrow = TRUE)
# indices <- as.integer(traces[ as.integer(traces[, 2]) > max_id_original_traces(), 2])
#
#
# if(length(indices)>0){
# plotly::plotlyProxy("plot-scatterselect", session) %>%
# plotly::plotlyProxyInvoke(
# "deleteTraces",
# max(indices)
# )
# }
# old_keys(NULL)
# })
# delete entire selection with button
shiny::observeEvent(
{
input$`lwrcontrol-clearselection`
},
{
shiny::validate(shiny::need(input[["plot-tracemap"]],
label = "need tracepam"
))
traces <- matrix(input[["plot-tracemap"]], ncol = 2, byrow = TRUE)
# indices <- as.integer(traces[ as.integer(traces[, 2]) > max_id_original_traces(), 2])
indices <- as.integer(traces[traces[, 1] == "O", 2])
if (length(indices) > 0) {
plotly::plotlyProxy("plot-scatterselect", session) %>%
plotly::plotlyProxyInvoke(
"deleteTraces",
indices
)
}
old_keys(NULL)
}
)
# // ----------------------------------------------------------------------
# PLOT HISTOGRAMS ---------------------------------------------------------
output$histogramupdatebutton <- shiny::renderUI({
# shiny::observeEvent(selected_data, {
shiny::validate(shiny::need(input[["selectors-startscatter"]],
label = "",
message = ""
))
shiny::tagList(shiny::actionButton(
inputId = "histogramupdate",
label = "Update",
icon = shiny::icon("sync-alt"),
class = "btn-info"
))
})
shiny::observeEvent(input$histogramupdate,
{
# shiny::observe({
if (shiny::req(action_tracking$plot_start)) {
shiny::callModule(
id = "plotvars",
module = module_server_histograms,
dframe = shiny::isolate(datareactive()),
selector_inputs = shiny::isolate(selector_vals),
sel_points = shiny::isolate(selected_data$df)
)
}
},
priority = 0
)
# // ----------------------------------------------------------------------
# ANNOTATION ADDING --------------------------------------------------------
# provide annotator button
shiny::observeEvent(input$`annotator-annotate_button`, {
selected_data$df <- shiny::callModule(module_server_text_annotator,
"annotator",
sel_data = shiny::isolate(selected_data)
)
})
# handle auto-annotation
selected_data_nrow_track <- shiny::reactiveValues(last_nrow = 0, cur_nrow = 0)
shiny::observeEvent(selected_data$df, {
selected_data_nrow_track$last_nrow <- selected_data_nrow_track$cur_nrow
selected_data_nrow_track$cur_nrow <- nrow(selected_data$df)
})
selected_data_nrow_track_lgl <- shiny::reactive({
shiny::req(selected_data$df)
return(selected_data_nrow_track$cur_nrow >= selected_data_nrow_track$last_nrow)
})
shiny::observeEvent(
selected_data$df,
{
if (input$`annotator-autoannotate` &
selected_data_nrow_track_lgl()) {
selected_data$df <- shiny::callModule(module_server_text_annotator,
"annotator",
sel_data = shiny::isolate(selected_data)
)
}
}
)
# ANNOTATION TABLE --------------------------------------------------------
# insert editable table for annotations
# shiny::observe({
shiny::observeEvent(selected_data$df,
{
# shiny::observeEvent(selected_data, {
shiny::validate(shiny::need(input[["selectors-startscatter"]],
label = "PlotStarter"
))
shiny::validate(shiny::need(selected_data,
label = "selected data"
))
# annotations <-
shiny::callModule(module_server_plot_annotation_table,
"dt",
df = recover_data(),
sel_points = selected_data
)
},
priority = 150
)
# // ---------------------------------------------------------------------
# EXTRACTION --------------------------------------------------------------
# code_out <- shiny::reactiveVal()
# shiny::observe({
# shiny::req(datareactive())
# if(!is.null(input$apply_filter) | nrow(selected_data$df) > 0 ){
# if(nrow(filter_df()) >= 0 | nrow(selected_data$df) >= 0 ){
# code_out(
code_out <- shiny::callModule(module_server_extract_code,
id = "extract",
df_label = df_name,
gvar = gvar,
filter_df = filter_df,
statements = filter_statements_lgl,
sel_points = selected_data,
overwrite = shiny::reactive(input$`config-overwrite`),
is_on_disk = is_on_disk,
out_path = out_path
)
# )
# }
# })
shiny::observeEvent(input$`config-codebtn`, {
context <- rstudioapi::getSourceEditorContext()
rstudioapi::insertText(
text = paste0("\n", code_out(), "\n"),
id = context$id
)
})
shiny::observeEvent(input$`config-copybtn`, {
clipr::write_clip(
content = code_out(),
object_type = "character"
)
})
out_data <- shiny::reactive({
dcr_code <- paste0("\n", code_out(), "\n")
class(dcr_code) <- c(class(dcr_code), "dcr_code")
out_data <- list(
df_name = df_name,
dcr_df =
dplyr::left_join(
x = datareactive(),
y = selected_data$df,
by = c(".dcrkey" = "keys")
) %>%
dplyr::select(-.data$.dcrindex),
dcr_selected_outliers =
selected_data$df %>%
dplyr::rename(.dcrkey = .data$keys),
dcr_groups = gvar(),
dcr_condition_df =
if (nrow(filter_df()) > 0) {
filter_df()[filter_statements_lgl(), ]
}
else {
NULL
},
dcr_code = dcr_code
)
return(out_data)
})
# EXTR - CONFIG, SAVE UI ---------------------
has_processed <- shiny::reactive({
selected_data$df
filter_df()
filter_statements_lgl()
if (nrow(selected_data$df) > 0 |
nrow(filter_df()[filter_statements_lgl(), ]) > 0) {
return(TRUE)
} else {
return(FALSE)
}
})
out_path <- shiny::callModule(module_server_extract_code_fileconfig,
id = "config",
df_label = df_name,
is_on_disk = is_on_disk,
has_processed = has_processed
)
# EXTR - SAVE ACTION ------------------
shiny::observeEvent(input$`config-save`, {
# req(nchar(out_path()$dirraw > 0))
# file_out_raw <- make_save_filepath(
# save_dir = out_path()$dirraw,
# input_filepath = df_name,
# suffix = "meta_RAW",
# ext = "Rds")
#
# file_out_cleaned <- make_save_filepath(
# save_dir = out_path()$dirclean,
# input_filepath = df_name,
# suffix = "CLEAN",
# ext = "Rds")
#
#
# file_script_cleaning <- make_save_filepath(
# save_dir = out_path()$dirclean,
# input_filepath = df_name,
# suffix = "cleaning_recipe",
# ext = "R")
shiny::req(!is.null(code_out()))
saveRDS(
object = out_data()$dcr_df,
file = out_path()$file_out_cleaned
)
saveRDS(
object = list(
dcr_condition_df = out_data()$dcr_condition_df,
dcr_selected_outliers = out_data()$dcr_selected_outliers
),
file = out_path()$file_out_raw
)
writeLines(
text = enc2utf8(out_data()$dcr_code),
con = out_path()$file_script_cleaning,
useBytes = TRUE
)
})
# // ----------------------------------------------------------------------
# Help Texts --------------------------------------------------------------
text_overview_group_panel <- shiny::tagList(
shiny::p(
"Select relevant groups",
shiny::tags$b("(order matters for plotting)"),
shiny::br(),
"The",
shiny::tags$b("grouping order"),
"should reflect units that are most convenient for breaking up the data,",
"and how you plan on cycling through them during visual cleaning. For example, useful groups could be",
shiny::tags$ol(
shiny::tags$li(shiny::tags$small("time periods")),
shiny::tags$li(shiny::tags$small("locations")),
shiny::tags$li(shiny::tags$small("sensors"))
),
"Smart combinations of grouping variables can, e.g. allow to cycle through multiple sensors for a given period with ease."
)
)
text_overview_start_panel <- shiny::tagList(
shiny::p(
"Click",
shiny::tags$b("Start"),
"to set groups for subsequent tabs and operations.",
"It also displays a summary (by columns, and optionally, by groups), and makes the other tabs' functions available."
),
shiny::p(
" If you",
shiny::tags$strong("change the grouping"),
"make sure to click",
shiny::tags$strong("Start"),
"and to update your",
shiny::tags$strong("filters and plot."),
class = "btn btn-default action-button btn-info"
)
)
text_overview_start_panel_summarize <- shiny::tagList(
shiny::p(
shiny::tags$strong("After setting the grouping structure"),
", click",
shiny::tags$b("Generate Overview"),
"to generate an informative overview summary (by columns, and optionally, by groups)."
),
shiny::p(
" If you",
shiny::tags$strong("change the grouping"),
"make sure to click",
shiny::tags$strong("Start"),
"and to update your",
shiny::tags$strong("filters and plot."),
class = "btn btn-default action-button btn-info"
)
)
text_filtering_side_panel <- shiny::tagList(
# shiny::p(
# shiny::tags$b("Add/Remove"),
# "text boxes and add unquoted filter statements."),
shiny::p(
shiny::tags$b("Add/Remove"),
"filter statements as necessary. These are passed to",
shiny::tags$b(shiny::tags$code("dplyr::filter()")), "."
),
shiny::p("Use", shiny::tags$b("single quotes"), "for values of character/factor variables."),
shiny::tags$p(
"For example, valid statements for filtering",
shiny::tags$b("iris"),
"are:"
),
shiny::tags$ol(
shiny::tags$li(shiny::tags$small(shiny::tags$code("Species == 'setosa'"))),
shiny::tags$li(shiny::tags$small(shiny::tags$code("Species %in% c('setosa','versicolor')"))),
shiny::tags$li(shiny::tags$small(shiny::tags$code("Sepal.Width > quantile(Sepal.Width, 0.05)")))
),
shiny::p("Any function returning a logical vector (i.e. ",
shiny::tags$code("TRUE/FALSE", .noWS = "after"),
"), can be employed here!",
.noWS = c("before", "after")
),
shiny::p("A dynamic text will inform you which filter statements are
viable, and how much of the data will be filtered when they are applied."),
shiny::br(),
shiny::p(
"Adjust the",
shiny::tags$b("Grouping scope"),
"in the drop down next to the text box. This allows to apply the filter statement to:"
),
shiny::tags$ol(
shiny::tags$li(shiny::tags$small("none (ungrouped filtering)")),
shiny::tags$li(shiny::tags$small("individual groups (scoped filtering)")),
shiny::tags$li(shiny::tags$small("all groups (grouped filtering)"))
),
shiny::p(
"Click",
shiny::tags$b("'Apply'"),
"when you're ready, and",
shiny::tags$b("'Reset'"),
"to start from scratch."
),
shiny::p(
class = "btn btn-default btn-info",
"Code in the",
shiny::tags$b("Extract Tab"),
"is generated for viable statements only."
)
# shiny::br(),
# shiny::br(),
#
# shiny::p("A table",
# shiny::tags$b("Data Overview"),
# "will inform you how many data points remain in the data set (by group)")
)
text_annotate_side_panel <- shiny::tagList(
shiny::p(
"After selecting points by",
shiny::tags$b("clicking/lasso-selecting"),
"the",
shiny::tags$b("last selection"),
"can be annotated with a text label by clicking the",
shiny::tags$b("Annotate"),
"button",
shiny::br(),
"The annotation for the last selection can be updated or
removed by deleting all characters in the input box and
clicking the button again.",
shiny::br()
),
shiny::p(
"When",
shiny::tags$b("Auto-annotate"),
"is selected, every new selection receives the current annotation automatically.",
),
shiny::p(
"Labels are collected and provided as an additional column",
shiny::tags$code(".annotation"),
"in the table to the right and outputted via the",
shiny::tags$b("Extraction Tab.")
),
)
text_distribution_side_panel <- shiny::tagList(
shiny::p(
"Clicking the",
shiny::tags$b("Update"),
"button will generate histograms of plotted, numeric variables, i.e",
shiny::tags$code("X, Y, Z", .noWS = "after"),
".",
shiny::br(),
"If any points have been selected via",
shiny::tags$b("clicking/lasso-selecting"),
"the histograms will show the difference between the raw and cleaned data set."
),
shiny::p(
class = "btn btn-default action-button btn-info",
"This plot mus tbe updated manually to visualize any changes."
)
)
text_plot_main_panel <- shiny::tagList(
shiny::h4(shiny::tags$b("Plotting overview"),
.noWS = c("before")
),
shiny::p(
"Select at least ",
shiny::tags$code("X"),
"and",
shiny::tags$code("Y"),
"(the ",
shiny::tags$code("Z"),
"variable adjusts point size)",
"and click",
shiny::tags$b("'Plot'.")
),
shiny::p(
"The legend entries correspond with the row-numbers (i.e. groups) of the",
shiny::tags$b("Data Overview"),
"Table.",
shiny::tags$b("Groups can be highlighted"),
"for selective display by clicking on the respective rows and updating the plot's groups.",
shiny::br(),
"Clicking on the plot's legend (single for hide/unhide, double for hide all others/show all) has a similar effect, but does not reset the grouping or zoom."
),
shiny::p(
shiny::tags$b("'Plot'"),
"must be clicked after any variable input",
shiny::code("(X, Y, Z)"),
"has been",
shiny::tags$b("clicked or changed"),
"to (re-)enable selecting."
),
shiny::p(
"The plot's",
shiny::tags$b("control bar"),
"allows to",
shiny::tags$b("zoom and reset views.")
),
shiny::h4(shiny::tags$b("Selecting outliers")),
shiny::p(
"To mark outliers, ",
shiny::tags$b("click or lasso/box select"),
"individual points.",
"Hit the",
shiny::tags$b("Undo last selection"),
"or",
shiny::tags$b("Clear all"),
"button to adjust/remove outliers.",
shiny::br(),
"Selected points appear in the",
shiny::tags$b(" table below"),
"and can be annotated with the tool (box and button) to the left."
),
shiny::p(
class = "btn btn-default btn-info",
"The",
shiny::tags$b("Extract Tab"),
"will provide code representing the outlier selection (and its removal)."
),
shiny::h4(shiny::tags$b("Other features")),
shiny::p(
"If columns",
shiny::tags$code("lon, lat"),
"are selected for",
shiny::tags$code("x, y"),
"an interactive map displays."
),
shiny::p(
"If a column",
shiny::tags$code(".dcrflag"),
"(logical;",
shiny::tags$code("TRUE, FALSE", .noWS = "after"),
")",
"is present in the data set, corresponding rows will
be plotted with triangle symbols, not cricles,
enabling e.g. comparison with manual outlier algorithms.",
)
)
text_repro_panel <- shiny::tagList(
shiny::h4(shiny::tags$b("Principle")),
shiny::p(
shiny::tags$code("datacleanr"),
"allows filtering and visual cleaning/annotating.",
"These steps are translated into code (",
shiny::tags$b("Reproducible Recipe", .noWS = c("before", "after")),
")."
),
shiny::h4(shiny::tags$b("Use")),
shiny::p(
"If",
shiny::tags$code("datacleanr"),
"is run interactively (i.e. with an object from",
shiny::tags$code("R", .noWS = "after"),
"s environment)",
"the code can be sent back to RStudio or copied into a script where
you are actively developing your workflow.",
shiny::br(),
"If",
shiny::tags$code("datacleanr"),
"is run with a file from disk, the",
shiny::tags$b("Extract Tab"),
"offers a range of settings for saving the generated outputs to file.",
shiny::br(),
"Note, that filters and selected outliers are written to files in this scenario."
),
shiny::h4(shiny::tags$b("On Close")),
shiny::p(
"If you click",
shiny::tags$b("Close"),
"and don't export/save any outputs, the filters, selected data and other meta info is
sent back to",
shiny::tags$code("R", .noWS = "after"),
"s current session invisibly.",
shiny::br(),
"Using",
shiny::tags$code("output <- .Last.value"),
"will capture this output (which can also be set-up when you launch",
shiny::tags$code("datacleanr", .noWS = "after"),
"; see",
shiny::tags$code("?datacleanr::dcr_app()", .noWS = "after"),
")."
)
)
# HELP LINKS --------------------------------------------------------------
## Filter Tab
shiny::observeEvent(input$`help-ov`, {
shiny::showModal(shiny::modalDialog(
text_overview_group_panel,
title = "Selecting Groups",
size = "m",
easyClose = TRUE,
footer = NULL
))
})
shiny::observeEvent(input$`help-start`, {
shiny::showModal(shiny::modalDialog(
text_overview_start_panel,
title = "Start, summarize and initialize other tabs",
size = "m",
easyClose = TRUE,
footer = NULL
))
})
shiny::observeEvent(input$`help-summarize`, {
shiny::showModal(shiny::modalDialog(
text_overview_start_panel_summarize,
title = "Summarize data set",
size = "m",
easyClose = TRUE,
footer = NULL
))
})
## Filter Tab
shiny::observeEvent(input$`help-filter`, {
shiny::showModal(shiny::modalDialog(
text_filtering_side_panel,
title = "How to filter data",
size = "m",
easyClose = TRUE,
footer = NULL
))
})
# VIZ tab - annotator tool
shiny::observeEvent(input$`help-annotator`, {
shiny::showModal(shiny::modalDialog(
text_annotate_side_panel,
title = "How to annotate outliers",
size = "m",
easyClose = TRUE,
footer = NULL
))
})
# VIZ tab - histogram tool
shiny::observeEvent(input$`help-hist`, {
shiny::showModal(shiny::modalDialog(
text_distribution_side_panel,
title = "Assessing outlier impact",
size = "m",
easyClose = TRUE,
footer = NULL
))
})
# Viz tab - plot + selector tool
shiny::observeEvent(input$`help-plot`, {
shiny::showModal(shiny::modalDialog(
text_plot_main_panel,
# title = "Plotting data and selecting outliers",
size = "m",
easyClose = TRUE,
footer = NULL
))
})
shiny::observeEvent(input$`help-repro`, {
shiny::showModal(shiny::modalDialog(
text_repro_panel,
# title = "Plotting data and selecting outliers",
size = "m",
easyClose = TRUE,
footer = NULL
))
})
# OUTLIST
# shiny::observeEvent(input[["selectors-startscatter"]], {
# outs <- outputOptions(output)
# lapply(names(outs), function(name) {
# outputOptions(output, name, suspendWhenHidden = FALSE)
# })
#
# })
# END ---------------------------
shiny::observeEvent(input$close, {
# dcr_code <- paste0("\n", code_out(), "\n")
# class(dcr_code) <- c(class(dcr_code), "dcr_code")
#
# out_data <- list(
# df_name = df_name,
# dcr_df =
# dplyr::left_join(x = datareactive(),
# y = selected_data$df,
# by = c(".dcrkey" = "keys")),
# dcr_selected_outliers =
# selected_data$df %>%
# dplyr::rename(.dcrkey = .data$keys),
# dcr_groups = gvar(),
# dcr_condition_df =
# if(nrow(filter_df()) > 0){
# filter_df()[filter_statements_lgl(), ]}
# else {NULL},
# dcr_code = dcr_code
# )
# handle plotly TZ issue
# Sys.setenv(TZ = old_tz)
shiny::stopApp(returnValue = invisible(out_data()))
})
shiny::observeEvent(input$cancel, {
# Sys.setenv(TZ = old_tz)
shiny::stopApp(NULL)
})
}
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.