如何用Python复刻D3.stratify式新冠病毒谱系层级树结构?
解决新冠病毒谱系树层级构建问题的几种方法
方法1:拆分谱系路径,逐层定位父节点
针对每个谱系名称(如BA.1.1),按.拆分出完整的层级路径列表(['BA', 'BA.1', 'BA.1.1']),从根节点开始逐层遍历路径,找到对应父节点后再添加子节点,自动形成正确的层级关系。
示例代码思路:
class LineageNode: def __init__(self, name): self.name = name self.children = {} # 用字典存子节点,快速查找 class LineageTree: def __init__(self): self.root = LineageNode("root") # 可根据数据集调整为顶级谱系节点 def add_lineage(self, lineage_name): parts = lineage_name.split('.') current_node = self.root current_path = [] for part in parts: current_path.append(part) full_path = '.'.join(current_path) # 不存在则创建节点并添加为当前节点的子节点 if full_path not in current_node.children: current_node.children[full_path] = LineageNode(full_path) # 移动到当前路径节点,继续处理下一层 current_node = current_node.children[full_path]
使用这个逻辑,BA.1.1会先关联到BA节点,再在BA下找到/创建BA.1,最后将BA.1.1添加为BA.1的子节点。
方法2:预构建父节点映射表
先遍历所有谱系名称,为每个节点生成对应的父节点名称(比如BA.1.1的父节点是BA.1,BA.1的父节点是BA),再按层级深度排序添加节点,确保父节点先于子节点被创建。
步骤及示例代码:
# 示例数据集 all_lineages = ["BA", "BA.1", "BA.1.1", "BA.2"] parent_map = {} # 生成父节点映射字典 for lineage in all_lineages: if '.' in lineage: parent = '.'.join(lineage.split('.')[:-1]) parent_map[lineage] = parent else: parent_map[lineage] = "root" # 顶级节点的父节点设为根 # 构建树结构 nodes = {"root": LineageNode("root")} # 按层级深度排序,确保先添加父节点 for lineage in sorted(all_lineages, key=lambda x: len(x.split('.'))): if lineage not in nodes: nodes[lineage] = LineageNode(lineage) parent_name = parent_map[lineage] nodes[parent_name].children[lineage] = nodes[lineage]
方法3:修改现有add_to_tree方法逻辑
如果要保留原有Lineage类,只需修改add_to_tree方法,拆分谱系路径并找到正确的父节点,而非直接添加到根节点:
class Lineage: def __init__(self, name): self.name = name self.children = [] def add_to_tree(root, lineage_name): parts = lineage_name.split('.') current = root # 逐层定位父节点 for i in range(len(parts)-1): parent_path = '.'.join(parts[:i+1]) # 在当前节点的子节点中查找父节点 found = None for child in current.children: if child.name == parent_path: found = child break if found: current = found else: # 父节点不存在则先创建 new_node = Lineage(parent_path) current.children.append(new_node) current = new_node # 添加当前谱系节点 new_node = Lineage(lineage_name) current.children.append(new_node)
调用add_to_tree(root, "BA.1.1")时,会自动将节点挂载到BA.1下,而非直接作为BA的子节点。
内容的提问来源于stack exchange,提问作者Christopher Rucinski
相关产品推荐
相关产品推荐

