如何让Plotly Sankey图节点按A/B/C/D/E或mapping_dict顺序排列?
如何让Plotly Sankey图节点按指定顺序排列?
我正在使用go.Plotly绘制Sankey图,希望节点按指定顺序输出:要么匹配mapping_dict的顺序,要么至少让每个节点的类别保持A、B、C、D、E的固定顺序(即使某个类别缺失也维持该顺序)。已查阅过相关问题,但初始结构与我的场景不同,因此不认为这是重复问题。
函数调用
fig = plot_sankey(links_dict, unique_source_targets, mapping_dict, colors=colors)
示例数据
mapping_dict
mapping_dict = { 'B_round1': 0, 'C_round1': 1, 'D_round1': 2, 'E_round1': 3, 'A_round2': 4, 'B_round2': 5, 'C_round2': 6, 'D_round2': 7, 'E_round2': 8, 'A_round3': 9, 'B_round3': 10, 'C_round3': 11, 'D_round3': 12, 'E_round3': 13 }
unique_source_targets
unique_source_targets = [ 'B_round1', 'C_round1', 'D_round1', 'E_round1', 'A_round2', 'B_round2', 'C_round2', 'D_round2', 'E_round2', 'A_round3', 'B_round3', 'C_round3', 'D_round3', 'E_round3' ]
links_dict
links_dict = { 'source': [0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8], 'target': [4, 5, 6, 7, 8, 4, 5, 6, 7, 8, 4, 5, 6, 7, 8, 4, 5, 6, 7, 8, 9, 10, 9, 10, 11, 12, 13, 9, 10, 11, 12, 13, 9, 10, 11, 12, 13, 9, 10, 11, 12, 13], 'value': [1433, 2761, 521, 205, 117, 239, 472, 122, 61, 31, 282, 222, 81, 71, 77, 276, 59, 41, 60, 161, 2224, 6, 548, 2449, 371, 110, 36, 155, 482, 80, 34, 14, 105, 164, 52, 46, 30, 175, 47, 23, 37, 104] }
核心代码
plot_sankey函数
import plotly.graph_objects as go def plot_sankey( links_dict, unique_source_targets, mapping_dict, colors=None, fig_title='Sankey Diagram', subtitle='' ): # 生成带数值和百分比的格式化标签 formatted_labels = compute_round_labels(links_dict, unique_source_targets, mapping_dict) # 将unique_source_target列表转换为用于展示的格式化标签 display_labels = [formatted_labels[label] for label in unique_source_targets] fig = go.Figure( data=[ go.Sankey( node=dict( pad=15, thickness=20, line=dict(color="black", width=0.5), label=display_labels, color=(colors if colors else "blue"), ), link=dict( source=links_dict["source"], target=links_dict["target"], value=links_dict["value"], ), ) ] ) # 使用HTML格式设置标题和副标题 full_title = f'{fig_title}<br><sub>{subtitle}</sub>' fig.update_layout(title_text=full_title, font_size=20) # 调整布局边距以容纳标题和副标题 fig.update_layout( margin=dict(t=100) # 顶部边距;如果标题和副标题被截断可增大该值 ) return fig
compute_labels函数
from collections import defaultdict def compute_labels(links_dict, unique_source_targets, mapping_dict): category_totals = defaultdict(int) label_counts = defaultdict(int) # 针对_round1和_round2,按源索引累加数值 for source, value in zip(links_dict['source'], links_dict['value']): label = unique_source_targets[source] category_type = label.rsplit('_', 1)[1] # 提取轮次类型,如'round1' category_totals[category_type] += value label_counts[label] += value # 针对_round3,使用目标索引做特殊处理 for target, value in zip(links_dict['target'], links_dict['value']): # 检查目标索引是否存在于mapping_dict的值中 if target in mapping_dict.values(): # 匹配目标索引对应的标签 label = next((label for label, index in mapping_dict.items() if index == target), None) if label and label.endswith('round3'): # 确保是_round3标签 category_type = label.rsplit('_', 1)[1] category_totals[category_type] += value label_counts[label] += value # 格式化标签,添加数值和百分比 formatted_labels = {} for label, count in label_counts.items(): category_type = label.rsplit('_', 1)[1] round_total = category_totals[category_type] percentage = int(round((count / round_total) * 100, 0)) formatted_labels[label] = f"{label} ({count}, {percentage}%)" return formatted_labels
内容的提问来源于stack exchange,提问作者CiviLearner
相关产品推荐
相关产品推荐

