250 lines
		
	
	
		
			9.6 KiB
		
	
	
	
		
			Python
		
	
	
	
			
		
		
	
	
			250 lines
		
	
	
		
			9.6 KiB
		
	
	
	
		
			Python
		
	
	
	
| #!/usr/bin/env python3
 | |
| """
 | |
| 胡汉三千年项目历史数据可视化工具
 | |
| Historical Data Visualization Tool for Hu-Han Three Thousand Years Project
 | |
| """
 | |
| 
 | |
| import matplotlib.pyplot as plt
 | |
| import seaborn as sns
 | |
| import pandas as pd
 | |
| import numpy as np
 | |
| from typing import Dict, List, Any
 | |
| import json
 | |
| import os
 | |
| 
 | |
| # 设置中文字体
 | |
| plt.rcParams['font.sans-serif'] = ['SimHei', 'DejaVu Sans']
 | |
| plt.rcParams['axes.unicode_minus'] = False
 | |
| 
 | |
| class HistoricalDataVisualizer:
 | |
|     """历史数据可视化器"""
 | |
|     
 | |
|     def __init__(self, output_dir: str = "tools/diagrams/generated"):
 | |
|         self.output_dir = output_dir
 | |
|         os.makedirs(output_dir, exist_ok=True)
 | |
|         
 | |
|         # 设置样式
 | |
|         sns.set_style("whitegrid")
 | |
|         sns.set_palette("husl")
 | |
|     
 | |
|     def plot_emperor_ages(self, dynasty_data: Dict[str, List[int]], 
 | |
|                          title: str = "各朝代皇帝死亡年龄分析"):
 | |
|         """绘制皇帝年龄分析图"""
 | |
|         
 | |
|         fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(15, 6))
 | |
|         
 | |
|         # 左图:年龄分布直方图
 | |
|         for dynasty, ages in dynasty_data.items():
 | |
|             ax1.hist(ages, alpha=0.7, label=f"{dynasty} (平均:{np.mean(ages):.1f}岁)", 
 | |
|                     bins=10, density=True)
 | |
|         
 | |
|         ax1.set_xlabel('死亡年龄')
 | |
|         ax1.set_ylabel('密度')
 | |
|         ax1.set_title('皇帝死亡年龄分布')
 | |
|         ax1.legend()
 | |
|         ax1.grid(True, alpha=0.3)
 | |
|         
 | |
|         # 右图:平均年龄对比
 | |
|         dynasties = list(dynasty_data.keys())
 | |
|         avg_ages = [np.mean(ages) for ages in dynasty_data.values()]
 | |
|         median_ages = [np.median(ages) for ages in dynasty_data.values()]
 | |
|         
 | |
|         x = np.arange(len(dynasties))
 | |
|         width = 0.35
 | |
|         
 | |
|         ax2.bar(x - width/2, avg_ages, width, label='平均年龄', alpha=0.8)
 | |
|         ax2.bar(x + width/2, median_ages, width, label='中位数年龄', alpha=0.8)
 | |
|         
 | |
|         ax2.set_xlabel('朝代')
 | |
|         ax2.set_ylabel('年龄')
 | |
|         ax2.set_title('各朝代统治者年龄对比')
 | |
|         ax2.set_xticks(x)
 | |
|         ax2.set_xticklabels(dynasties)
 | |
|         ax2.legend()
 | |
|         ax2.grid(True, alpha=0.3)
 | |
|         
 | |
|         # 添加数值标签
 | |
|         for i, (avg, med) in enumerate(zip(avg_ages, median_ages)):
 | |
|             ax2.text(i - width/2, avg + 1, f'{avg:.1f}', ha='center', va='bottom')
 | |
|             ax2.text(i + width/2, med + 1, f'{med:.1f}', ha='center', va='bottom')
 | |
|         
 | |
|         plt.suptitle(title, fontsize=16, fontweight='bold')
 | |
|         plt.tight_layout()
 | |
|         
 | |
|         # 保存图片
 | |
|         filename = f"{self.output_dir}/emperor_ages_analysis.png"
 | |
|         plt.savefig(filename, dpi=300, bbox_inches='tight')
 | |
|         plt.show()
 | |
|         
 | |
|         return filename
 | |
|     
 | |
|     def plot_cultural_influence_network(self, influence_data: Dict[str, Any],
 | |
|                                       title: str = "文化影响传播网络"):
 | |
|         """绘制文化影响网络图"""
 | |
|         
 | |
|         import networkx as nx
 | |
|         
 | |
