如何从目录树中构建谱系图?

31
给定一个根绝对目录路径,如何生成该路径下所有子路径的树状图对象,以便使用R可视化目录树?
假设以下调用返回了以下叶节点。 list.files(path, full.names = TRUE, recursive = TRUE)
root/a/some/file.R
root/a/another/file.R
root/a/another/cool/file.R
root/b/some/data.csv
root/b/more/data.csv

我想在R中制作一个类似于Unix tree程序输出的图表:

root
├── a
│   ├── another
│   │   ├── cool
│   │   │   └── file.R
│   │   └── file.R
│   └── some
│       └── file.R
└── b
    ├── more
    │   └── data.csv
    └── some
        └── data.csv

如果解决方案能够将文件系统树分解成两个 data.frame 表格,那将特别有用:

  1. 节点表格(我可以在其中包含修改日期等属性)
  2. 边缘表格(也具有属性)

然后从这两个 data.frame 中构建出谱系图对象。


你具体想要什么类型的图表?你能展示一下你想要的数据格式和如何绘制你的树状图的例子吗?任何有助于使问题更具可重复性的东西都会很有帮助。 - MrFlick
一个简单的分层树状图是一个很好的第一步。但我也希望制作一个树形地图。 - wdkrnls
我想对修改日期等属性进行着色。 - wdkrnls
目前这一切都是假设性的。如果您能具体说明问题,那将会很有帮助。问题出在读取文件系统上吗?还是绘图上出了问题?如果两者都有问题,最好将其分成两个部分(或许是两个独立的问题)。请提供所需数据或参考样本图。 - MrFlick
你在 Linux 下使用 R 吗? - Stéphane Laurent
我正在使用Linux。 - wdkrnls
3个回答

24

值得一提的是,优秀的fs包提供了dir_tree函数,以非常方便的方式将此功能提供给R语言。

tmp_dir <- tempdir()
# Create some directories
for (i in 1:10) {
    dir.create(path = file.path(tmp_dir,
                                basename(tempfile(pattern = "dir")),
                                basename(tempfile(pattern = "sub_dir"))),
               recursive = TRUE)
}
# Create directory tree
fs::dir_tree(path = tmp_dir, recurse = TRUE)

结果

/tmp/RtmpEhB0ne
├── dir15213121dd5903
│   └── sub_dir1521315a5425ba
├── dir152131227b086f
│   └── sub_dir1521314255d96b
├── dir152131353e6603
│   └── sub_dir1521315b52aeed
├── dir15213136870535
│   └── sub_dir15213127b34f64
├── dir1521313bbf738b
│   └── sub_dir152131473939ea
├── dir152131403f4fd5
│   └── sub_dir152131115296e7
├── dir152131503d0d55
│   └── sub_dir15213114368572
├── dir1521316f0bb0c3
│   └── sub_dir1521314aea266b
├── dir1521317fe305e9
│   └── sub_dir152131bcfe8a
└── dir1521319800dfb
    └── sub_dir15213129defd4a
除了打印目录树外,还可以将发现的路径返回到对象中。
sink(file = tempfile(fileext = ".log"))
res_fs_tree <- fs::dir_tree(path = tmp_dir, recurse = TRUE)
sink()
res_fs_tree[[1]]
# [1] "/tmp/RtmpEhB0ne/dir15213121dd5903/sub_dir1521315a5425ba"

1
太好了——我甚至使用了fs,但是因为dir_tree似乎与print/viz无关,所以找不到它。 - twedl
对我来说,将数据保存到 R 对象中是真正有价值的。如果 dir_tree 函数能够提供将数据保存到 R 对象的可选参数,那就太好了。 - hackR

22
这里提供一种可能的方法,以获得您最初要求的类似树形结构的系统。这将生成一个相当灵活的data.tree对象,并且可以按照您的要求绘制,但我不完全清楚您想要什么。
path <- c(
    "root/a/some/file.R", 
    "root/a/another/file.R", 
    "root/a/another/cool/file.R", 
    "root/b/some/data.csv", 
    "root/b/more/data.csv"
)


library(data.tree); library(plyr)

x <- lapply(strsplit(path, "/"), function(z) as.data.frame(t(z)))
x <- rbind.fill(x)
x$pathString <- apply(x, 1, function(x) paste(trimws(na.omit(x)), collapse="/"))
(mytree <- data.tree::as.Node(x))

