如何在Matplotlib中绘制尺寸精确无额外填充的圆角矩形?
如何在Matplotlib中绘制尺寸精确的圆角矩形
要实现类似CSS中裁剪边缘生成圆角(不改变原矩形尺寸)的效果,你可以通过两种方式解决:手动构建路径或者调整FancyBboxPatch的参数,避免使用导致尺寸扩展的pad属性。
方法一:手动构建Path路径(完全精确控制)
直接用matplotlib.path.Path绘制圆角矩形,所有顶点基于原矩形边界,从边角裁剪出圆角,完全不会改变原矩形的整体尺寸。
from datetime import datetime, timedelta import matplotlib.pyplot as plt import matplotlib.dates as mdates from matplotlib.path import Path import matplotlib.patches as patches fig = plt.figure() ax = fig.add_subplot(111) # 定义时间范围与坐标转换 startTime = datetime(1,1,1,10,0) endTime = startTime + timedelta(hours=2) start = mdates.date2num(startTime) end = mdates.date2num(endTime) width = end - start height = 1 # 设置圆角半径(这里对应15分钟的时间宽度,转换为Matplotlib日期数值) r = mdates.date2num(startTime + timedelta(minutes=15)) - start x0, y0 = start, 0 x1, y1 = end, height # 构建圆角矩形的顶点列表(按顺时针顺序) vertices = [ (x0 + r, y0), # 左下边缘起点(跳过圆角左端点) (x1 - r, y0), # 右下圆角左端点 (x1, y0), (x1, y0 + r),# 右下圆弧的控制点与终点 (x1, y1 - r), # 右上边缘起点 (x1, y1), (x1 - r, y1),# 右上圆弧的控制点与终点 (x0 + r, y1), # 左上边缘起点 (x0, y1), (x0, y1 - r),# 左上圆弧的控制点与终点 (x0, y0 + r), # 左下边缘终点 (x0, y0), (x0 + r, y0),# 左下圆弧的控制点与终点(闭合路径) ] # 路径指令:MOVETO(起始)、LINETO(直线)、CURVE3(二次贝塞尔)、CLOSEPOLY(闭合) codes = [ Path.MOVETO, Path.LINETO, Path.CURVE3, Path.CURVE3, Path.LINETO, Path.CURVE3, Path.CURVE3, Path.LINETO, Path.CURVE3, Path.CURVE3, Path.LINETO, Path.CURVE3, Path.CURVE3, Path.CLOSEPOLY, ] # 创建路径补丁并添加到轴上 rounded_path = Path(vertices, codes) rounded_patch = patches.PathPatch(rounded_path, color='yellow', alpha=0.3) rect = patches.Rectangle((start, 0), width, height, color='red', alpha=0.5) ax.add_patch(rect) ax.add_patch(rounded_patch) # 设置轴格式与范围 ax.xaxis.set_major_formatter(mdates.DateFormatter("%I:%M %p")) plt.xlim([start - width, end + width]) plt.ylim([-.5, 1.5]) plt.show()
方法二:调整FancyBboxPatch参数(更简洁)
FancyBboxPatch的pad参数是导致尺寸扩展的原因,设置pad=0关闭向外填充,同时用rounding_size指定圆角半径(需匹配当前轴的坐标单位)。
from datetime import datetime, timedelta from matplotlib.patches import Rectangle, FancyBboxPatch import matplotlib.pyplot as plt import matplotlib.dates as mdates fig = plt.figure() ax = fig.add_subplot(111) # 时间范围与坐标转换 startTime = datetime(1,1,1,10,0) endTime = startTime + timedelta(hours=2) start = mdates.date2num(startTime) end = mdates.date2num(endTime) width = end - start height = 1 # 圆角半径(转换为Matplotlib日期数值,对应15分钟) r = mdates.date2num(startTime + timedelta(minutes=15)) - start # 创建圆角矩形补丁:pad=0关闭扩展,rounding_size指定圆角大小 rounded_rect = FancyBboxPatch( (start, 0), width, height, boxstyle=f'Round, pad=0, rounding_size={r}', color='yellow', alpha=0.3 ) rect = Rectangle((start, 0), width, height, color='red', alpha=0.5) ax.add_patch(rect) ax.add_patch(rounded_rect) # 轴格式与范围设置 ax.xaxis.set_major_formatter(mdates.DateFormatter("%I:%M %p")) plt.xlim([start - width, end + width]) plt.ylim([-.5, 1.5]) plt.show()
关键说明
- 日期轴下,圆角半径
r需要转换为Matplotlib的日期数值(通过mdates.date2num计算时间差得到),确保圆角大小在视觉上符合预期。 - 方法一适合需要完全自定义路径的场景,方法二更简洁,适合快速实现需求。
内容的提问来源于stack exchange,提问作者Yousef Irshaid
相关产品推荐
相关产品推荐

