如何在Python中创建带无数值子节点的自定义分解树图表?
定制化分解树图表实现方案(类Power BI)
需求说明
- 实现层级化分解树图表,匹配Power BI分解树核心逻辑
- 支持仅含标题、无关联数值的「Sub-child」层级节点
- 节点样式为方形/矩形(替代Power BI默认的细水平条)
现有数据
import pandas as pd df = pd.DataFrame({'Parent': ['Parent', 'Parent', 'Parent', 'Parent', 'Parent', 'Parent', 'Parent', 'Parent', 'Parent', 'Parent', 'Parent', 'Parent'], 'Child': ['Child 1', 'Child 1', 'Child 1', 'Child 1', 'Child2', 'Child2', 'Child2', 'Child2', 'Child3', 'Child3', 'Child3', 'Child3'], 'Child-Values': ['40%', '40%', '40%', '40%', '35%', '35%', '35%', '35%', '25%', '25%', '25%', '25%'], 'Sub-Child': ['Sub-child 1', 'Sub-child 1', 'Sub-child 2', 'Sub-child 2', 'Sub-child 1', 'Sub-child 1', 'Sub-child 2', 'Sub-child 2', 'Sub-child 1', 'Sub-child 1', 'Sub-child 2', 'Sub-child 2'], 'Sub-Sub-Child': ['A1', 'A2', 'B1', 'B2', 'A1', 'A2', 'B1', 'B2', 'A1', 'A2', 'B1', 'B2'], 'Sub-Sub-Child-Values': ['40%', '60%', '25%', '75%', '80%', '20%', '45%', '55%', '35%', '65%', '30%', '70%']})
问题背景
尝试过pandas、Plotly等库未找到适配方案,使用treeplotter库调用create_tree_diagram时出现参数缺失错误。
解决方案
方案1:修复treeplotter参数问题
treeplotter的create_tree_diagram需要明确的树状结构映射,先整理数据为父-子节点字典,再传递必要参数:
from treeplotter import Tree # 去重并构建层级节点映射 parent_child_map = {} # 顶级节点 parent_child_map['Parent'] = [] # 处理Child层级(带数值) for child, val in df[['Child', 'Child-Values']].drop_duplicates().values: child_node = f"{child} ({val})" parent_child_map['Parent'].append(child_node) parent_child_map[child_node] = [] # 处理Sub-Child层级(无数值) for child, sub_child in df[['Child', 'Sub-Child']].drop_duplicates().values: parent_node = f"{child} ({df[df['Child']==child]['Child-Values'].iloc[0]})" parent_child_map[parent_node].append(sub_child) parent_child_map[sub_child] = [] # 处理Sub-Sub-Child层级(带数值) for sub_child, sub_sub_child, val in df[['Sub-Child', 'Sub-Sub-Child', 'Sub-Sub-Child-Values']].drop_duplicates().values: child_node = f"{sub_sub_child} ({val})" parent_child_map[sub_child].append(child_node) # 生成树状图 tree = Tree() tree.create_tree_diagram( root_name='Parent', parent_child_dict=parent_child_map, node_shape='square', # 指定方形节点 node_size=2200, font_size=10 )
方案2:自定义实现(NetworkX + Matplotlib)
如果treeplotter仍有兼容问题,用NetworkX构建树结构,Matplotlib完全自定义节点样式:
import networkx as nx import matplotlib.pyplot as plt # 构建有向树图 G = nx.DiGraph() # 添加节点与边 # 顶级节点 G.add_node('Parent', label='Parent') # Child层级 for child, val in df[['Child', 'Child-Values']].drop_duplicates().values: node_label = f"{child}\n({val})" G.add_node(child, label=node_label) G.add_edge('Parent', child) # Sub-Child层级(无数值) for child, sub_child in df[['Child', 'Sub-Child']].drop_duplicates().values: G.add_node(sub_child, label=sub_child) G.add_edge(child, sub_child) # Sub-Sub-Child层级 for sub_child, sub_sub_child, val in df[['Sub-Child', 'Sub-Sub-Child', 'Sub-Sub-Child-Values']].drop_duplicates().values: node_label = f"{sub_sub_child}\n({val})" G.add_node(sub_sub_child, label=node_label) G.add_edge(sub_child, sub_sub_child) # 层级布局 pos = nx.nx_agraph.graphviz_layout(G, prog='dot') # 绘制图表 plt.figure(figsize=(14, 9)) nx.draw_networkx_edges(G, pos, edge_color='gray', arrowstyle='-') # 方形节点 nx.draw_networkx_nodes(G, pos, node_shape='s', node_size=3500, node_color='#e6f2ff') # 节点标签 nx.draw_networkx_labels(G, pos, labels=nx.get_node_attributes(G, 'label'), font_size=9) plt.box(False) plt.tight_layout() plt.show()
内容的提问来源于stack exchange,提问作者Prem
相关产品推荐
相关产品推荐

