📜  使用 Squarify 在Python中创建树形图(1)

📅  最后修改于: 2023-12-03 15:06:51.249000             🧑  作者: Mango

使用 Squarify 在Python中创建树形图

Squarify是Python中一个非常好用的可视化库,通过它我们可以方便地创建各种图形,包括树形图。 在本文中,我们将介绍使用Squarify创建树形图的过程,并提供Python代码示例。

安装

在开始之前,请确保您已经安装了Squarify。 如果没有,请使用以下命令安装:

pip install squarify
准备数据

在创建树形图之前,我们需要准备好数据,并将其存储在Python列表中。 每个节点应该是一个字典,包含以下键:

{
    "name": 节点名称(字符串),
    "parent": 父节点名称(字符串),如果没有父节点则填None,
    "value": 节点值(浮点数)
}

例如,下面是我们将在本教程中使用的样本数据:

data = [
    {"name": "Root", "parent": "", "value": 10},
    {"name": "A", "parent": "Root", "value": 5},
    {"name": "B", "parent": "Root", "value": 5},
    {"name": "C", "parent": "A", "value": 2},
    {"name": "D", "parent": "A", "value": 3},
    {"name": "E", "parent": "B", "value": 1},
    {"name": "F", "parent": "B", "value": 4},
    {"name": "G", "parent": "E", "value": 1},
    {"name": "H", "parent": "F", "value": 3},
    {"name": "I", "parent": "F", "value": 1},
    {"name": "J", "parent": "H", "value": 2},
    {"name": "K", "parent": "H", "value": 1},
    {"name": "L", "parent": "I", "value": 1},
    {"name": "M", "parent": "I", "value": 1}
]
创建树形图

一旦我们准备好数据,我们就可以开始创建树形图了。 下面是使用Squarify创建树形图的基本步骤:

  1. 导入Squarify
import squarify
  1. 对数据进行处理,创建节点层级结构
nodes = {}
for d in data:
    name = d['name']
    parent = d['parent']
    value = d['value']
    
    if name not in nodes:
        nodes[name] = {'value': 0}
    nodes[name]['value'] += value
    
    if parent not in nodes:
        nodes[parent] = {'children': []}
    nodes[parent]['children'].append(name)
  1. 创建节点位置信息
def position(node, top, left, bottom, right, coordinates):
    if 'children' in nodes[node]:
        child_values = [nodes[child]['value'] for child in nodes[node]['children']]
        total_child_value = sum(child_values)
        child_ratio = [child_value/total_child_value for child_value in child_values]
        child_bottom = [top + (bottom - top)*sum(child_ratio[:i+1]) for i in range(len(child_ratio))]

        for idx, child in enumerate(nodes[node]['children']):
            child_left = left + (right - left)*sum([child_ratio[i]/2 for i in range(idx)])
            child_right = left + (right - left)*sum([child_ratio[i]/2 for i in range(idx+1)])
            coordinates[child] = (top, child_left, child_bottom[idx], child_right)
            position(child, *coordinates[child], coordinates)

    else:
        coordinates[node] = (top, left, bottom, right)

coordinates = {'Root': (0,0,100,100)}
position('Root', 0, 0, 100, 100, coordinates)
  1. 创建图形
import matplotlib.pyplot as plt

fig = plt.figure(figsize=(12,8))
ax = fig.add_subplot(111, aspect="equal")
ax.axis("off")

for node in nodes:
    top, left, bottom, right = coordinates[node]
    if 'children' in nodes[node]:
        ax.add_patch(plt.Rectangle((left,top),right-left,bottom-top,linewidth=1,edgecolor='black',facecolor='none'))
    else:
        ax.add_patch(plt.Rectangle((left,top),right-left,bottom-top,linewidth=1,edgecolor='black',facecolor='grey'))

    x = left + (right - left) / 2
    y = top + (bottom - top) / 2
    ax.text(x, y, node, ha="center", va="center", color="white" if 'children' in nodes[node] else "black")

plt.show()
完整代码
import squarify
import matplotlib.pyplot as plt

data = [
    {"name": "Root", "parent": "", "value": 10},
    {"name": "A", "parent": "Root", "value": 5},
    {"name": "B", "parent": "Root", "value": 5},
    {"name": "C", "parent": "A", "value": 2},
    {"name": "D", "parent": "A", "value": 3},
    {"name": "E", "parent": "B", "value": 1},
    {"name": "F", "parent": "B", "value": 4},
    {"name": "G", "parent": "E", "value": 1},
    {"name": "H", "parent": "F", "value": 3},
    {"name": "I", "parent": "F", "value": 1},
    {"name": "J", "parent": "H", "value": 2},
    {"name": "K", "parent": "H", "value": 1},
    {"name": "L", "parent": "I", "value": 1},
    {"name": "M", "parent": "I", "value": 1}
]

nodes = {}
for d in data:
    name = d['name']
    parent = d['parent']
    value = d['value']
    if name not in nodes:
        nodes[name] = {'value': 0}
    nodes[name]['value'] += value
    
    if parent not in nodes:
        nodes[parent] = {'children': []}
    nodes[parent]['children'].append(name)

def position(node, top, left, bottom, right, coordinates):
    if 'children' in nodes[node]:
        child_values = [nodes[child]['value'] for child in nodes[node]['children']]
        total_child_value = sum(child_values)
        child_ratio = [child_value/total_child_value for child_value in child_values]
        child_bottom = [top + (bottom - top)*sum(child_ratio[:i+1]) for i in range(len(child_ratio))]

        for idx, child in enumerate(nodes[node]['children']):
            child_left = left + (right - left)*sum([child_ratio[i]/2 for i in range(idx)])
            child_right = left + (right - left)*sum([child_ratio[i]/2 for i in range(idx+1)])
            coordinates[child] = (top, child_left, child_bottom[idx], child_right)
            position(child, *coordinates[child], coordinates)

    else:
        coordinates[node] = (top, left, bottom, right)

coordinates = {'Root': (0,0,100,100)}
position('Root', 0, 0, 100, 100, coordinates)

fig = plt.figure(figsize=(12,8))
ax = fig.add_subplot(111, aspect="equal")
ax.axis("off")

for node in nodes:
    top, left, bottom, right = coordinates[node]
    if 'children' in nodes[node]:
        ax.add_patch(plt.Rectangle((left,top),right-left,bottom-top,linewidth=1,edgecolor='black',facecolor='none'))
    else:
        ax.add_patch(plt.Rectangle((left,top),right-left,bottom-top,linewidth=1,edgecolor='black',facecolor='grey'))

    x = left + (right - left) / 2
    y = top + (bottom - top) / 2
    ax.text(x, y, node, ha="center", va="center", color="white" if 'children' in nodes[node] else "black")

plt.show()