codex/floor-ceiling-and-fractional-part.py

floor-ceiling-and-fractional-part.py
"""Endpoint conventions and the periodic fractional part, including negatives."""
from pathlib import Path

import matplotlib.pyplot as plt
import numpy as np


def main():
    plt.rcParams.update({"font.size": 11, "figure.facecolor": "white"})
    fig = plt.figure(figsize=(11.2, 6.8), layout="constrained")
    grid = fig.add_gridspec(2, 2, height_ratios=(1.35, 1))
    floor_ax = fig.add_subplot(grid[0, 0])
    ceil_ax = fig.add_subplot(grid[0, 1])
    frac_ax = fig.add_subplot(grid[1, :])
    integers = np.arange(-3, 4)
    for ax, name, color in ((floor_ax, "Floor: greatest integer not exceeding x", "#167e8d"),
                            (ceil_ax, "Ceiling: least integer not below x", "#c26030")):
        ax.plot([-3, 3], [-3, 3], "--", color="#88959e", lw=1, label="y = x")
        for n in range(-3, 3):
            y = n if ax is floor_ax else n + 1
            ax.plot([n, n + 1], [y, y], color=color, lw=2.2)
            open_end = n + 1 if ax is floor_ax else n
            ax.scatter([open_end], [y], facecolors="white", edgecolors=color,
                       s=46, zorder=5, linewidths=1.5)
        ax.scatter(integers, integers, color=color, s=30, zorder=6)
        ax.set(title=name, xlabel="Input x", xlim=(-3.18, 3.18),
               ylim=(-3.35, 3.35), xticks=integers, yticks=integers)
        ax.grid(alpha=0.16)
        ax.spines[["top", "right"]].set_visible(False)
        ax.legend(loc="upper left", fontsize=10)
    floor_ax.set_ylabel(r"$\lfloor x\rfloor$")
    ceil_ax.set_ylabel(r"$\lceil x\rceil$")
    for n in range(-3, 3):
        frac_ax.plot([n, n + 1], [0, 1], color="#6b61a2", lw=2.1)
        frac_ax.scatter([n + 1], [1], facecolors="white", edgecolors="#6b61a2",
                        s=46, linewidths=1.5, zorder=5)
    frac_ax.scatter(integers, np.zeros_like(integers), color="#6b61a2",
                   s=30, zorder=6)
    frac_ax.scatter([-2.7], [.3], color="#24343e", s=32, zorder=7)
    frac_ax.annotate(r"$\{-2.7\}=0.3$", (-2.7, .3), xytext=(-2.25, .55),
                     arrowprops={"arrowstyle": "->", "color": "#405660"},
                     fontsize=12)
    frac_ax.set(title="Fractional part repeats with period one",
                xlabel="Input x", ylabel=r"$\{x\}=x-\lfloor x\rfloor$",
                xlim=(-3.18, 3.18), ylim=(-.11, 1.13), xticks=integers)
    frac_ax.grid(alpha=.16)
    frac_ax.spines[["top", "right"]].set_visible(False)
    fig.suptitle("Directed integer bounds and the amount left above the floor", fontsize=17)
    fig.get_layout_engine().set(rect=(0, .055, 1, .92))
    fig.text(.5, .017, "Filled points are included; hollow points are excluded. At every integer, floor = ceiling and fractional part = 0.",
             ha="center", fontsize=10)
    x = np.linspace(-7, 7, 2801)
    assert np.all(np.floor(x) <= x) and np.all(x < np.floor(x) + 1)
    assert np.all(np.ceil(x) - 1 < x) and np.all(x <= np.ceil(x))
    assert np.array_equal(np.ceil(x), -np.floor(-x))
    assert np.allclose((x + 5) - np.floor(x + 5), x - np.floor(x), atol=2e-15)
    fig.savefig(Path(__file__).with_suffix(".png").name, dpi=100, facecolor="white")
    plt.close(fig)


if __name__ == "__main__":
    main()