#!/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()