如何为分类值图表添加边际直方图或密度图?
给分类时间散点图添加边际密度/直方图的实现方案
当然可以给这类散点图添加边际密度图或直方图,下面提供两种实用的实现方式:
方法一:基于Matplotlib手动布局
通过gridspec划分画布,在主散点图顶部添加边际图(直方图或密度图),完全自定义布局细节:
import pandas as pd import matplotlib.pyplot as plt import matplotlib.dates as mdates from matplotlib.gridspec import GridSpec import numpy as np from scipy.stats import gaussian_kde # 数据处理 source_data = [("user_1", "2023-11-24 10:30:00"), ("user_1", "2023-11-24 10:15:00"), ("user_1", "2023-11-24 09:55:00"), ("user_1", "2023-11-24 22:10:00"), ("user_1", "2023-11-24 15:55:00"), ("user_1", "2023-11-24 11:15:00"), ("user_1", "2023-11-24 09:30:00"), ("user_1", "2023-11-24 22:25:00"), ("user_1", "2023-11-24 17:20:00"), ("user_1", "2023-11-24 23:55:00")] df = pd.DataFrame(source_data, columns=['user', 'time']) df['time'] = pd.to_datetime(df['time']) # 划分画布:顶部1行放边际图,底部4行放主散点图 fig = plt.figure(figsize=(9, 9)) gs = GridSpec(5, 1, height_ratios=[1, 4]) # 顶部边际图(直方图+密度曲线) ax_marginal = fig.add_subplot(gs[0]) time_num = mdates.date2num(df['time']) ax_marginal.hist(time_num, bins=10, alpha=0.5, color='b') # 添加核密度估计曲线 kde = gaussian_kde(time_num) xvals = np.linspace(time_num.min(), time_num.max(), 1000) ax_marginal.plot(xvals, kde(xvals)*len(df)*np.diff(xvals)[0], color='darkblue', linewidth=2) # 简化边际图样式 ax_marginal.set_yticks([]) ax_marginal.spines[['right', 'top', 'left']].set_visible(False) # 主散点图 ax_main = fig.add_subplot(gs[1:], sharex=ax_marginal) ax_main.scatter(x=df['time'], y=df['user'], marker='.', color='b', alpha=0.7) # 设置时间轴格式 ax_main.xaxis.set_major_locator(mdates.HourLocator(byhour=range(0, 24, 2))) ax_main.xaxis.set_major_formatter(mdates.DateFormatter('%H:%M hr')) plt.setp(ax_main.get_xticklabels(), rotation=45, ha='right') fig.tight_layout() plt.show()
方法二:用Seaborn快速生成(更简洁)
Seaborn的jointplot可以一键生成带边际图的联合分布图,适合快速可视化:
import pandas as pd import seaborn as sns import matplotlib.pyplot as plt import matplotlib.dates as mdates # 数据处理同前 source_data = [("user_1", "2023-11-24 10:30:00"), ("user_1", "2023-11-24 10:15:00"), ("user_1", "2023-11-24 09:55:00"), ("user_1", "2023-11-24 22:10:00"), ("user_1", "2023-11-24 15:55:00"), ("user_1", "2023-11-24 11:15:00"), ("user_1", "2023-11-24 09:30:00"), ("user_1", "2023-11-24 22:25:00"), ("user_1", "2023-11-24 17:20:00"), ("user_1", "2023-11-24 23:55:00")] df = pd.DataFrame(source_data, columns=['user', 'time']) df['time'] = pd.to_datetime(df['time']) # 生成联合图,边际图同时显示直方图和密度曲线 g = sns.jointplot( x='time', y='user', data=df, kind='scatter', marker='.', color='b', alpha=0.7, marginal_kws={'fill': True, 'kde': True} ) # 设置x轴时间格式 g.ax_joint.xaxis.set_major_locator(mdates.HourLocator(byhour=range(0, 24, 2))) g.ax_joint.xaxis.set_major_formatter(mdates.DateFormatter('%H:%M hr')) plt.setp(g.ax_joint.get_xticklabels(), rotation=45, ha='right') plt.tight_layout() plt.show()
实用提示
- 若存在多个用户,只需保留y轴的分类变量即可,边际图会自动对应用户的时间分布;多用户场景下可考虑为每个用户单独生成子图+边际图
- 调整
bins(直方图)或bw_method(密度图)参数,可优化边际图的粒度和平滑度
内容的提问来源于stack exchange,提问作者user136555
相关产品推荐
相关产品推荐

