{"spec_id":"eye-diagram-basic","library":"seaborn","language":"python","code":"\"\"\" anyplot.ai\neye-diagram-basic: Signal Integrity Eye Diagram\nLibrary: seaborn 0.13.2 | Python 3.13.14\nQuality: 88/100 | Updated: 2026-06-18\n\"\"\"\n\nimport os\n\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport pandas as pd\nimport seaborn as sns\nfrom matplotlib.colors import LinearSegmentedColormap\nfrom matplotlib.patches import Rectangle\nfrom scipy.ndimage import gaussian_filter1d\n\n\n# Theme tokens — Imprint palette chrome\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\"\nANYPLOT_AMBER = \"#DDCC77\"\n\n# Seaborn theme — warm cream/near-black surfaces with Imprint chrome\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        \"grid.color\": INK,\n        \"grid.alpha\": 0.15,\n        \"legend.facecolor\": ELEVATED_BG,\n        \"legend.edgecolor\": INK_SOFT,\n    },\n)\n\n# Imprint sequential colormap — green → blue for trace density\nimprint_seq = LinearSegmentedColormap.from_list(\"imprint_seq\", [\"#009E73\", \"#4467A3\"])\n\n# Data — NRZ signal with bandwidth-limited transitions, jitter, and noise\nnp.random.seed(42)\nn_traces = 400\nsamples_per_ui = 200\nui_span = 2\nn_display = samples_per_ui * ui_span\nnoise_sigma = 0.05\njitter_sigma = 0.03\nbw_filter_sigma = 12\n\nall_time = []\nall_voltage = []\nt_ui = np.linspace(0, ui_span, n_display, endpoint=False)\n\nfor _ in range(n_traces):\n    n_bits = 8\n    bits = np.random.randint(0, 2, size=n_bits)\n    samples_total = samples_per_ui * n_bits\n\n    signal_raw = np.repeat(bits.astype(float), samples_per_ui)\n    signal_smooth = gaussian_filter1d(signal_raw, sigma=bw_filter_sigma)\n\n    jitter_shift = int(np.random.normal(0, jitter_sigma * samples_per_ui))\n    signal_smooth = np.roll(signal_smooth, jitter_shift)\n    signal_smooth += np.random.normal(0, noise_sigma, samples_total)\n\n    start_bit = 3\n    start_idx = start_bit * samples_per_ui\n    end_idx = start_idx + n_display\n    segment = signal_smooth[start_idx:end_idx]\n\n    all_time.extend(t_ui.tolist())\n    all_voltage.extend(segment.tolist())\n\ndf = pd.DataFrame({\"time\": all_time, \"voltage\": all_voltage})\n\n# Eye measurements — first eye center at t ≈ 0.5 UI (between transitions at t=0 and t=1)\neye_center_t = 0.5\ncenter_mask = (df[\"time\"] >= 0.35) & (df[\"time\"] <= 0.65)\ncenter_v = df.loc[center_mask, \"voltage\"]\nlogic0_center = center_v[center_v < 0.5]\nlogic1_center = center_v[center_v >= 0.5]\neye_floor = float(np.percentile(logic0_center, 99))\neye_ceiling = float(np.percentile(logic1_center, 1))\neye_height_v = max(eye_ceiling - eye_floor, 0.01)\n\n# Eye width: find the transition-free horizontal zone at mid-voltage\nn_tbins = 200\nbins_time = np.linspace(0, 2, n_tbins + 1)\nbin_centers = (bins_time[:-1] + bins_time[1:]) / 2\nnear_threshold = (df[\"voltage\"] > 0.3) & (df[\"voltage\"] < 0.7)\ncrossing_hist, _ = np.histogram(df.loc[near_threshold, \"time\"], bins=bins_time)\nin_eye = crossing_hist < crossing_hist.max() * 0.08\ncenter_bin = int(np.argmin(np.abs(bin_centers - eye_center_t)))\nleft = center_bin\nright = center_bin\nwhile left > 0 and in_eye[left - 1]:\n    left -= 1\nwhile right < len(in_eye) - 1 and in_eye[right + 1]:\n    right += 1\neye_t_left = float(bin_centers[left])\neye_t_right = float(bin_centers[right])\neye_width_ui = max(eye_t_right - eye_t_left, 0.01)\neye_mid_t = (eye_t_left + eye_t_right) / 2\n\n# Plot\nfig, ax = plt.subplots(figsize=(8, 4.5), dpi=400)\n\n# Seaborn 2D histogram — density heatmap; thresh=1 makes zero-count bins transparent\nsns.histplot(\n    data=df,\n    x=\"time\",\n    y=\"voltage\",\n    bins=[300, 180],\n    stat=\"count\",\n    thresh=1,\n    cbar=True,\n    cbar_kws={\"label\": \"Trace Density\", \"shrink\": 0.8},\n    cmap=imprint_seq,\n    ax=ax,\n)\n\n# NRZ reference levels — labeled for engineering context\nax.axhline(y=0.0, color=INK_SOFT, linewidth=0.8, linestyle=\"--\", alpha=0.4)\nax.axhline(y=1.0, color=INK_SOFT, linewidth=0.8, linestyle=\"--\", alpha=0.4)\nax.text(1.93, 0.04, \"Logic 0\", fontsize=7, color=INK_SOFT, va=\"bottom\", ha=\"right\")\nax.text(1.93, 0.96, \"Logic 1\", fontsize=7, color=INK_SOFT, va=\"top\", ha=\"right\")\n\n# Eye opening outline — dashed rectangle highlights the clear region\neye_rect = Rectangle(\n    (eye_t_left, eye_floor),\n    eye_width_ui,\n    eye_height_v,\n    linewidth=0.9,\n    edgecolor=ANYPLOT_AMBER,\n    facecolor=\"none\",\n    linestyle=\"--\",\n    alpha=0.8,\n)\nax.add_patch(eye_rect)\n\n# Eye height annotation — vertical double arrow at eye center\nax.annotate(\n    \"\",\n    xy=(eye_mid_t, eye_floor),\n    xytext=(eye_mid_t, eye_ceiling),\n    arrowprops={\"arrowstyle\": \"<->\", \"color\": ANYPLOT_AMBER, \"lw\": 1.0},\n)\nax.text(\n    eye_mid_t + 0.03,\n    (eye_floor + eye_ceiling) / 2,\n    f\"H: {eye_height_v:.2f} V\",\n    fontsize=6.5,\n    color=ANYPLOT_AMBER,\n    va=\"center\",\n    ha=\"left\",\n)\n\n# Eye width annotation — horizontal double arrow at mid-eye\nv_arrow = eye_floor + eye_height_v * 0.28\nax.annotate(\n    \"\",\n    xy=(eye_t_left, v_arrow),\n    xytext=(eye_t_right, v_arrow),\n    arrowprops={\"arrowstyle\": \"<->\", \"color\": ANYPLOT_AMBER, \"lw\": 1.0},\n)\nax.text(\n    eye_mid_t, v_arrow - 0.06, f\"W: {eye_width_ui:.2f} UI\", fontsize=6.5, color=ANYPLOT_AMBER, va=\"top\", ha=\"center\"\n)\n\nax.set_xlim(0, 2)\nax.set_ylim(-0.3, 1.3)\nax.set_xticks([0, 0.5, 1.0, 1.5, 2.0])\n\n# Style\ntitle = \"eye-diagram-basic · python · seaborn · anyplot.ai\"\nax.set_title(title, fontsize=12, fontweight=\"medium\", color=INK)\nax.set_xlabel(\"Time (UI)\", fontsize=10, color=INK)\nax.set_ylabel(\"Voltage (V)\", fontsize=10, color=INK)\nax.tick_params(axis=\"both\", labelsize=8, colors=INK_SOFT)\n\nsns.despine(ax=ax, top=True, right=True)\n\n# Style colorbar text\nif len(fig.axes) > 1:\n    cbar_ax = fig.axes[-1]\n    cbar_ax.tick_params(colors=INK_SOFT, labelsize=8)\n    cbar_ax.yaxis.label.set_color(INK)\n    for spine in cbar_ax.spines.values():\n        spine.set_color(INK_SOFT)\n\n# Save\nplt.savefig(f\"plot-{THEME}.png\", dpi=400, facecolor=PAGE_BG)\nplt.close()\n"}