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() |