当前位置:首页>python>Python编程小技巧--自制简易日历

Python编程小技巧--自制简易日历

  • 2026-09-24 10:50:04
Python编程小技巧--自制简易日历
今天我们尝试用Python制作一个简易日历,包含工作日,周末和特殊节假日~
先看效果图,大概如下,其中浅蓝色表示周末,深蓝色表示特殊节假日,其他表示工作日。
代码如下,可直接运行
自定义建议:
  • 通常只需要改103行的函数调用部分,包括年份,月份和特殊节假日(没有的话可以不传该参数)
  • 如果需要调整展示文字的位置等,可以修改第69行
import matplotlib.pyplot as pltimport numpy as npfrom datetime import datetime, timedeltaplt.rcParams['font.sans-serif'] = ['SimHei']  # 设置为黑体def plot_month_heatmap(year, month, custom_holidays=None, title=None):    """    生成指定月份的假期热力图    参数:        year: 年份 (int)        month: 月份 (1-12)        custom_holidays: 自定义节假日列表,格式 [(day, "名称"), ...]        title: 自定义标题 (可选)    """    # 默认节假日(可被custom_holidays覆盖)    if custom_holidays is None:        custom_holidays = []    # 创建日期矩阵 (6周×7天)    first_day = datetime(year, month, 1)    start_offset = first_day.weekday()  # Monday=0, Sunday=6    days_in_month = (datetime(year, month + 1, 1) - timedelta(days=1)).day if month < 12 else 31    # 初始化矩阵: 0=工作日, 0.4=周末, 0.9=节假日    calendar = np.zeros((6, 7))    day_labels = np.full((6, 7), "", dtype=object)    holiday_labels = {}    # 填充日期和类型    for day in range(1, days_in_month + 1):        date = datetime(year, month, day)        pos = start_offset + day - 1        row, col = divmod(pos, 7)        day_labels[row, col] = str(day)        calendar[row, col] = 0.4 if date.weekday() >= 5 else 0.0  # 周末标记    # 标记自定义节假日    for day, name in custom_holidays:        if 1 <= day <= days_in_month:            pos = start_offset + day - 1            row, col = divmod(pos, 7)            calendar[row, col] = 0.9            holiday_labels[(row, col)] = name    # 创建图形    fig, ax = plt.subplots(figsize=(10, 6.5), dpi=120)    fig.patch.set_facecolor('#FAF8F5')    # 高级配色:灰白→浅灰蓝→深海军蓝    cmap = plt.cm.colors.LinearSegmentedColormap.from_list(        "elegant", ['#F0EDE8', '#B8C8D9', '#1E3A5F']    )    ax.imshow(calendar, cmap=cmap, aspect='auto', vmin=0, vmax=1)    # 绘制日期数字    for i in range(6):        for j in range(7):            if day_labels[i, j]:                color = '#1E3A5F' if calendar[i, j] < 0.5 else '#5A7B9E'                ax.text(j, i, day_labels[i, j],                        ha='center', va='center',                        fontsize=14, color=color, fontweight='medium')    # 标注节假日名称    for (row, col), name in holiday_labels.items():        ax.text(col, row + 0.2, name,                ha='center', va='top',                fontsize=8, color='#8B6B42', fontweight='bold',                bbox=dict(boxstyle='round,pad=0.4',                          facecolor='#F9F4E9',                          edgecolor='none',                          alpha=0.95))    # 设置坐标轴    weekdays = ['MON', 'TUE', 'WED', 'THU', 'FRI', 'SAT', 'SUN']    ax.set_xticks(range(7))    ax.set_xticklabels(weekdays, fontsize=11, color='#5A5A5A', fontweight='medium')    ax.set_yticks([])    # 标题    month_name = first_day.strftime('%B').upper()    ax.set_title(title or f'{month_name}{year}',                 fontsize=24, fontweight='light', color='#1E3A5F', pad=20, loc='left')    # 美化    ax.set_xlim(-0.5, 6.5)    ax.set_ylim(5.5, -0.5)    for spine in ax.spines.values():        spine.set_visible(False)    ax.tick_params(left=False, bottom=False)    plt.tight_layout()    plt.savefig(f'{year}_{month:02d}_heatmap.png', dpi=300,                bbox_inches='tight', facecolor=fig.get_facecolor())    plt.show()# ============ 使用示例 ============# 示例1:2026年2月(含春节)plot_month_heatmap(    year=2026,    month=2,    custom_holidays=[        (15, "Spring\nFestival"),        (16, "Spring\nFestival"),        (17, "Spring\nFestival"),        (18, "Spring\nFestival"),        (19, "Spring\nFestival"),        (20, "Spring\nFestival"),        (21, "Spring\nFestival"),        (22, "Spring\nFestival"),        (23, "Spring\nFestival")    ],    title="FEBRUARY 2026")
上面代码的核心原理是通过数据编码 → 矩阵映射 → 颜色渲染 → 文本叠加等四步实现日历可视化。

步骤1:日历 → 矩阵映射(空间转换)

# 关键计算start_offset = first_day.weekday()  # 1号是星期几(0=周一)pos = start_offset + day - 1        # 日期在网格中的线性位置row, col = divmod(pos, 7)           # 转换为6×7网格坐标
  • 原理:将线性时间(1~31日)映射到二维日历网格
  • 技巧:divmod(pos, 7) 实现「行=周数,列=星期」的自动对齐
  • 结果:生成 (6周, 7天) 的空白画布,自动处理跨月空白格

步骤2:类型 → 数值编码(语义抽象)

calendar[row, col] = 0.0  # 工作日calendar[row, col] = 0.4  # 周末calendar[row, col] = 0.9  # 节假日
  • 原理:用连续数值表示离散类别(非分类变量 → 连续标量)
  • 优势:
    • 兼容 imshow() 的渐变色渲染(比离散色块更优雅)
    • 0.4/0.9 的间隔避免颜色混淆(工作日灰→周末蓝→节日深蓝)
  • 本质:将「日历语义」压缩为单通道灰度图

步骤3:数值 → 颜色映射(视觉编码)

cmap = LinearSegmentedColormap.from_list(    "elegant", ['#F0EDE8', '#B8C8D9', '#1E3A5F'])ax.imshow(calendar, cmap=cmap, vmin=0, vmax=1)

步骤4:数据 → 文本叠加(信息增强)

# 日期数字:根据背景色智能切换文字颜色color = '#1E3A5F' if calendar[i,j] < 0.5 else '#5A7B9E'# 节日标签:偏移位置+圆角背景避免遮挡ax.text(col, row+0.2, name,         bbox=dict(facecolor='#F9F4E9', alpha=0.95))
  • 关键技巧:
    • 日期数字与背景形成对比(深色背景用浅字,浅色背景用深字)
    • 节日名称向下偏移 row+0.2,避免覆盖日期数字
    • 半透明圆角标签 (bbox) 提升可读性而不破坏视觉流

过往文章/合集

合集

文章

Python编程小技巧

Python编程小技巧--用Python查询天气

Python编程小技巧--‌自制简易系统监控

Python--数据/图像可视化

Python编程小技巧--雷达图

Python编程小技巧--新年倒计时小工具2.0版

Python编程基础算法

Python编程基础算法--斐波那契数列的矩阵算法

Python编程基础算法--LeetCode编辑距离问题

细数那些经典教材

细数那些经典教材--算法与数据结构

细数那些经典教材--编程竞赛

Python库巡礼

Python库巡礼--Polars

Python库巡礼--SciPy

Python与数学之美

Python与数学之美--玫瑰线(Rhodonea Curve)

最新文章

随机文章