|         fig, ax = plt.subplots(figsize=(12, 8))
 | |
|         
 | |
|         # 创建网络图
 | |
|         G = nx.DiGraph()
 | |
|         
 | |
|         # 添加节点和边
 | |
|         for edge in influence_data['edges']:
 | |
|             G.add_edge(edge['from'], edge['to'], 
 | |
|                       weight=edge.get('strength', 1),
 | |
|                       influence=edge.get('influence', ''))
 | |
|         
 | |
|         # 设置布局
 | |
|         pos = nx.spring_layout(G, k=3, iterations=50)
 | |
|         
 | |
|         # 绘制节点
 | |
|         node_sizes = [3000 if node in influence_data.get('core_nodes', []) else 2000 
 | |
|                      for node in G.nodes()]
 | |
|         node_colors = ['red' if node in influence_data.get('core_nodes', []) else 'lightblue' 
 | |
|                       for node in G.nodes()]
 | |
|         
 | |
|         nx.draw_networkx_nodes(G, pos, node_size=node_sizes, 
 | |
|                               node_color=node_colors, alpha=0.8, ax=ax)
 | |
|         
 | |
|         # 绘制边
 | |
|         nx.draw_networkx_edges(G, pos, edge_color='gray', 
 | |
|                               arrows=True, arrowsize=20, 
 | |
|                               arrowstyle='->', alpha=0.6, ax=ax)
 | |
|         
 | |
|         # 添加标签
 | |
|         nx.draw_networkx_labels(G, pos, font_size=12, font_weight='bold', ax=ax)
 | |
|         
 | |
|         # 添加边标签(影响类型)
 | |
|         edge_labels = {(edge['from'], edge['to']): edge.get('influence', '') 
 | |
|                       for edge in influence_data['edges']}
 | |
|         nx.draw_networkx_edge_labels(G, pos, edge_labels, font_size=8, ax=ax)
 | |
|         
 | |
|         ax.set_title(title, fontsize=16, fontweight='bold')
 | |
|         ax.axis('off')
 | |
|         
 | |
|         # 添加图例
 | |
|         legend_elements = [
 | |
|             plt.Line2D([0], [0], marker='o', color='w', markerfacecolor='red', 
 | |
|                       markersize=15, label='核心影响源'),
 | |
|             plt.Line2D([0], [0], marker='o', color='w', markerfacecolor='lightblue', 
 | |
|                       markersize=15, label='影响接受方'),
 | |
|             plt.Line2D([0], [0], color='gray', label='影响路径')
 | |
|         ]
 | |
|         ax.legend(handles=legend_elements, loc='upper right')
 | |
|         
 | |
|         plt.tight_layout()
 | |
|         
 | |
|         # 保存图片
 | |
|         filename = f"{self.output_dir}/cultural_influence_network.png"
 | |
|         plt.savefig(filename, dpi=300, bbox_inches='tight')
 | |
|         plt.show()
 | |
|         
 | |
|         return filename
 | |
|     
 | |
|     def plot_timeline_analysis(self, timeline_data: List[Dict[str, Any]],
 | |
|                               title: str = "历史事件时间线分析"):
 | |
|         """绘制历史事件时间线"""
 | |
|         
 | |
|         fig, ax = plt.subplots(figsize=(15, 8))
 | |
|         
 | |
|         # 准备数据
 | |
|         events = sorted(timeline_data, key=lambda x: x['year'])
 | |
|         years = [event['year'] for event in events]
 | |
|         categories = list(set(event['category'] for event in events))
 | |
|         
 | |
|         # 为每个类别分配颜色和y位置
 | |
|         colors = plt.cm.Set3(np.linspace(0, 1, len(categories)))
 | |
|         category_colors = dict(zip(categories, colors))
 | |
|         category_positions = {cat: i for i, cat in enumerate(categories)}
 | |
|         
 | |
|         # 绘制时间线
 | |
|         for event in events:
 | |
|             y_pos = category_positions[event['category']]
 | |
|             color = category_colors[event['category']]
 | |
|             
 | |
|             # 绘制事件点
 | |
|             ax.scatter(event['year'], y_pos, s=200, c=[color], 
 | |
|                       alpha=0.8, edgecolors='black', linewidth=1)
 | |
|             
 | |
|             # 添加事件标签
 | |
|             ax.annotate(event['name'], 
 | |
|                        (event['year'], y_pos),
 | |
|                        xytext=(10, 10), textcoords='offset points',
 | |
|                        bbox=dict(boxstyle='round,pad=0.3', facecolor=color, alpha=0.7),
 | |
|                        fontsize=9, ha='left')
 | |
