Chris Parmer — home

Shmoo plot

Chip Test — pass/fail in V×F space, computed

Example from the compendium of canonical charts

Chip Test — Shmoo plot (pass/fail in V×F space, computed)

Python Code

"""Chip Test — Shmoo plot (pass/fail in V×F space, computed)."""
from pathlib import Path

# ── Palette + theme (matching the Plotly Studio gallery these charts ship in) ──
VIOLET, TEAL, GREEN, PINK, ORANGE = "#845EEE", "#52B3D0", "#55B685", "#DA5597", "#E9A23B"
PRIMARY, SECONDARY = VIOLET, TEAL
COLORWAY = [VIOLET, TEAL, GREEN, PINK, ORANGE]
BG, TEXT, GRID, MUTED = "#ffffff", "#1c2024", "#d9d9e0", "#60646c"
FONT = "Inter, -apple-system, BlinkMacSystemFont, sans-serif"
COLORSCALE = [[0, "rgba(132, 94, 238, 0.05)"], [1, "rgba(132, 94, 238, 0.9)"]]


def apply_theme(fig):
    """Light gallery theme: white background, Inter font, soft gridlines."""
    fig.update_layout(
        paper_bgcolor=BG, plot_bgcolor=BG, colorway=COLORWAY,
        font=dict(family=FONT, color=TEXT, size=12),
        legend=dict(font=dict(color=TEXT)),
        hoverlabel=dict(bgcolor="#f0f0f3", font=dict(color=TEXT, family=FONT), bordercolor=GRID),
    )
    fig.update_xaxes(gridcolor=GRID, linecolor=GRID, zerolinecolor=GRID)
    fig.update_yaxes(gridcolor=GRID, linecolor=GRID, zerolinecolor=GRID)


def fetch_csv(url, **kwargs):
    import io
    import pandas as pd
    import requests
    r = requests.get(url, timeout=60)
    r.raise_for_status()
    return pd.read_csv(io.StringIO(r.text), **kwargs)


def fetch_json(url):
    import requests
    r = requests.get(url, timeout=60)
    r.raise_for_status()
    return r.json()

import numpy as np
import plotly.graph_objects as go


def generate():
    V = np.linspace(0.6, 1.2, 60)   # voltage (V)
    F = np.linspace(0.1, 2.0, 80)   # frequency (GHz)

    # Fmax(V): max operating frequency given supply voltage
    Fmax = 2.0 * (1 - np.exp(-5 * (V - 0.7)))
    Fmax = np.clip(Fmax, 0, None)

    # Build pass/fail matrix
    pass_matrix = np.zeros((len(V), len(F)), dtype=int)
    for i, v in enumerate(V):
        if v >= 0.7:
            for j, f in enumerate(F):
                if f <= Fmax[i]:
                    pass_matrix[i, j] = 1

    print(f"  pass cells: {pass_matrix.sum()} / {pass_matrix.size}")

    colorscale = [
        [0.0,  "#DA5597"],
        [0.49, "#DA5597"],   # fail — PINK (sharp boundary)
        [0.51, "#55B685"],
        [1.0,  "#55B685"],   # pass — GREEN
    ]

    fig = go.Figure(go.Heatmap(
        x=F,
        y=V,
        z=pass_matrix,
        colorscale=colorscale,
        zmin=0,
        zmax=1,
        colorbar=dict(
            tickvals=[0.25, 0.75],
            ticktext=["FAIL", "PASS"],
            thickness=16,
            len=0.5,
        ),
        hovertemplate="Freq: %{x:.2f} GHz<br>Volt: %{y:.3f} V<br>%{z}<extra></extra>",
    ))

    # Overlay Fmax curve
    fig.add_trace(go.Scatter(
        x=Fmax,
        y=V,
        mode="lines",
        line=dict(color="white", width=2.5, dash="dash"),
        name="Fmax boundary",
        hovertemplate="V=%{y:.3f} V → Fmax=%{x:.2f} GHz<extra></extra>",
    ))

    fig.update_layout(
        xaxis=dict(title="Frequency (GHz)"),
        yaxis=dict(title="Voltage (V)"),
        legend=dict(x=0.02, y=0.98, bgcolor="rgba(0,0,0,0.4)", font=dict(color="white")),
        margin=dict(t=20, b=60, l=60, r=80),
    )

    apply_theme(fig)
    return fig


fig = generate()
fig.show()

Made with Plotly