1  root                  
2   ¦--a                 
3   ¦   ¦--some          
4   ¦   ¦   °--file.R    
5   ¦   °--another       
6   ¦       ¦--file.R    
7   ¦       °--cool      
8   ¦           °--file.R
9   °--b                 
10      ¦--some          
11      ¦   °--data.csv  
12      °--more          
13          °--data.csv  


plot(mytree)

你可以得到你想要的部分(我认为),但需要你自己做一些工作,找出在 data.tree 中数据类型之间的转换:https://cran.r-project.org/web/packages/data.tree/vignettes/data.tree.html#tree-conversionuse.data.tree = TRUE 时,我在我的 pathr 包的 tree 函数中使用这种方法:https://github.com/trinker/pathr#tree 编辑 根据 @Luke 的评论... data.tree::as.Node 直接接受路径:
(mytree <- data.tree::as.Node(data.frame(pathString = path)))

                levelName
1  root2                 
2   ¦--a                 
3   ¦   ¦--some          
4   ¦   ¦   °--file.R    
5   ¦   °--another       
6   ¦       ¦--file.R    
7   ¦       °--cool      
8   ¦           °--file.R
9   °--b                 
10      ¦--some          
11      ¦   °--data.csv  
12      °--more          
13          °--data.csv  

2
只是提醒一下,你可以替换掉所有的代码,只保留在顶部创建的 path 变量和 (mytree <- data.tree::as.Node(data.frame(pathString = path)))。你不需要使用 plyr 或进行任何操作。 - Luke W. Johnston
@Luke 很好,我会把这个加到答案中。 - Tyler Rinker
mytree 应该是一个环境,对吧?(class() 仍然返回 "Node" "R6") 我问是因为在 RStudio 中 plot(mytree) 打开了一个我从未使用过且几乎没注意到的 "Viewer" 标签页。是否有办法将其绘制在通常的图形设备中呢?在我的情况下控制台输出被截断,这就是我问的原因。 - mattu

7

如果你使用的是Windows系统,你可以使用我的软件包dir2json,按照以下方式安装:

drat::addRepo("stlarepo")
install.packages("dir2json")

这个工具也可以在Linux上使用,但是需要安装链接到GHC动态库的DLL文件(而在Windows上这个DLL文件是独立的)。

> library(dir2json)
> cat(dir2tree("src"))
src
|
`- contrib
   |
   +- PACKAGES.gz
   |
   +- PACKAGES
   |
   +- jsonAccess_0.1.1.tar.gz
   |
   +- expansions_1.2.tar.gz
   |
   `- dir2json_2.1.0.tar.gz
> cat(dir2tree("src", vertical=TRUE))
                                            src                                             
                                             |                                              
                                          contrib                                           
                                             |                                              
      ---------------------------------------------------------------------------           
     /          |                 |                       |                      \          
PACKAGES.gz  PACKAGES  jsonAccess_0.1.1.tar.gz  expansions_1.2.tar.gz  dir2json_2.1.0.tar.gz

该软件包还包含一个Shiny应用程序,可以生成一个交互式的Reingold-Tilford树形结构表示文件夹:

> dir2json::shinyDirTree(".")

Reingold-Tilford folder


嗨@Stéphane Laurent,我在安装dir2json包时遇到了麻烦。这是我收到的错误消息: .onLoad failed in loadNamespace() for 'rJava', details: call: fun(libname, pkgname) error: JAVA_HOME cannot be determined from the Registry Error: loading failed Execution halted *** arch - x64 ERROR: loading failed for 'i386' * removing 'C:/Users//Documents/R/win-library/3.6/dir2json' Warning in install.packages : installation of package ‘dir2json’ had non-zero exit status``` - Jasppo
似乎R无法打开此URL,对我来说它不存在:警告:在安装包时无法访问存储库https://stlarepo.github.io/drat/bin/windows/contrib/3.6的索引: 无法打开URL'https://stlarepo.github.io/drat/bin/windows/contrib/3.6/PACKAGES' - Jasppo
@Jasppo 哦,是的,它不存在于 R 3.6 中。您可以尝试 install.packages("dir2json", type = "source") 吗? - Stéphane Laurent

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接