| # server.R | |
| library(shiny) | |
| library(readxl) | |
| library(DT) | |
| library(dplyr) | |
| # Source the warning overlay and long operations code | |
| source("warning_overlay.R", local = TRUE) | |
| source("long_operations.R", local = TRUE) | |
| source("auth/hf_oauth.R", local = TRUE) | |
| source("utils/supabase_r.R", local = TRUE) | |
| # setwd("/Users/audrey/Downloads/research/ckweb/Tcellstates") | |
| # Define server logic | |
| function(input, output, session) { | |
| # --- START: Environment Variable Diagnostic --- | |
| print("=== Environment Variables Diagnostic ===") | |
| all_env <- Sys.getenv() | |
| # Print only relevant environment variables (filter sensitive ones) | |
| relevant_vars <- c("SUPABASE_URL", "SUPABASE_KEY", "OAUTH_CLIENT_ID", "OAUTH_CLIENT_SECRET", | |
| "SPACE_HOST", "SPACE_ID", "HF_TOKEN") | |
| for (var_name in relevant_vars) { | |
| var_value <- Sys.getenv(var_name, unset = "NOT_SET") | |
| if (var_name %in% c("SUPABASE_KEY", "OAUTH_CLIENT_SECRET", "HF_TOKEN")) { | |
| # Mask sensitive values | |
| print(paste(var_name, ":", if(var_value == "NOT_SET") "NOT_SET" else "[REDACTED]")) | |
| } else { | |
| print(paste(var_name, ":", var_value)) | |
| } | |
| } | |
| print("========================================") | |
| # --- END: Environment Variable Diagnostic --- | |
| # --- START: OAuth and Supabase Initialization --- | |
| oauth_config <- initialize_oauth() | |
| supabase_client <- initialize_supabase() | |
| # --- END: OAuth and Supabase Initialization --- | |
| # --- START: TaijiChat R Callback for Python Agent Thoughts --- | |
| python_agent_thought_callback <- function(thought_message_from_python) { | |
| # Attempt to explicitly convert to R character and clean up | |
| thought_message_text <- tryCatch({ | |
| as.character(thought_message_from_python)[1] # Take the first element after converting | |
| }, error = function(e) { | |
| print(paste("R Callback: Error converting thought to character:", e$message)) | |
| return(NULL) | |
| }) | |
| if (!is.null(thought_message_text) && is.character(thought_message_text) && length(thought_message_text) == 1 && nzchar(trimws(thought_message_text))) { | |
| # print(paste("R Callback: Valid thought from Python -", thought_message_text)) # For R console debugging | |
| session$sendCustomMessage(type = "agent_new_thought", message = list(text = trimws(thought_message_text))) | |
| } else { | |
| # Log the original and potentially converted type for better debugging | |
| print(paste("R Callback: Received invalid or empty thought. Original type:", class(thought_message_from_python), ", Value:", thought_message_from_python, ", Converted text:", thought_message_text)) | |
| } | |
| } | |
| # --- END: TaijiChat R Callback for Python Agent Thoughts --- | |
| # --- START: TaijiChat Agent Initialization --- | |
| # This assumes manager_agent_module is globally available from ui.R's sourcing. | |
| # ui.R does: manager_agent_module <- reticulate::import("agents.manager_agent") | |
| api_key_val <- NULL | |
| # First try to get API key from environment variable | |
| api_key_val <- Sys.getenv("OPENAI_API_KEY") | |
| # If environment variable is not set, try reading from file | |
| if (api_key_val == "") { | |
| tryCatch({ | |
| api_key_content <- readLines("api_key.txt", warn = FALSE) | |
| if (length(api_key_content) > 0 && nzchar(trimws(api_key_content[1]))) { | |
| api_key_val <- trimws(api_key_content[1]) | |
| print("TaijiChat: API key successfully read from file in server.R.") | |
| } else { | |
| warning("TaijiChat: api_key.txt is empty or not found. LLM features may be disabled.") | |
| print("TaijiChat: api_key.txt is empty or not found.") | |
| } | |
| }, error = function(e) { | |
| warning(paste("TaijiChat: Error reading api_key.txt in server.R:", e$message)) | |
| print(paste("TaijiChat: Error reading api_key.txt:", e$message)) | |
| }) | |
| } else { | |
| print("TaijiChat: API key successfully read from environment variable.") | |
| } | |
| py_openai_client_instance <- NULL | |
| if (!is.null(api_key_val)) { | |
| tryCatch({ | |
| # Ensure reticulate is configured to use the correct Python environment | |
| if (reticulate::py_available(initialize = TRUE)) { | |
| openai_py_module <- reticulate::import("openai", convert = FALSE) # convert=FALSE for raw Python objects | |
| py_openai_client_instance <- openai_py_module$OpenAI(api_key = api_key_val) | |
| print("TaijiChat: Python OpenAI client initialized successfully in server.R via reticulate.") | |
| } else { | |
| warning("TaijiChat: Python (reticulate) not available or not initialized. Cannot create OpenAI client.") | |
| print("TaijiChat: Python (reticulate) not available. Cannot create OpenAI client.") | |
| } | |
| }, error = function(e) { | |
| warning(paste("TaijiChat: Failed to initialize Python OpenAI client in server.R:", e$message)) | |
| print(paste("TaijiChat: Failed to initialize Python OpenAI client:", e$message)) | |
| py_openai_client_instance <- NULL | |
| }) | |
| } else { | |
| print("TaijiChat: API key is NULL, skipping Python OpenAI client initialization.") | |
| } | |
| rv_agent_instance <- reactiveVal(NULL) | |
| # Attempt to create the agent instance once. | |
| current_manager_agent_module <- NULL | |
| tryCatch({ | |
| # Force reload the module to ensure we get the latest version | |
| print("TaijiChat: Attempting to reload Python modules to ensure latest version...") | |
| reticulate::py_run_string(" | |
| import sys | |
| import importlib | |
| if 'agents.manager_agent' in sys.modules: | |
| print('Reloading agents.manager_agent module...') | |
| importlib.reload(sys.modules['agents.manager_agent']) | |
| ") | |
| current_manager_agent_module <- reticulate::import("agents.manager_agent", convert = FALSE) | |
| if (is.null(current_manager_agent_module)) { | |
| warning("TaijiChat: reticulate::import('agents.manager_agent') returned NULL in server.R.") | |
| print("TaijiChat: reticulate::import('agents.manager_agent') returned NULL in server.R.") | |
| } else { | |
| print("TaijiChat: Successfully imported/retrieved 'agents.manager_agent' module in server.R.") | |
| } | |
| }, error = function(e) { | |
| warning(paste("TaijiChat: Failed to import agents.manager_agent in server.R:", e$message)) | |
| print(paste("TaijiChat: Failed to import agents.manager_agent in server.R:", e$message)) | |
| }) | |
| if (!is.null(current_manager_agent_module)) { | |
| # Module is available, now try to instantiate the agent | |
| if (!is.null(py_openai_client_instance)) { | |
| tryCatch({ | |
| supabase_py_client <- if (!is.null(supabase_client)) supabase_client else NULL | |
| agent_inst <- current_manager_agent_module$ManagerAgent( | |
| openai_client = py_openai_client_instance, | |
| r_callback_fn = python_agent_thought_callback, | |
| supabase_client = supabase_py_client, | |
| user_id = NULL, | |
| hf_user_id = NULL | |
| ) | |
| rv_agent_instance(agent_inst) | |
| print("TaijiChat: Python ManagerAgent instance created in server.R using pre-initialized client and R callback.") | |
| }, error = function(e) { | |
| warning(paste("TaijiChat: Failed to instantiate ManagerAgent in server.R with client & callback:", e$message)) | |
| print(paste("TaijiChat: Failed to instantiate ManagerAgent with client & callback:", e$message)) | |
| }) | |
| } else if (!is.null(api_key_val)) { # Try with API key if client object failed but key exists | |
| tryCatch({ | |
| supabase_py_client <- if (!is.null(supabase_client)) supabase_client else NULL | |
| agent_inst <- current_manager_agent_module$ManagerAgent( | |
| openai_api_key = api_key_val, | |
| r_callback_fn = python_agent_thought_callback, | |
| supabase_client = supabase_py_client, | |
| user_id = NULL, | |
| hf_user_id = NULL | |
| ) | |
| rv_agent_instance(agent_inst) | |
| print("TaijiChat: Python ManagerAgent instance created in server.R with API key and R callback (client to be init by Python).") | |
| }, error = function(e) { | |
| warning(paste("TaijiChat: Failed to instantiate ManagerAgent with API key & callback in server.R:", e$message)) | |
| print(paste("TaijiChat: Failed to instantiate ManagerAgent with API key & callback:", e$message)) | |
| }) | |
| } else { | |
| # Neither client nor API key is available for the agent | |
| warning("TaijiChat: Cannot create ManagerAgent instance: OpenAI client/API key not available for agent constructor.") | |
| print("TaijiChat: Cannot create ManagerAgent: OpenAI client/API key not available for agent constructor.") | |
| } | |
| } else { | |
| # Module itself could not be imported/retrieved | |
| warning("TaijiChat: agents.manager_agent module is NULL after import attempt. Agent not created.") | |
| print("TaijiChat: agents.manager_agent module is NULL after import attempt. Agent not created.") | |
| } | |
| # --- END: TaijiChat Agent Initialization --- | |
| # --- START: Authentication Handlers --- | |
| # Handle login button click - generate OAuth URL (only once) | |
| observeEvent(input$hfSignInBtn, { | |
| req(input$hfSignInBtn) | |
| # Check if we're in OAuth callback (code in URL) | |
| query_string <- parseQueryString(session$clientData$url_search) | |
| if (!is.null(query_string$code)) { | |
| print("OAuth: In callback, skipping button redirect") | |
| return() | |
| } | |
| if (!oauth_config$enabled) { | |
| print("OAuth: Not enabled") | |
| return() | |
| } | |
| print(paste("OAuth: Button clicked, count:", input$hfSignInBtn)) | |
| # Generate random state for CSRF protection | |
| state <- generate_oauth_state() | |
| session$userData$oauth_state <- state | |
| # Get base URL - use SPACE_HOST if available (HF Spaces), otherwise use client URL | |
| space_host <- Sys.getenv("SPACE_HOST", "") | |
| if (space_host != "") { | |
| redirect_uri <- paste0("https://", space_host) | |
| } else { | |
| redirect_uri <- paste0(session$clientData$url_protocol, "//", | |
| session$clientData$url_hostname, | |
| if (session$clientData$url_port != "") paste0(":", session$clientData$url_port) else "") | |
| } | |
| print(paste("OAuth: Redirect URI:", redirect_uri)) | |
| # Generate authorization URL | |
| auth_url <- get_authorization_url(oauth_config, redirect_uri, state) | |
| if (!is.null(auth_url)) { | |
| print(paste("OAuth: Redirecting to:", auth_url)) | |
| # Send redirect message to JavaScript | |
| session$sendCustomMessage(type = 'redirect_to_oauth', message = list(url = auth_url)) | |
| } | |
| }, ignoreInit = TRUE, once = TRUE) | |
| # Send initial auth state on session start | |
| # Don't send if we're in OAuth callback (will be handled after auth completes) | |
| observe({ | |
| isolate({ | |
| # Check if we're in OAuth callback by looking at URL parameters | |
| query_string <- parseQueryString(session$clientData$url_search) | |
| if (is.null(query_string$code)) { | |
| # No OAuth code in URL, show login overlay | |
| session$sendCustomMessage('auth_state', list(authenticated = FALSE)) | |
| } | |
| }) | |
| }) | |
| # OAuth callback handler | |
| observeEvent(input$oauth_code, { | |
| if (!oauth_config$enabled || is.null(supabase_client)) { | |
| print("OAuth: Not enabled or Supabase not configured") | |
| return() | |
| } | |
| tryCatch({ | |
| # Get redirect URI - must match exactly what was used in authorization request | |
| space_host <- Sys.getenv("SPACE_HOST", "") | |
| if (space_host != "") { | |
| redirect_uri <- paste0("https://", space_host) | |
| } else { | |
| redirect_uri <- paste0(session$clientData$url_protocol, "//", | |
| session$clientData$url_hostname, | |
| if (session$clientData$url_port != "") paste0(":", session$clientData$url_port) else "") | |
| } | |
| print(paste("OAuth: Token exchange using redirect_uri:", redirect_uri)) | |
| # Exchange code for token | |
| token_result <- exchange_code_for_token(oauth_config, input$oauth_code, redirect_uri) | |
| if (is.null(token_result)) { | |
| print("OAuth: Failed to exchange code for token") | |
| return() | |
| } | |
| # Get user info from HF | |
| user_info <- get_user_info(token_result$access_token) | |
| if (is.null(user_info)) { | |
| print("OAuth: Failed to get user info") | |
| return() | |
| } | |
| # Create or retrieve user in Supabase | |
| supabase_user <- get_or_create_user( | |
| supabase_client, | |
| user_info$hf_user_id, | |
| user_info$hf_username, | |
| user_info$email | |
| ) | |
| if (is.null(supabase_user)) { | |
| print("OAuth: Failed to create/retrieve user in Supabase") | |
| return() | |
| } | |
| # Store in session | |
| session$userData$hf_user <- user_info | |
| session$userData$supabase_user <- supabase_user | |
| session$userData$access_token <- token_result$access_token | |
| print(paste("OAuth: User authenticated -", user_info$hf_username)) | |
| # Hide login overlay | |
| session$sendCustomMessage('auth_state', list(authenticated = TRUE)) | |
| # Show user info with quota | |
| tokens_used <- supabase_user$tokens_used %||% 0 | |
| token_quota <- supabase_user$token_quota %||% 100000 | |
| quota_text <- paste(tokens_used, "/", token_quota) | |
| session$sendCustomMessage('update_user_info', list( | |
| username = user_info$hf_username, | |
| quota = quota_text | |
| )) | |
| }, error = function(e) { | |
| print(paste("OAuth: Error in callback handler -", e$message)) | |
| }) | |
| }) | |
| # Logout handler | |
| observeEvent(input$logoutBtn, { | |
| logout_user(session) | |
| session$sendCustomMessage('auth_state', list(authenticated = FALSE)) | |
| print("OAuth: User logged out") | |
| }) | |
| # --- END: Authentication Handlers --- | |
| # Server logic for home tab | |
| output$home <- renderText({ | |
| "Welcome to the Home page" | |
| }) | |
| observeEvent(input$read_now, { | |
| # Trigger a redirect using JavaScript | |
| session$sendCustomMessage(type = "redirect", | |
| message = "https://doi.org/10.1101/2023.01.03.522354") | |
| }) | |
| # NEW READ EXCEL FILE FOR TRANSPOSED DATASET | |
| new_read_excel_file <- function(path) { | |
| df <- read_excel(path) | |
| colnames(df)[1] <- "Regulator Names" | |
| # Transpose the dataframe | |
| df_transposed <- as.data.frame(t(df)) | |
| # Fix the column names of the transposed dataframe (optional) | |
| colnames(df_transposed) <- df_transposed[1, ] # Set first row as column names | |
| df_transposed <- df_transposed[-1, ] # Remove the first row which is now used as column names | |
| return(df_transposed) | |
| } | |
| # # NEW FILTER FUNCTION FOR TRANSPOSED DATASET | |
| # new_filter_data <- function(df, keyword) { | |
| # | |
| # # Find the columns whose names contain the keyword | |
| # matching_columns <- grepl(keyword, colnames(df), ignore.case = TRUE) | |
| # | |
| # # Check if any matching columns exist | |
| # if (sum(matching_columns) == 0) { | |
| # # If no matching columns are found, return an empty dataframe with proper structure | |
| # return(data.frame()) | |
| # } | |
| # | |
| # # Subset the dataframe, ensuring the result is always a dataframe | |
| # filtered_df <- df[, matching_columns, drop = FALSE] | |
| # | |
| # return(filtered_df) | |
| # } | |
| #NEW FILTER FUNCTION FOR MULTIPLE GENE SEARCH | |
| # new_filter_data <- function(df, keywords) { | |
| # # Split the keywords by commas and remove any leading/trailing whitespace | |
| # keyword_list <- strsplit(keywords, ",")[[1]] | |
| # keyword_list <- trimws(keyword_list) | |
| # | |
| # # Initialize an empty logical vector for matching columns | |
| # matching_columns <- rep(FALSE, ncol(df)) | |
| # | |
| # # Loop through each keyword and update the matching_columns vector | |
| # for (keyword in keyword_list) { | |
| # matching_columns <- matching_columns | grepl(keyword, colnames(df), ignore.case = TRUE) | |
| # } | |
| # | |
| # # Check if any matching columns exist | |
| # if (sum(matching_columns) == 0) { | |
| # # If no matching columns are found, return an empty dataframe with proper structure | |
| # return(data.frame()) | |
| # } | |
| # | |
| # # Subset the dataframe, ensuring the result is always a dataframe | |
| # filtered_df <- df[, matching_columns, drop = FALSE] | |
| # | |
| # return(filtered_df) | |
| # } | |
| new_filter_data <- function(df, keywords) { | |
| # If no keywords are provided, return the full dataset | |
| if (is.null(keywords) || keywords == "") { | |
| return(df) | |
| } | |
| # Split the keywords by commas and remove any leading/trailing whitespace | |
| keyword_list <- strsplit(keywords, ",")[[1]] | |
| keyword_list <- trimws(keyword_list) # Remove leading/trailing spaces | |
| # Initialize an empty logical vector for matching columns | |
| matching_columns <- rep(FALSE, ncol(df)) | |
| # Loop through each keyword and update the matching_columns vector | |
| for (keyword in keyword_list) { | |
| matching_columns <- matching_columns | grepl(keyword, colnames(df), ignore.case = TRUE) | |
| } | |
| # Check if any matching columns exist | |
| if (sum(matching_columns) == 0) { | |
| # If no matching columns are found, return an empty dataframe | |
| return(data.frame()) | |
| } | |
| # Subset the dataframe, ensuring the result is always a dataframe | |
| filtered_df <- df[, matching_columns, drop = FALSE] | |
| return(filtered_df) | |
| } | |
| # TESTING FUNCTIONS | |
| #NEW ALL DATA SEARCH | |
| data <- reactive({ | |
| new_read_excel_file("www/tablePagerank/Table_TF PageRank Scores for Audrey.xlsx") | |
| }) | |
| # Track the current column page | |
| column_page <- reactiveVal(1) | |
| # Reset the column page when the search input changes for main page data | |
| observeEvent(input$search_input, { | |
| column_page(1) # Reset to page 1 when a new search is made | |
| }) | |
| # Update the column page when buttons are clicked | |
| observeEvent(input$next_btn, { | |
| current_page <- column_page() | |
| total_cols <- ncol(new_filter_data(data(), input$search_input)) | |
| # Calculate the maximum possible number of pages | |
| max_page <- ceiling(total_cols / 4) | |
| # Move to the next page, but do not exceed the max_page | |
| if (current_page < max_page) { | |
| column_page(current_page + 1) | |
| } | |
| # new_page <- column_page() + 1 | |
| # column_page(new_page) | |
| }) | |
| observeEvent(input$prev_btn, { | |
| current_page <- column_page() | |
| column_page(max(current_page - 1, 1)) | |
| # new_page <- max(column_page() - 1, 1) # Ensure the page does not go below 1 | |
| # column_page(new_page) | |
| }) | |
| # # OLD: Reactive for filtering the data based on input$search_input | |
| # new_filtered_data <- reactive({ | |
| # | |
| # df <- new_filter_data(data(), input$search_input) | |
| # | |
| # # Get the total number of columns in the filtered dataframe | |
| # total_cols <- ncol(df) | |
| # | |
| # # Ensure there are columns after filtering | |
| # if (total_cols == 0) { | |
| # return(data.frame()) # Return an empty dataframe if no columns match the search | |
| # } | |
| # | |
| # # Define the start and end index for columns based on the current page | |
| # start_col <- (column_page() - 1) * 4 + 1 | |
| # end_col <- min(start_col + 3, total_cols) # Show up to 4 columns | |
| # | |
| # # Ensure start_col is within the number of columns | |
| # if (start_col > total_cols) { | |
| # return(df) # Return the filtered dataframe as-is if start_col exceeds the number of columns | |
| # } | |
| # | |
| # # Subset the columns for the current page | |
| # df_subset <- df[, start_col:end_col, drop = FALSE] | |
| # return(df_subset) | |
| # }) | |
| #NEW FILTER DATA TO INCLUDE ADDITIONAL DESCRIPTION ROW + WORKS WITH SEARCHING INDIVIDUAL GENES | |
| new_filtered_data <- reactive({ | |
| # Filter the data and determine the total number of columns | |
| df <- new_filter_data(data(), input$search_input) | |
| total_cols <- ncol(df) | |
| # Return empty dataframe if no columns match the search | |
| if (total_cols == 0) return(data.frame()) | |
| # Define the column range for the current page | |
| start_col <- (column_page() - 1) * 4 + 1 | |
| end_col <- min(start_col + 3, total_cols) | |
| # Return filtered data if start_col exceeds the total columns | |
| if (start_col > total_cols) return(df) | |
| # Subset the dataframe for the current page | |
| df_subset <- df[, start_col:end_col, drop = FALSE] | |
| # Apply HTML formatting to description and "Cell state data" rows | |
| if (nrow(df_subset) >= 2) { | |
| description_row <- data.frame( | |
| matrix(NA, nrow = 1, ncol = ncol(df_subset), dimnames = list(NULL, colnames(df_subset))) | |
| ) | |
| # Define the HTML style for the description row (making "TF activity score" bold) | |
| style <- "<h5 style='font-weight: bold;'>TF activity score</h5>" | |
| # Apply style to both description and "Cell state data" | |
| description_row[1, ] <- style | |
| rownames(description_row)[1] <- "Cell state data" | |
| # Combine the data with the description and styled "Cell state data" row | |
| df_subset <- rbind(df_subset[1:2, , drop = FALSE], description_row, df_subset[-(1:2), , drop = FALSE]) | |
| } | |
| # Return the data with HTML rendering enabled, show all 45 rows, and remove the search box | |
| DT::datatable(df_subset, escape = FALSE, options = list( | |
| pageLength = 45, | |
| lengthChange = FALSE, | |
| searching = FALSE, # Remove the search box | |
| rowCallback = JS( | |
| "function(row, data, index) { | |
| var highlightedRow = 2; // Adjust this index to the row you want highlighted | |
| if (index === highlightedRow) { | |
| $('td', row).css({ | |
| 'background-color': '#95a5a6', | |
| 'color': 'white', | |
| 'font-weight': 'bold' | |
| }); | |
| } | |
| }" | |
| ) | |
| )) | |
| }) | |
| # Rendering the filtered data table and showing all rows | |
| output$table <- renderDT({ | |
| new_filtered_data() | |
| }, options = list(pageLength = nrow(new_filtered_data()), dom = 't')) | |
| #NEW NAIVE SEARCH | |
| naive_data <- reactive({ | |
| new_read_excel_file("www/tablePagerank/Naive.xlsx") | |
| }) | |
| # Track the current column page for naive data | |
| naive_column_page <- reactiveVal(1) | |
| # Reset the column page when the search input changes for naive data | |
| observeEvent(input$search_input_naive, { | |
| naive_column_page(1) # Reset to page 1 when a new search is made | |
| }) | |
| # Reset the column page when the search input changes for naive data | |
| observeEvent(input$search_input_naive, { | |
| naive_column_page(1) # Reset to page 1 when a new search is made | |
| }) | |
| # Update the column page when buttons are clicked for naive data | |
| observeEvent(input$naive_next_btn, { | |
| current_page <- naive_column_page() | |
| total_cols <- ncol(new_filter_data(naive_data(), input$search_input_naive)) | |
| # Calculate the maximum possible number of pages | |
| max_page <- ceiling(total_cols / 4) | |
| # Move to the next page, but do not exceed the max_page | |
| if (current_page < max_page) { | |
| naive_column_page(current_page + 1) | |
| } | |
| # new_page <- naive_column_page() + 1 | |
| # naive_column_page(new_page) | |
| }) | |
| observeEvent(input$naive_prev_btn, { | |
| current_page <- naive_column_page() | |
| naive_column_page(max(current_page - 1, 1)) | |
| # new_page <- max(naive_column_page() - 1, 1) # Ensure the page does not go below 1 | |
| # naive_column_page(new_page) | |
| }) | |
| #OLD FILTERED DATA | |
| # filtered_naive_data <- reactive({ | |
| # | |
| # df <- new_filter_data(naive_data(), input$search_input_naive) | |
| # | |
| # # Get the total number of columns in the filtered dataframe | |
| # total_cols <- ncol(df) | |
| # | |
| # # Ensure there are columns after filtering | |
| # if (total_cols == 0) { | |
| # return(data.frame()) # Return an empty dataframe if no columns match the search | |
| # } | |
| # | |
| # # Define the start and end index for columns based on the current page | |
| # start_col <- (naive_column_page() - 1) * 4 + 1 | |
| # end_col <- min(start_col + 3, total_cols) # Show up to 4 columns | |
| # | |
| # # Ensure start_col is within the number of columns | |
| # if (start_col > total_cols) { | |
| # return(df) # Return the filtered dataframe as-is if start_col exceeds the number of columns | |
| # } | |
| # | |
| # # Subset the columns for the current page | |
| # df_subset <- df[, start_col:end_col, drop = FALSE] | |
| # return(df_subset) | |
| # }) | |
| #NEW FILTERED DATA | |
| filtered_naive_data <- reactive({ | |
| # Filter the naive data and determine the total number of columns | |
| df <- new_filter_data(naive_data(), input$search_input_naive) | |
| total_cols <- ncol(df) | |
| # Return empty dataframe if no columns match the search | |
| if (total_cols == 0) return(data.frame()) | |
| # Define the column range for the current page | |
| start_col <- (naive_column_page() - 1) * 4 + 1 | |
| end_col <- min(start_col + 3, total_cols) | |
| # Return filtered data if start_col exceeds the total columns | |
| if (start_col > total_cols) return(df) | |
| # Subset the dataframe for the current page | |
| df_subset <- df[, start_col:end_col, drop = FALSE] | |
| # Apply HTML formatting to description and "Cell state data" rows, moving them to the first row | |
| if (nrow(df_subset) >= 2) { | |
| description_row <- data.frame( | |
| matrix(NA, nrow = 1, ncol = ncol(df_subset), dimnames = list(NULL, colnames(df_subset))) | |
| ) | |
| # Define the HTML style for the description row (making "TF activity score" bold with white font and background color) | |
| style <- "<h5 style='font-weight: bold; color: white;'>TF activity score</h5>" | |
| # Apply style to both description and "Cell state data" | |
| description_row[1, ] <- style | |
| rownames(description_row)[1] <- "Cell state data" | |
| # Move the description row to the first row of the subset | |
| df_subset <- rbind(description_row, df_subset) # Move this styled row to the first position | |
| } | |
| # Return the data with HTML rendering enabled, show all 45 rows, and remove the search box | |
| DT::datatable(df_subset, escape = FALSE, options = list( | |
| pageLength = 45, | |
| lengthChange = FALSE, | |
| searching = FALSE, # Remove the search box | |
| rowCallback = JS( | |
| "function(row, data, index) { | |
| var highlightedRow = 0; // Apply styling to the first row | |
| if (index === highlightedRow) { | |
| $('td', row).css({ | |
| 'background-color': '#95a5a6', | |
| 'color': 'white', | |
| 'font-weight': 'bold' | |
| }); | |
| } | |
| }" | |
| ) | |
| )) | |
| }) | |
| output$table_naive <- renderDT({ | |
| filtered_naive_data() | |
| }, options = list(pageLength = nrow(filtered_naive_data()), dom = 't')) | |
| #NEW TE SEARCH | |
| te_data <- reactive({ | |
| new_read_excel_file("www/tablePagerank/TE.xlsx") | |
| }) | |
| # Track the current column page for "te" data | |
| te_column_page <- reactiveVal(1) | |
| # Reset the column page when the search input changes for "te" data | |
| observeEvent(input$search_input_te, { | |
| te_column_page(1) # Reset to page 1 when a new search is made | |
| }) | |
| # Update the column page when buttons are clicked for "te" data | |
| observeEvent(input$te_next_btn, { | |
| current_page <- te_column_page() | |
| total_cols <- ncol(new_filter_data(te_data(), input$search_input_te)) | |
| # Calculate the maximum possible number of pages | |
| max_page <- ceiling(total_cols / 4) | |
| # Move to the next page, but do not exceed the max_page | |
| if (current_page < max_page) { | |
| te_column_page(current_page + 1) | |
| } | |
| }) | |
| observeEvent(input$te_prev_btn, { | |
| current_page <- te_column_page() | |
| te_column_page(max(current_page - 1, 1)) # Ensure the page does not go below 1 | |
| }) | |
| #OLD: Reactive for filtering and paginating the "te" page data | |
| # filtered_te_data <- reactive({ | |
| # df <- new_filter_data(te_data(), input$search_input_te) | |
| # | |
| # # Get the total number of columns in the filtered dataframe | |
| # total_cols <- ncol(df) | |
| # | |
| # # Ensure there are columns after filtering | |
| # if (total_cols == 0) { | |
| # return(data.frame()) # Return an empty dataframe if no columns match the search | |
| # } | |
| # | |
| # # Define the start and end index for columns based on the current page | |
| # start_col <- (te_column_page() - 1) * 4 + 1 | |
| # end_col <- min(start_col + 3, total_cols) # Show up to 4 columns | |
| # | |
| # # If start_col exceeds the total number of columns, return the last valid subset | |
| # if (start_col > total_cols) { | |
| # start_col <- (ceiling(total_cols / 4) - 1) * 4 + 1 # Set start_col to the last valid page | |
| # end_col <- total_cols # End with the last column | |
| # } | |
| # | |
| # # Subset the columns for the current page | |
| # df_subset <- df[, start_col:end_col, drop = FALSE] | |
| # | |
| # return(df_subset) | |
| # }) | |
| #NEW FILTERED DATA | |
| filtered_te_data <- reactive({ | |
| # Filter the TE data and determine the total number of columns | |
| df <- new_filter_data(te_data(), input$search_input_te) | |
| total_cols <- ncol(df) | |
| # Return empty dataframe if no columns match the search | |
| if (total_cols == 0) return(data.frame()) | |
| # Define the column range for the current page | |
| start_col <- (te_column_page() - 1) * 4 + 1 | |
| end_col <- min(start_col + 3, total_cols) | |
| # Return filtered data if start_col exceeds the total columns | |
| if (start_col > total_cols) return(df) | |
| # Subset the dataframe for the current page | |
| df_subset <- df[, start_col:end_col, drop = FALSE] | |
| # Apply HTML formatting to description and "Cell state data" rows, moving them to the first row | |
| if (nrow(df_subset) >= 2) { | |
| description_row <- data.frame( | |
| matrix(NA, nrow = 1, ncol = ncol(df_subset), dimnames = list(NULL, colnames(df_subset))) | |
| ) | |
| # Define the HTML style for the description row (making "TF activity score" bold with white font and background color) | |
| style <- "<h5 style='font-weight: bold; color: white;'>TF activity score</h5>" | |
| # Apply style to both description and "Cell state data" | |
| description_row[1, ] <- style | |
| rownames(description_row)[1] <- "Cell state data" | |
| # Move the description row to the first row of the subset | |
| df_subset <- rbind(description_row, df_subset) # Move this styled row to the first position | |
| } | |
| # Return the data with HTML rendering enabled, show all 45 rows, and remove the search box | |
| DT::datatable(df_subset, escape = FALSE, options = list( | |
| pageLength = 45, | |
| lengthChange = FALSE, | |
| searching = FALSE, # Remove the search box | |
| rowCallback = JS( | |
| "function(row, data, index) { | |
| var highlightedRow = 0; // Apply styling to the first row | |
| if (index === highlightedRow) { | |
| $('td', row).css({ | |
| 'background-color': '#95a5a6', | |
| 'color': 'white', | |
| 'font-weight': 'bold' | |
| }); | |
| } | |
| }" | |
| ) | |
| )) | |
| }) | |
| # Rendering the filtered "te" page data table and showing all rows | |
| output$table_te <- renderDT({ | |
| filtered_te_data() # Use the filtered data with pagination logic applied | |
| }, options = list( | |
| pageLength = nrow(filtered_te_data()), # Show all rows | |
| dom = 't', # Remove the row length dropdown | |
| scrollX = TRUE # Enable horizontal scrolling if needed | |
| )) | |
| #NEW MP SEARCH | |
| mp_data <- reactive({ | |
| new_read_excel_file("www/tablePagerank/MP.xlsx") | |
| }) | |
| # Track the current column page for "mp" data | |
| mp_column_page <- reactiveVal(1) | |
| # Reset the column page when the search input changes for "mp" data | |
| observeEvent(input$search_input_mp, { | |
| mp_column_page(1) # Reset to page 1 when a new search is made | |
| }) | |
| # Update the column page when buttons are clicked for "mp" data | |
| observeEvent(input$mp_next_btn, { | |
| current_page <- mp_column_page() | |
| total_cols <- ncol(new_filter_data(mp_data(), input$search_input_mp)) | |
| # Calculate the maximum possible number of pages | |
| max_page <- ceiling(total_cols / 4) | |
| # Move to the next page, but do not exceed the max_page | |
| if (current_page < max_page) { | |
| mp_column_page(current_page + 1) | |
| } | |
| }) | |
| observeEvent(input$mp_prev_btn, { | |
| current_page <- mp_column_page() | |
| mp_column_page(max(current_page - 1, 1)) # Ensure the page does not go below 1 | |
| }) | |
| #OLD: Reactive for filtering and paginating the "mp" page data | |
| # filtered_mp_data <- reactive({ | |
| # df <- new_filter_data(mp_data(), input$search_input_mp) | |
| # | |
| # # Get the total number of columns in the filtered dataframe | |
| # total_cols <- ncol(df) | |
| # | |
| # # Ensure there are columns after filtering | |
| # if (total_cols == 0) { | |
| # return(data.frame()) # Return an empty dataframe if no columns match the search | |
| # } | |
| # | |
| # # Define the start and end index for columns based on the current page | |
| # start_col <- (mp_column_page() - 1) * 4 + 1 | |
| # end_col <- min(start_col + 3, total_cols) # Show up to 4 columns | |
| # | |
| # # If start_col exceeds the total number of columns, return the last valid subset | |
| # if (start_col > total_cols) { | |
| # start_col <- (ceiling(total_cols / 4) - 1) * 4 + 1 # Set start_col to the last valid page | |
| # end_col <- total_cols # End with the last column | |
| # } | |
| # | |
| # # Subset the columns for the current page | |
| # df_subset <- df[, start_col:end_col, drop = FALSE] | |
| # | |
| # return(df_subset) | |
| # }) | |
| #NEW FILTERED DATA | |
| filtered_mp_data <- reactive({ | |
| # Filter the MP data and determine the total number of columns | |
| df <- new_filter_data(mp_data(), input$search_input_mp) | |
| total_cols <- ncol(df) | |
| # Return empty dataframe if no columns match the search | |
| if (total_cols == 0) return(data.frame()) | |
| # Define the column range for the current page | |
| start_col <- (mp_column_page() - 1) * 4 + 1 | |
| end_col <- min(start_col + 3, total_cols) | |
| # Return filtered data if start_col exceeds the total columns | |
| if (start_col > total_cols) return(df) | |
| # Subset the dataframe for the current page | |
| df_subset <- df[, start_col:end_col, drop = FALSE] | |
| # Apply HTML formatting to description and "Cell state data" rows, moving them to the first row | |
| if (nrow(df_subset) >= 2) { | |
| description_row <- data.frame( | |
| matrix(NA, nrow = 1, ncol = ncol(df_subset), dimnames = list(NULL, colnames(df_subset))) | |
| ) | |
| # Define the HTML style for the description row (making "TF activity score" bold with white font and background color) | |
| style <- "<h5 style='font-weight: bold; color: white;'>TF activity score</h5>" | |
| # Apply style to both description and "Cell state data" | |
| description_row[1, ] <- style | |
| rownames(description_row)[1] <- "Cell state data" | |
| # Move the description row to the first row of the subset | |
| df_subset <- rbind(description_row, df_subset) # Move this styled row to the first position | |
| } | |
| # Return the data with HTML rendering enabled, show all 45 rows, and remove the search box | |
| DT::datatable(df_subset, escape = FALSE, options = list( | |
| pageLength = 45, | |
| lengthChange = FALSE, | |
| searching = FALSE, # Remove the search box | |
| rowCallback = JS( | |
| "function(row, data, index) { | |
| var highlightedRow = 0; // Apply styling to the first row | |
| if (index === highlightedRow) { | |
| $('td', row).css({ | |
| 'background-color': '#95a5a6', | |
| 'color': 'white', | |
| 'font-weight': 'bold' | |
| }); | |
| } | |
| }" | |
| ) | |
| )) | |
| }) | |
| # Rendering the filtered "mp" page data table and showing all rows | |
| output$table_mp <- renderDT({ | |
| filtered_mp_data() # Use the filtered data with pagination logic applied | |
| }, options = list( | |
| pageLength = nrow(filtered_mp_data()), # Show all rows | |
| dom = 't', # Remove the row length dropdown | |
| scrollX = TRUE # Enable horizontal scrolling if needed | |
| )) | |
| #NEW TCM SEARCH | |
| tcm_data <- reactive({ | |
| new_read_excel_file("www/tablePagerank/TCM.xlsx") | |
| }) | |
| # Track the current column page for "tcm" data | |
| tcm_column_page <- reactiveVal(1) | |
| # Reset the column page when the search input changes for "tcm" data | |
| observeEvent(input$search_input_tcm, { | |
| tcm_column_page(1) # Reset to page 1 when a new search is made | |
| }) | |
| # Update the column page when buttons are clicked for "tcm" data | |
| observeEvent(input$tcm_next_btn, { | |
| current_page <- tcm_column_page() | |
| total_cols <- ncol(new_filter_data(tcm_data(), input$search_input_tcm)) | |
| # Calculate the maximum possible number of pages | |
| max_page <- ceiling(total_cols / 4) | |
| # Move to the next page, but do not exceed the max_page | |
| if (current_page < max_page) { | |
| tcm_column_page(current_page + 1) | |
| } | |
| }) | |
| observeEvent(input$tcm_prev_btn, { | |
| current_page <- tcm_column_page() | |
| tcm_column_page(max(current_page - 1, 1)) # Ensure the page does not go below 1 | |
| }) | |
| #OLD: Reactive for filtering and paginating the "tcm" page data | |
| # filtered_tcm_data <- reactive({ | |
| # df <- new_filter_data(tcm_data(), input$search_input_tcm) | |
| # | |
| # # Get the total number of columns in the filtered dataframe | |
| # total_cols <- ncol(df) | |
| # | |
| # # Ensure there are columns after filtering | |
| # if (total_cols == 0) { | |
| # return(data.frame()) # Return an empty dataframe if no columns match the search | |
| # } | |
| # | |
| # # Define the start and end index for columns based on the current page | |
| # start_col <- (tcm_column_page() - 1) * 4 + 1 | |
| # end_col <- min(start_col + 3, total_cols) # Show up to 4 columns | |
| # | |
| # # If start_col exceeds the total number of columns, return the last valid subset | |
| # if (start_col > total_cols) { | |
| # start_col <- (ceiling(total_cols / 4) - 1) * 4 + 1 # Set start_col to the last valid page | |
| # end_col <- total_cols # End with the last column | |
| # } | |
| # | |
| # # Subset the columns for the current page | |
| # df_subset <- df[, start_col:end_col, drop = FALSE] | |
| # | |
| # return(df_subset) | |
| # }) | |
| #NEW FILTERED DATA | |
| filtered_tcm_data <- reactive({ | |
| # Filter the TCM data and determine the total number of columns | |
| df <- new_filter_data(tcm_data(), input$search_input_tcm) | |
| total_cols <- ncol(df) | |
| # Return empty dataframe if no columns match the search | |
| if (total_cols == 0) return(data.frame()) | |
| # Define the column range for the current page | |
| start_col <- (tcm_column_page() - 1) * 4 + 1 | |
| end_col <- min(start_col + 3, total_cols) | |
| # Return filtered data if start_col exceeds the total columns | |
| if (start_col > total_cols) return(df) | |
| # Subset the dataframe for the current page | |
| df_subset <- df[, start_col:end_col, drop = FALSE] | |
| # Apply HTML formatting to description and "Cell state data" rows, moving them to the first row | |
| if (nrow(df_subset) >= 2) { | |
| description_row <- data.frame( | |
| matrix(NA, nrow = 1, ncol = ncol(df_subset), dimnames = list(NULL, colnames(df_subset))) | |
| ) | |
| # Define the HTML style for the description row (making "TF activity score" bold with white font and background color) | |
| style <- "<h5 style='font-weight: bold; color: white;'>TF activity score</h5>" | |
| # Apply style to both description and "Cell state data" | |
| description_row[1, ] <- style | |
| rownames(description_row)[1] <- "Cell state data" | |
| # Move the description row to the first row of the subset | |
| df_subset <- rbind(description_row, df_subset) # Move this styled row to the first position | |
| } | |
| # Return the data with HTML rendering enabled, show all 45 rows, and remove the search box | |
| DT::datatable(df_subset, escape = FALSE, options = list( | |
| pageLength = 45, | |
| lengthChange = FALSE, | |
| searching = FALSE, # Remove the search box | |
| rowCallback = JS( | |
| "function(row, data, index) { | |
| var highlightedRow = 0; // Apply styling to the first row | |
| if (index === highlightedRow) { | |
| $('td', row).css({ | |
| 'background-color': '#95a5a6', | |
| 'color': 'white', | |
| 'font-weight': 'bold' | |
| }); | |
| } | |
| }" | |
| ) | |
| )) | |
| }) | |
| # Rendering the filtered "tcm" page data table and showing all rows | |
| output$table_tcm <- renderDT({ | |
| filtered_tcm_data() # Use the filtered data with pagination logic applied | |
| }, options = list( | |
| pageLength = nrow(filtered_tcm_data()), # Show all rows | |
| dom = 't', # Remove the row length dropdown | |
| scrollX = TRUE # Enable horizontal scrolling if needed | |
| )) | |
| #NEW TEM SEARCH | |
| tem_data <- reactive({ | |
| new_read_excel_file("www/tablePagerank/TEM.xlsx") | |
| }) | |
| # Track the current column page for "tem" data | |
| tem_column_page <- reactiveVal(1) | |
| # Reset the column page when the search input changes for "tem" data | |
| observeEvent(input$search_input_tem, { | |
| tem_column_page(1) # Reset to page 1 when a new search is made | |
| }) | |
| # Update the column page when buttons are clicked for "tem" data | |
| observeEvent(input$tem_next_btn, { | |
| current_page <- tem_column_page() | |
| total_cols <- ncol(new_filter_data(tem_data(), input$search_input_tem)) | |
| # Calculate the maximum possible number of pages | |
| max_page <- ceiling(total_cols / 4) | |
| # Move to the next page, but do not exceed the max_page | |
| if (current_page < max_page) { | |
| tem_column_page(current_page + 1) | |
| } | |
| }) | |
| observeEvent(input$tem_prev_btn, { | |
| current_page <- tem_column_page() | |
| tem_column_page(max(current_page - 1, 1)) # Ensure the page does not go below 1 | |
| }) | |
| #OLD: Reactive for filtering and paginating the "tem" page data | |
| # filtered_tem_data <- reactive({ | |
| # df <- new_filter_data(tem_data(), input$search_input_tem) | |
| # | |
| # # Get the total number of columns in the filtered dataframe | |
| # total_cols <- ncol(df) | |
| # | |
| # # Ensure there are columns after filtering | |
| # if (total_cols == 0) { | |
| # return(data.frame()) # Return an empty dataframe if no columns match the search | |
| # } | |
| # | |
| # # Define the start and end index for columns based on the current page | |
| # start_col <- (tem_column_page() - 1) * 4 + 1 | |
| # end_col <- min(start_col + 3, total_cols) # Show up to 4 columns | |
| # | |
| # # If start_col exceeds the total number of columns, return the last valid subset | |
| # if (start_col > total_cols) { | |
| # start_col <- (ceiling(total_cols / 4) - 1) * 4 + 1 # Set start_col to the last valid page | |
| # end_col <- total_cols # End with the last column | |
| # } | |
| # | |
| # # Subset the columns for the current page | |
| # df_subset <- df[, start_col:end_col, drop = FALSE] | |
| # | |
| # return(df_subset) | |
| # }) | |
| #NEW FILTERED DATA | |
| filtered_tem_data <- reactive({ | |
| # Filter the TEM data and determine the total number of columns | |
| df <- new_filter_data(tem_data(), input$search_input_tem) | |
| total_cols <- ncol(df) | |
| # Return empty dataframe if no columns match the search | |
| if (total_cols == 0) return(data.frame()) | |
| # Define the column range for the current page | |
| start_col <- (tem_column_page() - 1) * 4 + 1 | |
| end_col <- min(start_col + 3, total_cols) | |
| # Return filtered data if start_col exceeds the total columns | |
| if (start_col > total_cols) return(df) | |
| # Subset the dataframe for the current page | |
| df_subset <- df[, start_col:end_col, drop = FALSE] | |
| # Apply HTML formatting to description and "Cell state data" rows, moving them to the first row | |
| if (nrow(df_subset) >= 2) { | |
| description_row <- data.frame( | |
| matrix(NA, nrow = 1, ncol = ncol(df_subset), dimnames = list(NULL, colnames(df_subset))) | |
| ) | |
| # Define the HTML style for the description row (making "TF activity score" bold with white font and background color) | |
| style <- "<h5 style='font-weight: bold; color: white;'>TF activity score</h5>" | |
| # Apply style to both description and "Cell state data" | |
| description_row[1, ] <- style | |
| rownames(description_row)[1] <- "Cell state data" | |
| # Move the description row to the first row of the subset | |
| df_subset <- rbind(description_row, df_subset) # Move this styled row to the first position | |
| } | |
| # Return the data with HTML rendering enabled, show all 45 rows, and remove the search box | |
| DT::datatable(df_subset, escape = FALSE, options = list( | |
| pageLength = 45, | |
| lengthChange = FALSE, | |
| searching = FALSE, # Remove the search box | |
| rowCallback = JS( | |
| "function(row, data, index) { | |
| var highlightedRow = 0; // Apply styling to the first row | |
| if (index === highlightedRow) { | |
| $('td', row).css({ | |
| 'background-color': '#95a5a6', | |
| 'color': 'white', | |
| 'font-weight': 'bold' | |
| }); | |
| } | |
| }" | |
| ) | |
| )) | |
| }) | |
| # Rendering the filtered "tem" page data table and showing all rows | |
| output$table_tem <- renderDT({ | |
| filtered_tem_data() # Use the filtered data with pagination logic applied | |
| }, options = list( | |
| pageLength = nrow(filtered_tem_data()), # Show all rows | |
| dom = 't', # Remove the row length dropdown | |
| scrollX = TRUE # Enable horizontal scrolling if needed | |
| )) | |
| #NEW TRM SEARCH | |
| trm_data <- reactive({ | |
| new_read_excel_file("www/tablePagerank/TRM.xlsx") | |
| }) | |
| # Track the current column page for "trmm" data | |
| trm_column_page <- reactiveVal(1) | |
| # Reset the column page when the search input changes for "trmm" data | |
| observeEvent(input$search_input_trm, { | |
| trm_column_page(1) # Reset to page 1 when a new search is made | |
| }) | |
| # Update the column page when buttons are clicked for "trmm" data | |
| observeEvent(input$trm_next_btn, { | |
| current_page <- trm_column_page() | |
| total_cols <- ncol(new_filter_data(trm_data(), input$search_input_trm)) | |
| # Calculate the maximum possible number of pages | |
| max_page <- ceiling(total_cols / 4) | |
| # Move to the next page, but do not exceed the max_page | |
| if (current_page < max_page) { | |
| trm_column_page(current_page + 1) | |
| } | |
| }) | |
| observeEvent(input$trm_prev_btn, { | |
| current_page <- trm_column_page() | |
| trm_column_page(max(current_page - 1, 1)) # Ensure the page does not go below 1 | |
| }) | |
| #OLD: Reactive for filtering and paginating the "trmm" page data | |
| # filtered_trm_data <- reactive({ | |
| # df <- new_filter_data(trm_data(), input$search_input_trm) | |
| # | |
| # # Get the total number of columns in the filtered dataframe | |
| # total_cols <- ncol(df) | |
| # | |
| # # Ensure there are columns after filtering | |
| # if (total_cols == 0) { | |
| # return(data.frame()) # Return an empty dataframe if no columns match the search | |
| # } | |
| # | |
| # # Define the start and end index for columns based on the current page | |
| # start_col <- (trm_column_page() - 1) * 4 + 1 | |
| # end_col <- min(start_col + 3, total_cols) # Show up to 4 columns | |
| # | |
| # # If start_col exceeds the total number of columns, return the last valid subset | |
| # if (start_col > total_cols) { | |
| # start_col <- (ceiling(total_cols / 4) - 1) * 4 + 1 # Set start_col to the last valid page | |
| # end_col <- total_cols # End with the last column | |
| # } | |
| # | |
| # # Subset the columns for the current page | |
| # df_subset <- df[, start_col:end_col, drop = FALSE] | |
| # | |
| # return(df_subset) | |
| # }) | |
| #NEW FILTERED DATA | |
| filtered_trm_data <- reactive({ | |
| # Filter the TRM data and determine the total number of columns | |
| df <- new_filter_data(trm_data(), input$search_input_trm) | |
| total_cols <- ncol(df) | |
| # Return empty dataframe if no columns match the search | |
| if (total_cols == 0) return(data.frame()) | |
| # Define the column range for the current page | |
| start_col <- (trm_column_page() - 1) * 4 + 1 | |
| end_col <- min(start_col + 3, total_cols) | |
| # Return filtered data if start_col exceeds the total columns | |
| if (start_col > total_cols) return(df) | |
| # Subset the dataframe for the current page | |
| df_subset <- df[, start_col:end_col, drop = FALSE] | |
| # Apply HTML formatting to description and "Cell state data" rows, moving them to the first row | |
| if (nrow(df_subset) >= 2) { | |
| description_row <- data.frame( | |
| matrix(NA, nrow = 1, ncol = ncol(df_subset), dimnames = list(NULL, colnames(df_subset))) | |
| ) | |
| # Define the HTML style for the description row (making "TF activity score" bold with white font and background color) | |
| style <- "<h5 style='font-weight: bold; color: white;'>TF activity score</h5>" | |
| # Apply style to both description and "Cell state data" | |
| description_row[1, ] <- style | |
| rownames(description_row)[1] <- "Cell state data" | |
| # Move the description row to the first row of the subset | |
| df_subset <- rbind(description_row, df_subset) # Move this styled row to the first position | |
| } | |
| # Return the data with HTML rendering enabled, show all 45 rows, and remove the search box | |
| DT::datatable(df_subset, escape = FALSE, options = list( | |
| pageLength = 45, | |
| lengthChange = FALSE, | |
| searching = FALSE, # Remove the search box | |
| rowCallback = JS( | |
| "function(row, data, index) { | |
| var highlightedRow = 0; // Apply styling to the first row | |
| if (index === highlightedRow) { | |
| $('td', row).css({ | |
| 'background-color': '#95a5a6', | |
| 'color': 'white', | |
| 'font-weight': 'bold' | |
| }); | |
| } | |
| }" | |
| ) | |
| )) | |
| }) | |
| # Rendering the filtered "trmm" page data table and showing all rows | |
| output$table_trm <- renderDT({ | |
| filtered_trm_data() # Use the filtered data with pagination logic applied | |
| }, options = list( | |
| pageLength = nrow(filtered_trm_data()), # Show all rows | |
| dom = 't', # Remove the row length dropdown | |
| scrollX = TRUE # Enable horizontal scrolling if needed | |
| )) | |
| #NEW TEX PROG SEARCH | |
| texprog_data <- reactive({ | |
| new_read_excel_file("www/tablePagerank/TEXprog.xlsx") | |
| }) | |
| # Track the current column page for "texprog" data | |
| texprog_column_page <- reactiveVal(1) | |
| # Reset the column page when the search input changes for "texprog" data | |
| observeEvent(input$search_input_texprog, { | |
| texprog_column_page(1) # Reset to page 1 when a new search is made | |
| }) | |
| # Update the column page when buttons are clicked for "texprog" data | |
| observeEvent(input$texprog_next_btn, { | |
| current_page <- texprog_column_page() | |
| total_cols <- ncol(new_filter_data(texprog_data(), input$search_input_texprog)) | |
| # Calculate the maximum possible number of pages | |
| max_page <- ceiling(total_cols / 4) | |
| # Move to the next page, but do not exceed the max_page | |
| if (current_page < max_page) { | |
| texprog_column_page(current_page + 1) | |
| } | |
| }) | |
| observeEvent(input$texprog_prev_btn, { | |
| current_page <- texprog_column_page() | |
| texprog_column_page(max(current_page - 1, 1)) # Ensure the page does not go below 1 | |
| }) | |
| #OLD: Reactive for filtering and paginating the "texprog" page data | |
| # filtered_texprog_data <- reactive({ | |
| # df <- new_filter_data(texprog_data(), input$search_input_texprog) | |
| # | |
| # # Get the total number of columns in the filtered dataframe | |
| # total_cols <- ncol(df) | |
| # | |
| # # Ensure there are columns after filtering | |
| # if (total_cols == 0) { | |
| # return(data.frame()) # Return an empty dataframe if no columns match the search | |
| # } | |
| # | |
| # # Define the start and end index for columns based on the current page | |
| # start_col <- (texprog_column_page() - 1) * 4 + 1 | |
| # end_col <- min(start_col + 3, total_cols) # Show up to 4 columns | |
| # | |
| # # If start_col exceeds the total number of columns, return the last valid subset | |
| # if (start_col > total_cols) { | |
| # start_col <- (ceiling(total_cols / 4) - 1) * 4 + 1 # Set start_col to the last valid page | |
| # end_col <- total_cols # End with the last column | |
| # } | |
| # | |
| # # Subset the columns for the current page | |
| # df_subset <- df[, start_col:end_col, drop = FALSE] | |
| # | |
| # return(df_subset) | |
| # }) | |
| #NEW FILTERED DATA | |
| filtered_texprog_data <- reactive({ | |
| # Filter the TEXprog data and determine the total number of columns | |
| df <- new_filter_data(texprog_data(), input$search_input_texprog) | |
| total_cols <- ncol(df) | |
| # Return empty dataframe if no columns match the search | |
| if (total_cols == 0) return(data.frame()) | |
| # Define the column range for the current page | |
| start_col <- (texprog_column_page() - 1) * 4 + 1 | |
| end_col <- min(start_col + 3, total_cols) | |
| # Return filtered data if start_col exceeds the total columns | |
| if (start_col > total_cols) return(df) | |
| # Subset the dataframe for the current page | |
| df_subset <- df[, start_col:end_col, drop = FALSE] | |
| # Apply HTML formatting to description and "Cell state data" rows, moving them to the first row | |
| if (nrow(df_subset) >= 2) { | |
| description_row <- data.frame( | |
| matrix(NA, nrow = 1, ncol = ncol(df_subset), dimnames = list(NULL, colnames(df_subset))) | |
| ) | |
| # Define the HTML style for the description row (making "TF activity score" bold with white font and background color) | |
| style <- "<h5 style='font-weight: bold; color: white;'>TF activity score</h5>" | |
| # Apply style to both description and "Cell state data" | |
| description_row[1, ] <- style | |
| rownames(description_row)[1] <- "Cell state data" | |
| # Move the description row to the first row of the subset | |
| df_subset <- rbind(description_row, df_subset) # Move this styled row to the first position | |
| } | |
| # Return the data with HTML rendering enabled, show all 45 rows, and remove the search box | |
| DT::datatable(df_subset, escape = FALSE, options = list( | |
| pageLength = 45, | |
| lengthChange = FALSE, | |
| searching = FALSE, # Remove the search box | |
| rowCallback = JS( | |
| "function(row, data, index) { | |
| var highlightedRow = 0; // Apply styling to the first row | |
| if (index === highlightedRow) { | |
| $('td', row).css({ | |
| 'background-color': '#95a5a6', | |
| 'color': 'white', | |
| 'font-weight': 'bold' | |
| }); | |
| } | |
| }" | |
| ) | |
| )) | |
| }) | |
| # Rendering the filtered "texprog" page data table and showing all rows | |
| output$table_texprog <- renderDT({ | |
| filtered_texprog_data() # Use the filtered data with pagination logic applied | |
| }, options = list( | |
| pageLength = nrow(filtered_texprog_data()), # Show all rows | |
| dom = 't', # Remove the row length dropdown | |
| scrollX = TRUE # Enable horizontal scrolling if needed | |
| )) | |
| #NEW TEX EFF LIKE SEARCH | |
| texefflike_data <- reactive({ | |
| new_read_excel_file("www/tablePagerank/TEXeff.xlsx") | |
| }) | |
| # Track the current column page for "texefflike" data | |
| texefflike_column_page <- reactiveVal(1) | |
| # Reset the column page when the search input changes for "texefflike" data | |
| observeEvent(input$search_input_texefflike, { | |
| texefflike_column_page(1) # Reset to page 1 when a new search is made | |
| }) | |
| # Update the column page when buttons are clicked for "texefflike" data | |
| observeEvent(input$texefflike_next_btn, { | |
| current_page <- texefflike_column_page() | |
| total_cols <- ncol(new_filter_data(texefflike_data(), input$search_input_texefflike)) | |
| # Calculate the maximum possible number of pages | |
| max_page <- ceiling(total_cols / 4) | |
| # Move to the next page, but do not exceed the max_page | |
| if (current_page < max_page) { | |
| texefflike_column_page(current_page + 1) | |
| } | |
| }) | |
| observeEvent(input$texefflike_prev_btn, { | |
| current_page <- texefflike_column_page() | |
| texefflike_column_page(max(current_page - 1, 1)) # Ensure the page does not go below 1 | |
| }) | |
| #OLD: Reactive for filtering and paginating the "texefflike" page data | |
| # filtered_texefflike_data <- reactive({ | |
| # df <- new_filter_data(texefflike_data(), input$search_input_texefflike) | |
| # | |
| # # Get the total number of columns in the filtered dataframe | |
| # total_cols <- ncol(df) | |
| # | |
| # # Ensure there are columns after filtering | |
| # if (total_cols == 0) { | |
| # return(data.frame()) # Return an empty dataframe if no columns match the search | |
| # } | |
| # | |
| # # Define the start and end index for columns based on the current page | |
| # start_col <- (texefflike_column_page() - 1) * 4 + 1 | |
| # end_col <- min(start_col + 3, total_cols) # Show up to 4 columns | |
| # | |
| # # If start_col exceeds the total number of columns, return the last valid subset | |
| # if (start_col > total_cols) { | |
| # start_col <- (ceiling(total_cols / 4) - 1) * 4 + 1 # Set start_col to the last valid page | |
| # end_col <- total_cols # End with the last column | |
| # } | |
| # | |
| # # Subset the columns for the current page | |
| # df_subset <- df[, start_col:end_col, drop = FALSE] | |
| # | |
| # return(df_subset) | |
| # }) | |
| #NEW FILTERED DATA | |
| filtered_texefflike_data <- reactive({ | |
| # Filter the TEXefflike data and determine the total number of columns | |
| df <- new_filter_data(texefflike_data(), input$search_input_texefflike) | |
| total_cols <- ncol(df) | |
| # Return empty dataframe if no columns match the search | |
| if (total_cols == 0) return(data.frame()) | |
| # Define the column range for the current page | |
| start_col <- (texefflike_column_page() - 1) * 4 + 1 | |
| end_col <- min(start_col + 3, total_cols) | |
| # Return filtered data if start_col exceeds the total columns | |
| if (start_col > total_cols) return(df) | |
| # Subset the dataframe for the current page | |
| df_subset <- df[, start_col:end_col, drop = FALSE] | |
| # Apply HTML formatting to description and "Cell state data" rows, moving them to the first row | |
| if (nrow(df_subset) >= 2) { | |
| description_row <- data.frame( | |
| matrix(NA, nrow = 1, ncol = ncol(df_subset), dimnames = list(NULL, colnames(df_subset))) | |
| ) | |
| # Define the HTML style for the description row (making "TF activity score" bold with white font and background color) | |
| style <- "<h5 style='font-weight: bold; color: white;'>TF activity score</h5>" | |
| # Apply style to both description and "Cell state data" | |
| description_row[1, ] <- style | |
| rownames(description_row)[1] <- "Cell state data" | |
| # Move the description row to the first row of the subset | |
| df_subset <- rbind(description_row, df_subset) # Move this styled row to the first position | |
| } | |
| # Return the data with HTML rendering enabled, show all 45 rows, and remove the search box | |
| DT::datatable(df_subset, escape = FALSE, options = list( | |
| pageLength = 45, | |
| lengthChange = FALSE, | |
| searching = FALSE, # Remove the search box | |
| rowCallback = JS( | |
| "function(row, data, index) { | |
| var highlightedRow = 0; // Apply styling to the first row | |
| if (index === highlightedRow) { | |
| $('td', row).css({ | |
| 'background-color': '#95a5a6', | |
| 'color': 'white', | |
| 'font-weight': 'bold' | |
| }); | |
| } | |
| }" | |
| ) | |
| )) | |
| }) | |
| # Rendering the filtered "texefflike" page data table and showing all rows | |
| output$table_texefflike <- renderDT({ | |
| filtered_texefflike_data() # Use the filtered data with pagination logic applied | |
| }, options = list( | |
| pageLength = nrow(filtered_texefflike_data()), # Show all rows | |
| dom = 't', # Remove the row length dropdown | |
| scrollX = TRUE # Enable horizontal scrolling if needed | |
| )) | |
| #NEW TEX TERM SEARCH | |
| texterm_data <- reactive({ | |
| new_read_excel_file("www/tablePagerank/TEXterm.xlsx") | |
| }) | |
| # Track the current column page for "texterm" data | |
| texterm_column_page <- reactiveVal(1) | |
| # Reset the column page when the search input changes for "texterm" data | |
| observeEvent(input$search_input_texterm, { | |
| texterm_column_page(1) # Reset to page 1 when a new search is made | |
| }) | |
| # Update the column page when buttons are clicked for "texterm" data | |
| observeEvent(input$texterm_next_btn, { | |
| current_page <- texterm_column_page() | |
| total_cols <- ncol(new_filter_data(texterm_data(), input$search_input_texterm)) | |
| # Calculate the maximum possible number of pages | |
| max_page <- ceiling(total_cols / 4) | |
| # Move to the next page, but do not exceed the max_page | |
| if (current_page < max_page) { | |
| texterm_column_page(current_page + 1) | |
| } | |
| }) | |
| observeEvent(input$texterm_prev_btn, { | |
| current_page <- texterm_column_page() | |
| texterm_column_page(max(current_page - 1, 1)) # Ensure the page does not go below 1 | |
| }) | |
| #OLD: Reactive for filtering and paginating the "texterm" page data | |
| # filtered_texterm_data <- reactive({ | |
| # df <- new_filter_data(texterm_data(), input$search_input_texterm) | |
| # | |
| # # Get the total number of columns in the filtered dataframe | |
| # total_cols <- ncol(df) | |
| # | |
| # # Ensure there are columns after filtering | |
| # if (total_cols == 0) { | |
| # return(data.frame()) # Return an empty dataframe if no columns match the search | |
| # } | |
| # | |
| # # Define the start and end index for columns based on the current page | |
| # start_col <- (texterm_column_page() - 1) * 4 + 1 | |
| # end_col <- min(start_col + 3, total_cols) # Show up to 4 columns | |
| # | |
| # # If start_col exceeds the total number of columns, return the last valid subset | |
| # if (start_col > total_cols) { | |
| # start_col <- (ceiling(total_cols / 4) - 1) * 4 + 1 # Set start_col to the last valid page | |
| # end_col <- total_cols # End with the last column | |
| # } | |
| # | |
| # # Subset the columns for the current page | |
| # df_subset <- df[, start_col:end_col, drop = FALSE] | |
| # | |
| # return(df_subset) | |
| # }) | |
| #NEW FILTERED DATA | |
| filtered_texterm_data <- reactive({ | |
| # Filter the TEXterm data and determine the total number of columns | |
| df <- new_filter_data(texterm_data(), input$search_input_texterm) | |
| total_cols <- ncol(df) | |
| # Return empty dataframe if no columns match the search | |
| if (total_cols == 0) return(data.frame()) | |
| # Define the column range for the current page | |
| start_col <- (texterm_column_page() - 1) * 4 + 1 | |
| end_col <- min(start_col + 3, total_cols) | |
| # Return filtered data if start_col exceeds the total columns | |
| if (start_col > total_cols) return(df) | |
| # Subset the dataframe for the current page | |
| df_subset <- df[, start_col:end_col, drop = FALSE] | |
| # Apply HTML formatting to description and "Cell state data" rows, moving them to the first row | |
| if (nrow(df_subset) >= 2) { | |
| description_row <- data.frame( | |
| matrix(NA, nrow = 1, ncol = ncol(df_subset), dimnames = list(NULL, colnames(df_subset))) | |
| ) | |
| # Define the HTML style for the description row (making "TF activity score" bold with white font and background color) | |
| style <- "<h5 style='font-weight: bold; color: white;'>TF activity score</h5>" | |
| # Apply style to both description and "Cell state data" | |
| description_row[1, ] <- style | |
| rownames(description_row)[1] <- "Cell state data" | |
| # Move the description row to the first row of the subset | |
| df_subset <- rbind(description_row, df_subset) # Move this styled row to the first position | |
| } | |
| # Return the data with HTML rendering enabled, show all 45 rows, and remove the search box | |
| DT::datatable(df_subset, escape = FALSE, options = list( | |
| pageLength = 45, | |
| lengthChange = FALSE, | |
| searching = FALSE, # Remove the search box | |
| rowCallback = JS( | |
| "function(row, data, index) { | |
| var highlightedRow = 0; // Apply styling to the first row | |
| if (index === highlightedRow) { | |
| $('td', row).css({ | |
| 'background-color': '#95a5a6', | |
| 'color': 'white', | |
| 'font-weight': 'bold' | |
| }); | |
| } | |
| }" | |
| ) | |
| )) | |
| }) | |
| # Rendering the filtered "texterm" page data table and showing all rows | |
| output$table_texterm <- renderDT({ | |
| filtered_texterm_data() # Use the filtered data with pagination logic applied | |
| }, options = list( | |
| pageLength = nrow(filtered_texterm_data()), # Show all rows | |
| dom = 't', # Remove the row length dropdown | |
| scrollX = TRUE # Enable horizontal scrolling if needed | |
| )) | |
| # # ORIGINAL READ EXCEL FILE | |
| # read_excel_file <- function(path) { | |
| # df <- read_excel(path) | |
| # colnames(df)[1] <- "Regulator Names" | |
| # return(df) | |
| # } | |
| # | |
| # # ORIGINAL FILTER FUNCTION | |
| # filter_data <- function(data, keyword) { | |
| # if (is.null(keyword) || is.na(keyword) || keyword == "") { | |
| # return(data) | |
| # } else { | |
| # keyword <- tolower(keyword) | |
| # return(data[apply(data, 1, function(x) any(grepl(keyword, tolower(x)))), ]) | |
| # } | |
| # } | |
| # | |
| # #ORIGINAL DISPLAY TABLE FUNCTION | |
| # # Main page data | |
| # data <- reactive({ | |
| # read_excel_file("www/tablePagerank/Table_TF PageRank Scores for Audrey.xlsx") | |
| # }) | |
| # | |
| # filtered_data <- reactive({ | |
| # filter_data(data(), input$search_input) | |
| # }) | |
| # | |
| # output$table <- renderDT({ | |
| # filtered_data() | |
| # }) | |
| # Server logic for naive tab | |
| output$naive <- renderText({ | |
| "TF Activity Score: Naive" | |
| }) | |
| # OLD NAIVE DATA TABLE | |
| # naive_data <- reactive({ | |
| # read_excel_file("www/tablePagerank/Naive.xlsx") | |
| # }) | |
| # | |
| # filtered_naive_data <- reactive({ | |
| # filter_data(naive_data(), input$search_input_naive) | |
| # }) | |
| # | |
| # output$table_naive <- renderDT({ | |
| # filtered_naive_data() | |
| # }) | |
| # Server logic for TE tab | |
| output$te <- renderText({ | |
| "TF Activity Score: TE" | |
| }) | |
| # OLD TE DATA TABLE | |
| # te_data <- reactive({ | |
| # read_excel_file("www/tablePagerank/TE.xlsx") | |
| # }) | |
| # | |
| # filtered_te_data <- reactive({ | |
| # filter_data(te_data(), input$search_input_te) | |
| # }) | |
| # | |
| # output$table_te <- renderDT({ | |
| # filtered_te_data() | |
| # }) | |
| # Server logic for MP tab | |
| output$mp <- renderText({ | |
| "TF Activity Score: MP" | |
| }) | |
| # OLD MP DATA | |
| # mp_data <- reactive({ | |
| # read_excel_file("www/tablePagerank/MP.xlsx") | |
| # }) | |
| # | |
| # filtered_mp_data <- reactive({ | |
| # filter_data(mp_data(), input$search_input_mp) | |
| # }) | |
| # | |
| # output$table_mp <- renderDT({ | |
| # filtered_mp_data() | |
| # }) | |
| # Server logic for T CM tab | |
| output$tcm <- renderText({ | |
| "TF Activity Score: T CM" | |
| }) | |
| # OLD TCM DATA | |
| # tcm_data <- reactive({ | |
| # read_excel_file("www/tablePagerank/TCM.xlsx") | |
| # }) | |
| # | |
| # filtered_tcm_data <- reactive({ | |
| # filter_data(tcm_data(), input$search_input_tcm) | |
| # }) | |
| # | |
| # output$table_tcm <- renderDT({ | |
| # filtered_tcm_data() | |
| # }) | |
| # Server logic for T EM tab | |
| output$tem <- renderText({ | |
| "TF Activity Score: T EM" | |
| }) | |
| # OLD TEM DATA | |
| # tem_data <- reactive({ | |
| # read_excel_file("www/tablePagerank/TEM.xlsx") | |
| # }) | |
| # | |
| # filtered_tem_data <- reactive({ | |
| # filter_data(tem_data(), input$search_input_tem) | |
| # }) | |
| # | |
| # output$table_tem <- renderDT({ | |
| # filtered_tem_data() | |
| # }) | |
| # | |
| # # Server logic for T RM tab | |
| # output$trm <- renderText({ | |
| # "TF Activity Score: T RM" | |
| # }) | |
| # OLD TRM DATA | |
| # trm_data <- reactive({ | |
| # read_excel_file("www/tablePagerank/TRM.xlsx") | |
| # }) | |
| # | |
| # filtered_trm_data <- reactive({ | |
| # filter_data(trm_data(), input$search_input_trm) | |
| # }) | |
| # | |
| # output$table_trm <- renderDT({ | |
| # filtered_trm_data() | |
| # }) | |
| # Server logic for Tex Prog tab | |
| output$texprog <- renderText({ | |
| "TF Activity Score: Tex Prog" | |
| }) | |
| # OLD TEX PROG DATA | |
| # texprog_data <- reactive({ | |
| # read_excel_file("www/tablePagerank/TEXprog.xlsx") | |
| # }) | |
| # | |
| # filtered_texprog_data <- reactive({ | |
| # filter_data(texprog_data(), input$search_input_texprog) | |
| # }) | |
| # | |
| # output$table_texprog <- renderDT({ | |
| # filtered_texprog_data() | |
| # }) | |
| # Server logic for Tex Eff-like tab | |
| output$texefflike <- renderText({ | |
| "TF Activity Score: Tex Eff-like" | |
| }) | |
| # OLD TEX EFF LIKE DATA | |
| # texefflike_data <- reactive({ | |
| # read_excel_file("www/tablePagerank/TEXeff.xlsx") | |
| # }) | |
| # | |
| # filtered_texefflike_data <- reactive({ | |
| # filter_data(texefflike_data(), input$search_input_texefflike) | |
| # }) | |
| # | |
| # output$table_texefflike <- renderDT({ | |
| # filtered_texefflike_data() | |
| # }) | |
| # Server logic for Tex Term tab | |
| output$texterm <- renderText({ | |
| "TF Activity Score: Tex Term" | |
| }) | |
| # OLD TEX TERM DATA | |
| # texterm_data <- reactive({ | |
| # read_excel_file("www/tablePagerank/TEXterm.xlsx") | |
| # }) | |
| # | |
| # filtered_texterm_data <- reactive({ | |
| # filter_data(texterm_data(), input$search_input_texterm) | |
| # }) | |
| # | |
| # output$table_texterm <- renderDT({ | |
| # filtered_texterm_data() | |
| # }) | |
| #click image code for TF Wave Analysis | |
| observeEvent(input$c1_link, { | |
| updateNavbarPage(session, "mainNav", selected = "c1") | |
| }) | |
| observeEvent(input$c2_link, { | |
| updateNavbarPage(session, "mainNav", selected = "c2") | |
| }) | |
| observeEvent(input$c3_link, { | |
| updateNavbarPage(session, "mainNav", selected = "c3") | |
| }) | |
| observeEvent(input$c4_link, { | |
| updateNavbarPage(session, "mainNav", selected = "c4") | |
| }) | |
| observeEvent(input$c5_link, { | |
| updateNavbarPage(session, "mainNav", selected = "c5") | |
| }) | |
| observeEvent(input$c6_link, { | |
| updateNavbarPage(session, "mainNav", selected = "c6") | |
| }) | |
| observeEvent(input$c7_link, { | |
| updateNavbarPage(session, "mainNav", selected = "c7") | |
| }) | |
| # Handle specific image part clicks to navigate to the subpages | |
| observeEvent(input$to_tfcat, { | |
| updateNavbarPage(session, "mainNav", selected = "tfcatpage") | |
| }) | |
| observeEvent(input$to_tfwave, { | |
| updateNavbarPage(session, "mainNav", selected = "overview") | |
| }) | |
| observeEvent(input$to_tfnet, { | |
| updateNavbarPage(session, "mainNav", selected = "tfnetpage") | |
| }) | |
| # SEARCH FOR A TF AND FIND OUT WHICH WAVE THEY ARE APART OF | |
| # Function to read the file and assign proper column names | |
| read_searchwave_file <- function(path) { | |
| df <- read_excel(path) # Read the Excel file | |
| colnames(df) <- c("Wave1", "Wave2", "Wave3", "Wave4", "Wave5", "Wave6", "Wave7") # Customize as needed | |
| return(df) | |
| return(df) | |
| } | |
| # Load data reactively | |
| searchwavedata <- reactive({ | |
| # Provide the path to your Excel file | |
| read_searchwave_file("www/waveanalysis/searchtfwaves.xlsx") # Path to your file | |
| }) | |
| # Reactive function to search and filter the data based on the wave search input | |
| filtered_wave_data <- reactive({ | |
| # Get the search input | |
| search_term <- input$search_input_wave | |
| # If no search term, return the entire dataset in the desired transposed format | |
| if (is.null(search_term) || search_term == "") { | |
| # Initialize an empty list to store the gene names for each wave | |
| wave_genes <- list() | |
| # Iterate over each wave column and get the associated genes | |
| for (col in colnames(searchwavedata())) { | |
| wave_genes[[col]] <- searchwavedata()[[col]] # Store all gene names for each wave | |
| } | |
| # Create a data frame with waves as columns and genes as rows | |
| result_df <- data.frame(wave_genes) | |
| # Return the transposed data frame with wave numbers as column headers and genes as rows | |
| return(result_df) | |
| } | |
| # Initialize an empty list to store the result | |
| result <- list() | |
| # Iterate through each column and check if the search term exists | |
| for (col in colnames(searchwavedata())) { | |
| # Filter genes for each column where the search term matches | |
| matching_genes <- searchwavedata()[[col]][grepl(search_term, searchwavedata()[[col]], ignore.case = TRUE)] | |
| # If there are matching genes, store them | |
| if (length(matching_genes) > 0) { | |
| result[[col]] <- paste(matching_genes, collapse = ", ") # Combine matching genes as a string | |
| } | |
| } | |
| # If no results are found, return an empty dataframe | |
| if (length(result) == 0) { | |
| return(data.frame(Wave = character(0), Gene = character(0))) # Return empty data frame if nothing matches | |
| } | |
| # Convert the result list to a data frame | |
| result_df <- data.frame( | |
| Wave = names(result), # Column names as 'Wave' | |
| Gene = unlist(result), # Concatenated list of matching gene names | |
| stringsAsFactors = FALSE | |
| ) | |
| # Remove any duplicate wave names (keep only one occurrence per wave) | |
| result_df <- result_df[!duplicated(result_df$Wave), ] | |
| # Remove rows where Gene column is NA or empty | |
| result_df <- result_df[!is.na(result_df$Gene) & result_df$Gene != "", ] | |
| # Create a matrix with wave names as columns and gene names as rows | |
| transposed_df <- matrix(unlist(result_df$Gene), nrow = 1) # Convert the gene names to a row | |
| # Set the column names to the wave numbers, replacing "Wave 1" instead of "wave.1" | |
| colnames(transposed_df) <- paste("Wave", seq_along(result_df$Wave)) | |
| # Return the transposed result | |
| return(as.data.frame(transposed_df)) | |
| }) | |
| # Render the table output based on the filtered and transposed data | |
| output$table_wave <- renderDT({ | |
| # Get the filtered and transposed data | |
| df <- filtered_wave_data() | |
| # Render the data table without row names and disable the default search box | |
| datatable(df, options = list(searching = FALSE), rownames = FALSE) | |
| }) | |
| # # Function to read Excel files | |
| # read_regulator_file <- function(path) { | |
| # df <- read_excel(path) | |
| # colnames(df)[1] <- " " # Adjust column name as needed | |
| # return(df) | |
| # } | |
| # | |
| # # Load data initially | |
| # tfregulated_data <- reactive({ | |
| # read_regulator_file("www/networkanalysis/comp_log2FC_RegulatedData_TRMTEXterm.xlsx") | |
| # }) | |
| # | |
| # # Filtered data based on search input | |
| # filtered_tfregulated_data <- reactive({ | |
| # req(tfregulated_data()) # Ensure tfregulated_data() is available | |
| # if (is.null(input$search_tfregulated_data) || input$search_tfregulated_data == "") { | |
| # return(tfregulated_data()) | |
| # } else { | |
| # # Perform filtering based on input$search_tfregulated_data | |
| # # Example filtering logic: | |
| # # filtered_data <- tfregulated_data() %>% | |
| # # filter(...) # Add your filtering logic here | |
| # # return(filtered_data) | |
| # # Replace the above with your actual filtering logic | |
| # return(tfregulated_data()) # Placeholder for now | |
| # } | |
| # }) | |
| # | |
| # # Render the DataTable | |
| # output$table_tfregulated_data <- renderDT({ | |
| # datatable(filtered_tfregulated_data()) | |
| # }) | |
| # ORIGINALLY SEARCH TRM TEXterm COORELATION | |
| # Load Excel file when the app starts | |
| data_tftfimage <- read_excel("www/TFcorintextrm/TF-TFcorTRMTEX.xlsx") | |
| # Reactive function to filter the data based on the search input (case-insensitive) | |
| filtered_data_tftfimage <- reactive({ | |
| req(input$search) # Ensure search input is available | |
| # Convert both the column and search input to lowercase for case-insensitive comparison | |
| data_filtered <- data_tftfimage[tolower(data_tftfimage[["TF Name"]]) == tolower(input$search), ] | |
| return(data_filtered) | |
| }) | |
| # Render the first column (Gene Names) as clickable links | |
| output$gene_list_table <- renderUI({ | |
| tagList( | |
| lapply(data_tftfimage[[1]], function(gene_name) { # Assuming the first column contains gene names | |
| tags$div( | |
| actionLink( | |
| inputId = paste0("gene_", gene_name), # Unique input ID for each gene | |
| label = gene_name | |
| ), | |
| style = "margin-bottom: 10px;" # Add spacing between links | |
| ) | |
| }) | |
| ) | |
| }) | |
| # Generate dynamic observers for each gene link | |
| lapply(data_tftfimage[[1]], function(gene_name) { | |
| observeEvent(input[[paste0("gene_", gene_name)]], { | |
| # Find the row corresponding to the clicked gene | |
| selected_gene_data <- data_tftfimage[data_tftfimage[[1]] == gene_name, ] | |
| img_src <- selected_gene_data[["TF Merged Graph Path"]] # Replace with the actual image column name | |
| # Update the image gallery output with the selected gene's image | |
| output$image_gallery <- renderUI({ | |
| if (!is.null(img_src) && nchar(img_src) > 0) { | |
| tags$div( | |
| style = "text-align: center;", | |
| tags$img(src = img_src, style = "max-width: 100%; height: auto;"), | |
| tags$p(gene_name) # Optionally display the gene name below the image | |
| ) | |
| } else { | |
| "No image available for the selected gene." | |
| } | |
| }) | |
| }) | |
| }) | |
| # Event to handle search functionality (unchanged from your original code) | |
| observeEvent(input$search_btn, { | |
| output$result_table <- renderTable({ | |
| if (nrow(filtered_data_tftfimage()) > 0) { | |
| filtered_data_tftfimage()[, -which(names(filtered_data_tftfimage()) == "TF Merged Graph Path")] # Show all columns except the image path | |
| } else { | |
| NULL # If no results, display nothing | |
| } | |
| }) | |
| output$image_gallery <- renderUI({ | |
| if (nrow(filtered_data_tftfimage()) > 0) { | |
| image_list <- lapply(1:nrow(filtered_data_tftfimage()), function(i) { | |
| img_src <- filtered_data_tftfimage()[[ "TF Merged Graph Path" ]][i] | |
| tags$div( | |
| style = "text-align: center; margin-bottom: 20px;", | |
| tags$img(src = img_src, style = "max-width: 100%; height: auto;") | |
| ) | |
| }) | |
| do.call(tags$div, image_list) | |
| } else { | |
| "TF not found. Please search for a valid TF." | |
| } | |
| }) | |
| }) | |
| #tf communities | |
| # Read the first Excel file directly from the specified path | |
| datatrm <- read_excel("www/tfcommunities/trmcommunities.xlsx") | |
| # Read the second Excel file directly from the specified path | |
| datatex <- read_excel("www/tfcommunities/texcommunities.xlsx") | |
| # Render the first table without the search button | |
| output$trmcom <- renderDT({ | |
| datatable( | |
| datatrm, | |
| options = list( | |
| lengthChange = FALSE, | |
| pageLength = 5, | |
| searching = FALSE # Disable the search button | |
| ) | |
| ) | |
| }) | |
| # Render the second table without the search button | |
| output$texcom <- renderDT({ | |
| datatable( | |
| datatex, | |
| options = list( | |
| lengthChange = FALSE, | |
| pageLength = 5, | |
| searching = FALSE # Disable the search button | |
| ) | |
| ) | |
| }) | |
| # Load your multiomics file | |
| multiexcel_data <- read_excel("www/multi-omicsdata.xlsx") | |
| # #Render data table + hyperlinks author's name to DOI | |
| # output$multiomicsdatatable <- renderDT({ | |
| # # Transform the "author" column to contain hyperlinks using the "DOI" column | |
| # multiexcel_data <- multiexcel_data %>% | |
| # mutate( | |
| # Author = paste0( | |
| # "<a href='", | |
| # DOI, # Column with the full DOI URLs | |
| # "' target='_blank'>", | |
| # Author, # Column with the display text (e.g., author name) | |
| # "</a>" | |
| # ) | |
| # ) %>% | |
| # select(-DOI) # Remove the "DOI" column after linking it to the "author" column | |
| # | |
| # # Dynamically remove empty columns ("18", "19", etc.) | |
| # multiexcel_data <- multiexcel_data %>% | |
| # select(where(~ !all(is.na(.)) & !all(. == ""))) # Keep only non-empty columns | |
| # | |
| # # Render the data table with HTML content and no row names | |
| # datatable(multiexcel_data, | |
| # options = list(searching = FALSE), | |
| # rownames = FALSE, | |
| # escape = FALSE) # Allow HTML rendering | |
| # }) | |
| #Render and hyperlink table + edit size so that everything fits into webpage | |
| output$multiomicsdatatable <- renderDT({ | |
| # Transform the "author" column to contain hyperlinks using the "DOI" column | |
| multiexcel_data <- multiexcel_data %>% | |
| mutate( | |
| Author = paste0( | |
| "<a href='", | |
| DOI, # Column with the full DOI URLs | |
| "' target='_blank'>", | |
| Author, # Column with the display text (e.g., author name) | |
| "</a>" | |
| ) | |
| ) %>% | |
| select(-DOI) # Remove the "DOI" column after linking it to the "author" column | |
| # Dynamically remove empty columns ("18", "19", etc.) | |
| multiexcel_data <- multiexcel_data %>% | |
| select(where(~ !all(is.na(.)) & !all(. == ""))) # Keep only non-empty columns | |
| # Render the data table with fit-to-page options | |
| datatable( | |
| multiexcel_data, | |
| options = list( | |
| autoWidth = TRUE, # Adjust column widths automatically | |
| scrollX = TRUE, # Enable horizontal scrolling | |
| pageLength = 10 # Limit rows displayed per page (adjustable) | |
| ), | |
| rownames = FALSE, | |
| escape = FALSE # Allow HTML rendering for links | |
| ) | |
| }) | |
| # --- START: TaijiChat Message Handling --- | |
| chat_history <- reactiveVal(list()) # Stores list of lists: list(role="user/assistant", content="message") | |
| observeEvent(input$user_chat_message, { | |
| req(input$user_chat_message) | |
| user_message_text <- trimws(input$user_chat_message) | |
| print(paste("TaijiChat: Received user_chat_message -", user_message_text)) | |
| if (nzchar(user_message_text)) { | |
| # Check authentication (implement OAuth later in ui.R) | |
| # For now, system works without auth, but logs as "anonymous" | |
| current_user <- session$userData$hf_user | |
| hf_user_id <- if (!is.null(current_user)) current_user$hf_user_id else "anonymous" | |
| # Check quota before processing | |
| if (!is.null(supabase_client) && !is.null(current_user)) { | |
| quota_result <- check_user_quota(supabase_client, hf_user_id) | |
| if (!quota_result$has_quota) { | |
| session$sendCustomMessage(type = "agent_response", message = list( | |
| text = paste("Token quota exceeded. Used:", quota_result$tokens_used, "Remaining: 0") | |
| )) | |
| return() | |
| } | |
| } | |
| current_hist <- chat_history() | |
| updated_hist_user <- append(current_hist, list(list(role = "user", content = user_message_text))) | |
| chat_history(updated_hist_user) | |
| agent_instance_val <- rv_agent_instance() | |
| # Set user context in agent | |
| if (!is.null(agent_instance_val) && !is.null(current_user)) { | |
| supabase_user <- session$userData$supabase_user | |
| agent_instance_val$set_user_context( | |
| user_id = supabase_user$id, | |
| hf_user_id = hf_user_id | |
| ) | |
| } | |
| if (!is.null(agent_instance_val)) { | |
| # Ensure history is a list of R named lists, then r_to_py will convert to list of Python dicts | |
| py_hist_for_agent <- lapply(updated_hist_user, function(turn) { | |
| list(role = turn$role, content = turn$content) | |
| }) | |
| # py_hist_for_agent_converted <- reticulate::r_to_py(py_hist_for_agent) | |
| # Send a "Thinking..." message to UI before long computation | |
| session$sendCustomMessage(type = "agent_thinking_started", message = list(text = "Thinking...")) | |
| tryCatch({ | |
| print(paste("TaijiChat: Sending to Python agent - Query:", user_message_text)) | |
| # For debugging, convert history to JSON string to see its structure if needed | |
| # hist_json_debug <- jsonlite::toJSON(py_hist_for_agent, auto_unbox = TRUE) | |
| # print(paste("TaijiChat: Conversation history (JSON for debug):", hist_json_debug)) | |
| # Get literature search preference (default to FALSE if not set) | |
| literature_enabled <- if (is.null(input$literature_search_enabled)) FALSE else input$literature_search_enabled | |
| print(paste("TaijiChat: Literature search enabled:", literature_enabled)) | |
| # Call Python agent method with literature preference | |
| # The process_single_query method in Python expects history as a list of dicts. | |
| # reticulate::r_to_py should handle the conversion of the list of R named lists. | |
| agent_reply_py <- agent_instance_val$process_single_query_with_preferences( | |
| user_query_text = user_message_text, | |
| conversation_history_from_r = py_hist_for_agent, # Pass the R list of lists | |
| literature_enabled = literature_enabled | |
| ) | |
| # Explicitly convert potential Python object to R character string | |
| agent_reply_text <- as.character(agent_reply_py) | |
| print(paste("TaijiChat: Received from Python agent -", agent_reply_text)) | |
| # Check if this is an image response | |
| if (startsWith(agent_reply_text, "TAIJICHAT_IMAGE_RESPONSE:")) { | |
| # Extract the JSON part - START AFTER THE COLON IN THE PREFIX | |
| json_str <- substr(agent_reply_text, 26, nchar(agent_reply_text)) | |
| # Debug the JSON string | |
| print(paste("Attempting to parse JSON:", json_str)) | |
| # Try parsing in a safer way | |
| tryCatch({ | |
| # Remove any leading/trailing whitespace and ensure proper JSON format | |
| json_str <- trimws(json_str) | |
| # Try to parse the JSON | |
| image_info <- NULL | |
| if (nchar(json_str) > 0) { | |
| # Attempt to parse using various approaches | |
| image_info <- tryCatch({ | |
| jsonlite::fromJSON(json_str) | |
| }, error = function(e1) { | |
| tryCatch({ | |
| # Try unescaping first | |
| jsonlite::fromJSON(gsub('\\\\"', '"', json_str)) | |
| }, error = function(e2) { | |
| NULL | |
| }) | |
| }) | |
| } | |
| if (!is.null(image_info) && !is.null(image_info$image_path)) { | |
| # Debug image path | |
| image_path_original <- image_info$image_path | |
| image_path_normalized <- sub("^www/", "", image_info$image_path) | |
| # Check if file exists | |
| file_exists_check <- file.exists(image_path_original) | |
| print(paste("Image path debug - Original:", image_path_original, | |
| "Normalized:", image_path_normalized, | |
| "File exists:", file_exists_check)) | |
| # Add a special marker to the message to trigger image display in UI | |
| image_html <- paste0( | |
| '<div class="chat-image-container">', | |
| '<img src="', image_path_normalized, '" class="chat-image-preview" onclick="showFullImage(\'', | |
| image_path_normalized, '\')">', | |
| '</div>' | |
| ) | |
| # Get original response or use a default | |
| original_response <- ifelse(!is.null(image_info$original_response), | |
| image_info$original_response, | |
| "I've analyzed this image.") | |
| # Combine the image HTML with the original text response | |
| enhanced_reply <- paste0( | |
| image_html, | |
| "<br>", | |
| original_response | |
| ) | |
| agent_reply_text <- enhanced_reply | |
| # Send a custom message to ensure the image display script is active | |
| session$sendCustomMessage(type = "activate_image_viewer", message = list()) | |
| } else { | |
| warning("Failed to extract image path from JSON") | |
| agent_reply_text <- paste("I analyzed an image but had trouble displaying it. Here's what I found:", | |
| gsub("TAIJICHAT_IMAGE_RESPONSE:.*", "", agent_reply_text)) | |
| } | |
| }, error = function(e) { | |
| warning(paste("JSON parsing error:", e$message, "- JSON string:", json_str)) | |
| print(paste("JSON parsing error:", e$message, "- JSON string:", json_str)) | |
| # Just use the original text in case of parsing error | |
| agent_reply_text <- paste("I analyzed an image but had trouble displaying it. Here's what I found:", | |
| substr(agent_reply_text, 25, nchar(agent_reply_text))) | |
| }) | |
| } | |
| final_hist <- append(updated_hist_user, list(list(role = "assistant", content = agent_reply_text))) | |
| chat_history(final_hist) | |
| session$sendCustomMessage(type = "agent_chat_response", message = list(text = agent_reply_text)) | |
| # Update quota display after successful query | |
| if (!is.null(supabase_client) && !is.null(current_user)) { | |
| quota_result <- check_user_quota(supabase_client, hf_user_id) | |
| tokens_used <- quota_result$tokens_used | |
| token_quota <- session$userData$supabase_user$token_quota %||% 100000 | |
| quota_text <- paste(tokens_used, "/", token_quota) | |
| session$sendCustomMessage('update_quota', list(quota = quota_text)) | |
| } | |
| }, error = function(e) { | |
| error_message <- paste("TaijiChat: Error calling Python agent or processing response:", e$message) | |
| warning(error_message) | |
| print(error_message) | |
| session$sendCustomMessage(type = "agent_chat_response", message = list(text = paste("Sorry, an error occurred with the agent."))) | |
| }) | |
| } else { | |
| warning("TaijiChat: Agent instance is NULL. Cannot process chat message.") | |
| print("TaijiChat: Agent instance is NULL. Cannot process chat message.") | |
| session$sendCustomMessage(type = "agent_chat_response", message = list(text = "The chat agent is not available. Please check server logs.")) | |
| } | |
| } else { | |
| print("TaijiChat: Received empty user_chat_message.") | |
| } | |
| }) | |
| # --- END: TaijiChat Message Handling --- | |
| #Render and hyperlink table + edit size so that everything fits into webpage | |
| output$multiomicsdatatable <- renderDT({ | |
| # Transform the "author" column to contain hyperlinks using the "DOI" column | |
| multiexcel_data <- multiexcel_data %>% | |
| mutate( | |
| Author = paste0( | |
| "<a href='", | |
| DOI, # Column with the full DOI URLs | |
| "' target='_blank'>", | |
| Author, # Column with the display text (e.g., author name) | |
| "</a>" | |
| ) | |
| ) %>% | |
| select(-DOI) # Remove the "DOI" column after linking it to the "author" column | |
| # Dynamically remove empty columns ("18", "19", etc.) | |
| multiexcel_data <- multiexcel_data %>% | |
| select(where(~ !all(is.na(.)) & !all(. == ""))) # Keep only non-empty columns | |
| # Render the data table with fit-to-page options | |
| datatable( | |
| multiexcel_data, | |
| options = list( | |
| autoWidth = TRUE, # Adjust column widths automatically | |
| scrollX = TRUE, # Enable horizontal scrolling | |
| pageLength = 10 # Limit rows displayed per page (adjustable) | |
| ), | |
| rownames = FALSE, | |
| escape = FALSE # Allow HTML rendering for links | |
| ) | |
| }) | |
| # Update reactive expressions to use warning overlay | |
| output$tfData <- renderDT({ | |
| withWarningOverlayReactive(session, { | |
| # Your existing reactive code here | |
| # This will automatically show the warning overlay for long-running operations | |
| }, "get_processed_tf_data") | |
| }) | |
| } | |
| # # ############################## CODE GRAVEYARD ############################## |