Python or PBI visualization - condensed tree chart - 如何实现以及如何正确调用视觉?

Python or PBI visualization - condensed tree chart - how to achieve and how the visual is properly called?

也许有点奇怪和随机的问题,但仍然。

不久前,我在一次网络研讨会上看到了下面的图表,它可视化了一个组织的组织结构(谁向谁报告等等):

如你所见,它基本上表明 CEO 在组织的最高层,制造总监、财务总监和运营总监向 CEO 等汇报。每个框的长度表示每个节点有多少个子节点(所以对于 CEO 来说它是组织中的所有人,对于制造总监来说,是所有直接或间接向他报告的人等)。这些框根据位置所在的位置进行颜色编码(例如红色 - 美国,蓝色 - 亚太地区等)

现在,我喜欢视觉效果本身,它以简洁的方式很好地传达了整个组织结构图。

我想使用我自己的数据集复制此图表,但我什至不确定从哪里开始,因为我什至不知道这种图表类型是如何调用的。我尝试 google 它或在线查看不同的图表库,但没有发现任何类似的东西。

因此我有两个问题:

  1. 有谁知道如何正确调用这样的图表?
  2. 即使您不知道它的名称,有没有人有机会做过类似的事情,最好是在 PowerBI 或 Python 中?

为了说明,我的虚拟数据集如下:

任何建议将不胜感激。

给定经理矩形的 x、y 位置、宽度和高度,计算该人直接管理的人员的位置和形状非常简单。 由于“Reporting to”关系定义了一个有向无环图,我们可以从根开始递归遍历图来计算所有矩形的位置和形状。这确保我们总是在计算经理管理的任何人的矩形之前计算该经理的矩形。

#!/usr/bin/env python
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import networkx as nx


def get_layout_recursively(G, predecessor, layout, base_width, base_height):
    x, y, _, _ = layout[predecessor]
    y -= base_height
    for node in G.successors(predecessor):
        width = get_total_children(G, node) * base_width
        layout[node] = x, y, width, base_height
        x += width
        layout = get_layout_recursively(G, node, layout, base_width, base_height)
    return layout


def get_total_children(G, node):
    return len(nx.nodes(nx.dfs_tree(G, node)))


if __name__ == '__main__':

    data = dict(
        ID          = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
        predecessor = [pd.NA, 1, 1, 2, 2, 4, 4, 4, 3, 3],
        label       = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'],
        color       = ['tab:blue', 'tab:orange', 'tab:green', 'tab:orange', 'tab:orange', 'tab:pink', 'tab:pink', 'tab:pink', 'tab:green', 'tab:green'],
    )
    data = pd.DataFrame(data)
    data.set_index('ID', inplace=True)

    # create graph 
    G = nx.DiGraph([(predecessor, successor) for (successor, predecessor) in data['predecessor'].iteritems() if not predecessor is pd.NA])

    # compute layout recursively starting with the root
    base_width = 2
    base_height = 10
    root = next(nx.topological_sort(G))
    layout = {root : (0, 0, get_total_children(G, root) * base_width, base_height)}
    layout = get_layout_recursively(G, root, layout, base_width, base_height)
    
    # plot        
    fig, ax = plt.subplots()
    for node in data.index:
        x, y, width, height = layout[node]
        color = data['color'].loc[node]
        label = data['label'].loc[node]
        ax.add_patch(plt.Rectangle((x, y), width, height, facecolor=color, edgecolor='white'))
        ax.text(x + 0.5*width, y + 0.5 * height, label, ha='center', va='center', color='white')

    # rescale the axis such that it encompasses all rectangles
    ax.autoscale_view()

    # remove axes spines, ticks, labels
    ax.axis('off')

    plt.show()