繁体   English   中英

使用 plotly graph 对象创建显示目录结构的树状图

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM