如何获取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
相关产品推荐
相关产品推荐

