{"spec_id":"eye-diagram-basic","library":"letsplot","language":"python","code":"\"\"\" anyplot.ai\neye-diagram-basic: Signal Integrity Eye Diagram\nLibrary: letsplot 4.10.1 | Python 3.13.13\nQuality: 92/100 | Updated: 2026-06-18\n\"\"\"\n\nimport os\n\nimport numpy as np\nimport pandas as pd\nfrom lets_plot import (\n    LetsPlot,\n    aes,\n    element_blank,\n    element_rect,\n    element_text,\n    geom_hline,\n    geom_raster,\n    geom_segment,\n    geom_text,\n    ggplot,\n    ggsize,\n    guide_colorbar,\n    labs,\n    layer_tooltips,\n    scale_fill_gradientn,\n    scale_x_continuous,\n    scale_y_continuous,\n    theme,\n)\nfrom lets_plot.export import ggsave\n\n\nLetsPlot.setup_html()\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# Oscilloscope screen always dark (domain-appropriate regardless of theme)\nSCOPE_BG = \"#000004\"\n\n# Imprint palette — imprint_seq colormap anchored to scope background:\n# scope black → brand green → Imprint blue (imprint_seq with dark low)\nDENSITY_COLORS = [\"#000004\", \"#009E73\", \"#4467A3\"]\n\n# Imprint cyan for eye measurement annotations\nANN_COLOR = \"#2ABCCD\"\n\n# Data — Simulated NRZ eye diagram\nnp.random.seed(42)\nn_traces = 400\nsamples_per_ui = 150\n# Use 7 bits total and extract from interior to eliminate boundary artifacts\nn_bits_total = 7\nn_samples = samples_per_ui * n_bits_total\ntime_full = np.linspace(0, n_bits_total, n_samples, endpoint=False)\n\namplitude = 1.0\nnoise_sigma = 0.05 * amplitude\njitter_sigma = 0.03\nsteepness = 8.0 / 0.7\n\nall_time = []\nall_voltage = []\n\nfor _ in range(n_traces):\n    bits = np.random.randint(0, 2, n_bits_total + 1)\n    voltage = np.ones(n_samples) * bits[0] * amplitude\n\n    for bit_idx in range(1, n_bits_total + 1):\n        transition_time = bit_idx + np.random.normal(0, jitter_sigma)\n        if bits[bit_idx] != bits[bit_idx - 1]:\n            direction = (bits[bit_idx] - bits[bit_idx - 1]) * amplitude\n            voltage += direction / (1.0 + np.exp(-steepness * (time_full - transition_time)))\n\n    voltage += np.random.normal(0, noise_sigma, n_samples)\n\n    # Extract 2 UI window from bits 3–5 — well away from signal boundaries\n    mask = (time_full >= 3.0) & (time_full < 5.0)\n    t_window = time_full[mask] - 3.0\n    v_window = voltage[mask]\n\n    all_time.extend(t_window)\n    all_voltage.extend(v_window)\n\nall_time = np.array(all_time)\nall_voltage = np.array(all_voltage)\n\n# 2D density heatmap\nn_time_bins = 300\nn_voltage_bins = 180\ntime_edges = np.linspace(0, 2.0, n_time_bins + 1)\nvoltage_edges = np.linspace(-0.3, 1.3, n_voltage_bins + 1)\n\ndensity, _, _ = np.histogram2d(all_time, all_voltage, bins=[time_edges, voltage_edges])\ndensity = density / density.max()\n\n# Long-form DataFrame\ntime_centers = (time_edges[:-1] + time_edges[1:]) / 2\nvoltage_centers = (voltage_edges[:-1] + voltage_edges[1:]) / 2\ntime_grid, voltage_grid = np.meshgrid(time_centers, voltage_centers, indexing=\"ij\")\n\ndf = pd.DataFrame({\"time_ui\": time_grid.ravel(), \"voltage\": voltage_grid.ravel(), \"density\": density.ravel()})\ndf = df[df[\"density\"] > 0].reset_index(drop=True)\n\n# Eye measurements at center column\ncenter_col = n_time_bins // 2\ncenter_density = density[center_col, :]\nthreshold = 0.05\nlow_density_mask = center_density < threshold\nvoltage_center_vals = voltage_centers[low_density_mask]\neye_region = voltage_center_vals[(voltage_center_vals > 0.15) & (voltage_center_vals < 0.85)]\neye_bottom = eye_region.min() if len(eye_region) > 0 else 0.25\neye_top = eye_region.max() if len(eye_region) > 0 else 0.75\neye_height = eye_top - eye_bottom\neye_mid_v = (eye_top + eye_bottom) / 2\n\nmid_row = np.argmin(np.abs(voltage_centers - eye_mid_v))\nrow_density = density[:, mid_row]\nlow_density_time = time_centers[row_density < threshold]\neye_time_region = low_density_time[(low_density_time > 0.6) & (low_density_time < 1.4)]\neye_left = eye_time_region.min() if len(eye_time_region) > 0 else 0.75\neye_right = eye_time_region.max() if len(eye_time_region) > 0 else 1.25\neye_width = eye_right - eye_left\n\n# Annotation DataFrames\nheight_x = 1.34\nheight_seg = pd.DataFrame({\"x\": [height_x], \"y\": [eye_bottom], \"xend\": [height_x], \"yend\": [eye_top]})\nwidth_seg = pd.DataFrame({\"x\": [eye_left], \"y\": [eye_mid_v], \"xend\": [eye_right], \"yend\": [eye_mid_v]})\nheight_label = pd.DataFrame({\"x\": [height_x + 0.08], \"y\": [eye_mid_v], \"label\": [f\"Eye Height: {eye_height:.2f} V\"]})\nwidth_label = pd.DataFrame(\n    {\"x\": [(eye_left + eye_right) / 2], \"y\": [eye_mid_v - 0.09], \"label\": [f\"Eye Width: {eye_width:.2f} UI\"]}\n)\n\n# Title with font scaling\ntitle = \"eye-diagram-basic · python · letsplot · anyplot.ai\"\ntitle_size = round(16 * min(1.0, 67 / len(title)))\n\n# Plot\nplot = (\n    ggplot(df, aes(x=\"time_ui\", y=\"voltage\", fill=\"density\"))\n    + geom_raster(\n        tooltips=layer_tooltips()\n        .format(\"@time_ui\", \".2f\")\n        .format(\"@voltage\", \".2f\")\n        .format(\"@density\", \".3f\")\n        .line(\"Time: @time_ui UI\")\n        .line(\"Voltage: @voltage V\")\n        .line(\"Density: @density\")\n    )\n    + geom_hline(yintercept=0, color=INK_SOFT, size=0.6, linetype=\"dashed\", alpha=0.5)\n    + geom_hline(yintercept=1, color=INK_SOFT, size=0.6, linetype=\"dashed\", alpha=0.5)\n    + geom_segment(\n        aes(x=\"x\", y=\"y\", xend=\"xend\", yend=\"yend\"), data=height_seg, color=ANN_COLOR, size=1.2, inherit_aes=False\n    )\n    + geom_segment(\n        aes(x=\"x\", y=\"y\", xend=\"xend\", yend=\"yend\"), data=width_seg, color=ANN_COLOR, size=1.2, inherit_aes=False\n    )\n    + geom_text(\n        aes(x=\"x\", y=\"y\", label=\"label\"), data=height_label, color=ANN_COLOR, size=5, hjust=0, inherit_aes=False\n    )\n    + geom_text(\n        aes(x=\"x\", y=\"y\", label=\"label\"), data=width_label, color=ANN_COLOR, size=5, hjust=0.5, inherit_aes=False\n    )\n    + scale_fill_gradientn(\n        colors=DENSITY_COLORS, name=\"Trace\\nDensity\", guide=guide_colorbar(barwidth=10, barheight=200, nbin=256)\n    )\n    + scale_x_continuous(name=\"Time (UI)\", breaks=[0.0, 0.5, 1.0, 1.5, 2.0], expand=[0, 0])\n    + scale_y_continuous(name=\"Voltage (V)\", breaks=[0.0, 0.5, 1.0], labels=[\"0.0\", \"0.5\", \"1.0\"], expand=[0, 0])\n    + labs(title=title)\n    + theme(\n        plot_title=element_text(size=title_size, face=\"bold\", color=INK),\n        axis_title=element_text(size=12, color=INK_SOFT),\n        axis_text=element_text(size=10, color=INK_SOFT),\n        axis_ticks=element_blank(),\n        axis_line=element_blank(),\n        legend_text=element_text(size=10, color=INK_SOFT),\n        legend_title=element_text(size=12, face=\"bold\", color=INK),\n        panel_grid=element_blank(),\n        panel_background=element_rect(fill=SCOPE_BG, color=SCOPE_BG),\n        plot_background=element_rect(fill=PAGE_BG, color=PAGE_BG),\n        plot_margin=[40, 30, 20, 20],\n        legend_background=element_rect(fill=ELEVATED_BG, color=INK_SOFT),\n    )\n    + ggsize(800, 450)\n)\n\n# Save\nggsave(plot, f\"plot-{THEME}.png\", path=\".\", scale=4)\nggsave(plot, f\"plot-{THEME}.html\", path=\".\")\n"}