import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from scipy.stats import gaussian_kde
plt.rcParams['font.sans-serif'] = ['SimSun'] # 修改为宋体
plt.rcParams['axes.unicode_minus'] = False # 解决负号显示问题
# 读取Excel数据文件
file_path = r"C:\Users.xlsx"
df = pd.read_excel(file_path)
# 数据清洗
df['year'] = df['year'].astype(int)
df['value'] = pd.to_numeric(df['value'], errors='coerce')
df = df.dropna()
# 设置绘图参数
years = sorted(df['year'].unique())
n_years = len(years)
offset_step = 5 # 初始层间距
x_margin = 0.5 # 缩小横向留白
line_alpha = 1
# 创建紧凑画布
plt.figure(figsize=(7, 5), dpi=120) # 进一步缩小画布
ax = plt.gca()
# 动态计算坐标范围
global_min = df['value'].min()
global_max = df['value'].max()
x_range = global_max - global_min
x = np.linspace(global_min - x_margin * x_range,
global_max + x_margin * x_range,
2000)
max_y_total = 0 # 记录最大高度
year_labels = [] # 存储年份标签位置
# 绘制密度曲线
for idx, year in enumerate(years):
year_data = df[df['year'] == year]['value'].values
kde = gaussian_kde(year_data)
y = kde.evaluate(x)
vertical_offset = idx * offset_step
# 动态调整层间距
current_peak = y.max() + vertical_offset
if current_peak > max_y_total:
max_y_total = current_peak
# 控制曲线边界不接触坐标轴
mask = y > 0.005 # 仅显示密度>0.5%的区域
filtered_x = x[mask]
filtered_y = y[mask]
ax.fill_between(filtered_x,
vertical_offset,
filtered_y + vertical_offset,
color='#f0f0f0',
alpha=0.8,
edgecolor='none')
ax.plot(filtered_x,
filtered_y + vertical_offset,
color='k',
lw=0.8,
alpha=line_alpha)
year_labels.append(vertical_offset + offset_step / 2) # 标签居中位置
# 设置坐标轴边界
ax.set_xlim(x.min(), x.max())
ax.set_ylim(0, max_y_total * 1.08) # 自动适配顶部空间
# 设置X轴刻度(关键修改)
xticks = np.linspace(0, x.max(), 5) # 从0开始生成刻度
ax.set_xticks(xticks)
ax.set_xticklabels([f"{t:.2f}" if t != 0 else "0" for t in xticks]) # 格式化标签
# 设置年份刻度
ax.set_yticks(year_labels)
ax.set_yticklabels(years)
ax.tick_params(axis='y', labelsize=8)
ax.set_ylabel("年份", fontsize=9, labelpad=5)
# 优化其他元素
plt.xlabel("哈哈哈", fontsize=9, labelpad=6)
plt.tight_layout()
# 显示图形
plt.show()
这是山峦型核密度曲线的绘制代码,分享出来欢迎探讨优化