[英]Create a treemap showing directory structure with plotly graph object
我想创建一个树状图来显示给定目录中的文件夹,包括使用plotly.graph_objects.Treemap的所有子文件夹和文件。 我理解像这个和这个这样的简单例子。
问题:我无法弄清楚如何生成ids
列以使我的图形正确呈现。 我将有重复的labels
,所以我需要使用ids
。 现在,该图呈现空白。
代码:
下面是一些生成示例目录结构的代码,以帮助您帮助我:
import os
folder = 'Documents'
for i in range(10):
for j in range(100):
path = os.path.join(folder, f'folder_{i}', f'sub-folder-{j}')
if not os.path.isdir(path):
os.makedirs(path)
for k in range(20):
with open(os.path.join(path, f'file_{k + 1}.txt'), 'w') as file_out:
file_out.write(f'Hello from file {k + 1}!\n')
下面是计算文件大小和创建树状图的代码:
import os
from pathlib import Path
import pandas as pd
import plotly.graph_objects as go
directory = '[input your directory here]/Documents'
def calculate_size(folder):
result = []
for root, dirs, files in os.walk(folder):
relpath = Path(root).relative_to(Path(folder).parent)
# Calculate directory size
dir_size = sum(os.path.getsize(os.path.join(root, name)) for name in files)
result.append({
'parents': str(relpath),
'labels': str(Path(root).name),
'size': dir_size,
'ids': str(relpath),
})
# Calculate individual file size
for f in files:
fp = os.path.join(root, f)
relpath_fp = Path(fp).relative_to(Path(folder).parent)
result.append({
'parents': str(relpath_fp),
'labels': str(Path(fp).name),
'size': os.path.getsize(fp),
'ids': str(relpath_fp),
})
return result
result = calculate_size(directory)
df = pd.DataFrame(result)
# Set root
df.loc[df.index == 0, 'parents'] = ""
labels = df['labels'].tolist()
parents = df['parents'].tolist()
ids = df['ids'].tolist()
values = df['size'].tolist()
fig = go.Figure(go.Treemap(
labels = labels,
parents = parents,
ids = ids,
values = values,
# maxdepth=3
))
fig.update_traces(root_color="lightgrey")
fig.update_layout(margin = dict(t=50, l=25, r=25, b=25))
fig.show()
您可以使用 plotly.express 创建树状图。 您需要为树图中的每个级别创建一个新列(使用正则表达式从数据框中的父列中提取该信息)。
df['level1'] = df['parents'].str.replace(pat = '^(.*?)\\\\(.*?)\\\\(.*?)\\\\(.*)', repl = r'\1')
df['level2'] = df['parents'].str.replace(pat = '^(.*?)\\\\(.*?)\\\\(.*?)\\\\(.*)', repl = r'\2')
df['level3'] = df['parents'].str.replace(pat = '^(.*?)\\\\(.*?)\\\\(.*?)\\\\(.*)', repl = r'\3')
df['level4'] = df['parents'].str.replace(pat = '^(.*?)\\\\(.*?)\\\\(.*?)\\\\(.*)', repl = r'\4')
df = df.query("labels.str.contains('.txt')")
fig = px.treemap(df,
title = 'treemap of folder structure',
values = 'size',
path = ['level1', 'level2', 'level3', 'level4'],
maxdepth = 2,
)
你真的很接近。 但是,当您拥有多层树状图时,您的 ID 和父母将有所不同。 他们一起为 Plotly 创建地图。
在这里我添加了另一个功能。
def parPath(idpath):
"""determine if path is top or not, then determine parent path"""
if idpath == os.path.split(directory)[1]:
parpath = idpath
else:
parpath = os.path.split(idpath)[0]
return parpath
此函数parPath
在您的函数calculate_size
中调用。 此功能有四处更改(注释)。
def calculate_size(folder):
result = []
for root, dirs, files in os.walk(folder):
relpath = Path(root).relative_to(Path(folder).parent)
newpar = parPath(relpath) # determine if parent and id are different
# Calculate directory size
dir_size = sum(os.path.getsize(os.path.join(root, name)) for name in files)
result.append({
'parents': str(newpar), # was str(relpath)
'labels': str(Path(root).name),
'size': dir_size,
'ids': str(relpath),
})
# Calculate individual file size
for f in files:
fp = os.path.join(root, f)
relpath_fp = Path(fp).relative_to(Path(folder).parent)
newpar2 = parPath(relpath_fp) # determine if parent and id are different
result.append({
'parents': str(newpar2), # was str(relpath)
'labels': str(Path(fp).name),
'size': os.path.getsize(fp),
'ids': str(relpath_fp),
})
return result
除了您更改第一个父母的电话之外,还有另一个修改; 您还将更改第一个id
。
df.loc[df.index == 0, 'ids'] = os.path.split(df.loc[0, 'ids'])[1] # get first folder
你准备好阴谋了。
fig = go.Figure(go.Treemap(
labels = labels,
parents = parents,
ids = ids,
values = values,
))
fig.update_traces(root_color="lightgrey")
fig.update_layout(margin = dict(t=50, l=25, r=25, b=25))
fig.show()
这是我在测试中使用的我自己的文件夹之一的深入分析。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.