# 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 <- "
TF activity score
" # 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 <- "
TF activity score
" # 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 <- "
TF activity score
" # 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 <- "
TF activity score
" # 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 <- "
TF activity score
" # 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 <- "
TF activity score
" # 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 <- "
TF activity score
" # 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 <- "
TF activity score
" # 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 <- "
TF activity score
" # 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 <- "
TF activity score
" # 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( # "", # Author, # Column with the display text (e.g., author name) # "" # ) # ) %>% # 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( "", Author, # Column with the display text (e.g., author name) "" ) ) %>% 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( '
', '', '
' ) # 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, "
", 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( "", Author, # Column with the display text (e.g., author name) "" ) ) %>% 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 ##############################