############################################# # 安全封装:避免 is.empty() 报错 ############################################# safe_is_empty <- function(x) { if (is.null(x) || !is.character(x)) return(TRUE) is.empty(x) } ############################################# # 其余代码保持不变,仅替换 is.empty() 调用 ############################################# viz_type <- c( "分布图(dist)" = "dist", "密度图(density)" = "density", "散点图(scatter)" = "scatter", "曲面图(surface)" = "surface", "折线图(line)" = "line", "条形图(bar)" = "bar", "箱线图(box)" = "box" ) viz_check <- c( "直线(line)" = "line", "局部加权回归(loess)" = "loess", "抖动(jitter)" = "jitter", "插值(interpolate)" = "interpolate" ) viz_axes <- c( "翻转坐标轴(flip)" = "flip", "X轴对数变换(log_x)" = "log_x", "Y轴对数变换(log_y)" = "log_y", "Y轴缩放(scale_y)" = "scale_y", "密度(density)" = "density", "排序(sort)" = "sort" ) viz_theme <- c( "灰色主题(gray)" = "theme_gray", "黑白主题(bw)" = "theme_bw", "明亮主题(light)" = "theme_light", "暗黑主题(dark)" = "theme_dark", "极简主题(minimal)" = "theme_minimal", "经典主题(classic)" = "theme_classic" ) os_type <- Sys.info()["sysname"] if (os_type == "Windows") { fnt <- names(windowsFonts()) names(fnt) <- tools::toTitleCase(fnt) viz_base_family <- c("Theme default" = "", fnt) } else { viz_base_family <- c( "Theme default" = "", "Helvetica" = "Helvetica", "Serif" = "serif", "Sans" = "sans", "Mono" = "mono", "Courier" = "Courier", "Times" = "Times" ) } viz_labs <- c(i18n$t("title"), i18n$t("subtitle"), i18n$t("caption"), i18n$t("x"), i18n$t("y")) viz_add_labs <- function() { lab_list <- list() for (l in viz_labs) { inp <- input[[paste0("viz_labs_", l)]] if (!safe_is_empty(inp)) lab_list[[l]] <- inp } lab_list } viz_args <- as.list(formals(visualize)) viz_inputs <- reactive({ viz_args$data_filter <- if (isTRUE(input$show_filter)) input$data_filter else "" viz_args$arr <- if (isTRUE(input$show_filter)) input$data_arrange else "" viz_args$rows <- if (isTRUE(input$show_filter)) input$data_rows else "" viz_args$dataset <- input$dataset viz_args$shiny <- input$shiny viz_args$labs <- viz_add_labs() for (i in r_drop(names(viz_args), drop = c(i18n$t("dataset"), i18n$t("data_filter"), i18n$t("arr"), i18n$t("rows"), i18n$t("labs")))) { viz_args[[i]] <- input[[paste0("viz_", i)]] } viz_args }) output$ui_viz_type <- renderUI({ selectInput( inputId = "viz_type", label = i18n$t("Plot-type:"), choices = viz_type, selected = state_single("viz_type", viz_type), multiple = FALSE ) }) output$ui_viz_nrobs <- renderUI({ req(input$viz_type == "scatter") nrobs <- nrow(.get_data()) choices <- c("1,000" = 1000, "5,000" = 5000, "10,000" = 10000, "All" = -1) %>% .[. < nrobs] selectInput( "viz_nrobs", i18n$t("Number of data points plotted:"), choices = choices, selected = state_single("viz_nrobs", choices, 1000) ) }) output$ui_viz_yvar <- renderUI({ req(input$viz_type) vars <- varying_vars() req(available(vars)) vars <- vars["date" != .get_class()[vars]] if (input$viz_type %in% c("line", "bar", "scatter", "surface", "box")) { vars <- vars["character" != .get_class()[vars]] } if (input$viz_type %in% c("box", "scatter")) { vars <- vars["factor" != .get_class()[vars]] } selectInput( inputId = "viz_yvar", label = i18n$t("Y-variable:"), choices = vars, selected = state_multiple("viz_yvar", vars, isolate(input$viz_yvar)), multiple = TRUE, size = min(3, length(vars)), selectize = FALSE ) }) output$ui_viz_xvar <- renderUI({ req(input$viz_type) vars <- varying_vars() req(available(vars)) if (input$viz_type == "dist") vars <- vars["date" != .get_class()[vars]] if (input$viz_type == "density") vars <- vars["factor" != .get_class()[vars]] if (input$viz_type %in% c("box", "bar")) vars <- groupable_vars_nonum() selectInput( inputId = "viz_xvar", label = i18n$t("X-variable:"), choices = vars, selected = state_multiple("viz_xvar", vars, isolate(input$viz_xvar)), multiple = TRUE, size = min(3, length(vars)), selectize = FALSE ) }) output$ui_viz_comby <- renderUI({ checkboxInput( "viz_comby", i18n$t("Combine Y-variables in one plot"), state_init("viz_comby", FALSE) ) }) output$ui_viz_combx <- renderUI({ checkboxInput( "viz_combx", i18n$t("Combine X-variables in one plot"), state_init("viz_combx", FALSE) ) }) observeEvent(length(input$viz_xvar) < 2, { updateCheckboxInput(session, "viz_combx", value = FALSE) }) observeEvent(length(input$viz_yvar) < 2, { updateCheckboxInput(session, "viz_comby", value = FALSE) }) observeEvent(input$viz_type, { if (input$viz_type %in% c("dist", "density")) { updateCheckboxInput(session, "viz_comby", value = FALSE) } else { updateCheckboxInput(session, "viz_combx", value = FALSE) } }) observeEvent(input$viz_check, { if (!"loess" %in% input$viz_check && input$viz_smooth != 1) { updateSliderInput(session, "viz_smooth", value = 1) } }) output$ui_viz_facet_row <- renderUI({ vars <- c("None" = ".", groupable_vars_nonum()) selectizeInput( "viz_facet_row", i18n$t("Facet row:"), vars, selected = state_single("viz_facet_row", vars, init = "."), multiple = FALSE ) }) output$ui_viz_facet_col <- renderUI({ vars <- c("None" = ".", groupable_vars_nonum()) selectizeInput( "viz_facet_col", i18n$t("Facet column:"), vars, selected = state_single("viz_facet_col", vars, init = "."), multiple = FALSE ) }) output$ui_viz_color <- renderUI({ req(input$viz_type) if (input$viz_type == "line") { vars <- c("None" = "none", groupable_vars()) } else { vars <- c("None" = "none", varnames()) } if (isTRUE(input$viz_comby) && length(input$viz_yvar) > 1) vars <- c("None" = "none") selectizeInput( "viz_color", i18n$t("Color:"), vars, multiple = FALSE, selected = state_single("viz_color", vars, init = "none") ) }) output$ui_viz_fill <- renderUI({ vars <- c("None" = "none", groupable_vars()) if (isTRUE(input$viz_combx) && length(input$viz_xvar) > 1) vars <- vars[1] selectizeInput( "viz_fill", i18n$t("Fill:"), vars, multiple = FALSE, selected = state_single("viz_fill", vars, init = "none") ) }) output$ui_viz_size <- renderUI({ req(input$viz_type) isNum <- .get_class() %in% c("integer", "numeric", "ts") vars <- c("None" = "none", varnames()[isNum]) if (isTRUE(input$viz_comby) && length(input$viz_yvar) > 1) vars <- c("None" = "none") selectizeInput( "viz_size", i18n$t("Size:"), vars, multiple = FALSE, selected = state_single("viz_size", vars, init = "none") ) }) output$ui_viz_axes <- renderUI({ req(input$viz_type) ind <- 1 if (input$viz_type %in% c("line", "scatter", "surface")) { ind <- 1:3 } else if (input$viz_type == "dist") { ind <- c(1:2, 5) } else if (input$viz_type == "density") { ind <- 1:2 } else if (input$viz_type %in% c("bar", "box")) { ind <- c(1, 3) } if (input$viz_facet_row != "." || input$viz_facet_col != ".") ind <- c(ind, 4) if (input$viz_type == "bar") ind <- c(ind, 6) checkboxGroupInput( "viz_axes", NULL, viz_axes[ind], selected = state_group("viz_axes", ""), inline = TRUE ) }) output$ui_viz_check <- renderUI({ req(input$viz_type) if (input$viz_type == "scatter") { ind <- 1:3 } else if (input$viz_type == "box") { ind <- 3 } else if (input$viz_type == "surface") { ind <- 4 } else { ind <- c() } if (!input$viz_type %in% c("scatter", "box")) { r_state$viz_check <<- gsub("jitter", "", r_state$viz_check) } if (input$viz_type != "scatter") { r_state$viz_check <<- gsub("line", "", r_state$viz_check) r_state$viz_check <<- gsub("loess", "", r_state$viz_check) } checkboxGroupInput( "viz_check", NULL, viz_check[ind], selected = state_group("viz_check", ""), inline = TRUE ) }) output$ui_viz_run <- renderUI({ req(input$dataset) actionButton("viz_run", i18n$t("Create plot"), width = "100%", icon = icon("play", verify_fa = FALSE), class = "btn-success") }) output$ui_viz_labs <- renderUI({ req(input$dataset) wellPanel( textAreaInput("viz_labs_title", NULL, "", placeholder = i18n$t("Title"), rows = 1), textAreaInput("viz_labs_subtitle", NULL, "", placeholder = i18n$t("Subtitle"), rows = 1), textAreaInput("viz_labs_caption", NULL, "", placeholder = i18n$t("Caption"), rows = 1), textAreaInput("viz_labs_y", NULL, "", placeholder = i18n$t("Y-label"), rows = 1), textAreaInput("viz_labs_x", NULL, "", placeholder = i18n$t("X-label"), rows = 1) ) }) output$ui_viz_colors <- renderUI({ tagList( conditionalPanel( condition = "input.viz_type == 'bar' || input.viz_type == 'dist' || input.viz_type == 'box' || input.viz_type == 'density'", selectInput( "viz_fillcol", i18n$t("Fill color:"), choices = colors(), selected = state_single("viz_fillcol", colors(), "blue") ) ), conditionalPanel( condition = "input.viz_type == 'dist' || input.viz_type == 'density' || input.viz_type == 'box' || input.viz_type == 'scatter' || input.viz_type == 'line'", selectInput( "viz_linecol", i18n$t("Line color:"), choices = colors(), selected = state_single("viz_linecol", colors(), "black") ) ), conditionalPanel( condition = "input.viz_type == 'scatter' || input.viz_type == 'line' || input.viz_type == 'box'", selectInput( "viz_pointcol", i18n$t("Point color:"), choices = colors(), selected = state_single("viz_pointcol", colors(), "black") ) ) ) }) run_refresh( viz_args, "viz", init = c("xvar", "yvar"), label = i18n$t("Create plot"), relabel = i18n$t("Update plot"), inputs = c("labs_title", "labs_subtitle", "labs_caption", "labs_y", "labs_x") ) output$ui_Visualize <- renderUI({ tagList( wellPanel( uiOutput("ui_viz_run") ), checkboxInput("viz_details_main", i18n$t("Main"), state_init("viz_details_main", TRUE)), conditionalPanel( "input.viz_details_main == true", wellPanel( uiOutput("ui_viz_type"), conditionalPanel( "input.viz_type == 'scatter'", uiOutput("ui_viz_nrobs") ), conditionalPanel( condition = "input.viz_type != 'dist' && input.viz_type != 'density'", uiOutput("ui_viz_yvar"), conditionalPanel( "input.viz_yvar != undefined && input.viz_yvar != null && input.viz_yvar.length > 1", uiOutput("ui_viz_comby") ) ), uiOutput("ui_viz_xvar"), conditionalPanel( "input.viz_type == 'dist' || input.viz_type == 'density'", conditionalPanel( "input.viz_xvar != undefined && input.viz_xvar != null && input.viz_xvar.length > 1", uiOutput("ui_viz_combx") ) ), uiOutput("ui_viz_facet_row"), uiOutput("ui_viz_facet_col"), conditionalPanel( condition = "input.viz_type == 'bar' || input.viz_type == 'dist' || input.viz_type == 'density' || input.viz_type == 'surface'", uiOutput("ui_viz_fill") ), conditionalPanel( condition = "input.viz_type == 'scatter' || input.viz_type == 'line' || input.viz_type == 'box'", uiOutput("ui_viz_color") ), conditionalPanel( condition = "input.viz_type == 'scatter'", uiOutput("ui_viz_size") ), conditionalPanel( condition = "input.viz_type == 'bar' || input.viz_type == 'scatter' || input.viz_type == 'line'", selectInput( "viz_fun", i18n$t("Function:"), choices = getOption("radiant.functions"), selected = state_single("viz_fun", getOption("radiant.functions"), "mean") ) ), conditionalPanel( condition = "input.viz_type == 'scatter' || input.viz_type == 'line' || input.viz_type == 'surface' || input.viz_type == 'box'", uiOutput("ui_viz_check") ), uiOutput("ui_viz_axes"), conditionalPanel( condition = "input.viz_type == 'dist'", sliderInput( "viz_bins", label = i18n$t("Number of bins:"), value = state_init("viz_bins", 10), min = 2, max = 50, step = 1 ) ), conditionalPanel( "input.viz_type == 'density' || input.viz_type == 'dist' && (input.viz_axes && input.viz_axes.indexOf('density')) >= 0 || (input.viz_type == 'scatter' && (input.viz_check && input.viz_check.indexOf('loess') >= 0))", sliderInput( "viz_smooth", label = i18n$t("Smooth:"), value = state_init("viz_smooth", 1), min = 0.1, max = 3, step = .1 ) ) ) ), checkboxInput("viz_details_labels", i18n$t("Labels"), state_init("viz_details_labels", FALSE)), conditionalPanel( "input.viz_details_labels == true", uiOutput("ui_viz_labs") ), checkboxInput("viz_details_style", i18n$t("Style"), state_init("viz_details_style", FALSE)), conditionalPanel( "input.viz_details_style == true", wellPanel( selectInput( "viz_theme", i18n$t("Plot theme:"), choices = viz_theme, selected = state_single("viz_theme", viz_theme, "theme_gray") ), numericInput( "viz_base_size", i18n$t("Base font size:"), value = state_init("viz_base_size", 11) ), selectInput( "viz_base_family", i18n$t("Font family:"), choices = viz_base_family, selected = state_single("viz_base_family", viz_base_family, "helvetica") ), uiOutput("ui_viz_colors"), sliderInput( "viz_alpha", label = i18n$t("Opacity:"), value = state_init("viz_alpha", .5), min = 0, max = 1, step = .01 ), tags$table( tags$td( numericInput( "viz_plot_height", label = i18n$t("Plot height:"), min = 100, max = 2000, step = 50, value = state_init("viz_plot_height", r_info[["plot_height"]]), width = "117px" ) ), tags$td( numericInput( "viz_plot_width", label = i18n$t("Plot width:"), min = 100, max = 2000, step = 50, value = state_init("viz_plot_width", r_info[["plot_width"]]), width = "117px" ), width = "100%" ) ) ) ), help_and_report( modal_title = i18n$t("Visualize"), fun_name = "visualize", help_file = inclRmd(file.path(getOption("radiant.path.data"), "app/tools/help/visualize.md")), lic = "by-sa" ) ) }) viz_plot_width <- reactive({ if (safe_is_empty(input$viz_plot_width)) r_info[["plot_width"]] else input$viz_plot_width }) viz_plot_height <- eventReactive( { input$viz_run input$viz_plot_height input$viz_plot_width }, { if (safe_is_empty(input$viz_plot_height)) { r_info[["plot_height"]] } else { lx <- ifelse(not_available(input$viz_xvar) || isTRUE(input$viz_combx), 1, length(input$viz_xvar)) ly <- ifelse(not_available(input$viz_yvar) || input$viz_type %in% c("dist", "density") || isTRUE(input$viz_comby), 1, length(input$viz_yvar)) nr <- lx * ly if (nr > 1) { (input$viz_plot_height / 2) * ceiling(nr / 2) } else { input$viz_plot_height } } } ) output$visualize <- renderPlot({ req(input$viz_type) p <- .visualize() if (is.null(p)) return(NULL) print(p) }, width = viz_plot_width, height = viz_plot_height, res = 96) .visualize <- eventReactive(input$viz_run, { req(input$viz_type) if (input$viz_type == "scatter") req(input$viz_nrobs) req(input$viz_plot_height && input$viz_plot_width) if (not_available(input$viz_xvar) && !input$viz_type %in% c("box", "line")) { return(NULL) } if (input$viz_type %in% c("scatter", "line", "box", "bar", "surface") && not_available(input$viz_yvar)) { return(NULL) } vizi <- viz_inputs() vizi$dataset <- input$dataset vizi$shiny <- TRUE vizi$envir <- r_data withProgress(message = i18n$t("Making plot"), value = 1, { p <- do.call(visualize, vizi) if (is.character(p)) return(NULL) p }) }) visualize_report <- function() { vi <- viz_inputs() if (input$viz_type != "dist") { vi$bins <- viz_args$bins } if (input$viz_type %in% c("dist", "density")) { vi$yvar <- viz_args$yvar } if (!input$viz_type %in% c("density", "scatter", "dist") || !("loess" %in% input$viz_check || "density" %in% input$viz_axes || input$viz_type == "density")) { vi$smooth <- viz_args$smooth } if (!input$viz_type %in% c("scatter", "box") && "jitter" %in% input$viz_check) { vi$check <- base::setdiff(vi$check, "jitter") } if (input$viz_type != "scatter") { vi$size <- "none" vi$nrobs <- NULL } else { vi$nrobs <- as_integer(vi$nrobs) } if (!input$viz_type %in% c("scatter", "line", "box")) { vi$color <- NULL } if (!input$viz_type %in% c("bar", "dist", "density", "surface")) { vi$fill <- NULL } if (!input$viz_type %in% c("bar", "dist", "box", "density")) { vi$fillcol <- "blue" } if (!input$viz_type %in% c("dist", "density", "box", "scatter", "line")) { vi$linecol <- "black" } if (!input$viz_type %in% c("box", "scatter", "line")) { vi$pointcol <- "black" } if (!input$viz_type %in% c("bar", "line", "scatter")) { vi$fun <- "mean" } if (safe_is_empty(input$data_rows)) { vi$rows <- NULL } inp_main <- c(clean_args(vi, viz_args), custom = FALSE) update_report( inp_main = inp_main, fun_name = "visualize", outputs = character(0), pre_cmd = "", figs = TRUE, fig.width = viz_plot_width(), fig.height = viz_plot_height() ) } download_handler( id = "dlp_visualize", fun = download_handler_plot, fn = function() paste0(input$dataset, "_visualize"), type = "png", caption = i18n$t("Save visualize plot"), plot = .visualize, width = viz_plot_width, height = viz_plot_height ) observeEvent(input$visualize_report, { r_info[["latest_screenshot"]] <- NULL visualize_report() }) observeEvent(input$visualize_screenshot, { r_info[["latest_screenshot"]] <- NULL radiant_screenshot_modal("modal_visualize_screenshot") }) observeEvent(input$modal_visualize_screenshot, { visualize_report() removeModal() })