codexbidirectional-level-reordering.py
bidirectional-level-reordering.py
"""Illustrate UAX9 L2 with supplied levels, not a bidi implementation; PNG to cwd."""
from pathlib import Path
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
from matplotlib.patches import FancyBboxPatch
def reverse_at_level(items, threshold):
result = list(items)
start = 0
while start < len(result):
if result[start][1] < threshold:
start += 1
continue
end = start + 1
while end < len(result) and result[end][1] >= threshold:
end += 1
result[start:end] = reversed(result[start:end])
start = end
return result
def main():
logical = [("a", 0), ("R1", 1), ("R2", 1), ("1", 2),
("2", 2), ("R3", 1), ("b", 0)]
after_two = reverse_at_level(logical, 2)
visual = reverse_at_level(after_two, 1)
assert [x[0] for x in visual] == ["a", "R3", "1", "2", "R2", "R1", "b"]
assert [x[0] for x in after_two] == ["a", "R1", "R2", "2", "1", "R3", "b"]
colors = {0: ("#e8f1eb", "#236541"), 1: ("#e5eef8", "#245d91"),
2: ("#fcf0da", "#8c5b0c")}
fig = plt.figure(figsize=(9, 4.8), dpi=100, facecolor="white")
ax = fig.add_axes([0.025, 0.18, 0.95, 0.64])
ax.set_xlim(0, 10.2)
ax.set_ylim(-0.1, 3)
ax.axis("off")
for y, label, items in [(2.25, "Logical order", logical),
(1.25, "Reverse level 2", after_two),
(0.25, "Then levels 1–2", visual)]:
ax.text(0.05, y + 0.28, label, fontsize=11, va="center", color="#243641")
for j, (token, level) in enumerate(items):
x = 2.45 + j * 1.06
background, foreground = colors[level]
ax.add_patch(FancyBboxPatch((x, y), 0.87, 0.6,
boxstyle="round,pad=0.035", facecolor=background,
edgecolor=foreground, linewidth=1.1))
ax.text(x + 0.435, y + 0.36, token, ha="center", va="center",
fontsize=13, weight="bold", color=foreground)
ax.text(x + 0.435, y + 0.105, f"level {level}", ha="center", va="center",
fontsize=8, color=foreground)
fig.suptitle("Nested reversals preserve the order of the digits", y=0.96,
fontsize=15, weight="bold", color="#172330")
fig.text(0.5, 0.86, "UAX #9, rule L2: each pass reverses contiguous items at or above its level",
ha="center", fontsize=10.5, color="#45535d")
fig.text(0.5, 0.085, "R1, R2 and R3 stand for separate right-to-left characters; read every row left to right.",
ha="center", fontsize=10, color="#45535d")
fig.text(0.5, 0.035, "Illustrative supplied levels. Resolving levels, shaping and mirroring are separate steps.",
ha="center", fontsize=9.5, color="#45535d")
fig.savefig(Path.cwd() / (Path(__file__).stem + ".png"), dpi=100,
facecolor="white", transparent=False)
plt.close(fig)
if __name__ == "__main__":
main()