from collections import defaultdict from sys import argv import matplotlib.pyplot as plt import numpy as np def read_points(filename: str) -> list[tuple[float, float, str]]: points = [] with open(filename, "r", encoding="utf-8") as f: for line in f: line = line.strip() if line and not line.startswith("#"): parts = line.split() if len(parts) >= 3: x = float(parts[0]) y = float(parts[1]) label = parts[2] points.append((x, y, label)) return points def main() -> None: points = read_points(argv[1]) plt.figure(figsize=(8.27, 11.69)) plt.xlim(0, 30) plt.ylim(0, 20) plt.gca().set_aspect("equal", adjustable="box") plt.grid(True, linewidth=0.3) plt.xticks(range(0, 31, 2)) plt.yticks(range(0, 21, 2)) grouped = defaultdict(list) for x, y, phi in points: grouped[phi].append((x, y)) for x, y, label in points: plt.scatter(x, y, color="red", s=15) plt.text(x + 0.3, y + 0.3, label, fontsize=9) for phi, coords in grouped.items(): coords.sort(key=lambda p: p[1]) xs, ys = zip(*coords) plt.plot(xs, ys, linewidth=0.8, label=f"φ={phi} В") for i in range(len(coords) - 1): x1, y1 = coords[i] x2, y2 = coords[i + 1] mid_x = (x1 + x2) / 2 mid_y = (y1 + y2) / 2 dx = x2 - x1 dy = y2 - y1 perp_dx = -dy perp_dy = dx length = np.sqrt(perp_dx**2 + perp_dy**2) if length > 0: arrow_length = 0.5 perp_dx = perp_dx / length * arrow_length perp_dy = perp_dy / length * arrow_length plt.arrow( mid_x, mid_y, perp_dx, perp_dy, head_width=0.2, head_length=0.15, fc="green", ec="green", linewidth=1.5, ) if int(argv[2]): theta = np.linspace(0, 2 * np.pi, 200) cx, cy = 15, 9 for r in [5, 6]: x = cx + r * np.cos(theta) y = cy + r * np.sin(theta) plt.plot(x, y, color="blue", linewidth=1) plt.xlabel("X (см)") plt.ylabel("Y (см)") plt.title("Эквипотенциальные линии с силовыми стрелками") plt.savefig("points.png", dpi=300) if __name__ == "__main__": main()