在数据可视化世界中我们经常用直方图来描述数据的分布情况但今天我想介绍两种特别而优雅的点状图变体威尔金森点状图和麦穗图。它们像数据世界的点彩派画家用简单的点创造出丰富的信息层次。与直方图相比这种点绘法不仅能够更直观地展示数据分布的细节还能更好地揭示数据之间的关系和模式使得观察者能够从更广阔的视角理解数据集的特点。1. 威尔金森点状图想象一下你有一袋彩色弹珠需要按颜色分类展示。如果只是简单地把所有弹珠倒出来它们会杂乱无章。但如果你为每种颜色准备一个小盒子把相同颜色的弹珠整齐地堆叠在里面这就是威尔金森点状图的基本思想。威尔金森点状图将数据点堆叠在对应的数值区域形成类似直方图的分布展示但保留了每个数据点的个体性。它不是用条形的高度表示频率而是用实际的数据点数量来可视化分布。下面基于matplotlib库封装了一个绘制威尔金森点状图的函数。def wilkinson_dot_plot( data, bins10, dot_size40, dot_spacing0.8, show_statsTrue, random_seed42 ): 创建威尔金森点状图 参数: data: 输入数据一维数组 bins: 分组数量或分组边界 dot_size: 点的大小 dot_spacing: 点之间的垂直间距 random_seed: 随机种子 np.random.seed(random_seed) # 创建图形 fig, ax plt.subplots(figsize(10, 7)) # 计算直方图数据 hist, bin_edges np.histogram(data, binsbins) # 为每个分组创建点 max_count 0 # 记录最大堆叠高度 bin_centers [] # 保存每个分组的中心位置 # 省略... plt.tight_layout() return fig, ax, (bin_edges, hist)威尔金森点状图的核心算法可以分解为几个步骤数据分箱将连续数据分成若干个等宽的区间点位置计算在每个区间内将数据点垂直堆叠避免重叠通过调整点的垂直位置防止重叠同时保持可读性使用起来也简单# 生成示例数据 np.random.seed(42) # 数据集正态分布 data_normal np.random.normal(100, 15, 100) dot_size 200 # 创建威尔金森点状图 fig1, ax1, stats1 wilkinson_dot_plot(data_normal, bins12, dot_sizedot_size) plt.show()2. 麦穗图如果把威尔金森点状图比作整齐堆叠的弹珠那么麦穗图就像是田野中的麦穗——每个数据点都像一颗麦粒精确地生长在自己的位置上展示其实际数值。麦穗图是威尔金森点状图的一种变体它将点放置在其实际数值位置而不是分组中心。这保留了数据的精确性同时通过堆叠避免了重叠。麦穗图的实现与威尔金森点状图类似但有一个关键区别点沿x轴放置在实际数据值位置而不是分组中心。# 封装麦穗图函数 def strip_plot( data, bin_edgesNone, bins10, dot_size40, dot_spacing0.8, jitter_amount0.2, random_seed42, ): 创建麦穗图在威尔金森点状图基础上显示实际值 参数: data: 输入数据一维数组 bin_edges: 可选使用预定义的分组边界 bins: 如果未提供bin_edges则使用此参数创建分组 dot_size: 点的大小 dot_spacing: 点之间的垂直间距 jitter_amount: 水平抖动程度避免重叠 random_seed: 随机种子 np.random.seed(random_seed) # 创建图形 fig, ax plt.subplots(figsize(10, 7)) # 如果没有提供分组边界则计算 if bin_edges is None: hist, bin_edges np.histogram(data, binsbins) else: hist, bin_edges np.histogram(data, binsbin_edges) # 对数据进行排序 sorted_data np.sort(data) # 将数据分配到对应的分组 data_by_bin [] for i in range(len(bin_edges) - 1): lower, upper bin_edges[i], bin_edges[i 1] bin_data sorted_data[(sorted_data lower) (sorted_data upper)] data_by_bin.append(bin_data) # 处理最后一个分组包含最大值 if len(data) 0: last_bin_data sorted_data[sorted_data bin_edges[-2]] if len(data_by_bin) 0: data_by_bin[-1] last_bin_data # 绘制麦穗图 max_points_in_bin 0 # 省略 ... plt.tight_layout() return fig, ax, (bin_edges, data_by_bin)使用起来也简单# 生成示例数据 np.random.seed(42) # 数据集正态分布 data_normal np.random.normal(100, 15, 100) dot_size 200 # 创建的麦穗图 bin_edges 12 fig2, ax2, stats2 strip_plot( data_normal, bin_edgesbin_edges, dot_sizedot_size, jitter_amount0.15 ) plt.show()3. 两种图的应用场景下面模拟一个学生考试成绩分布的分析场景看看上面两种点状图的应用。# 示例学生考试成绩分布分析 print(示例学生考试成绩分布分析) print(- * 40) # 创建模拟的考试成绩数据 np.random.seed(42) exam_scores np.concatenate( [ np.random.normal(65, 8, 45), # 中等水平学生 np.random.normal(85, 6, 30), # 优秀学生 np.random.normal(45, 10, 24), # 需要帮助的学生 ] ) # 过滤掉不合理分数 exam_scores np.clip(exam_scores, 0, 100) print(f学生总数: {len(exam_scores)}) print(f分数范围: {exam_scores.min():.1f} - {exam_scores.max():.1f}) print(f平均分: {exam_scores.mean():.1f}) print(f及格率: {(exam_scores 60).sum() / len(exam_scores) * 100:.1f}%\n) # 使用威尔金森点状图 print(创建威尔金森点状图...) fig1, ax1, stats1 wilkinson_dot_plot( exam_scores, bins[0, 40, 60, 70, 80, 90, 100], ) plt.show() # 使用麦穗图 print(创建麦穗图...) fig2, ax2, stats2 strip_plot( exam_scores, bins[0, 40, 60, 70, 80, 90, 100], jitter_amount0.15, ) plt.show() ## 输出结果 示例学生考试成绩分布分析 ---------------------------------------- 学生总数: 99 分数范围: 25.1 - 94.4 平均分: 65.3 及格率: 63.6% 在学生考试成绩分析这个场景中威尔金森点状图将分数分组成区间如60-70分所有该区间的学生点都堆叠在区间中心清晰地展示了分数段的整体分布形态类似直方图但能看到个体点。麦穗图点在实际分数位置堆叠如65分、68分等既显示了每个学生的具体分数又通过垂直堆叠避免了重叠保留了数据的精确性。总的来说威尔金森点状图看分布形态区间视角麦穗图看具体数值精确视角。