Skip to content

Add INDRA integration to MSstatsShiny#110

Merged
tonywu1999 merged 35 commits intodevelfrom
devel-bionet
Jul 28, 2025
Merged

Add INDRA integration to MSstatsShiny#110
tonywu1999 merged 35 commits intodevelfrom
devel-bionet

Conversation

@tonywu1999
Copy link
Copy Markdown
Contributor

@tonywu1999 tonywu1999 commented Jul 23, 2025

PR Type

Enhancement


Description

  • Integrate INDRA-based network visualization module

  • Add UI with Cytoscape and interactive filters

  • Implement server logic: load, annotate, extract subnetwork

  • Update DESCRIPTION and NAMESPACE dependencies


Diagram Walkthrough

flowchart LR
  Upload["Upload Data or Comparison"] --> Filter["Filter by Label"]
  Filter --> Annotate["Annotate via INDRA"]
  Annotate --> Subnet["Extract Subnetwork"]
  Subnet --> JS["Generate Cytoscape JS"]
  JS --> UI["Render Network & DataTables"]
Loading

File Walkthrough

Relevant files
Dependencies
DESCRIPTION
Add new package dependencies                                                         

DESCRIPTION

  • Added MSstatsBioNet and shinydashboard dependencies
  • Updated RoxygenNote version
+3/-2     
NAMESPACE
Extend imports for network visualization                                 

NAMESPACE

  • Imported DT functions: DTOutput, datatable, renderDT
  • Imported MSstatsBioNet INDRA methods
  • Imported shinydashboard dashboard components
+14/-0   
Enhancement
module-visualize-network-server.R
Implement network server logic                                                     

R/module-visualize-network-server.R

  • Added helper functions for data load and filtering
  • Implemented INDRA annotation and subnetwork extraction
  • Created Cytoscape node/edge element generators and JS
  • Defined main visualizeNetworkServer module logic
+422/-0 
module-visualize-network-ui.R
Create network visualization UI                                                   

R/module-visualize-network-ui.R

  • Included Cytoscape.js and Dagre scripts
  • Defined upload, filter, slider, and dropdown inputs
  • Built shinydashboard layout with network and tables
+324/-0 
server.R
Call visualizeNetworkServer module                                             

R/server.R

  • Registered visualizeNetworkServer in server logic
+2/-0     
ui.R
Insert network tab into main UI                                                   

R/ui.R

  • Added "5. Network Interpretation" tab in navbar
+1/-0     

Summary by CodeRabbit

  • New Features

    • Introduced a new "Network Interpretation" tab for interactive visualization of protein interaction networks.
    • Added support for uploading CSV data or using existing comparison data to explore protein networks.
    • Enabled customizable network filtering and visualization options, including p-value, evidence, statement types, data sources, and forced protein inclusion.
    • Integrated interactive Cytoscape.js network visualization and dynamic data tables for nodes and edges.
    • Added comprehensive network visualization module with enhanced UI controls and event-driven interactivity.
  • Documentation

    • Updated package description to include new dependencies for network visualization features.
    • Added detailed documentation for new network visualization functions and configuration utilities.
  • Tests

    • Added extensive unit tests covering network visualization logic, UI components, data processing, and integration scenarios.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jul 23, 2025

"""

Walkthrough

A new Shiny module for interactive protein network visualization was added, including both UI and server components. The DESCRIPTION and NAMESPACE files were updated to include new dependencies. The main Shiny app's UI and server were modified to integrate the new network visualization tab and module. Extensive unit tests and documentation for the new visualization functions were also introduced.

Changes

File(s) Change Summary
Package Metadata
DESCRIPTION Added MSstatsBioNet and shinydashboard to Imports; reordered imports; updated RoxygenNote version.
NAMESPACE Added importFrom directives for DT, MSstatsBioNet, shinydashboard, grDevices, and shiny functions; exported networkUI.
Network Visualization Module - Server
R/module-visualize-network-server.R New module implementing server logic for interactive protein network visualization, including color mapping, edge consolidation, Cytoscape config generation, Shiny event handling, data filtering, annotation, subnetwork extraction, and UI table rendering.
Network Visualization Module - UI
R/module-visualize-network-ui.R New module defining Shiny UI components for network visualization, including input controls, Cytoscape.js integration, layout, and data tables; exports networkUI.
Main Application Integration
R/server.R Integrated visualizeNetworkServer module into main server function.
R/ui.R Added new "Network Interpretation" tab with networkUI to main navigation bar.
Documentation
man/generateCytoscapeConfig.Rd Added documentation for generateCytoscapeConfig function.
man/generateCytoscapeJSForShiny.Rd Added documentation for generateCytoscapeJSForShiny function.
man/generateJavaScriptCode.Rd Added documentation for internal function generateJavaScriptCode.
man/MSstatsShiny.Rd Updated maintainer and authorship information.
man/networkUI.Rd Added documentation for networkUI function.
man/visualizeNetworkServer.Rd Added documentation for visualizeNetworkServer function.
Testing
tests/testthat/test_network_visualization.R Added comprehensive unit tests covering color mapping, edge consolidation, styling, Cytoscape config generation, Shiny integration, data filtering, annotation, subnetwork extraction, error handling, UI components, and session updates.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Shiny_UI
    participant NetworkUI_Module
    participant NetworkServer_Module
    participant MSstatsBioNet
    participant CytoscapeJS

    User->>Shiny_UI: Navigates to "Network Interpretation" tab
    Shiny_UI->>NetworkUI_Module: Renders networkUI
    User->>NetworkUI_Module: Uploads CSV/selects parameters
    NetworkUI_Module->>NetworkServer_Module: Triggers server logic (show network)
    NetworkServer_Module->>MSstatsBioNet: Annotate proteins / extract subnetwork
    NetworkServer_Module->>CytoscapeJS: Prepares and sends visualization data
    CytoscapeJS-->>User: Displays interactive network
    User->>CytoscapeJS: Clicks edge/node
    CytoscapeJS->>NetworkServer_Module: Sends selection event
    NetworkServer_Module->>NetworkUI_Module: Updates edge/node tables
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~35 minutes

Poem

In the warren where proteins connect,
A new network blooms—what did you expect?
With Cytoscape’s light and DT’s bright rows,
Rabbits now visualize how interaction flows.
Tabs and sliders, a dashboard delight—
Hop in and explore, the network’s in sight!
🐇✨
"""

Note

⚡️ Unit Test Generation is now available in beta!

