refactor(praca/generate_images): fix ruff violations in generate_q9_all_diagrams.py

This commit is contained in:
Krzysztof kuhy Rudnicki 2026-03-14 16:28:34 +01:00
parent 9b4e9722f0
commit 33f5c957df

View File

@ -4,6 +4,11 @@
Replaces every ASCII diagram with a monochrome A4-printable PNG (300 DPI). Replaces every ASCII diagram with a monochrome A4-printable PNG (300 DPI).
""" """
from __future__ import annotations
import logging
from typing import TYPE_CHECKING
import matplotlib as mpl import matplotlib as mpl
mpl.use("Agg") mpl.use("Agg")
@ -14,6 +19,12 @@ from matplotlib.patches import FancyBboxPatch
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
import numpy as np import numpy as np
if TYPE_CHECKING:
from matplotlib.axes import Axes
from matplotlib.figure import Figure
_logger = logging.getLogger(__name__)
DPI = 300 DPI = 300
BG = "white" BG = "white"
LN = "black" LN = "black"
@ -29,24 +40,26 @@ GRAY2 = "#D0D0D0"
GRAY3 = "#B8B8B8" GRAY3 = "#B8B8B8"
GRAY4 = "#F5F5F5" GRAY4 = "#F5F5F5"
GRAY5 = "#C0C0C0" GRAY5 = "#C0C0C0"
OCCUPIED_SLOTS = 2
def draw_box( def draw_box(
ax, ax: Axes,
x, x: float,
y, y: float,
w, w: float,
h, h: float,
text, text: str,
fill="white", fill: str = "white",
lw=1.2, lw: float = 1.2,
fontsize=FS, fontsize: float = FS,
fontweight="normal", fontweight: str = "normal",
ha="center", ha: str = "center",
va="center", va: str = "center",
rounded=True, *,
edgecolor=LN, rounded: bool = True,
linestyle="-", edgecolor: str = LN,
linestyle: str = "-",
) -> None: ) -> None:
"""Draw box.""" """Draw box."""
if rounded: if rounded:
@ -83,7 +96,16 @@ def draw_box(
) )
def draw_arrow(ax, x1, y1, x2, y2, lw=1.2, style="->", color=LN) -> None: def draw_arrow(
ax: Axes,
x1: float,
y1: float,
x2: float,
y2: float,
lw: float = 1.2,
style: str = "->",
color: str = LN,
) -> None:
"""Draw arrow.""" """Draw arrow."""
ax.annotate( ax.annotate(
"", "",
@ -93,7 +115,15 @@ def draw_arrow(ax, x1, y1, x2, y2, lw=1.2, style="->", color=LN) -> None:
) )
def draw_double_arrow(ax, x1, y1, x2, y2, lw=1.2, color=LN) -> None: def draw_double_arrow(
ax: Axes,
x1: float,
y1: float,
x2: float,
y2: float,
lw: float = 1.2,
color: str = LN,
) -> None:
"""Draw double arrow.""" """Draw double arrow."""
ax.annotate( ax.annotate(
"", "",
@ -103,26 +133,26 @@ def draw_double_arrow(ax, x1, y1, x2, y2, lw=1.2, color=LN) -> None:
) )
def save_fig(fig, name) -> None: def save_fig(fig: Figure, name: str) -> None:
"""Save fig.""" """Save fig."""
path = str(Path(OUTPUT_DIR) / name) path = str(Path(OUTPUT_DIR) / name)
fig.savefig(path, dpi=DPI, bbox_inches="tight", facecolor=BG, pad_inches=0.15) fig.savefig(path, dpi=DPI, bbox_inches="tight", facecolor=BG, pad_inches=0.15)
plt.close(fig) plt.close(fig)
print(f" Saved: {path}") _logger.info(" Saved: %s", path)
def draw_table( def draw_table(
ax, ax: Axes,
headers, headers: list[str],
rows, rows: list[list[str]],
x0, x0: float,
y0, y0: float,
col_widths, col_widths: list[float],
row_h=0.4, row_h: float = 0.4,
header_fill=GRAY2, header_fill: str = GRAY2,
row_fills=None, row_fills: list[str] | None = None,
fontsize=FS, fontsize: float = FS,
header_fontsize=None, header_fontsize: float | None = None,
) -> None: ) -> None:
"""Draw a clean table on axes.""" """Draw a clean table on axes."""
if header_fontsize is None: if header_fontsize is None:
@ -540,7 +570,7 @@ def gen_speed_comparison() -> None:
fontweight="bold", fontweight="bold",
) )
# Left: creation # Creation time panel
ax = axes[0] ax = axes[0]
ops = ["fork()\n(nowy proces)", "pthread_create()\n(nowy wątek)"] ops = ["fork()\n(nowy proces)", "pthread_create()\n(nowy wątek)"]
times = [3.0, 0.05] # ms times = [3.0, 0.05] # ms
@ -1177,15 +1207,8 @@ def gen_starvation_priority() -> None:
# ============================================================ # ============================================================
# 14. Bounded buffer + readers-writers + philosophers # 14. Bounded buffer + readers-writers + philosophers
# ============================================================ # ============================================================
def gen_classic_problems() -> None: def _draw_bounded_buffer_panel(ax: Axes) -> None:
"""Gen classic problems.""" """Draw the bounded-buffer (producer-consumer) panel."""
fig, axes = plt.subplots(1, 3, figsize=(12, 5))
fig.suptitle(
"Klasyczne problemy synchronizacji", fontsize=FS_TITLE, fontweight="bold"
)
# Panel 1: Bounded Buffer with semaphores
ax = axes[0]
ax.set_xlim(0, 8) ax.set_xlim(0, 8)
ax.set_ylim(0, 7) ax.set_ylim(0, 7)
ax.set_aspect("auto") ax.set_aspect("auto")
@ -1204,7 +1227,6 @@ def gen_classic_problems() -> None:
fill=GRAY1, fill=GRAY1,
fontsize=5.5, fontsize=5.5,
) )
# Buffer
items = ["A", "B", "", ""] items = ["A", "B", "", ""]
for i, item in enumerate(items): for i, item in enumerate(items):
x = 2.8 + i * 0.9 x = 2.8 + i * 0.9
@ -1235,7 +1257,6 @@ def gen_classic_problems() -> None:
draw_arrow(ax, 2.2, 4.6, 2.8, 4.65, lw=1.2) draw_arrow(ax, 2.2, 4.6, 2.8, 4.65, lw=1.2)
draw_arrow(ax, 6.4, 4.65, 6.0, 4.6, lw=1.2) draw_arrow(ax, 6.4, 4.65, 6.0, 4.6, lw=1.2)
# Semaphores
sems = [("mutex = 1", GRAY2), ("empty = N", GRAY1), ("full = 0", GRAY3)] sems = [("mutex = 1", GRAY2), ("empty = N", GRAY1), ("full = 0", GRAY3)]
for i, (s, c) in enumerate(sems): for i, (s, c) in enumerate(sems):
draw_box( draw_box(
@ -1261,8 +1282,9 @@ def gen_classic_problems() -> None:
bbox={"boxstyle": "round", "facecolor": "#F8D7DA", "edgecolor": "#C62828"}, bbox={"boxstyle": "round", "facecolor": "#F8D7DA", "edgecolor": "#C62828"},
) )
# Panel 2: Readers-Writers
ax = axes[1] def _draw_readers_writers_panel(ax: Axes) -> None:
"""Draw the readers-writers panel."""
ax.set_xlim(0, 8) ax.set_xlim(0, 8)
ax.set_ylim(0, 7) ax.set_ylim(0, 7)
ax.set_aspect("auto") ax.set_aspect("auto")
@ -1271,7 +1293,6 @@ def gen_classic_problems() -> None:
"Czytelnicy-Pisarze\n(Readers-Writers)", fontsize=FS, fontweight="bold" "Czytelnicy-Pisarze\n(Readers-Writers)", fontsize=FS, fontweight="bold"
) )
# Resource
draw_box( draw_box(
ax, ax,
2.5, 2.5,
@ -1284,7 +1305,6 @@ def gen_classic_problems() -> None:
fontweight="bold", fontweight="bold",
) )
# Readers
for i in range(3): for i in range(3):
x = 0.3 + i * 1.0 x = 0.3 + i * 1.0
draw_box( draw_box(
@ -1309,7 +1329,6 @@ def gen_classic_problems() -> None:
fontweight="bold", fontweight="bold",
) )
# Writer
draw_box( draw_box(
ax, 5.5, 5.5, 1.5, 0.7, "Pisarz", fill=GRAY5, fontsize=FS, fontweight="bold" ax, 5.5, 5.5, 1.5, 0.7, "Pisarz", fill=GRAY5, fontsize=FS, fontweight="bold"
) )
@ -1324,7 +1343,6 @@ def gen_classic_problems() -> None:
color="#C62828", color="#C62828",
) )
# Rules
rules = [ rules = [
"Wielu czytelników = OK", "Wielu czytelników = OK",
"Jeden pisarz = wyłączny", "Jeden pisarz = wyłączny",
@ -1343,8 +1361,9 @@ def gen_classic_problems() -> None:
bbox={"boxstyle": "round,pad=0.2", "facecolor": GRAY4, "edgecolor": GRAY3}, bbox={"boxstyle": "round,pad=0.2", "facecolor": GRAY4, "edgecolor": GRAY3},
) )
# Panel 3: Dining Philosophers
ax = axes[2] def _draw_philosophers_panel(ax: Axes) -> None:
"""Draw the dining-philosophers panel."""
ax.set_xlim(0, 8) ax.set_xlim(0, 8)
ax.set_ylim(0, 7) ax.set_ylim(0, 7)
ax.set_aspect("auto") ax.set_aspect("auto")
@ -1353,13 +1372,11 @@ def gen_classic_problems() -> None:
"Ucztujący filozofowie\n(Dining Philosophers)", fontsize=FS, fontweight="bold" "Ucztujący filozofowie\n(Dining Philosophers)", fontsize=FS, fontweight="bold"
) )
# Draw circular table
cx, cy, r = 4.0, 3.8, 1.8 cx, cy, r = 4.0, 3.8, 1.8
table = plt.Circle((cx, cy), 0.8, fill=True, facecolor=GRAY2, edgecolor=LN, lw=1.5) table = plt.Circle((cx, cy), 0.8, fill=True, facecolor=GRAY2, edgecolor=LN, lw=1.5)
ax.add_patch(table) ax.add_patch(table)
ax.text(cx, cy, "Stół", fontsize=FS, ha="center", fontweight="bold") ax.text(cx, cy, "Stół", fontsize=FS, ha="center", fontweight="bold")
# 5 philosophers around table
for i in range(5): for i in range(5):
angle = np.pi / 2 + i * 2 * np.pi / 5 angle = np.pi / 2 + i * 2 * np.pi / 5
px = cx + r * np.cos(angle) px = cx + r * np.cos(angle)
@ -1372,7 +1389,6 @@ def gen_classic_problems() -> None:
px, py, f"F{i}", ha="center", va="center", fontsize=FS, fontweight="bold" px, py, f"F{i}", ha="center", va="center", fontsize=FS, fontweight="bold"
) )
# Fork between philosophers
fork_angle = np.pi / 2 + (i + 0.5) * 2 * np.pi / 5 fork_angle = np.pi / 2 + (i + 0.5) * 2 * np.pi / 5
fx = cx + (r * 0.6) * np.cos(fork_angle) fx = cx + (r * 0.6) * np.cos(fork_angle)
fy = cy + (r * 0.6) * np.sin(fork_angle) fy = cy + (r * 0.6) * np.sin(fork_angle)
@ -1385,7 +1401,6 @@ def gen_classic_problems() -> None:
) )
ax.text(fx + 0.2, fy + 0.15, f"w{i}", fontsize=5, color="#555555") ax.text(fx + 0.2, fy + 0.15, f"w{i}", fontsize=5, color="#555555")
# Rules
rules = [ rules = [
"Jedzenie = 2 widelce", "Jedzenie = 2 widelce",
"Naiwne → DEADLOCK", "Naiwne → DEADLOCK",
@ -1395,6 +1410,21 @@ def gen_classic_problems() -> None:
for i, r in enumerate(rules): for i, r in enumerate(rules):
ax.text(4.0, 1.2 - i * 0.35, r, fontsize=FS_SMALL, ha="center") ax.text(4.0, 1.2 - i * 0.35, r, fontsize=FS_SMALL, ha="center")
# ============================================================
# 14. Bounded buffer + readers-writers + philosophers
# ============================================================
def gen_classic_problems() -> None:
"""Gen classic problems."""
fig, axes = plt.subplots(1, 3, figsize=(12, 5))
fig.suptitle(
"Klasyczne problemy synchronizacji", fontsize=FS_TITLE, fontweight="bold"
)
_draw_bounded_buffer_panel(axes[0])
_draw_readers_writers_panel(axes[1])
_draw_philosophers_panel(axes[2])
fig.tight_layout(rect=[0, 0, 1, 0.88]) fig.tight_layout(rect=[0, 0, 1, 0.88])
save_fig(fig, "q9_classic_problems.png") save_fig(fig, "q9_classic_problems.png")
@ -1523,7 +1553,7 @@ def gen_semaphore_concept() -> None:
# Parking slots # Parking slots
for i in range(3): for i in range(3):
x = 2.0 + i * 2.0 x = 2.0 + i * 2.0
occupied = i < 2 # 2 occupied, 1 free occupied = i < OCCUPIED_SLOTS
fill = GRAY3 if occupied else "white" fill = GRAY3 if occupied else "white"
label = f"Wątek {i + 1}" if occupied else "(wolne)" label = f"Wątek {i + 1}" if occupied else "(wolne)"
draw_box( draw_box(
@ -1578,7 +1608,7 @@ def gen_semaphore_concept() -> None:
# MAIN — generate all # MAIN — generate all
# ============================================================ # ============================================================
if __name__ == "__main__": if __name__ == "__main__":
print("Generating ALL PYTANIE 9 diagrams...") _logger.info("Generating ALL PYTANIE 9 diagrams...")
gen_process_vs_thread() gen_process_vs_thread()
gen_memory_layout() gen_memory_layout()
gen_process_states() gen_process_states()
@ -1595,4 +1625,4 @@ if __name__ == "__main__":
gen_classic_problems() gen_classic_problems()
gen_sync_comparison() gen_sync_comparison()
gen_semaphore_concept() gen_semaphore_concept()
print("\nAll 16 PYTANIE 9 diagrams generated successfully!") _logger.info("All 16 PYTANIE 9 diagrams generated successfully!")