{"spec_id":"smith-chart-basic","library":"seaborn","language":"python","code":"\"\"\" anyplot.ai\nsmith-chart-basic: Smith Chart for RF/Impedance\nLibrary: seaborn 0.13.2 | Python 3.13.13\nQuality: 86/100 | Updated: 2026-05-20\n\"\"\"\n\nimport os\n\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport pandas as pd\nimport seaborn as sns\n\n\n# Theme tokens\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\"\n\n# Okabe-Ito data colors (categorical series)\nREACT_COLOR = \"#C475FD\"  # Reactance arcs — second series\nVSWR_COLOR = \"#4467A3\"  # VSWR reference circle — third series\n\n# Apply seaborn theme for chrome elements\nsns.set_theme(\n    style=\"ticks\",\n    rc={\n        \"figure.facecolor\": PAGE_BG,\n        \"axes.facecolor\": PAGE_BG,\n        \"axes.edgecolor\": INK_SOFT,\n        \"axes.labelcolor\": INK,\n        \"text.color\": INK,\n        \"xtick.color\": INK_SOFT,\n        \"ytick.color\": INK_SOFT,\n        \"legend.facecolor\": ELEVATED_BG,\n        \"legend.edgecolor\": INK_SOFT,\n    },\n)\n\n# Data — antenna impedance sweep 1–6 GHz, Z₀ = 50 Ω\nnp.random.seed(42)\nz0 = 50\nn_points = 100  # Dense for smooth frequency-gradient locus\nfreq_ghz = np.linspace(1, 6, n_points)\n\nt = np.linspace(0, 1.8 * np.pi, n_points)\nz_real = 50 + 30 * np.sin(t) + 15 * np.cos(2 * t) + 10 * (t / (2 * np.pi))\nz_imag = 40 * np.sin(1.5 * t) + 20 * np.cos(t) - 15 * (t / (2 * np.pi))\n\nz_norm = (z_real + 1j * z_imag) / z0\ngamma = (z_norm - 1) / (z_norm + 1)\ngamma_real = gamma.real\ngamma_imag = gamma.imag\n\n# Plot — square canvas (2400×2400 px)\nfig, ax = plt.subplots(figsize=(6, 6), dpi=400, facecolor=PAGE_BG)\nax.set_facecolor(PAGE_BG)\n\n# Smith chart grid — constant resistance circles\ntheta = np.linspace(0, 2 * np.pi, 300)\nfor r in [0, 0.2, 0.5, 1, 2, 5]:\n    cx = r / (r + 1) + (1 / (r + 1)) * np.cos(theta)\n    cy = (1 / (r + 1)) * np.sin(theta)\n    mask = cx**2 + cy**2 <= 1.001\n    ax.plot(cx[mask], cy[mask], color=INK_SOFT, linewidth=0.8, alpha=0.6, zorder=1)\n    if r > 0:\n        lx = r / (r + 1) - 1 / (r + 1) + 0.02\n        if lx > -0.95:\n            ax.text(lx, 0.03, f\"r={r}\", fontsize=8, color=INK_SOFT, va=\"bottom\", zorder=2)\n\n# Constant reactance arcs\narc_theta = np.linspace(-np.pi / 2, np.pi / 2, 300)\nfor x in [0.2, 0.5, 1, 2, 5]:\n    radius = 1 / x\n    arc_x = 1 + radius * np.cos(arc_theta)\n    arc_y_pos = (1 / x) + radius * np.sin(arc_theta)\n    arc_y_neg = -(1 / x) + radius * np.sin(arc_theta)\n\n    mask_pos = (arc_x**2 + arc_y_pos**2 <= 1.001) & (arc_x >= -0.001)\n    ax.plot(arc_x[mask_pos], arc_y_pos[mask_pos], color=REACT_COLOR, linewidth=0.8, alpha=0.6, zorder=1)\n\n    mask_neg = (arc_x**2 + arc_y_neg**2 <= 1.001) & (arc_x >= -0.001)\n    ax.plot(arc_x[mask_neg], arc_y_neg[mask_neg], color=REACT_COLOR, linewidth=0.8, alpha=0.6, zorder=1)\n\n    if x <= 2:\n        ang = np.arctan(1 / x)\n        lxp = 0.87 * np.cos(ang)\n        lyp = 0.87 * np.sin(ang)\n        ax.text(lxp, lyp + 0.03, f\"x={x}\", fontsize=8, color=REACT_COLOR, va=\"bottom\", ha=\"center\")\n        ax.text(lxp, -lyp - 0.03, f\"x=-{x}\", fontsize=8, color=REACT_COLOR, va=\"top\", ha=\"center\")\n\n# Unit circle boundary and real axis\nax.plot(np.cos(theta), np.sin(theta), color=INK_SOFT, linewidth=1.5, zorder=1)\nax.axhline(0, color=INK_SOFT, linewidth=1.0, alpha=0.6, zorder=1)\n\n# VSWR 3:1 circle (|Γ| = 0.5)\nvswr_r = 0.5\nax.plot(vswr_r * np.cos(theta), vswr_r * np.sin(theta), \"--\", color=VSWR_COLOR, linewidth=1.5, zorder=2)\nax.text(0.36, 0.37, \"VSWR 3:1\", fontsize=8, color=VSWR_COLOR, fontweight=\"bold\")\n\n# Impedance locus DataFrame\ndf_locus = pd.DataFrame({\"gamma_real\": gamma_real, \"gamma_imag\": gamma_imag, \"freq_ghz\": freq_ghz})\n\n# Thin background line for trajectory continuity\nax.plot(gamma_real, gamma_imag, color=INK_SOFT, linewidth=1.2, alpha=0.4, zorder=4)\n\n# Frequency-gradient scatter — seaborn continuous hue encoding with viridis colormap.\n# Coloring each point by freq_ghz reveals sweep direction (purple=1 GHz → yellow=6 GHz).\nsns.scatterplot(\n    data=df_locus,\n    x=\"gamma_real\",\n    y=\"gamma_imag\",\n    hue=\"freq_ghz\",\n    palette=\"viridis\",\n    hue_norm=(1.0, 6.0),\n    s=40,\n    ax=ax,\n    zorder=5,\n    legend=False,\n    edgecolor=\"none\",\n)\n\n# Colorbar to decode frequency gradient\nnorm = plt.Normalize(1.0, 6.0)\nsm = plt.cm.ScalarMappable(cmap=\"viridis\", norm=norm)\nsm.set_array([])\ncbar = fig.colorbar(sm, ax=ax, shrink=0.5, aspect=20, pad=0.05)\ncbar.set_label(\"Frequency (GHz)\", fontsize=8, color=INK)\ncbar.ax.tick_params(labelsize=7, colors=INK_SOFT)\ncbar.outline.set_edgecolor(INK_SOFT)\n\n# Key frequency markers — dark outline for contrast against viridis gradient\nkey_indices = [0, n_points // 4, n_points // 2, 3 * n_points // 4, n_points - 1]\ndf_markers = df_locus.iloc[key_indices].copy()\nsns.scatterplot(\n    data=df_markers,\n    x=\"gamma_real\",\n    y=\"gamma_imag\",\n    s=100,\n    color=INK,\n    edgecolor=PAGE_BG,\n    linewidth=1.5,\n    ax=ax,\n    zorder=10,\n    legend=False,\n)\n\n# Frequency annotations — 1.0 GHz placed below its point, clear of 2.3 GHz above\nlabel_offsets = {\n    0: (8, -18),\n    n_points // 4: (10, 8),\n    n_points // 2: (8, -14),\n    3 * n_points // 4: (-45, 8),\n    n_points - 1: (-45, -12),\n}\nfor idx in key_indices:\n    ox, oy = label_offsets.get(idx, (8, 8))\n    ax.annotate(\n        f\"{freq_ghz[idx]:.1f} GHz\",\n        (gamma_real[idx], gamma_imag[idx]),\n        textcoords=\"offset points\",\n        xytext=(ox, oy),\n        fontsize=8,\n        fontweight=\"bold\",\n        color=INK,\n    )\n\n# Center marker — matched condition Z = Z₀\nax.scatter([0], [0], s=80, color=INK, marker=\"+\", linewidths=2, zorder=10)\nax.annotate(\"Z₀ (50 Ω)\", (0, 0), textcoords=\"offset points\", xytext=(-38, -14), fontsize=8, color=INK)\n\n# Style\nax.set_xlim(-1.15, 1.15)\nax.set_ylim(-1.15, 1.15)\nax.set_aspect(\"equal\")\nax.set_xlabel(\"Real(Γ)\", fontsize=10, color=INK)\nax.set_ylabel(\"Imag(Γ)\", fontsize=10, color=INK)\nax.set_title(\"smith-chart-basic · python · seaborn · anyplot.ai\", fontsize=12, fontweight=\"medium\", color=INK)\nax.tick_params(axis=\"both\", labelsize=8, colors=INK_SOFT)\nax.grid(False)\n\nax.spines[\"top\"].set_visible(False)\nax.spines[\"right\"].set_visible(False)\nax.spines[\"left\"].set_color(INK_SOFT)\nax.spines[\"bottom\"].set_color(INK_SOFT)\n\n# Legend (locus entry replaced by colorbar above)\nax.plot([], [], color=INK_SOFT, linewidth=0.8, alpha=0.6, label=\"Constant R circles\")\nax.plot([], [], color=REACT_COLOR, linewidth=0.8, alpha=0.6, label=\"Constant X arcs\")\nax.plot([], [], color=VSWR_COLOR, linewidth=1.5, linestyle=\"--\", label=\"VSWR 3:1 circle\")\nlegend = ax.legend(loc=\"upper left\", fontsize=8, framealpha=0.9)\nlegend.get_frame().set_facecolor(ELEVATED_BG)\nlegend.get_frame().set_edgecolor(INK_SOFT)\n\nplt.tight_layout()\n\n# Save\nplt.savefig(f\"plot-{THEME}.png\", dpi=400, bbox_inches=\"tight\", facecolor=PAGE_BG)\n"}