import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from matplotlib.cm import ScalarMappable
from matplotlib.colors import Normalize
from matplotlib.patches import Patch
# ===== 强制中文字体设置 =====
plt.rcParams['font.sans-serif'] = ['SimHei', 'Microsoft YaHei', 'Arial Unicode MS']
plt.rcParams['axes.unicode_minus'] = False
# ========== 1. 读取Excel数据 ==========
file_path = r"D:/趋势图.xlsx"
df = pd.read_excel(file_path, engine='openpyxl')
categories = df["区间"].values
area_before = df["作业前面积"].values
area_after = df["作业后面积"].values
# 清洗标签
clean_categories = []
for label in categories:
label_str = str(label)
label_str = label_str.replace('-0.0', '0')
label_str = label_str.replace('--', '-')
clean_categories.append(label_str)
# ========== 2. 双环形图 ==========
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(14, 7), subplot_kw=dict(projection='polar'))
fig.suptitle('作业前后面积分布对比', fontsize=18, fontweight='bold', y=0.98)
angles = np.linspace(0, 2 * np.pi, len(categories), endpoint=False).tolist()
angles += angles[:1]
# ===== 统一刻度:0-50,步长5 =====
max_val = 50
yticks = np.arange(0, 51, 5)
# ===== 两边都用蓝色 =====
colors = plt.cm.Blues(np.linspace(0.3, 0.9, len(categories)))
# ----- 左图:作业前面积 -----
data_before = area_before.tolist() + area_before[:1].tolist()
ax1.bar(angles, data_before, width=0.6, color=colors, alpha=0.8, edgecolor='white', linewidth=1)
ax1.set_xticks(angles[:-1])
ax1.set_xticklabels(clean_categories, fontsize=15)
ax1.set_title('作业前面积', fontsize=14, fontweight='bold', pad=15)
ax1.set_ylim(0, max_val)
ax1.set_yticks(yticks)
ax1.set_yticklabels([str(int(y)) for y in yticks], fontsize=12)
# for i, (angle, val) in enumerate(zip(angles[:-1], area_before)):
# if val > 1:
# ax1.text(angle, val + 2, f'{val:.1f}', fontsize=8, ha='center', va='center', color='blue')
# ----- 右图:作业后面积 -----
data_after = area_after.tolist() + area_after[:1].tolist()
ax2.bar(angles, data_after, width=0.6, color=colors, alpha=0.8, edgecolor='white', linewidth=1)
ax2.set_xticks(angles[:-1])
ax2.set_xticklabels(clean_categories, fontsize=15)
ax2.set_title('作业后面积', fontsize=14, fontweight='bold', pad=15)
ax2.set_ylim(0, max_val)
ax2.set_yticks(yticks)
ax2.set_yticklabels([str(int(y)) for y in yticks], fontsize=12)
# for i, (angle, val) in enumerate(zip(angles[:-1], area_after)):
# if val > 1:
# ax2.text(angle, val + 2, f'{val:.1f}', fontsize=8, ha='center', va='center', color='blue')
# ========== 3. 添加图例(说明外圈是NDVI区间)==========
from matplotlib.patches import Patch
# 创建一个图例,说明外圈标签的含义
legend_elements = [
Patch(facecolor='none', edgecolor='none', label='外圈 = NDVI区间'),
Patch(facecolor='#4a9eff', alpha=0.6, edgecolor='white', label='面积值(颜色越深越大)')
]
# 左图图例
ax1.legend(handles=legend_elements, loc='upper center', bbox_to_anchor=(1.2, 1.2), fontsize=10,
facecolor='white', edgecolor='black', framealpha=0.9)
# 右图图例
ax2.legend(handles=legend_elements, loc='upper center', bbox_to_anchor=(1.2, 1.2), fontsize=10,
facecolor='white', edgecolor='black', framealpha=0.9)
# ========== 4. 添加颜色条 ==========
norm = Normalize(vmin=0, vmax=50)
cbar1 = fig.colorbar(ScalarMappable(norm=norm, cmap=plt.cm.Blues), ax=ax1, orientation='vertical',
pad=0.12, shrink=0.6)
cbar1.set_label('面积值', fontsize=10)
cbar2 = fig.colorbar(ScalarMappable(norm=norm, cmap=plt.cm.Blues), ax=ax2, orientation='vertical',
pad=0.12, shrink=0.6)
cbar2.set_label('面积值', fontsize=10)
plt.tight_layout()
plt.show()