|         
 | |
|         # 设置坐标轴
 | |
|         ax.set_xlabel('年份', fontsize=12)
 | |
|         ax.set_ylabel('事件类别', fontsize=12)
 | |
|         ax.set_yticks(range(len(categories)))
 | |
|         ax.set_yticklabels(categories)
 | |
|         ax.set_title(title, fontsize=16, fontweight='bold')
 | |
|         
 | |
|         # 添加网格
 | |
|         ax.grid(True, alpha=0.3)
 | |
|         
 | |
|         # 设置x轴范围
 | |
|         year_range = max(years) - min(years)
 | |
|         ax.set_xlim(min(years) - year_range * 0.05, max(years) + year_range * 0.05)
 | |
|         
 | |
|         plt.tight_layout()
 | |
|         
 | |
|         # 保存图片
 | |
|         filename = f"{self.output_dir}/timeline_analysis.png"
 | |
|         plt.savefig(filename, dpi=300, bbox_inches='tight')
 | |
|         plt.show()
 | |
|         
 | |
|         return filename
 | |
| 
 | |
| def create_northern_wei_analysis():
 | |
|     """创建北魏分析示例"""
 | |
|     
 | |
|     viz = HistoricalDataVisualizer()
 | |
|     
 | |
|     # 示例数据:各朝代皇帝年龄
 | |
|     dynasty_data = {
 | |
|         '北魏': [16, 23, 29, 31, 33, 28, 25, 39, 27, 24, 32, 26],  # 平均29岁
 | |
|         '唐朝': [49, 52, 45, 55, 47, 38, 43, 51, 46, 44, 48, 50],  # 平均47岁
 | |
|         '宋朝': [42, 38, 54, 46, 49, 41, 35, 52, 44, 47, 43, 45],  # 平均45岁
 | |
|         '日本天皇': [34, 31, 28, 36, 32, 29, 35, 33, 30, 37, 31, 34]  # 平均32岁
 | |
|     }
 | |
|     
 | |
|     # 生成皇帝年龄分析图
 | |
|     viz.plot_emperor_ages(dynasty_data, "北魏生殖崇拜理论:皇帝年龄数据支撑")
 | |
|     
 | |
|     # 文化影响网络数据
 | |
|     influence_data = {
 | |
|         'core_nodes': ['北魏'],
 | |
|         'edges': [
 | |
|             {'from': '北魏', 'to': '高句丽', 'influence': '政治制度', 'strength': 3},
 | |
|             {'from': '北魏', 'to': '百济', 'influence': '佛教文化', 'strength': 2},
 | |
|             {'from': '高句丽', 'to': '日本', 'influence': '建筑艺术', 'strength': 2},
 | |
|             {'from': '百济', 'to': '日本', 'influence': '宗教仪式', 'strength': 3},
 | |
|             {'from': '北魏', 'to': '新罗', 'influence': '文字系统', 'strength': 1},
 | |
|             {'from': '新罗', 'to': '日本', 'influence': '学术传统', 'strength': 1}
 | |
|         ]
 | |
|     }
 | |
|     
 | |
|     # 生成文化影响网络图
 | |
|     viz.plot_cultural_influence_network(influence_data, "北魏对日本文化影响的传播路径")
 | |
|     
 | |
|     # 时间线数据
 | |
|     timeline_data = [
 | |
|         {'year': 386, 'name': '北魏建立', 'category': '政治事件'},
 | |
|         {'year': 398, 'name': '迁都平城', 'category': '政治事件'},
 | |
|         {'year': 494, 'name': '孝文帝改革', 'category': '文化改革'},
 | |
|         {'year': 538, 'name': '佛教传入日本', 'category': '文化传播'},
 | |
|         {'year': 552, 'name': '百济使者访日', 'category': '外交事件'},
 | |
|         {'year': 593, 'name': '圣德太子摄政', 'category': '政治事件'},
 | |
|         {'year': 645, 'name': '大化改新', 'category': '文化改革'}
 | |
|     ]
 | |
|     
 | |
|     # 生成时间线分析图
 | |
|     viz.plot_timeline_analysis(timeline_data, "北魏影响日本的历史时间线")
 | |
|     
 | |
|     print("✅ 北魏分析可视化图表已生成!")
 | |
|     print(f"📁 图片保存位置: {viz.output_dir}")
 | |
| 
 | |
| if __name__ == "__main__":
 | |
|     create_northern_wei_analysis() |