{"spec_id":"smith-chart-basic","library":"matplotlib","language":"python","code":"\"\"\" anyplot.ai\nsmith-chart-basic: Smith Chart for RF/Impedance\nLibrary: matplotlib 3.10.9 | Python 3.13.13\nQuality: 92/100 | Updated: 2026-05-20\n\"\"\"\n\nimport os\nimport sys\n\n\n# Remove script directory from path to avoid name collision (this script is named matplotlib.py)\nsys.path = [p for p in sys.path if p != \"\" and \"implementations\" not in p]\n\nimport matplotlib.patches as mpatches\nimport matplotlib.pyplot as plt\nimport numpy as np\nfrom matplotlib.collections import LineCollection\nfrom matplotlib.colors import Normalize\n\n\n# Theme\nTHEME = os.getenv(\"ANYPLOT_THEME\", \"light\")\nPAGE_BG = \"#FAF8F1\" if THEME == \"light\" else \"#1A1A17\"\nELEVATED_BG = \"#FFFDF6\" if THEME == \"light\" else \"#242420\"\nINK = \"#1A1A17\" if THEME == \"light\" else \"#F0EFE8\"\nINK_SOFT = \"#4A4A44\" if THEME == \"light\" else \"#B8B7B0\"\nINK_MUTED = \"#6B6A63\" if THEME == \"light\" else \"#A8A79F\"\nOI_2 = \"#C475FD\"  # Okabe-Ito position 2 — VSWR circles\nOI_3 = \"#4467A3\"  # Okabe-Ito position 3 — boundary / matched condition\n\n# Data — antenna impedance sweep 1–6 GHz\nZ0 = 50\nnp.random.seed(42)\nfrequency = np.linspace(1e9, 6e9, 50)\nz_real = 50 + 30 * np.sin(2 * np.pi * (frequency - 1e9) / 2e9) + 10 * np.cos(4 * np.pi * (frequency - 1e9) / 5e9)\nz_imag = 20 * np.cos(2 * np.pi * (frequency - 1e9) / 1.5e9) + 15 * np.sin(3 * np.pi * (frequency - 1e9) / 5e9)\nz_norm = (z_real + 1j * z_imag) / Z0\ngamma = (z_norm - 1) / (z_norm + 1)\nfreq_ghz = frequency / 1e9\n\n# Plot — square canvas for Smith chart (2400×2400 px)\nfig, ax = plt.subplots(figsize=(6, 6), dpi=400, facecolor=PAGE_BG)\nax.set_facecolor(PAGE_BG)\nax.set_aspect(\"equal\")\n\n# Smith chart grid — constant resistance circles\ntheta = np.linspace(0, 2 * np.pi, 500)\nfor r in [0, 0.2, 0.5, 1, 2, 5]:\n    center = r / (r + 1)\n    radius = 1 / (r + 1)\n    x_c = center + radius * np.cos(theta)\n    y_c = radius * np.sin(theta)\n    mask = x_c**2 + y_c**2 <= 1.001\n    ax.plot(np.where(mask, x_c, np.nan), np.where(mask, y_c, np.nan), color=INK_MUTED, linewidth=0.7, alpha=0.35)\n    if r > 0:\n        label_x = center + radius\n        if label_x <= 1.0:\n            ax.text(label_x + 0.02, 0.02, f\"{r}\", fontsize=6, color=INK_MUTED, ha=\"left\", va=\"bottom\")\n\n# Constant reactance arcs\narc_theta = np.linspace(0, np.pi, 500)\nfor x in [0.2, 0.5, 1, 2, 5]:\n    center_y = 1 / x\n    radius = 1 / x\n    x_arc = 1 + radius * np.cos(arc_theta + np.pi)\n\n    # Inductive (upper half)\n    y_arc_pos = center_y + radius * np.sin(arc_theta + np.pi)\n    mask = x_arc**2 + y_arc_pos**2 <= 1.001\n    ax.plot(\n        np.where(mask, x_arc, np.nan), np.where(mask, y_arc_pos, np.nan), color=INK_MUTED, linewidth=0.7, alpha=0.35\n    )\n\n    # Capacitive (lower half)\n    y_arc_neg = -center_y + radius * np.sin(arc_theta)\n    mask = x_arc**2 + y_arc_neg**2 <= 1.001\n    ax.plot(\n        np.where(mask, x_arc, np.nan), np.where(mask, y_arc_neg, np.nan), color=INK_MUTED, linewidth=0.7, alpha=0.35\n    )\n\n    if x <= 1:\n        angle = 2 * np.arctan(1 / x)\n        lx, ly = np.cos(angle), np.sin(angle)\n        ax.text(lx, ly + 0.06, f\"+j{x}\", fontsize=6, color=INK_MUTED, ha=\"center\", va=\"bottom\")\n        ax.text(lx, -ly - 0.06, f\"-j{x}\", fontsize=6, color=INK_MUTED, ha=\"center\", va=\"top\")\n\n# Real axis\nax.axhline(y=0, color=INK_MUTED, linewidth=0.7, alpha=0.35)\n\n# Unit circle boundary\nax.plot(np.cos(theta), np.sin(theta), color=INK_SOFT, linewidth=1.5)\n\n# VSWR circles via matplotlib.patches.Circle — distinctive matplotlib feature\nfor vswr in [1.5, 2, 3]:\n    gamma_mag = (vswr - 1) / (vswr + 1)\n    vswr_circle = mpatches.Circle(\n        (0, 0), gamma_mag, fill=False, linestyle=\"--\", edgecolor=OI_2, linewidth=1.0, alpha=0.55, zorder=3\n    )\n    ax.add_patch(vswr_circle)\n    ax.text(0, gamma_mag + 0.04, f\"VSWR={vswr}\", fontsize=6, color=OI_2, ha=\"center\", alpha=0.8)\n\n# Matched condition marker\nax.plot(0, 0, \"o\", color=OI_3, markersize=7, zorder=6, label=\"Matched (Z=Z₀)\")\n\n# Impedance locus via LineCollection colored by frequency — distinctive matplotlib feature\n# cividis colormap chosen for sequential continuous data (perceptually uniform + colorblind-safe)\npoints = np.array([gamma.real, gamma.imag]).T.reshape(-1, 1, 2)\nsegments = np.concatenate([points[:-1], points[1:]], axis=1)\nnorm = Normalize(vmin=freq_ghz[0], vmax=freq_ghz[-1])\nlc = LineCollection(segments, cmap=\"cividis\", norm=norm, linewidth=2.5, zorder=5, label=\"Impedance Locus\")\nlc.set_array(freq_ghz[:-1])\nax.add_collection(lc)\n\n# Key frequency markers, color-matched to the locus colormap\nkey_indices = [0, 12, 24, 36, 49]\nax.scatter(\n    gamma.real[key_indices],\n    gamma.imag[key_indices],\n    c=freq_ghz[key_indices],\n    cmap=\"cividis\",\n    norm=norm,\n    s=40,\n    edgecolors=PAGE_BG,\n    linewidths=0.8,\n    zorder=7,\n)\n\n# Frequency labels at key points\nfor idx in key_indices:\n    x_pos, y_pos = gamma.real[idx], gamma.imag[idx]\n    offset_x = 0.10 if x_pos < 0.5 else -0.10\n    offset_y = 0.08 if y_pos >= 0 else -0.08\n    ax.annotate(\n        f\"{freq_ghz[idx]:.1f} GHz\",\n        (x_pos, y_pos),\n        xytext=(x_pos + offset_x, y_pos + offset_y),\n        fontsize=7,\n        color=INK,\n        arrowprops={\"arrowstyle\": \"->\", \"color\": INK_SOFT, \"lw\": 0.8},\n        zorder=10,\n    )\n\n# Colorbar — frequency scale for the cividis locus\ncbar = plt.colorbar(lc, ax=ax, shrink=0.72, pad=0.02, fraction=0.03)\ncbar.set_label(\"Frequency (GHz)\", fontsize=8, color=INK)\ncbar.ax.tick_params(labelsize=7, labelcolor=INK_SOFT)\ncbar.outline.set_edgecolor(INK_SOFT)\n\n# Style\nax.set_xlim(-1.3, 1.3)\nax.set_ylim(-1.3, 1.3)\nax.set_xlabel(\"Real(Γ)\", fontsize=10, color=INK)\nax.set_ylabel(\"Imag(Γ)\", fontsize=10, color=INK)\nax.set_title(\"smith-chart-basic · python · matplotlib · anyplot.ai\", fontsize=12, fontweight=\"medium\", color=INK)\nax.tick_params(axis=\"both\", labelsize=8, colors=INK_SOFT)\nax.set_xticks([])\nax.set_yticks([])\n\nfor spine in ax.spines.values():\n    spine.set_color(INK_SOFT)\n\n# Cardinal direction labels\nax.text(1.18, 0, \"Open\\n(Γ=1)\", fontsize=7, ha=\"center\", va=\"center\", color=INK_SOFT)\nax.text(-1.18, 0, \"Short\\n(Γ=-1)\", fontsize=7, ha=\"center\", va=\"center\", color=INK_SOFT)\nax.text(0, 1.18, \"+jX\\n(Inductive)\", fontsize=7, ha=\"center\", va=\"center\", color=INK_MUTED)\nax.text(0, -1.18, \"-jX\\n(Capacitive)\", fontsize=7, ha=\"center\", va=\"center\", color=INK_MUTED)\n\n# Legend\nleg = ax.legend(fontsize=7, loc=\"upper left\")\nif leg:\n    leg.get_frame().set_facecolor(ELEVATED_BG)\n    leg.get_frame().set_edgecolor(INK_SOFT)\n    plt.setp(leg.get_texts(), color=INK_SOFT)\n\nplt.tight_layout()\nplt.savefig(f\"plot-{THEME}.png\", dpi=400, bbox_inches=\"tight\", facecolor=PAGE_BG)\n"}