Learn more here, or try it out under "Finishing Touches" below.


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 78c7798 and bccf84d.

📒 Files selected for processing (1)
  • R/module-visualize-network-server.R (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build
🔇 Additional comments (5)
R/module-visualize-network-server.R (5)

10-38: LGTM! Color mapping function is well-implemented.

The function properly handles edge cases including missing values, uniform data, and NA values. The previous concern about NA handling in the max() function has been addressed with na.rm = TRUE.


218-276: LGTM! Element creation functions are well-structured.

Both createNodeElements and createEdgeElements properly handle missing data, provide appropriate fallbacks, and integrate well with the styling system.


643-732: LGTM! Data management functions are well-structured.

The helper functions provide good abstraction with proper error handling, null checks, and validation of input parameters. The handling of "all" selections and dropdown updates is implemented correctly.


738-772: LGTM! Data processing functions have proper error handling.

The data processing pipeline functions are well-abstracted with consistent error handling and user notifications. The integration with MSstatsBioNet functions is properly wrapped.


1-913: Excellent implementation with all previous concerns addressed.

This comprehensive network visualization module demonstrates excellent code organization and quality. All issues identified in previous reviews have been properly addressed:

  • JavaScript syntax errors fixed
  • Required validation added throughout
  • Proper roxygen documentation included
  • Null checks implemented in observers
  • Namespacing issues resolved

The code shows good separation of concerns between package functions and Shiny-specific implementations, with consistent error handling and user experience considerations.

✨ Finishing Touches
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch devel-bionet

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@github-actions
Copy link
Copy Markdown

PR Reviewer Guide 🔍

Here are some key observations to aid the review process:

⏱️ Estimated effort to review: 5 🔵🔵🔵🔵🔵
🧪 No relevant tests
🔒 Security concerns

Cross-site scripting:
The client-side handler uses eval(message) to execute Cytoscape JS built from server data and embeds unsanitized values (e.g., protein IDs, labels) directly into JS strings. This can allow injection of arbitrary JavaScript if input data contains malicious content. Use safe serialization (e.g., JSON) and avoid eval, or sanitize all embedded values before generating the script.

⚡ Recommended focus areas for review

Duplicate Import

The DT package is listed twice in the Imports field, creating redundancy. Remove the duplicate entry to keep dependencies clean.

ggrepel, uuid, utils, stats, htmltools, methods, tidyr, grDevices, graphics,mockery, MSstatsBioNet,
DT, shinydashboard
Maintainability

The dropdown choice lists for statementTypes and sources are very long and manually hardcoded. Consider externalizing these options or generating them dynamically to improve readability and maintainability.

tagList(
  selectInput(ns("statementTypes"),
              "Statement Types",
              choices = list("All Types" = "all",
                             "Complex" = "Complex",
                             "Inhibition" = "Inhibition", 
                             "Activation" = "Activation",
                             "Increase Amount" = "IncreaseAmount",
                             "Decrease Amount" = "DecreaseAmount",
                             "Phosphorylation" = "Phosphorylation",
                             "Dephosphorylation" = "Dephosphorylation",
                             "Ubiquitination" = "Ubiquitination",
                             "Deubiquitination" = "Deubiquitination",
                             "Sumoylation" = "Sumoylation",
                             "Desumoylation" = "Desumoylation",
                             "Hydroxylation" = "Hydroxylation",
                             "Dehydroxylation" = "Dehydroxylation",
                             "Acetylation" = "Acetylation",
                             "Deacetylation" = "Deacetylation",
                             "Glycosylation" = "Glycosylation",
                             "Deglycosylation" = "Deglycosylation",
                             "Farnesylation" = "Farnesylation",
                             "Defarnesylation" = "Defarnesylation",
                             "Geranylgeranylation" = "Geranylgeranylation",
                             "Degeranylgeranylation" = "Degeranylgeranylation",
                             "Palmitoylation" = "Palmitoylation",
                             "Depalmitoylation" = "Depalmitoylation",
                             "Myristoylation" = "Myristoylation",
                             "Demyristoylation" = "Demyristoylation",
                             "Ribosylation" = "Ribosylation",
                             "Deribosylation" = "Deribosylation",
                             "Methylation" = "Methylation",
                             "Demethylation" = "Demethylation"),
              selected = "all",
              multiple = TRUE),
  selectInput(ns("sources"),
              "Sources",
              choices = list("All Sources" = "all",
                             "Reach" = "reach",
                             "Trips" = "trips",
                             "Sparser" = "sparser",
                             "Medscan" = "medscan",
                             "TEES" = "tees",
                             "ISI" = "isi",
                             "Geneways" = "geneways",
                             "RLIMS-P" = "rlimsp",
                             "Eidos" = "eidos",
                             "GNBR" = "gnbr",
                             "SemRep" = "semrep",
                             "BEL" = "bel",
                             "BioPAX" = "biopax",
                             "SIGNOR" = "signor",
                             "BioGRID" = "biogrid",
                             "HPRD" = "hprd",
                             "TRRUST" = "trrust",
                             "PhosphoELM" = "phosphoelm",
                             "VirHostNet" = "virhostnet",
                             "OmniPath" = "omnipath",
                             "UbiBrowser" = "ubibrowser",
                             "ACSN" = "acsn",
                             "WormBase" = "wormbase",
                             "CTD" = "ctd",
                             "DrugBank" = "drugbank",
                             "DGI" = "dgi",
                             "TAS" = "tas",
                             "CROG" = "crog",
                             "CREEDS" = "creeds"),
              selected = "all",
              multiple = TRUE)
)

@github-actions
Copy link
Copy Markdown

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
Possible issue
Flatten elements list to vector

Coerce the combined node and edge elements into a flat character vector to prevent
list-to-string conversion errors. Use unlist() on edge_elements when merging with
node_elements.

R/module-visualize-network-server.R [183-189]

-elements <- c(node_elements, edge_elements)
+elements <- c(node_elements, unlist(edge_elements))
 
 paste0("
     cytoscape.use(cytoscapeDagre);
     ...
     elements: [", paste(elements, collapse = ", "), "],
     ...
 ")
Suggestion importance[1-10]: 8

__

Why: Flattening the edge_elements list prevents unintended list-to-string conversion in paste(...), ensuring the Cytoscape elements vector is correctly formatted.

Medium
Use vector for edge elements

Use a plain character vector instead of a named list for edge elements to preserve
order and simplify concatenation. Initialize edge_elements with
character(nrow(edges)) and fill by index.

R/module-visualize-network-server.R [137-150]

 createEdgeElements <- function(edges) {
-  edge_elements <- list()
+  edge_elements <- character(nrow(edges))
   
-  for (i in 1:nrow(edges)) {
+  for (i in seq_len(nrow(edges))) {
     row <- edges[i,]
     edge_key <- paste(row['source'], row['target'], row['interaction'], sep = "-")
-    edge_elements[[edge_key]] <- paste0("{ data: { source: '", row['source'], 
-                                        "', target: '", row['target'], 
-                                        "', id: '", edge_key, 
-                                        "', interaction: '", row['interaction'], "' } }")
+    edge_elements[i] <- paste0("{ data: { source: '", row['source'], 
+                               "', target: '", row['target'], 
+                               "', id: '", edge_key, 
+                               "', interaction: '", row['interaction'], "' } }")
   }
   
   return(edge_elements)
 }
Suggestion importance[1-10]: 6

__

Why: Initializing edge_elements as a character vector preserves ordering and produces a flat vector compatible with downstream concatenation.

Low
Security
Avoid eval in custom handler

Avoid using eval() on incoming messages to reduce injection risk. Instead, create a
new Function from the string and invoke it.

R/module-visualize-network-ui.R [11-16]

 tags$script("
             Shiny.addCustomMessageHandler('runCytoscape', function(message) {
-                console.log(message)
-                eval(message);  // Executes the Cytoscape.js code in the frontend
+                console.log(message);
+                (new Function(message))();  // Safely executes the Cytoscape.js code
             });
         ")
Suggestion importance[1-10]: 6

__

Why: Using new Function(message)() instead of eval() reduces injection risk and improves security of the custom message handler.

Low

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🧹 Nitpick comments (7)
R/module-visualize-network-server.R (7)

30-31: Simplify the setNames usage.

The setNames call is redundant here since you're using the same values for both names and values.

-    updateSelectInput(session, "selectedLabel",
-                      choices = c(setNames(unique_labels, unique_labels)))
+    updateSelectInput(session, "selectedLabel",
+                      choices = unique_labels)

45-49: Remove redundant req() call.

The req(input$statementTypes) on line 45 is redundant since you already require it on line 42.

-  # Handle "all" selections for statement type
-  statementTypes <- if("all" %in% req(input$statementTypes)) {
+  # Handle "all" selections for statement type
+  statementTypes <- if("all" %in% input$statementTypes) {
     NULL
   } else {
     input$statementTypes
   }

100-101: Consider using proper logging instead of print().

The print() statement might not be appropriate for production use. Consider using Shiny's logging capabilities or remove it.

     showNotification(paste("Error in subnetwork extraction:", e$message), type = "error")
-    print(e$message)
+    # Log error for debugging if needed
+    # shiny::logError(e)
     return(NULL)

125-134: Consider using lapply for better performance and JSON safety.

Using apply() with cbind() can be inefficient, and manual string concatenation for JSON-like structures is error-prone.

-  apply(cbind(nodes, color = node_colors), 1, function(row) {
-    # Use the appropriate label, fallback to id if hgncName is missing/empty
-    display_label <- if(label_column == "hgncName" && !is.na(row['hgncName']) && row['hgncName'] != "") {
-      row['hgncName']
-    } else {
-      row['id']
-    }
-    
-    paste0("{ data: { id: '", row['id'], "', label: '", display_label, "', color: '", row['color'], "' } }")
-  })
+  nodes$color <- node_colors
+  lapply(1:nrow(nodes), function(i) {
+    row <- nodes[i, ]
+    # Use the appropriate label, fallback to id if hgncName is missing/empty
+    display_label <- if(label_column == "hgncName" && !is.na(row[[label_column]]) && row[[label_column]] != "") {
+      row[[label_column]]
+    } else {
+      row[["id"]]
+    }
+    
+    # Consider using jsonlite::toJSON for proper escaping
+    paste0("{ data: { id: '", row[["id"]], "', label: '", display_label, "', color: '", row[["color"]], "' } }")
+  })

Also consider using jsonlite::toJSON() to properly escape special characters in labels that could break the JavaScript.


137-150: Use lapply for more idiomatic R code.

Replace the for loop with lapply for better R style and potential performance benefits.

 createEdgeElements <- function(edges) {
-  edge_elements <- list()
-  
-  for (i in 1:nrow(edges)) {
-    row <- edges[i,]
-    edge_key <- paste(row['source'], row['target'], row['interaction'], sep = "-")
-    edge_elements[[edge_key]] <- paste0("{ data: { source: '", row['source'], 
-                                        "', target: '", row['target'], 
-                                        "', id: '", edge_key, 
-                                        "', interaction: '", row['interaction'], "' } }")
-  }
-  
-  return(edge_elements)
+  lapply(1:nrow(edges), function(i) {
+    row <- edges[i,]
+    edge_key <- paste(row[['source']], row[['target']], row[['interaction']], sep = "-")
+    paste0("{ data: { source: '", row[['source']], 
+           "', target: '", row[['target']], 
+           "', id: '", edge_key, 
+           "', interaction: '", row[['interaction']], "' } }")
+  })
 }

257-261: Consider parameterizing the Shiny namespace.

The hardcoded 'network-' prefix in the Shiny input ID might cause issues if the module is used with a different namespace.

Consider passing the namespace as a parameter to make the function more reusable:

-generateCytoscapeJS <- function(node_elements, edge_elements) {
+generateCytoscapeJS <- function(node_elements, edge_elements, ns = "network") {
   # ... existing code ...
-        Shiny.setInputValue('network-edgeClicked', { 
+        Shiny.setInputValue('" + ns + "-edgeClicked', { 

410-416: Consider caching network data to avoid recomputation.

The renderNetwork() reactive is called again in the edge click observer, which might trigger unnecessary recomputation.

Consider storing the network data in a reactive value to avoid recomputation:

+  # Cache network data
+  networkData <- reactiveVal(NULL)
+  
+  observeEvent(renderNetwork(), {
+    networkData(renderNetwork())
+  })
+  
   # Observe edge click events
   observeEvent(input$edgeClicked, {
     edge_data <- input$edgeClicked
-    edges_table <- renderNetwork()$edges_table
+    edges_table <- networkData()$edges_table
     
     highlightEdgeInTable(output, edge_data, edges_table)
   })
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9964f06 and 1959fbf.

📒 Files selected for processing (6)
  • DESCRIPTION (2 hunks)
  • NAMESPACE (2 hunks)
  • R/module-visualize-network-server.R (1 hunks)
  • R/module-visualize-network-ui.R (1 hunks)
  • R/server.R (1 hunks)
  • R/ui.R (1 hunks)
🔇 Additional comments (16)
DESCRIPTION (1)

45-45: RoxygenNote version update looks good.

The update from 7.3.1 to 7.3.2 is appropriate for the new code being added.

R/server.R (1)

53-53: Clean integration of the network visualization module.

The module integration is implemented correctly, passing the appropriate session and data_comparison reactive objects to the network visualization server.

R/ui.R (1)

59-59: Well-structured UI integration for the network module.

The new tab panel is properly integrated with consistent ID usage, appropriate icon selection, and clear labeling that follows the established pattern.

NAMESPACE (3)

33-36: DT imports properly configured.

The additional DT imports (DTOutput, datatable, renderDT) complement the existing ones and support the interactive tables needed for the network visualization.


39-40: MSstatsBioNet imports enable INDRA functionality.

The imported functions annotateProteinInfoFromIndra and getSubnetworkFromIndra provide the core INDRA integration capabilities for protein network analysis.


156-164: Comprehensive shinydashboard imports for UI components.

All necessary shinydashboard components are imported to support the dashboard-style layout used in the network visualization module.

R/module-visualize-network-ui.R (4)

57-71: Well-structured radio button configurations.

The protein ID type and display label radio buttons are properly configured with clear options and sensible defaults.


84-155: Comprehensive filtering options provided.

The statement types and sources dropdowns offer extensive filtering capabilities that align well with INDRA's data structure and functionality.


193-225: Well-designed color legend component.

The color legend provides clear visual guidance for interpreting log fold change values in the network visualization with proper styling and layout.


312-324: Clean module structure with proper namespacing.

The main UI function follows Shiny module best practices with proper namespacing and integration of all components.

R/module-visualize-network-server.R (6)

6-21: Well-implemented data loading function with proper error handling.

The function correctly handles both data sources (upload and reactive) and includes appropriate error handling for file reading operations.


74-81: Clean implementation of label filtering.

The function properly handles the case where the Label column might not exist and correctly filters out NA values.


83-90: Good error handling for external package call.

The function properly wraps the external call with error handling and user notification.


153-180: Well-implemented color mapping function.

Excellent handling of edge cases including NA values and single unique values. The normalization and color gradient logic is sound.


270-287: Clean implementation of data table rendering.

Good use of consistent options across both tables with appropriate selection mode for the edges table.


1-422: Overall excellent implementation of the INDRA network visualization module.

The code is well-structured, includes proper error handling, and successfully integrates INDRA functionality as intended. The suggested improvements are mostly for optimization and code style rather than critical issues.

Comment thread DESCRIPTION Outdated
Comment thread R/module-visualize-network-server.R
Comment thread R/module-visualize-network-server.R
Comment thread R/module-visualize-network-ui.R
Comment thread R/module-visualize-network-ui.R
Comment thread R/module-visualize-network-ui.R
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (3)
R/module-visualize-network-ui.R (2)

40-44: Consider extracting inline styles to external CSS for better maintainability.

Multiple UI components use inline CSS styles. Consider moving these to an external stylesheet or using CSS classes for better maintainability and consistency across the application.

Create a www/network-styles.css file and include it in the UI:

/* www/network-styles.css */
.data-source-info {
  padding: 10px;
  background-color: #d9edf7;
  border: 1px solid #bce8f1;
  border-radius: 4px;
  margin-bottom: 15px;
}

.icon-wrapper {
  position: absolute;
  top: 8px;
  right: 10px;
  z-index: 1000;
}

.loading-indicator {
  display: none;
  text-align: center;
}

.color-legend {
  position: absolute;
  top: 10px;
  right: 10px;
  background-color: rgba(255, 255, 255, 0.9);
  border: 1px solid #ddd;
  border-radius: 5px;
  padding: 10px;
  box-shadow: 0 2px 4px rgba(0,0,0,0.1);
  z-index: 1000;
  min-width: 150px;
}

Then update the UI components to use classes instead of inline styles.

Also applies to: 158-173, 184-188, 215-244


255-255: Consider making the network visualization height responsive.

The network container has a fixed height of 500px, which may not be optimal for different screen sizes and resolutions.

Consider using viewport-relative units or making the height configurable:

-      style = "position: relative; width: 100%; height: 500px;",
+      style = "position: relative; width: 100%; height: 70vh; min-height: 400px; max-height: 800px;",
R/module-visualize-network-server.R (1)

131-131: Remove or replace console print with proper logging.

The error message is being printed to console which may not be appropriate in production.

Consider removing the print statement or using a proper logging mechanism:

-    print(e$message)
+    # Error is already shown via notification
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1959fbf and 6ca2436.

📒 Files selected for processing (2)
  • R/module-visualize-network-server.R (1 hunks)
  • R/module-visualize-network-ui.R (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build

Comment thread R/module-visualize-network-server.R Outdated
Comment thread R/module-visualize-network-server.R
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (2)
R/module-visualize-network-ui.R (2)

5-18: Address security and version issues identified in past reviews.

The past review comments have already identified critical issues in this code segment:

  1. Cytoscape.js version 3.19.1 needs to be updated to 3.32.0
  2. The eval(message) call on line 14 poses a security risk and should be replaced with a safer pattern using new Function(code)() wrapped in try-catch

334-348: Address missing NAMESPACE export identified in past reviews.

The past review comments have already identified that the networkUI function needs to be exported in the NAMESPACE file since it's called from R/ui.R.

🧹 Nitpick comments (2)
R/module-visualize-network-ui.R (2)

87-156: Consider extracting the long choice lists to constants or configuration.

The statement types and sources choice lists are quite extensive and hardcoded within the function. For better maintainability, consider extracting these to named constants at the module level or in a configuration file.

Example refactor:

+# Define constants at module level
+STATEMENT_TYPES <- list(
+  "All Types" = "all",
+  "Complex" = "Complex",
+  "Inhibition" = "Inhibition",
+  # ... rest of choices
+)
+
+DATA_SOURCES <- list(
+  "All Sources" = "all", 
+  "Reach" = "reach",
+  # ... rest of choices
+)

 createFilterDropdowns <- function(ns) {
   tagList(
     selectInput(ns("statementTypes"),
                 "Statement Types",
-                choices = list("All Types" = "all", ...),
+                choices = STATEMENT_TYPES,
                 selected = "all",
                 multiple = TRUE),
     selectInput(ns("sources"),
                 "Sources", 
-                choices = list("All Sources" = "all", ...),
+                choices = DATA_SOURCES,
                 selected = "all",
                 multiple = TRUE)
   )
 }

217-249: Consider extracting inline CSS to improve maintainability.

The createColorLegend() function contains substantial inline CSS styling that could be better organized for maintainability and reusability.

Consider moving the styles to a separate CSS file or at least organizing them as named style constants:

+# Define CSS styles as constants
+LEGEND_CONTAINER_STYLE <- paste(
+  "position: absolute; top: 10px; right: 10px;",
+  "background-color: rgba(255, 255, 255, 0.9);",
+  "border: 1px solid #ddd; border-radius: 5px;",
+  "padding: 10px; box-shadow: 0 2px 4px rgba(0,0,0,0.1);",
+  "z-index: 1000; min-width: 150px;"
+)

+GRADIENT_BAR_STYLE <- paste(
+  "height: 20px; width: 100%;",
+  "background: linear-gradient(to right, #ADD8E6, #D3D3D3, #FFA590);",
+  "border: 1px solid #ccc; border-radius: 3px; margin-bottom: 5px;"
+)

 createColorLegend <- function() {
   div(
-    style = "position: absolute; top: 10px; right: 10px; ...",
+    style = LEGEND_CONTAINER_STYLE,
     # ... rest of implementation
   )
 }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6ca2436 and dc2fcd6.

📒 Files selected for processing (2)
  • R/module-visualize-network-server.R (1 hunks)
  • R/module-visualize-network-ui.R (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • R/module-visualize-network-server.R
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (4)
R/module-visualize-network-server.R (4)

220-220: Fix container ID mismatch between UI and JavaScript code.

The JavaScript code references 'network-cy' but the UI module creates a div with id ns("cy") which will be namespaced.

The container ID needs to be dynamically generated to match the namespaced ID:

-        container: document.getElementById('network-cy'),
+        container: document.getElementById('", session$ns("cy"), "'),

322-325: Add validation for edge_data fields.

The function assumes edge_data contains source, target, and interaction fields without validation.

 highlightEdgeInTable <- function(output, edge_data, edges_table) {
+  # Validate edge_data has required fields
+  req(edge_data$source, edge_data$target, edge_data$interaction)
+  
   source <- edge_data$source
   target <- edge_data$target
   interaction <- edge_data$interaction

350-352: Add roxygen documentation for the main server function.

The main server function lacks documentation. Consider adding roxygen comments to describe parameters and functionality.

+#' Server logic for network visualization module
+#'
+#' @param input Shiny input object
+#' @param output Shiny output object
+#' @param session Shiny session object
+#' @param parent_session Parent Shiny session
+#' @param dataComparison Reactive expression containing comparison data
+#'
+#' @return None (side effects only)
+#'
 #' @importFrom MSstatsBioNet annotateProteinInfoFromIndra getSubnetworkFromIndra
 #' @importFrom DT renderDT datatable
 visualizeNetworkServer <- function(input, output, session, parent_session, dataComparison) {

446-451: Add null check for network data in edge click observer.

The edge click observer could fail if renderNetwork() returns NULL.

Add validation to ensure network data exists:

 observeEvent(input$edgeClicked, {
   edge_data <- input$edgeClicked
-  edges_table <- renderNetwork()$edges_table
+  network_data <- renderNetwork()
+  req(network_data)
+  edges_table <- network_data$edges_table
   
   highlightEdgeInTable(output, edge_data, edges_table)
 })
🧹 Nitpick comments (1)
R/module-visualize-network-server.R (1)

102-136: Good error handling in data processing functions.

The data processing functions properly handle errors and provide user feedback. However, consider removing the debug print statement.

Consider removing the debug print statement:

  }, error = function(e) {
    showNotification(paste("Error in subnetwork extraction:", e$message), type = "error")
-   print(e$message)
    return(NULL)
  })
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between dc2fcd6 and bff2f1b.

📒 Files selected for processing (1)
  • R/module-visualize-network-server.R (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build
🔇 Additional comments (1)
R/module-visualize-network-server.R (1)

6-95: Well-structured data management functions with proper error handling.

The data management helper functions demonstrate good practices:

  • Proper use of req() for input validation
  • Graceful handling of missing columns in dropdown updates
  • Comprehensive error handling with user notifications
  • Clear separation of concerns between different data operations

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
R/module-visualize-network-ui.R (1)

5-18: Previous security and version concerns still apply.

The existing review comments about updating Cytoscape.js to version 3.32.0 and replacing the unsafe eval() usage with a more secure message handling pattern remain valid and should be addressed.

🧹 Nitpick comments (2)
R/module-visualize-network-ui.R (2)

87-179: Consider extracting hardcoded choices to constants or configuration.

The createFilterDropdowns function contains extensive hardcoded lists of statement types and sources. This makes the code harder to maintain and test.

Consider extracting these to named constants at the top of the file:

+# Statement type choices
+STATEMENT_TYPE_CHOICES <- list(
+  "All Types" = "all",
+  "Complex" = "Complex",
+  "Inhibition" = "Inhibition",
+  # ... rest of choices
+)
+
+# Source choices  
+SOURCE_CHOICES <- list(
+  "All Sources" = "all",
+  "Reach" = "reach",
+  "Trips" = "trips",
+  # ... rest of choices
+)

 createFilterDropdowns <- function(ns) {
   tagList(
     selectInput(ns("statementTypes"),
                 "Statement Types",
-                choices = list("All Types" = "all", ...),
+                choices = STATEMENT_TYPE_CHOICES,
                 selected = "all",
                 multiple = TRUE),
     selectInput(ns("sources"),
                 "Sources", 
-                choices = list("All Sources" = "all", ...),
+                choices = SOURCE_CHOICES,
                 selected = "all",
                 multiple = TRUE),

217-249: Consider extracting inline CSS to external stylesheet or CSS classes.

The createColorLegend function contains extensive inline CSS styling which makes the code harder to read and maintain.

Consider moving the CSS to an external stylesheet or defining CSS classes:

+# Add to a CSS file or at the top of the UI
+tags$style("
+.color-legend {
+  position: absolute; top: 10px; right: 10px; 
+  background-color: rgba(255, 255, 255, 0.9);
+  border: 1px solid #ddd; border-radius: 5px; 
+  padding: 10px; box-shadow: 0 2px 4px rgba(0,0,0,0.1);
+  z-index: 1000; min-width: 150px;
+}
+.legend-title { font-weight: bold; font-size: 12px; margin-bottom: 8px; text-align: center; color: #333; }
+.gradient-bar { height: 20px; width: 100%; background: linear-gradient(to right, #ADD8E6, #D3D3D3, #FFA590); border: 1px solid #ccc; border-radius: 3px; margin-bottom: 5px; }
+.legend-labels { display: flex; justify-content: space-between; font-size: 10px; color: #666; }
+.legend-info { margin-top: 8px; font-size: 9px; color: #888; text-align: center; border-top: 1px solid #eee; padding-top: 5px; }
+")

 createColorLegend <- function() {
   div(
-    style = "position: absolute; top: 10px; right: 10px; ...",
+    class = "color-legend",
     div(class = "legend-title", "LogFC Legend"),
-    div(style = "height: 20px; width: 100%; ...", 
+    div(class = "gradient-bar"),
     # ... rest with classes instead of inline styles
   )
 }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bff2f1b and 55b8cef.

📒 Files selected for processing (2)
  • R/module-visualize-network-server.R (1 hunks)
  • R/module-visualize-network-ui.R (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • R/module-visualize-network-server.R
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build
🔇 Additional comments (3)
R/module-visualize-network-ui.R (3)

301-314: Clean and well-structured layout function.

The layout design with settings on the left (4 columns) and visualization on the right (8 columns) provides a good user experience balance.


320-328: Good abstraction of dashboard components.

The helper functions provide clean separation of concerns and make the main UI function more readable.


334-348: Main UI function is well-structured with proper namespacing.

The function correctly uses NS() for module namespacing and organizes components logically. The @importFrom documentation is comprehensive.

Note: Ensure the networkUI function is properly exported in the NAMESPACE file as mentioned in previous reviews.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (4)
R/module-visualize-network-server.R (4)

406-412: Fix container ID mismatch between UI and JavaScript code.

The container ID is hardcoded as 'network-cy' but should use the namespaced ID from the UI module.

Apply this diff to fix the container ID:

-        container: document.getElementById('network-cy'),
+        container: document.getElementById('", session$ns("cy"), "'),

550-583: Add validation for edge_data fields.

The function assumes edge_data contains required fields without validation.

Apply this diff to add validation:

 highlightEdgeInTable <- function(output, edge_data, edges_table) {
+  # Validate edge_data has required fields
+  req(edge_data$source, edge_data$target, edge_data$interaction)
+  
   source <- edge_data$source
   target <- edge_data$target
   interaction <- gsub(" \\(bidirectional\\)", "", edge_data$interaction)

589-591: Add roxygen documentation for the main server function.

The main server function lacks proper documentation.

Add roxygen documentation:

+#' Server logic for network visualization module
+#'
+#' @param input Shiny input object
+#' @param output Shiny output object
+#' @param session Shiny session object
+#' @param parent_session Parent Shiny session
+#' @param dataComparison Reactive expression containing comparison data
+#'
+#' @return None (side effects only)
+#'
 #' @importFrom MSstatsBioNet annotateProteinInfoFromIndra getSubnetworkFromIndra
 #' @importFrom DT renderDT datatable
 visualizeNetworkServer <- function(input, output, session, parent_session, dataComparison) {

685-690: Add null check for network data in edge click observer.

The observer could fail if renderNetwork() returns NULL.

Apply this diff to add validation:

 observeEvent(input$edgeClicked, {
   edge_data <- input$edgeClicked
-  edges_table <- renderNetwork()$edges_table
+  network_data <- renderNetwork()
+  req(network_data)
+  edges_table <- network_data$edges_table
   
   highlightEdgeInTable(output, edge_data, edges_table)
 })
🧹 Nitpick comments (2)
R/module-visualize-network-server.R (2)

133-133: Consider using proper logging instead of print statement.

Using print() for error messages is not ideal in production code.

Consider using Shiny's logging capabilities or the logger package:

-    print(e$message)
+    # Use Shiny's built-in logging or a logging package
+    message("Subnetwork extraction error: ", e$message)

591-591: Remove unused parent_session parameter.

The parent_session parameter is not used anywhere in the function.

If this parameter is not needed, consider removing it:

-visualizeNetworkServer <- function(input, output, session, parent_session, dataComparison) {
+visualizeNetworkServer <- function(input, output, session, dataComparison) {

Note: Only remove if you're certain it's not needed by the calling code.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2cdf82b and c736aa8.

📒 Files selected for processing (2)
  • R/module-visualize-network-server.R (1 hunks)
  • R/module-visualize-network-ui.R (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • R/module-visualize-network-ui.R
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build
🔇 Additional comments (2)
R/module-visualize-network-server.R (2)

6-96: Well-structured data management functions with proper validation.

The helper functions for data loading, choice updates, and parameter extraction are well-implemented with appropriate error handling, null checks, and input validation.


102-137: Data processing functions properly handle edge cases.

The filtering, annotation, and subnetwork extraction functions have appropriate error handling and gracefully handle missing columns or processing failures.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (4)
R/module-visualize-network-server.R (4)

413-457: Container ID mismatch needs fixing

The container ID in the JavaScript code doesn't account for Shiny's namespacing in modules.

The JavaScript code references the container by a direct ID, but in a Shiny module, IDs are namespaced. This will cause the Cytoscape initialization to fail.


566-599: Add validation for edge_data fields

The function assumes edge_data contains required fields without validation.

The function accesses edge_data properties without checking if they exist, which could cause runtime errors if the data structure is incomplete.


750-752: Add roxygen documentation for the main server function

The main server function lacks documentation.

The function needs proper roxygen documentation to describe its purpose and parameters.


845-850: Add null check for network data in edge click observer

The edge click observer could fail if renderNetwork() returns NULL.

The observer accesses the edges_table without verifying that renderNetwork() returned valid data.

🧹 Nitpick comments (1)
R/module-visualize-network-server.R (1)

209-234: Optimize node element creation for better performance

Using apply() with cbind() converts all columns to character type, which is inefficient for large networks.

Consider using vectorized operations:

-  apply(cbind(nodes, color = node_colors), 1, function(row) {
-    # Use the appropriate label, fallback to id if hgncName is missing/empty
-    display_label <- if(label_column == "hgncName" && !is.na(row['hgncName']) && row['hgncName'] != "") {
-      row['hgncName']
-    } else {
-      row['id']
-    }
-    
-    paste0("{ data: { id: '", row['id'], "', label: '", display_label, "', color: '", row['color'], "' } }")
-  })
+  # Vectorized label selection
+  display_labels <- if(label_column == "hgncName" && label_column %in% names(nodes)) {
+    ifelse(!is.na(nodes[[label_column]]) & nodes[[label_column]] != "", 
+           nodes[[label_column]], nodes$id)
+  } else {
+    nodes$id
+  }
+  
+  # Vectorized element creation
+  paste0("{ data: { id: '", nodes$id, "', label: '", display_labels, 
+         "', color: '", node_colors, "' } }")
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6dae9a5 and 38580ac.

📒 Files selected for processing (2)
  • R/module-visualize-network-server.R (1 hunks)
  • R/module-visualize-network-ui.R (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • R/module-visualize-network-ui.R
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build
🔇 Additional comments (13)
R/module-visualize-network-server.R (13)

7-35: Well-implemented color mapping function

The function correctly handles edge cases (NA values, uniform data) and uses appropriate normalization. The default max value of 2 provides good color distribution for typical logFC ranges.


38-77: Clean configuration structure for relationship properties

Good separation of concerns by centralizing relationship styling configuration. The consolidation rules will help manage bidirectional edges effectively.


170-207: Robust edge styling logic

Good handling of different relationship categories and edge types. The special handling for regulatory colors and bidirectional arrows is well-implemented.


236-267: Good edge element creation with proper consolidation

The function correctly consolidates edges before creating elements and includes all necessary styling attributes in the edge data.


269-411: Excellent documentation and comprehensive configuration

Well-documented function with clear parameter descriptions and examples. The dynamic node sizing based on label length and comprehensive style configuration are particularly well-implemented.


459-503: Well-implemented R to JavaScript converters

Both helper functions properly handle type conversion and quote escaping. The distinction between different value types (strings, functions, booleans, numbers) is handled correctly.


547-564: Clean data table rendering

Good use of consistent options across both tables. The single selection mode for edges table aligns well with the edge highlighting feature.


615-630: Robust data loading with proper error handling

Good implementation that handles both data sources (comparison results and file uploads) with appropriate error handling and user notifications.


633-647: Well-implemented dropdown update logic

Good handling of edge cases including NA values and missing Label column. The fallback behavior provides clear user feedback.


650-667: Efficient protein dropdown with server-side processing

Good use of server-side selectize input for handling potentially large protein lists. This will perform well even with thousands of proteins.


669-704: Clean parameter extraction with proper validation

Good use of req() for validation and clean handling of "all" selections. The NULL conversion for "all" values simplifies downstream filtering logic.


706-744: Well-structured helper functions with consistent error handling

Good abstraction of data processing steps with consistent error handling and user notifications across all functions.


80-167: Fix bidirectional edge processing bug

The function creates reverse_key on line 90 but never uses it. More critically, when consolidating bidirectional edges, only pair_key is added to processed_pairs (line 146), which means the reverse edge could still be processed separately, leading to duplicate edges.

Apply this fix to properly track both directions:

-      # Mark both directions as processed
-      processed_pairs <- c(processed_pairs, pair_key)
+      # Mark both directions as processed
+      reverse_pair_key <- paste(c(edge$target, edge$source, edge$interaction), collapse = "-")
+      processed_pairs <- c(processed_pairs, pair_key, reverse_pair_key)

Also remove the unused reverse_key variable on line 90.

Likely an incorrect or invalid review comment.

Comment thread R/module-visualize-network-server.R
Comment thread R/module-visualize-network-server.R Outdated
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (6)
R/module-visualize-network-server.R (6)

509-554: Fix Shiny input namespacing for module reusability

The function hardcodes input names which breaks module namespacing conventions. This prevents module reusability.

The input names 'network-edgeClicked' and 'network-nodeClicked' need to be properly namespaced using the session's namespace function.


596-599: Add validation for edge_data fields

The function assumes edge_data contains required fields without validation.

Add validation using req() to ensure edge_data has the required fields before accessing them.


780-782: Add roxygen documentation for the main server function

The main server function lacks documentation.

Add roxygen comments to describe the function's purpose and parameters.


836-836: Pass namespace to Cytoscape generation function

The function calls generateCytoscapeJSForShiny without passing the namespace parameter.

The namespace needs to be passed to ensure proper input handling in the module context.


875-880: Add null check for network data in edge click observer

The edge click observer could fail if renderNetwork() returns NULL.

Add validation using req() to ensure network data exists before accessing edges_table.


448-448: Fix container ID to use proper namespacing

The container ID needs to be dynamically generated using the session namespace instead of hardcoded value.

The container ID should use session$ns("cy") to match the namespaced ID in the UI module.

🧹 Nitpick comments (3)
R/module-visualize-network-server.R (3)

90-90: Remove unused variable reverse_key

The variable reverse_key is created but never used in the function.

     pair_key <- paste(sort(c(edge$source, edge$target)), edge$interaction, collapse = "-")
-    reverse_key <- paste(sort(c(edge$source, edge$target), decreasing = TRUE), edge$interaction, sep = "-")

224-233: Consider vectorized approach for better performance

Using apply() with row-wise operations can be slow for large datasets. Consider a vectorized approach for better performance.

-  apply(cbind(nodes, color = node_colors), 1, function(row) {
-    # Use the appropriate label, fallback to id if hgncName is missing/empty
-    display_label <- if(label_column == "hgncName" && !is.na(row['hgncName']) && row['hgncName'] != "") {
-      row['hgncName']
-    } else {
-      row['id']
-    }
-    
-    paste0("{ data: { id: '", row['id'], "', label: '", display_label, "', color: '", row['color'], "' } }")
-  })
+  # Vectorized label selection
+  display_labels <- if(label_column == "hgncName" && "hgncName" %in% names(nodes)) {
+    ifelse(!is.na(nodes$hgncName) & nodes$hgncName != "", nodes$hgncName, nodes$id)
+  } else {
+    nodes$id
+  }
+  
+  # Vectorized element creation
+  paste0("{ data: { id: '", nodes$id, "', label: '", display_labels, "', color: '", node_colors, "' } }")

244-264: Optimize edge element creation with vectorization

The for loop can be replaced with vectorized operations for better performance with large edge sets.

Consider using lapply() or vectorized string operations instead of a for loop for creating edge elements, especially when dealing with large networks.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fbf8c6e and de71efd.

📒 Files selected for processing (1)
  • R/module-visualize-network-server.R (1 hunks)
🔇 Additional comments (8)
R/module-visualize-network-server.R (8)

38-77: Well-structured relationship properties definition

The function provides a clean, maintainable way to define visual properties for different relationship types. Good separation of concerns.


170-207: Clean edge styling logic

The function effectively handles different edge types and categories with appropriate visual styling. Good fallback handling for unknown relationships.


269-411: Well-designed configuration generator

Excellent function design with clear documentation, sensible defaults, and flexibility through optional parameters. The style configuration is comprehensive and handles various edge cases.


413-503: Robust JavaScript code generation

The JavaScript generation functions properly handle type conversions and string escaping. Good separation of style and layout conversion logic.


556-573: Standard datatable rendering implementation

Good implementation with appropriate options for searchability and scrolling.


645-697: Well-implemented data management functions

Good error handling, null checking, and use of server-side selectize for handling large protein lists efficiently.


699-734: Clean parameter extraction with proper validation

Good use of req() for validation and logical handling of "all" selections.


740-774: Consistent error handling in data processing functions

Excellent use of tryCatch with user notifications for all data processing steps.

Comment thread R/module-visualize-network-server.R Outdated
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

♻️ Duplicate comments (4)
R/module-visualize-network-server.R (4)

587-588: LGTM - Input validation properly implemented

The req() validation for edge_data fields has been properly added as suggested in previous reviews.


772-784: LGTM - Proper documentation added

The roxygen documentation for the main server function has been properly added as requested in previous reviews.


839-844: LGTM - Namespace issues resolved

The container_id and module_id are now properly passed to address the namespace concerns raised in previous reviews.


883-887: LGTM - Null check properly implemented

The null check for network data has been properly added as suggested in previous reviews.

🧹 Nitpick comments (4)
R/module-visualize-network-server.R (4)

93-93: Remove unused variable

The reverse_key variable is defined but never used in the consolidation logic.

-    reverse_key <- paste(sort(c(edge$source, edge$target), decreasing = TRUE), edge$interaction, sep = "-")

227-236: Consider vectorized approach for better performance

Using apply() with cbind() can be inefficient for large datasets. Consider a more vectorized approach.

-  apply(cbind(nodes, color = node_colors), 1, function(row) {
-    # Use the appropriate label, fallback to id if hgncName is missing/empty
-    display_label <- if(label_column == "hgncName" && !is.na(row['hgncName']) && row['hgncName'] != "") {
-      row['hgncName']
-    } else {
-      row['id']
-    }
-    
-    paste0("{ data: { id: '", row['id'], "', label: '", display_label, "', color: '", row['color'], "' } }")
-  })
+  # Vectorized approach
+  display_labels <- ifelse(
+    label_column == "hgncName" & !is.na(nodes[[label_column]]) & nodes[[label_column]] != "",
+    nodes[[label_column]],
+    nodes$id
+  )
+  
+  paste0("{ data: { id: '", nodes$id, "', label: '", display_labels, "', color: '", node_colors, "' } }")

449-493: Consider input sanitization for JavaScript generation

While the current usage is internal, the JavaScript generation functions could theoretically be vulnerable to code injection if user-controlled data reaches the style/layout configurations.

Consider adding input validation if these functions might ever process user-provided configuration data:

 convertStyleToJS <- function(style_list) {
+  # Validate input is a list
+  if (!is.list(style_list)) {
+    stop("style_list must be a list")
+  }
+  
   style_items <- sapply(style_list, function(item) {

800-828: Consider caching network computation

The renderNetwork() reactive is called multiple times but performs expensive operations. Consider optimizing the reactive chain.

The current implementation may recompute the network multiple times. Consider restructuring to cache intermediate results:

 # Create a reactive expression to generate the network data
 renderNetwork <- reactive({
+  # Add caching key based on input parameters
+  cache_key <- paste(input$selectedLabel, input$pValue, input$evidence, 
+                     paste(input$statementTypes, collapse=","),
+                     paste(input$sources, collapse=","),
+                     input$absLogFC, 
+                     paste(input$selectedProteins, collapse=","),
+                     sep="_")
+  
   params <- getInputParameters(input)
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0ffe6c7 and 78c7798.

📒 Files selected for processing (9)
  • DESCRIPTION (2 hunks)
  • NAMESPACE (7 hunks)
  • R/module-visualize-network-server.R (1 hunks)
  • R/module-visualize-network-ui.R (1 hunks)
  • man/generateCytoscapeConfig.Rd (1 hunks)
  • man/generateCytoscapeJSForShiny.Rd (1 hunks)
  • man/networkUI.Rd (1 hunks)
  • man/visualizeNetworkServer.Rd (1 hunks)
  • tests/testthat/test_network_visualization.R (1 hunks)
✅ Files skipped from review due to trivial changes (2)
  • man/networkUI.Rd
  • man/visualizeNetworkServer.Rd
🚧 Files skipped from review as they are similar to previous changes (6)
  • DESCRIPTION
  • NAMESPACE
  • man/generateCytoscapeConfig.Rd
  • man/generateCytoscapeJSForShiny.Rd
  • R/module-visualize-network-ui.R
  • tests/testthat/test_network_visualization.R
🔇 Additional comments (4)
R/module-visualize-network-server.R (4)

10-38: LGTM - Robust color mapping implementation

The color mapping function handles edge cases well, including NA values and uniform data. The past review comment about NA handling has been properly addressed with na.rm = TRUE in the max() function.


290-401: Excellent decoupled architecture

The generateCytoscapeConfig function provides a clean separation between configuration logic and UI rendering. The comprehensive styling and layout options create a professional visualization.


637-726: Well-structured data management functions

The helper functions properly handle edge cases, validate inputs, and provide appropriate fallbacks for missing data. The separation of concerns is excellent.


742-766: Excellent error handling for external dependencies

The wrapper functions properly handle errors from external MSstatsBioNet functions with user-friendly notifications. This defensive programming approach will improve user experience.

Comment thread R/module-visualize-network-server.R
Comment thread R/module-visualize-network-server.R Outdated
Comment thread R/module-visualize-network-server.R Outdated
Comment thread R/module-visualize-network-server.R
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants