You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何基于R语言源文件生成符合特定要求的静态函数调用图

静态函数调用图生成方案

需求清单

  • 静态特性:无需运行代码或做性能分析,覆盖所有分支的全部可能调用路径
  • 按源文件分组:函数需根据定义所在的.R源文件分组展示
  • 无需打包:开发初期,大量.R文件暂不打包为R包
  • 可编辑导出:导出格式支持拖拽节点,箭头自动贴合节点

现有实现问题

目前使用foodwebr包生成的调用图仅展示函数间调用关系,未实现按源文件分组,且导出的静态图片无法编辑,不满足需求中的第2、4项。现有代码如下:

f <- function (x)
{
    x + 1
}

g <- function (y)
{
    f(y)*2
}

h <- function (x, y)
{
    f(x)+g(y)
}

library(foodwebr)

x <- foodweb(h)
plot(x)

解决方案

1. 实现按源文件分组+可编辑导出(HTML交互式方案)

使用codetools做静态分析,visNetwork生成可交互的分组图,导出的HTML支持拖拽节点、箭头自动适配:

# 加载依赖包
library(codetools)
library(visNetwork)
library(purrr)
library(dplyr)

# 从单个R文件提取函数、调用关系及所属文件
extract_func_info <- function(file_path) {
  file_env <- new.env()
  source(file_path, local = file_env)
  
  # 获取文件中的自定义函数
  func_names <- ls(file_env)[sapply(ls(file_env), function(x) is.function(get(x, file_env)))]
  if (length(func_names) == 0) return(NULL)
  
  # 静态分析每个函数的调用目标(仅保留自定义函数)
  all_custom_funcs <- unlist(map(list.files(pattern = "\\.R$"), function(f) {
    e <- new.env(); source(f, local = e); ls(e)[sapply(ls(e), function(x) is.function(get(x, e)))]
  }))
  
  func_calls <- map_dfr(func_names, function(name) {
    target_funcs <- findGlobals(get(name, file_env), merge = FALSE)$functions
    target_funcs <- target_funcs[target_funcs %in% all_custom_funcs]
    if (length(target_funcs) == 0) return(NULL)
    data.frame(from = name, to = target_funcs, file = basename(file_path))
  })
  
  # 生成节点数据
  nodes <- data.frame(id = func_names, label = func_names, group = basename(file_path))
  list(nodes = nodes, edges = func_calls)
}

# 遍历所有R文件,整合数据
all_r_files <- list.files(pattern = "\\.R$")
all_func_data <- map(all_r_files, extract_func_info) %>% compact()
nodes <- bind_rows(map(all_func_data, "nodes")) %>% distinct(id, .keep_all = TRUE)
edges <- bind_rows(map(all_func_data, "edges"))

# 生成可交互网络图
interactive_graph <- visNetwork(nodes, edges) %>%
  visOptions(highlightNearest = TRUE, nodesIdSelection = TRUE) %>%
  visLayout(randomSeed = 456)  # 固定初始布局

# 导出为可编辑的HTML文件
visSave(interactive_graph, "function_call_graph.html")
  • 效果:节点按所属文件自动分组(不同颜色区分),打开HTML后可拖拽节点调整位置,箭头会自动贴合节点
  • 静态分析:通过findGlobals获取函数内的所有调用,无需运行代码,覆盖所有分支

2. 备选方案(Mermaid可编辑格式)

如果偏好文本格式的可编辑图,可使用DiagrammeR生成Mermaid代码,导出后在Mermaid编辑器中编辑:

library(DiagrammeR)
library(glue)
library(dplyr)

# 复用上面的nodes和edges数据生成Mermaid代码
mermaid_code <- glue("
graph LR
{edges %>% mutate(line = glue('{from} --> {to}')) %>% pull(line) %>% paste(collapse = '\\n')}
{paste0('classDef ', unique(nodes$group), ' fill:#88f,stroke:#333,stroke-width:2px;', collapse = '')}
{nodes %>% mutate(class_assign = glue('{id}:::{group}')) %>% pull(class_assign) %>% paste(collapse = '\\n')}
")

# 预览图
grViz(mermaid_code)

# 保存Mermaid代码到文件
writeLines(mermaid_code, "function_call_graph.mmd")
  • 效果:将.mmd文件内容复制到Mermaid编辑器中,即可拖拽节点、调整布局,箭头自动适配

内容的提问来源于stack exchange,提问作者Tomas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 11:11:16