| Title: | Visualize Function Call Dependencies in R Source Code |
|---|---|
| Description: | Provides tools to analyze R source code and detect function definitions and their internal dependencies across multiple files. Creates interactive network visualizations using 'visNetwork' to display function call relationships, with detailed tooltips showing function arguments, return values, and documentation. Supports both individual files and directory-based analysis with automatic file detection. Useful for understanding code structure, identifying dependencies, and documenting R projects. |
| Authors: | Chathura Jayalath [aut, cre] (ORCID: <https://orcid.org/0000-0002-2056-0211>) |
| Maintainer: | Chathura Jayalath <[email protected]> |
| License: | GPL-3 |
| Version: | 0.1.1 |
| Built: | 2026-06-01 11:22:08 UTC |
| Source: | https://github.com/deamonpog/funviewr |
Parses multiple R files to identify function definitions and their internal dependencies. Creates a comprehensive map of which functions call which other functions within the analyzed codebase.
analyze_internal_dependencies_multi(file_paths)analyze_internal_dependencies_multi(file_paths)
file_paths |
Character vector of R file paths to analyze. |
This function uses codetools::findGlobals() to detect function calls
within function bodies. Only functions defined within the analyzed files are
tracked. External package functions and base R functions are not included in
the dependency map.
A list with the following components:
Named list mapping function names to character vectors of their dependencies
Environment containing all parsed functions
Character vector of all code lines from all files
Named list mapping function names to their source file paths
List of functions defined in multiple files with their source locations
# Create temporary R files for demonstration temp_file1 <- tempfile(fileext = ".R") temp_file2 <- tempfile(fileext = ".R") # Write sample R code to temporary files writeLines(c( "add_numbers <- function(a, b) {", " a + b", "}", "", "calculate_sum <- function(x) {", " add_numbers(x, 10)", "}" ), temp_file1) writeLines(c( "multiply <- function(a, b) {", " a * b", "}", "", "process_data <- function(x) {", " result <- add_numbers(x, 5)", " multiply(result, 2)", "}" ), temp_file2) # Analyze the files dep_info <- analyze_internal_dependencies_multi(c(temp_file1, temp_file2)) # View the dependency map print(dep_info$dependency_map) # Check for duplicate function definitions if (length(dep_info$duplicates) > 0) { message("Warning: Functions defined in multiple files:") print(dep_info$duplicates) } # Clean up unlink(c(temp_file1, temp_file2))# Create temporary R files for demonstration temp_file1 <- tempfile(fileext = ".R") temp_file2 <- tempfile(fileext = ".R") # Write sample R code to temporary files writeLines(c( "add_numbers <- function(a, b) {", " a + b", "}", "", "calculate_sum <- function(x) {", " add_numbers(x, 10)", "}" ), temp_file1) writeLines(c( "multiply <- function(a, b) {", " a * b", "}", "", "process_data <- function(x) {", " result <- add_numbers(x, 5)", " multiply(result, 2)", "}" ), temp_file2) # Analyze the files dep_info <- analyze_internal_dependencies_multi(c(temp_file1, temp_file2)) # View the dependency map print(dep_info$dependency_map) # Check for duplicate function definitions if (length(dep_info$duplicates) > 0) { message("Warning: Functions defined in multiple files:") print(dep_info$duplicates) } # Clean up unlink(c(temp_file1, temp_file2))
Reads an R source file and parses it into a list of expressions. This is a
utility function primarily used internally by
analyze_internal_dependencies_multi.
get_all_expressions(file_path)get_all_expressions(file_path)
file_path |
Character string. Path to an R file to parse. |
A list of parsed expressions, or NULL if parsing fails.
# Create a temporary R file temp_file <- tempfile(fileext = ".R") writeLines(c( "my_function <- function(x) { x + 1 }", "another_function <- function(y) { y * 2 }" ), temp_file) # Parse the file exprs <- get_all_expressions(temp_file) if (!is.null(exprs)) { print(length(exprs)) } # Clean up unlink(temp_file)# Create a temporary R file temp_file <- tempfile(fileext = ".R") writeLines(c( "my_function <- function(x) { x + 1 }", "another_function <- function(y) { y * 2 }" ), temp_file) # Parse the file exprs <- get_all_expressions(temp_file) if (!is.null(exprs)) { print(length(exprs)) } # Clean up unlink(temp_file)
Recursively or non-recursively searches a directory for R source files
matching a specified pattern. Returns full paths suitable for use with
analyze_internal_dependencies_multi.
get_r_files(directory, recursive = FALSE, pattern = "\\.R$")get_r_files(directory, recursive = FALSE, pattern = "\\.R$")
directory |
Character string. Path to directory containing R files. |
recursive |
Logical. If |
pattern |
Character string. Regular expression pattern for filenames.
Default is |
Character vector of full paths to R files found in the directory. Returns an empty vector with a warning if no files are found.
# Create a temporary directory with R files temp_dir <- tempfile() dir.create(temp_dir) # Create some R files writeLines("f1 <- function(x) { x + 1 }", file.path(temp_dir, "file1.R")) writeLines("f2 <- function(y) { y * 2 }", file.path(temp_dir, "file2.R")) # Get all R files in the directory files <- get_r_files(temp_dir) print(files) # Create subdirectory subdir <- file.path(temp_dir, "subdir") dir.create(subdir) writeLines("f3 <- function(z) { z - 1 }", file.path(subdir, "file3.R")) # Search recursively files_recursive <- get_r_files(temp_dir, recursive = TRUE) print(files_recursive) # Clean up unlink(temp_dir, recursive = TRUE)# Create a temporary directory with R files temp_dir <- tempfile() dir.create(temp_dir) # Create some R files writeLines("f1 <- function(x) { x + 1 }", file.path(temp_dir, "file1.R")) writeLines("f2 <- function(y) { y * 2 }", file.path(temp_dir, "file2.R")) # Get all R files in the directory files <- get_r_files(temp_dir) print(files) # Create subdirectory subdir <- file.path(temp_dir, "subdir") dir.create(subdir) writeLines("f3 <- function(z) { z - 1 }", file.path(subdir, "file3.R")) # Search recursively files_recursive <- get_r_files(temp_dir, recursive = TRUE) print(files_recursive) # Clean up unlink(temp_dir, recursive = TRUE)
Convenience function that analyzes R files and directly returns the interactive dependency graph without exposing intermediate analysis results. Automatically detects whether paths are files or directories.
plot_dependency_graph( file_paths, include_disconnected = TRUE, recursive = FALSE )plot_dependency_graph( file_paths, include_disconnected = TRUE, recursive = FALSE )
file_paths |
Character vector of R file paths, directory paths, or a mix. The function automatically detects files vs directories. |
include_disconnected |
Logical. If |
recursive |
Logical. If directories are encountered, search subdirectories
recursively. Default is |
This is a convenience wrapper around analyze_internal_dependencies_multi
and plot_interactive_dependency_graph. It automatically:
Detects whether each path is a file or directory
Collects all R files from directories
Analyzes function dependencies
Creates an interactive visualization
A visNetwork HTML widget displaying the interactive dependency
graph. The graph can be saved using htmlwidgets::saveWidget().
# Create temporary directory and files temp_dir <- tempfile() dir.create(temp_dir) # Create sample R files writeLines(c( "add <- function(a, b) { a + b }", "calc <- function(x) { add(x, 10) }" ), file.path(temp_dir, "math.R")) writeLines(c( "process <- function(data) { add(data, 5) }" ), file.path(temp_dir, "process.R")) # Analyze and plot - single file graph <- plot_dependency_graph(file.path(temp_dir, "math.R")) # Analyze directory graph <- plot_dependency_graph(temp_dir) # Exclude disconnected nodes graph <- plot_dependency_graph(temp_dir, include_disconnected = FALSE) # Clean up unlink(temp_dir, recursive = TRUE)# Create temporary directory and files temp_dir <- tempfile() dir.create(temp_dir) # Create sample R files writeLines(c( "add <- function(a, b) { a + b }", "calc <- function(x) { add(x, 10) }" ), file.path(temp_dir, "math.R")) writeLines(c( "process <- function(data) { add(data, 5) }" ), file.path(temp_dir, "process.R")) # Analyze and plot - single file graph <- plot_dependency_graph(file.path(temp_dir, "math.R")) # Analyze directory graph <- plot_dependency_graph(temp_dir) # Exclude disconnected nodes graph <- plot_dependency_graph(temp_dir, include_disconnected = FALSE) # Clean up unlink(temp_dir, recursive = TRUE)
Creates an interactive network visualization of function dependencies using
visNetwork. Nodes represent functions and edges represent function calls.
The graph uses hierarchical layout with color-coding based on distance from
the most-connected function.
plot_interactive_dependency_graph(dep_info, include_disconnected = TRUE)plot_interactive_dependency_graph(dep_info, include_disconnected = TRUE)
dep_info |
List. Output from |
include_disconnected |
Logical. If |
The visualization includes:
Node colors: Functions are color-coded by their distance (number of hops) from the most-connected function
Node shapes: Boxes for defined functions, ellipses for undefined/external functions
Tooltips: Hover over nodes to see function arguments, return values, source file, and documentation
Interactive controls: Zoom, pan, drag nodes, and navigation buttons
The center node (most-connected function) is fixed at position (0,0) and rendered in dark red. Other nodes are positioned using a force-directed layout.
A visNetwork HTML widget displaying the interactive dependency
graph. The widget can be displayed in RStudio Viewer, web browser, or saved
to HTML using htmlwidgets::saveWidget().
# Create temporary R files with sample code temp_file <- tempfile(fileext = ".R") writeLines(c( "helper_function <- function(x) { x * 2 }", "main_function <- function(a) { helper_function(a) + 1 }", "another_function <- function(b) { main_function(b) }" ), temp_file) # Analyze the file dep_info <- analyze_internal_dependencies_multi(temp_file) # Create interactive graph graph <- plot_interactive_dependency_graph(dep_info) # Show only connected components graph <- plot_interactive_dependency_graph(dep_info, include_disconnected = FALSE) # Clean up unlink(temp_file)# Create temporary R files with sample code temp_file <- tempfile(fileext = ".R") writeLines(c( "helper_function <- function(x) { x * 2 }", "main_function <- function(a) { helper_function(a) + 1 }", "another_function <- function(b) { main_function(b) }" ), temp_file) # Analyze the file dep_info <- analyze_internal_dependencies_multi(temp_file) # Create interactive graph graph <- plot_interactive_dependency_graph(dep_info) # Show only connected components graph <- plot_interactive_dependency_graph(dep_info, include_disconnected = FALSE) # Clean up unlink(temp_file)