You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何获取Seaborn jointplot的最大密度坐标并标注最密区域?

嘿,我来帮你搞定这个问题!你想在Seaborn的jointplot里找到KDE密度最高的位置,还要给中心图的最密区域做标注对吧?其实不用瞎找那些复杂的绘图属性,我们可以直接从KDE模型或者绘图元素里提取数据,一步步来:

1. 获取顶部/右侧单变量KDE的峰值位置

jointplot返回的对象p里,顶部的x轴KDE子图是p.ax_marg_x,右侧的y轴KDE子图是p.ax_marg_y。每个子图里的KDE曲线是lines对象,我们可以提取它的坐标数据,找到密度最大的位置:

# 获取顶部x轴KDE的峰值位置
x_kde_line = p.ax_marg_x.lines[0]
x_kde_x = x_kde_line.get_xdata()  # x轴变量的取值
x_kde_y = x_kde_line.get_ydata()  # 对应的密度值
x_peak = x_kde_x[np.argmax(x_kde_y)]  # 密度最大的x值

# 获取右侧y轴KDE的峰值位置
y_kde_line = p.ax_marg_y.lines[0]
y_kde_x = y_kde_line.get_xdata()  # y轴变量的取值
y_kde_y = y_kde_line.get_ydata()  # 对应的密度值
y_peak = y_kde_x[np.argmax(y_kde_y)]  # 密度最大的y值

print(f"x轴单变量密度峰值位置: {x_peak:.2f}")
print(f"y轴单变量密度峰值位置: {y_peak:.2f}")

2. 获取中心二维KDE的最密区域(峰值点)

如果要找中心图里二维密度最高的点,直接从等高线里提取可能不够准确,我们可以用Seaborn底层依赖的scipy.stats.gaussian_kde重新拟合数据,生成精细网格后找到最大值位置:

from scipy.stats import gaussian_kde

# 用原始数据拟合二维KDE模型
kde = gaussian_kde(df[['x','y']].T)

# 创建覆盖数据范围的精细网格
xx, yy = np.meshgrid(
    np.linspace(df['x'].min(), df['x'].max(), 1000),
    np.linspace(df['y'].min(), df['y'].max(), 1000)
)

# 计算网格上每个点的密度值
z = kde(np.vstack([xx.ravel(), yy.ravel()]))
z = z.reshape(xx.shape)

# 找到密度最大的点坐标
max_idx = np.unravel_index(np.argmax(z), z.shape)
peak_x, peak_y = xx[max_idx], yy[max_idx]

print(f"二维KDE密度峰值位置: ({peak_x:.2f}, {peak_y:.2f})")

3. 在图上标注峰值位置

拿到峰值坐标后,我们可以用散点和文本在中心图上标注出来:

# 用红色星号标记峰值点
p.ax_joint.scatter(peak_x, peak_y, color='red', s=120, marker='*', label='Density Peak')

# 添加文本标注(位置微调避免遮挡)
p.ax_joint.text(
    peak_x + 0.15, peak_y + 0.15,
    f"({peak_x:.2f}, {peak_y:.2f})",
    fontsize=10, color='darkred', weight='bold'
)

# 显示图例
p.ax_joint.legend()

完整可运行代码

把所有步骤整合起来,就是这样:

import seaborn as sns
import pandas as pd
import numpy as np
from scipy.stats import gaussian_kde
import matplotlib.pyplot as plt

# Generate some random multivariate data
x, y = np.random.RandomState(8).multivariate_normal([0, 0], [(1, 0), (0, 1)], 1000).T
# Add to a dataframe
df = pd.DataFrame({"x":x,"y":y})
# Plot
p = sns.jointplot(data=df,x='x', y='y',kind='kde')

# --- 获取单变量KDE峰值 ---
x_kde_line = p.ax_marg_x.lines[0]
x_kde_x = x_kde_line.get_xdata()
x_kde_y = x_kde_line.get_ydata()
x_peak = x_kde_x[np.argmax(x_kde_y)]

y_kde_line = p.ax_marg_y.lines[0]
y_kde_x = y_kde_line.get_xdata()
y_kde_y = y_kde_line.get_ydata()
y_peak = y_kde_x[np.argmax(y_kde_y)]

print(f"x轴单变量密度峰值: {x_peak:.2f}")
print(f"y轴单变量密度峰值: {y_peak:.2f}")

# --- 获取二维KDE峰值 ---
kde = gaussian_kde(df[['x','y']].T)
xx, yy = np.meshgrid(
    np.linspace(df['x'].min(), df['x'].max(), 1000),
    np.linspace(df['y'].min(), df['y'].max(), 1000)
)
z = kde(np.vstack([xx.ravel(), yy.ravel()]))
z = z.reshape(xx.shape)
max_idx = np.unravel_index(np.argmax(z), z.shape)
peak_x, peak_y = xx[max_idx], yy[max_idx]

print(f"二维密度峰值位置: ({peak_x:.2f}, {peak_y:.2f})")

# --- 标注峰值 ---
p.ax_joint.scatter(peak_x, peak_y, color='red', s=120, marker='*', label='Density Peak')
p.ax_joint.text(
    peak_x + 0.15, peak_y + 0.15,
    f"({peak_x:.2f}, {peak_y:.2f})",
    fontsize=10, color='darkred', weight='bold'
)
p.ax_joint.legend()

# 显示图形
plt.show()

这样运行后,你就能看到标注了密度峰值的jointplot,而且控制台也会输出对应的峰值坐标~

内容的提问来源于stack exchange,提问作者Dman2

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 15:57:26