diff --git "a/server.R" "b/server.R" --- "a/server.R" +++ "b/server.R" @@ -1,2328 +1,2272 @@ -# 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) - -# setwd("/Users/audrey/Downloads/research/ckweb/Tcellstates") - -# Define server logic -function(input, output, session) { - - # --- 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({ - agent_inst <- current_manager_agent_module$ManagerAgent( - openai_client = py_openai_client_instance, - r_callback_fn = python_agent_thought_callback # Pass the R callback here - ) - 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({ - agent_inst <- current_manager_agent_module$ManagerAgent( - openai_api_key = api_key_val, - r_callback_fn = python_agent_thought_callback # Pass the R callback here - ) - 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 --- - - # 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) { - withWarningOverlay(session, function() { - 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) - }, "Reading and processing Excel file...") - } - - # # 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)) { - 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() - - 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)) - - # Call Python agent method - # 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( - user_query_text = user_message_text, - conversation_history_from_r = py_hist_for_agent # Pass the R list of lists - ) - # 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 a literature confirmation request - if (startsWith(agent_reply_text, "TAIJICHAT_LITERATURE_CONFIRMATION:")) { - # Extract the JSON part - json_str <- substr(agent_reply_text, 35, nchar(agent_reply_text)) # 35 = length of "TAIJICHAT_LITERATURE_CONFIRMATION:" - - tryCatch({ - confirmation_info <- jsonlite::fromJSON(json_str) - session$sendCustomMessage(type = "literature_confirmation_request", - message = list( - text = confirmation_info$message, - type = confirmation_info$type - )) - }, error = function(e) { - warning(paste("Failed to parse literature confirmation JSON:", e$message)) - session$sendCustomMessage(type = "agent_chat_response", - message = list(text = "Error processing literature confirmation request.")) - }) - - # Don't update chat history or send response yet - wait for user confirmation - return() - } - - # 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)) - - }, 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.") - } - }) - - # --- Literature Confirmation Handler --- - observeEvent(input$literature_confirmation_response, { - req(input$literature_confirmation_response) - - user_response <- input$literature_confirmation_response - print(paste("TaijiChat: Received literature confirmation response:", user_response)) - - agent_instance_val <- rv_agent_instance() - - if (!is.null(agent_instance_val)) { - tryCatch({ - # Call the agent's literature confirmation handler - agent_reply_py <- agent_instance_val$handle_literature_confirmation( - user_response = as.character(user_response) - ) - agent_reply_text <- as.character(agent_reply_py) - - print(paste("TaijiChat: Literature confirmation processed, response:", agent_reply_text)) - - # Update chat history with the agent's response - current_hist <- chat_history() - final_hist <- append(current_hist, list(list(role = "assistant", content = agent_reply_text))) - chat_history(final_hist) - - # Send the response to UI - session$sendCustomMessage(type = "agent_chat_response", message = list(text = agent_reply_text)) - - }, error = function(e) { - error_message <- paste("TaijiChat: Error processing literature confirmation:", e$message) - warning(error_message) - print(error_message) - session$sendCustomMessage(type = "agent_chat_response", - message = list(text = "Sorry, an error occurred processing your literature preference.")) - }) - } else { - warning("TaijiChat: Agent instance is NULL during literature confirmation.") - session$sendCustomMessage(type = "agent_chat_response", - message = list(text = "The chat agent is not available for literature confirmation.")) - } - }) - - # --- 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") - }) -} - - +# 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) + +# setwd("/Users/audrey/Downloads/research/ckweb/Tcellstates") + +# Define server logic +function(input, output, session) { + + # --- 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({ + agent_inst <- current_manager_agent_module$ManagerAgent( + openai_client = py_openai_client_instance, + r_callback_fn = python_agent_thought_callback # Pass the R callback here + ) + 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({ + agent_inst <- current_manager_agent_module$ManagerAgent( + openai_api_key = api_key_val, + r_callback_fn = python_agent_thought_callback # Pass the R callback here + ) + 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 --- + + # 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) { + withWarningOverlay(session, function() { + 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) + }, "Reading and processing Excel file...") + } + + # # 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)) { + 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() + + 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)) + + }, 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 ############################## \ No newline at end of file