DEV Community

Albert
Albert

Posted on

How to build a mouth calendar by Python?


import calendar
from pathlib import Path
import matplotlib.pyplot as plt
import matplotlib
from matplotlib.patches import Rectangle

matplotlib.use("Agg")

def draw_pretty_calendar_grid(
    year,
    month,
    week_start="mon",
    title=None,
    landscape=True,
    dpi=300,
    outdir=Path("."),
    fmts=["pdf", "png"],
    style="classic",
    draw_grid=True,
):
    a4_w, a4_h = 8.27, 11.69
    if landscape:
        a4_w, a4_h = a4_h, a4_w

    fig, ax = plt.subplots(figsize=(a4_w, a4_h), dpi=dpi)
    ax.set_axis_off()

    margin = 0.05
    fig.subplots_adjust(left=margin, right=1-margin, top=1-margin, bottom=margin)

    _title = title or f"{calendar.month_name[month]} {year}"
    title_color = "#2E8B57"
    title_fontsize = 36
    title_rel_height = title_fontsize / (dpi * a4_h)

    ax.text(
        0.5,
        1.0,
        _title,
        ha="center",
        va="top",
        fontsize=title_fontsize,
        fontweight="bold",
        color=title_color,
        transform=ax.transAxes,
    )

    blank_height = 0.04
    weekday_height = 0.06
    n_cols = 7
    labels = list(calendar.day_abbr)
    firstweekday = 0 if week_start == "mon" else 6
    calendar.setfirstweekday(firstweekday)
    if week_start != "mon":
        labels = labels[-1:] + labels[:-1]

    y_weekday_bottom = 1.0 - margin - title_rel_height - weekday_height + 0.02 * weekday_height
    for c, day in enumerate(labels):
        x_pos = c / n_cols + 0.02 / n_cols
        ax.text(
            x_pos,
            y_weekday_bottom,
            day,
            ha="left",
            va="bottom",
            fontsize=20,
            fontweight="bold",
            transform=ax.transAxes,
        )

    month_matrix = calendar.monthcalendar(year, month)
    n_rows = len(month_matrix)
    calendar_space = 1.0 - margin - title_rel_height - weekday_height - blank_height
    cell_h = calendar_space / n_rows
    cell_w = 1.0 / n_cols
    x0, y0 = 0, 0

    for r, week in enumerate(month_matrix):
        for c, day in enumerate(week):
            if day != 0:
                x_left = x0 + c * cell_w
                y_bottom = y0 + (n_rows - r - 1) * cell_h
                weekend_color = "#D3D3D3"
                weekend_cols = [5, 6] if week_start == "mon" else [6, 0]
                if c in weekend_cols:
                    rect = Rectangle(
                        (x_left, y_bottom),
                        cell_w,
                        cell_h,
                        facecolor=weekend_color,
                        edgecolor=None,
                        transform=ax.transAxes,
                        zorder=0,
                    )
                    ax.add_patch(rect)

                padding_x = 0.05 * cell_w
                padding_y = 0.05 * cell_h
                x_pos = x0 + c * cell_w + padding_x
                y_pos = y0 + (n_rows - r - 1) * cell_h + cell_h - padding_y
                ax.text(
                    x_pos,
                    y_pos,
                    str(day),
                    ha="left",
                    va="top",
                    fontsize=20,
                    transform=ax.transAxes,
                )
    if draw_grid:
        for r, week in enumerate(month_matrix):
            for c, day in enumerate(week):
                x_left = x0 + c * cell_w
                y_bottom = y0 + (n_rows - r - 1) * cell_h
                rect = Rectangle(
                    (x_left, y_bottom),
                    cell_w,
                    cell_h,
                    fill=False,
                    edgecolor="black",
                    lw=0.8,
                    transform=ax.transAxes
                )
                ax.add_patch(rect)

    outdir.mkdir(parents=True, exist_ok=True)
    grid_tag = "grid" if draw_grid else "line"
    stem = f"calendar_{year}_{month:02d}_{style}{'_landscape' if landscape else ''}_{grid_tag}"

    for f in fmts:
        path = outdir / f"{stem}.{f}"
        fig.savefig(path, dpi=dpi)
        print(f"Saved -> {path.resolve()}")

    plt.close(fig)

draw_pretty_calendar_grid(2025, 8, style="colorful", fmts=["png"], draw_grid=False)
draw_pretty_calendar_grid(2025, 8, style="colorful", fmts=["png"], draw_grid=True)

Enter fullscreen mode Exit fullscreen mode

Top comments (1)

Collapse
 
roshan_650272631d16fcdaae profile image
Roshan

Your script already creates a visual monthly calendar using Python. It uses the calendar module to get the month layout and matplotlib to draw each day as a rectangle, with weekends optionally highlighted. You can customize the start of the week, orientation (landscape/portrait), grid lines, and output format (png, pdf). Simply call draw_pretty_calendar_grid(year, month, fmts=["png"], draw_grid=True) to generate a calendar image, and loop through months to create a full-year calendar. You can also extend it to show events by adding text or colored highlights on specific days.