huhan3000/胡汉三千年项目/可视化工具/符号可视化系统.py

492 lines
17 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
符号传承可视化系统
胡汉三千年项目可视化工具
功能:实现符号传播路径、阴阳对应关系、跨文明关联的可视化展示
"""
import json
import sqlite3
import matplotlib.pyplot as plt
import networkx as nx
from typing import Dict, List, Tuple
from datetime import datetime
import numpy as np
from enum import Enum
class VisualizationType(Enum):
"""可视化类型枚举"""
TRANSMISSION_MAP = "transmission_map" # 传播地图
TIMELINE = "timeline" # 时间线
YIN_YANG_MATRIX = "yin_yang_matrix" # 阴阳矩阵
CIVILIZATION_NETWORK = "civilization_network" # 文明网络
class SymbolVisualizer:
"""符号可视化系统"""
def __init__(self, db_path: str = "symbols.db"):
"""初始化可视化系统"""
self.db_path = db_path
self.conn = sqlite3.connect(db_path)
# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei', 'DejaVu Sans']
plt.rcParams['axes.unicode_minus'] = False
def plot_transmission_map(self, symbol_id: str, save_path: str = None):
"""
绘制符号传播地图
Args:
symbol_id: 符号ID
save_path: 保存路径(可选)
"""
# 获取传播路径数据
cursor = self.conn.cursor()
cursor.execute("""
WITH RECURSIVE symbol_path AS (
SELECT s.symbol_id, s.origin_civilization, s.origin_period, 0 as depth
FROM symbols s
WHERE s.symbol_id = ?
UNION ALL
SELECT s.symbol_id, s.origin_civilization, s.origin_period, sp.depth + 1
FROM symbols s
JOIN cross_civilization_links l ON s.symbol_id = l.target_symbol_id
JOIN symbol_path sp ON l.source_symbol_id = sp.symbol_id
WHERE sp.depth < 10
)
SELECT * FROM symbol_path
ORDER BY depth
""", (symbol_id,))
path_data = cursor.fetchall()
if not path_data:
print("未找到传播路径数据")
return
# 创建图形
fig, ax = plt.subplots(figsize=(12, 8))
# 定义文明位置(简化版世界地图)
civilization_positions = {
"Chinese": (1, 3), # 中国
"Greek": (0, 2), # 希腊
"Roman": (-1, 1), # 罗马
"European": (-2, 0), # 欧洲
"Global": (-3, -1) # 全球
}
# 绘制传播路径
x_coords = []
y_coords = []
labels = []
for i, (sym_id, civ, period, depth) in enumerate(path_data):
if civ in civilization_positions:
x, y = civilization_positions[civ]
x_coords.append(x)
y_coords.append(y)
labels.append(f"{sym_id}\n({civ}, {period})")
# 绘制连线
ax.plot(x_coords, y_coords, 'o-', linewidth=2, markersize=8,
markerfacecolor='red', markeredgecolor='black')
# 添加标签
for i, (x, y) in enumerate(zip(x_coords, y_coords)):
ax.annotate(labels[i], (x, y), xytext=(5, 5),
textcoords='offset points', fontsize=8)
# 设置图形属性
ax.set_title(f'符号传播路径:{symbol_id}', fontsize=14, fontweight='bold')
ax.set_xlabel('文明传播方向(西→东)')
ax.set_ylabel('时间维度')
ax.grid(True, alpha=0.3)
# 调整坐标轴范围
ax.set_xlim(min(x_coords)-1, max(x_coords)+1)
ax.set_ylim(min(y_coords)-1, max(y_coords)+1)
if save_path:
plt.savefig(save_path, dpi=300, bbox_inches='tight')
print(f"传播地图已保存至:{save_path}")
plt.show()
def plot_timeline(self, symbol_family: List[str], save_path: str = None):
"""
绘制符号家族时间线
Args:
symbol_family: 符号家族ID列表
save_path: 保存路径(可选)
"""
cursor = self.conn.cursor()
# 获取符号时间数据
timeline_data = []
for symbol_id in symbol_family:
cursor.execute("""
SELECT symbol_id, symbol_form, symbol_name, origin_civilization, origin_period
FROM symbols
WHERE symbol_id = ?
""", (symbol_id,))
result = cursor.fetchone()
if result:
timeline_data.append(result)
if not timeline_data:
print("未找到符号数据")
return
# 解析时间信息(简化处理)
time_mapping = {
"Zhou Dynasty": -1000, # 周朝
"8th century BCE": -800, # 公元前8世纪
"Roman": -200, # 罗马时期
"European": 1000, # 欧洲中世纪
"Global": 1500 # 大航海时代
}
# 创建时间线图
fig, ax = plt.subplots(figsize=(14, 6))
y_positions = []
time_points = []
labels = []
for i, (sym_id, form, name, civ, period) in enumerate(timeline_data):
time_point = time_mapping.get(civ, 0)
time_points.append(time_point)
y_positions.append(i)
labels.append(f"{form} ({name})\n{civ}, {period}")
# 绘制时间线
ax.plot(time_points, y_positions, 'o-', linewidth=3, markersize=10,
markerfacecolor='blue', markeredgecolor='black')
# 添加标签
for i, (time, y, label) in enumerate(zip(time_points, y_positions, labels)):
ax.annotate(label, (time, y), xytext=(10, 0),
textcoords='offset points', fontsize=9,
bbox=dict(boxstyle="round,pad=0.3", facecolor="lightblue", alpha=0.7))
# 设置图形属性
ax.set_title('符号家族时间线', fontsize=14, fontweight='bold')
ax.set_xlabel('时间(公元前→公元后)')
ax.set_ylabel('符号序列')
ax.grid(True, alpha=0.3)
# 调整坐标轴
ax.set_xlim(min(time_points)-500, max(time_points)+500)
ax.set_ylim(-1, len(y_positions))
if save_path:
plt.savefig(save_path, dpi=300, bbox_inches='tight')
print(f"时间线图已保存至:{save_path}")
plt.show()
def plot_yin_yang_matrix(self, save_path: str = None):
"""
绘制阴阳符号矩阵
Args:
save_path: 保存路径(可选)
"""
cursor = self.conn.cursor()
# 获取所有符号的阴阳属性
cursor.execute("""
SELECT symbol_id, symbol_form, yin_yang_attribute, engraving_type, origin_civilization
FROM symbols
ORDER BY origin_civilization, yin_yang_attribute
""")
symbols_data = cursor.fetchall()
if not symbols_data:
print("未找到符号数据")
return
# 创建阴阳矩阵
civilizations = sorted(set([row[4] for row in symbols_data]))
yin_yang_types = ['yin', 'yang', 'neutral']
# 统计每个文明-阴阳组合的符号数量
matrix_data = np.zeros((len(civilizations), len(yin_yang_types)))
for row in symbols_data:
sym_id, form, yin_yang, engraving, civ = row
civ_index = civilizations.index(civ)
yin_yang_index = yin_yang_types.index(yin_yang)
matrix_data[civ_index, yin_yang_index] += 1
# 创建热力图
fig, ax = plt.subplots(figsize=(10, 8))
im = ax.imshow(matrix_data, cmap='YlOrRd', aspect='auto')
# 设置坐标轴标签
ax.set_xticks(np.arange(len(yin_yang_types)))
ax.set_yticks(np.arange(len(civilizations)))
ax.set_xticklabels(yin_yang_types)
ax.set_yticklabels(civilizations)
# 添加数值标签
for i in range(len(civilizations)):
for j in range(len(yin_yang_types)):
text = ax.text(j, i, int(matrix_data[i, j]),
ha="center", va="center", color="black", fontweight='bold')
# 设置图形属性
ax.set_title('阴阳符号分布矩阵', fontsize=14, fontweight='bold')
ax.set_xlabel('阴阳属性')
ax.set_ylabel('文明')
# 添加颜色条
cbar = ax.figure.colorbar(im, ax=ax)
cbar.ax.set_ylabel('符号数量', rotation=-90, va="bottom")
if save_path:
plt.savefig(save_path, dpi=300, bbox_inches='tight')
print(f"阴阳矩阵图已保存至:{save_path}")
plt.show()
def plot_civilization_network(self, save_path: str = None):
"""
绘制文明网络图
Args:
save_path: 保存路径(可选)
"""
cursor = self.conn.cursor()
# 获取文明关联数据
cursor.execute("""
SELECT DISTINCT s1.origin_civilization, s2.origin_civilization, COUNT(*) as link_count
FROM cross_civilization_links l
JOIN symbols s1 ON l.source_symbol_id = s1.symbol_id
JOIN symbols s2 ON l.target_symbol_id = s2.symbol_id
WHERE s1.origin_civilization != s2.origin_civilization
GROUP BY s1.origin_civilization, s2.origin_civilization
HAVING link_count > 0
""")
network_data = cursor.fetchall()
if not network_data:
print("未找到文明关联数据")
return
# 创建网络图
G = nx.Graph()
# 添加节点和边
for source_civ, target_civ, weight in network_data:
G.add_edge(source_civ, target_civ, weight=weight)
# 设置节点位置
pos = nx.spring_layout(G, k=1, iterations=50)
# 绘制网络图
fig, ax = plt.subplots(figsize=(12, 10))
# 计算节点大小(基于连接数量)
node_sizes = [G.degree(node) * 500 for node in G.nodes()]
# 绘制边
edge_widths = [G[u][v]['weight'] for u, v in G.edges()]
nx.draw_networkx_edges(G, pos, alpha=0.5, width=edge_widths,
edge_color='gray')
# 绘制节点
nx.draw_networkx_nodes(G, pos, node_size=node_sizes,
node_color='lightblue', alpha=0.9,
edgecolors='black')
# 绘制标签
nx.draw_networkx_labels(G, pos, font_size=10, font_weight='bold')
# 设置图形属性
ax.set_title('文明符号传播网络', fontsize=16, fontweight='bold')
ax.axis('off')
# 添加图例
ax.text(0.02, 0.98, '节点大小:连接数量\n边宽度:关联强度',
transform=ax.transAxes, fontsize=10,
bbox=dict(boxstyle="round,pad=0.3", facecolor="white", alpha=0.8))
if save_path:
plt.savefig(save_path, dpi=300, bbox_inches='tight')
print(f"文明网络图已保存至:{save_path}")
plt.show()
def create_comparison_chart(self, symbol_list: List[str], save_path: str = None):
"""
创建符号对比图表
Args:
symbol_list: 符号ID列表
save_path: 保存路径(可选)
"""
cursor = self.conn.cursor()
# 获取符号对比数据
comparison_data = []
for symbol_id in symbol_list:
cursor.execute("""
SELECT symbol_id, symbol_form, symbol_name, yin_yang_attribute,
engraving_type, origin_civilization, origin_period
FROM symbols
WHERE symbol_id = ?
""", (symbol_id,))
result = cursor.fetchone()
if result:
comparison_data.append(result)
if not comparison_data:
print("未找到符号数据")
return
# 创建对比图表
fig, axes = plt.subplots(2, 2, figsize=(15, 12))
fig.suptitle('符号对比分析', fontsize=16, fontweight='bold')
# 1. 阴阳属性分布
yin_yang_counts = {'yin': 0, 'yang': 0, 'neutral': 0}
for data in comparison_data:
yin_yang = data[3]
yin_yang_counts[yin_yang] += 1
axes[0, 0].pie(yin_yang_counts.values(), labels=yin_yang_counts.keys(),
autopct='%1.1f%%', startangle=90)
axes[0, 0].set_title('阴阳属性分布')
# 2. 刻法类型分布
engraving_counts = {'yin_engraving': 0, 'yang_engraving': 0, 'mixed': 0}
for data in comparison_data:
engraving = data[4]
engraving_counts[engraving] += 1
axes[0, 1].bar(engraving_counts.keys(), engraving_counts.values(),
color=['lightcoral', 'lightblue', 'lightgreen'])
axes[0, 1].set_title('刻法类型分布')
axes[0, 1].tick_params(axis='x', rotation=45)
# 3. 文明分布
civilization_counts = {}
for data in comparison_data:
civ = data[5]
civilization_counts[civ] = civilization_counts.get(civ, 0) + 1
axes[1, 0].barh(list(civilization_counts.keys()), list(civilization_counts.values()),
color='lightsteelblue')
axes[1, 0].set_title('文明分布')
# 4. 符号形态展示
symbol_forms = [data[1] for data in comparison_data]
symbol_names = [data[2] for data in comparison_data]
axes[1, 1].text(0.5, 0.5, '\n'.join([f"{form}: {name}" for form, name in zip(symbol_forms, symbol_names)]),
ha='center', va='center', transform=axes[1, 1].transAxes,
fontsize=12, bbox=dict(boxstyle="round,pad=0.5", facecolor="wheat", alpha=0.5))
axes[1, 1].set_title('符号形态列表')
axes[1, 1].axis('off')
plt.tight_layout()
if save_path:
plt.savefig(save_path, dpi=300, bbox_inches='tight')
print(f"对比图表已保存至:{save_path}")
plt.show()
def export_visualization_report(self, symbol_id: str, output_dir: str = "./reports"):
"""
导出完整的可视化报告
Args:
symbol_id: 符号ID
output_dir: 输出目录
"""
import os
os.makedirs(output_dir, exist_ok=True)
# 生成各种可视化图表
visualizations = [
("transmission_map", self.plot_transmission_map),
("yin_yang_matrix", self.plot_yin_yang_matrix),
("civilization_network", self.plot_civilization_network)
]
generated_files = []
for viz_name, viz_func in visualizations:
file_path = os.path.join(output_dir, f"{symbol_id}_{viz_name}.png")
try:
if viz_name == "transmission_map":
viz_func(symbol_id, file_path)
else:
viz_func(file_path)
generated_files.append(file_path)
print(f"生成图表:{file_path}")
except Exception as e:
print(f"生成 {viz_name} 时出错:{e}")
# 创建报告文件
report_path = os.path.join(output_dir, f"{symbol_id}_visualization_report.md")
with open(report_path, 'w', encoding='utf-8') as f:
f.write(f"# 符号可视化报告:{symbol_id}\n\n")
f.write(f"生成时间:{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n\n")
for file_path in generated_files:
filename = os.path.basename(file_path)
f.write(f"## {filename.replace('_', ' ').replace('.png', '')}\n\n")
f.write(f"![{filename}]({filename})\n\n")
print(f"可视化报告已生成:{report_path}")
return generated_files
# 使用示例
def main():
"""主函数示例"""
# 创建可视化系统
visualizer = SymbolVisualizer()
# 示例1绘制P符号传播地图
print("=== 绘制P符号传播地图 ===")
visualizer.plot_transmission_map("P_yin_001")
# 示例2绘制阴阳符号矩阵
print("=== 绘制阴阳符号矩阵 ===")
visualizer.plot_yin_yang_matrix()
# 示例3绘制文明网络图
print("=== 绘制文明网络图 ===")
visualizer.plot_civilization_network()
# 示例4创建符号对比图表
print("=== 创建符号对比图表 ===")
symbol_list = ["P_yin_001", "T_yang_001", "Pi_yin_001", "Tau_yang_001"]
visualizer.create_comparison_chart(symbol_list)
# 示例5导出完整可视化报告
print("=== 导出完整可视化报告 ===")
visualizer.export_visualization_report("P_yin_001")
if __name__ == "__main__":
main()