使用matplotlib.patches.Rectangle绘制矩形出现内外线宽不一致问题求助
问题描述
我用matplotlib的matplotlib.patches.Rectangle把矩阵的列绘制成独立矩形,但所有“内部”线条的宽度看起来比“外部”线条更粗,这是怎么回事?这是否和相关GitHub issue有关?
以下是最小可复现示例:
import numpy as np import matplotlib.pyplot as plt import seaborn as sns import matplotlib.patches as patches # 设置随机种子 np.random.seed(42) # 定义行列数 num_rows = 5 num_cols = 5 # 定义矩阵列之间的间隙大小 column_gap = 0.3 # 定义线条宽度 linewidth = 5 # 定义每个方形单元格的边长 cell_size = 1 # 初始化矩阵 matrix = np.random.rand(num_rows, num_cols) # 创建画布和轴 fig, ax = plt.subplots(figsize=(8,6)) # 创建seaborn颜色调色板并反转 palette = sns.color_palette("RdYlBu", as_cmap=True).reversed() # 逐个绘制带列间隙的单元格 for i in range(num_rows): for j in range(num_cols): # 计算单元格颜色 color = palette(matrix[i, j]) edgecolor = 'black' if column_gap > 0 else None # 添加仅在x方向带间隙的矩形补丁 rect = patches.Rectangle( (j * (cell_size + column_gap), i * cell_size), # 列间隙应用到x位置 cell_size, # 单元格宽度 cell_size, # 单元格高度 facecolor=color, edgecolor=edgecolor, linewidth=linewidth ) ax.add_patch(rect) if column_gap > 0: # 隐藏默认边框 ax.spines[:].set_visible(False) # 设置轴范围以容纳所有单元格 ax.set_xlim(0, num_cols * (cell_size + column_gap) - column_gap) ax.set_ylim(0, num_rows * cell_size) # 禁用刻度 ax.set_xticks([]) ax.set_yticks([]) fig.show()
运行效果如下:
原因与解决方案
原因分析
你看到的“内部线条更粗”是相邻矩形边框重叠绘制导致的:
- 同一行中,相邻矩形的右侧边框与左侧边框在x方向紧挨着(无间隙),黑色边框叠加后,视觉宽度变成了
linewidth*2。 - 最左/最右侧的矩形只有单侧边框,显示的是原始
linewidth宽度,因此看起来比内部线条细。
这个现象和你提到的GitHub issue无关,那个问题是关于缩放级别对线条宽度的影响,而这里是纯粹的边框叠加问题。
解决方案
避免边框重叠的核心是让每个矩形只绘制必要的边框,而非四条边全画:
- 第一列矩形:保留四条边
- 中间列矩形:只保留上、下、右边框(左边框与前一个矩形的右边框重叠,无需重复绘制)
- 最后一列矩形:保留上、下、左边框(右侧无相邻矩形,不会重叠)
修改后的核心代码如下:
# 逐个绘制带列间隙的单元格 for i in range(num_rows): for j in range(num_cols): # 计算单元格颜色 color = palette(matrix[i, j]) if column_gap > 0: edgecolor = 'black' # 根据列位置设置分边线条宽度 if j == 0: # 第一列:绘制四条边 side_linewidths = [linewidth, linewidth, linewidth, linewidth] # 左、右、上、下 elif j == num_cols - 1: # 最后一列:不画右侧边框 side_linewidths = [linewidth, 0, linewidth, linewidth] else: # 中间列:不画左侧边框 side_linewidths = [0, linewidth, linewidth, linewidth] else: edgecolor = None side_linewidths = None # 添加矩形补丁 rect = patches.Rectangle( (j * (cell_size + column_gap), i * cell_size), cell_size, cell_size, facecolor=color, edgecolor=edgecolor, linewidth=side_linewidths # 使用分边宽度 ) ax.add_patch(rect)
更简洁的替代方案
如果不想逐个列判断,也可以统一把所有矩形的左侧边框设为0,仅保留第一列的左侧边框:
for i in range(num_rows): for j in range(num_cols): color = palette(matrix[i, j]) edgecolor = 'black' if column_gap > 0 else None # 仅第一列保留左侧边框,其余列左侧边框宽度为0 left_lw = linewidth if j == 0 else 0 rect = patches.Rectangle( (j * (cell_size + column_gap), i * cell_size), cell_size, cell_size, facecolor=color, edgecolor=edgecolor, linewidth=[left_lw, linewidth, linewidth, linewidth] ) ax.add_patch(rect)
修改后,所有内部线条与外部线条的视觉宽度会完全一致。
内容的提问来源于stack exchange,提问作者Johannes Wiesner
相关产品推荐
相关产品推荐

