{"spec_id":"barcode-code128","library":"plotly","language":"python","code":"\"\"\" anyplot.ai\nbarcode-code128: Code 128 Barcode\nLibrary: plotly 6.7.0 | Python 3.13.13\nQuality: 94/100 | Updated: 2026-05-21\n\"\"\"\n\nimport os\n\nimport plotly.graph_objects as go\n\n\n# Theme tokens\nTHEME = os.getenv(\"ANYPLOT_THEME\", \"light\")\nPAGE_BG = \"#FAF8F1\" if THEME == \"light\" else \"#1A1A17\"\nINK = \"#1A1A17\" if THEME == \"light\" else \"#F0EFE8\"\nINK_SOFT = \"#4A4A44\" if THEME == \"light\" else \"#B8B7B0\"\n\n# Code 128 encoding patterns (11-module per symbol; STOP is 13 modules)\nCODE128_PATTERNS = {\n    \"START_A\": \"11010000100\",\n    \"START_B\": \"11010010000\",\n    \"START_C\": \"11010011100\",\n    \"STOP\": \"1100011101011\",\n    0: \"11011001100\",\n    1: \"11001101100\",\n    2: \"11001100110\",\n    3: \"10010011000\",\n    4: \"10010001100\",\n    5: \"10001001100\",\n    6: \"10011001000\",\n    7: \"10011000100\",\n    8: \"10001100100\",\n    9: \"11001001000\",\n    10: \"11001000100\",\n    11: \"11000100100\",\n    12: \"10110011100\",\n    13: \"10011011100\",\n    14: \"10011001110\",\n    15: \"10111001100\",\n    16: \"10011101100\",\n    17: \"10011100110\",\n    18: \"11001110010\",\n    19: \"11001011100\",\n    20: \"11001001110\",\n    21: \"11011100100\",\n    22: \"11001110100\",\n    23: \"11101101110\",\n    24: \"11101001100\",\n    25: \"11100101100\",\n    26: \"11100100110\",\n    27: \"11101100100\",\n    28: \"11100110100\",\n    29: \"11100110010\",\n    30: \"11011011000\",\n    31: \"11011000110\",\n    32: \"11000110110\",\n    33: \"10100011000\",\n    34: \"10001011000\",\n    35: \"10001000110\",\n    36: \"10110001000\",\n    37: \"10001101000\",\n    38: \"10001100010\",\n    39: \"11010001000\",\n    40: \"11000101000\",\n    41: \"11000100010\",\n    42: \"10110111000\",\n    43: \"10110001110\",\n    44: \"10001101110\",\n    45: \"10111011000\",\n    46: \"10111000110\",\n    47: \"10001110110\",\n    48: \"11101110110\",\n    49: \"11010001110\",\n    50: \"11000101110\",\n    51: \"11011101000\",\n    52: \"11011100010\",\n    53: \"11011101110\",\n    54: \"11101011000\",\n    55: \"11101000110\",\n    56: \"11100010110\",\n    57: \"11101101000\",\n    58: \"11101100010\",\n    59: \"11100011010\",\n    60: \"11101111010\",\n    61: \"11001000010\",\n    62: \"11110001010\",\n    63: \"10100110000\",\n    64: \"10100001100\",\n    65: \"10010110000\",\n    66: \"10010000110\",\n    67: \"10000101100\",\n    68: \"10000100110\",\n    69: \"10110010000\",\n    70: \"10110000100\",\n    71: \"10011010000\",\n    72: \"10011000010\",\n    73: \"10000110100\",\n    74: \"10000110010\",\n    75: \"11000010010\",\n    76: \"11001010000\",\n    77: \"11110111010\",\n    78: \"11000010100\",\n    79: \"10001111010\",\n    80: \"10100111100\",\n    81: \"10010111100\",\n    82: \"10010011110\",\n    83: \"10111100100\",\n    84: \"10011110100\",\n    85: \"10011110010\",\n    86: \"11110100100\",\n    87: \"11110010100\",\n    88: \"11110010010\",\n    89: \"11011011110\",\n    90: \"11011110110\",\n    91: \"11110110110\",\n    92: \"10101111000\",\n    93: \"10100011110\",\n    94: \"10001011110\",\n    95: \"10111101000\",\n    96: \"10111100010\",\n    97: \"11110101000\",\n    98: \"11110100010\",\n    99: \"10111011110\",\n    100: \"10111101110\",\n    101: \"11101011110\",\n    102: \"11110101110\",\n    103: \"11010000100\",\n    104: \"11010010000\",\n    105: \"11010011100\",\n    106: \"1100011101011\",\n}\n\n# Code 128B: ASCII 32-127 mapped to values 0-95\nCODE128B_MAP = {chr(i): i - 32 for i in range(32, 128)}\n\n# Data — shipping tracking code (Code 128B subset covers full alphanumeric range)\ncontent = \"SHIP-2024-ABC123\"\n\n# Encode using Code 128B subset\nvalues = [104]  # START_B\nfor char in content:\n    values.append(CODE128B_MAP.get(char, 0))\n\n# Check digit: modulo 103 algorithm (mandatory per spec)\nchecksum = values[0]\nfor i, val in enumerate(values[1:], 1):\n    checksum += i * val\nchecksum = checksum % 103\nvalues.append(checksum)\n\n# Build binary pattern: START_B + data symbols + check digit + STOP\nbarcode_pattern = CODE128_PATTERNS[\"START_B\"]\nfor val in values[1:-1]:\n    barcode_pattern += CODE128_PATTERNS[val]\nbarcode_pattern += CODE128_PATTERNS[values[-1]]\nbarcode_pattern += CODE128_PATTERNS[\"STOP\"]\n\n# Calculate bar positions and widths from binary pattern\nQUIET_ZONE = 80  # generous quiet zone for reliable scanning\nMODULE_W = 4  # data units per module\nx_positions = []\nbar_widths_list = []\ncurrent_x = QUIET_ZONE\n\nfor i, bit in enumerate(barcode_pattern):\n    if bit == \"1\":\n        if i == 0 or barcode_pattern[i - 1] == \"0\":\n            width = MODULE_W\n            j = i + 1\n            while j < len(barcode_pattern) and barcode_pattern[j] == \"1\":\n                width += MODULE_W\n                j += 1\n            x_positions.append(current_x + width / 2)\n            bar_widths_list.append(width)\n    current_x += MODULE_W\n\ntotal_width = QUIET_ZONE + len(barcode_pattern) * MODULE_W + QUIET_ZONE\n\n# Structural region boundaries in x coordinates (modules: START=11, each char=11, STOP=13)\nSTART_X0 = QUIET_ZONE\nSTART_X1 = QUIET_ZONE + 11 * MODULE_W\n\ndata_start_x = START_X1\ndata_end_x = data_start_x + len(content) * 11 * MODULE_W\n\ncheck_x0 = data_end_x\ncheck_x1 = check_x0 + 11 * MODULE_W\n\nstop_x0 = check_x1\nstop_x1 = stop_x0 + 13 * MODULE_W\n\n# Plot\nfig = go.Figure()\n\nBAR_Y0 = 90\nBAR_Y1 = 510\nmid_bar_y = (BAR_Y0 + BAR_Y1) / 2\n\n# Barcode bars — tall to utilize canvas space\nfor x, w in zip(x_positions, bar_widths_list, strict=True):\n    fig.add_shape(type=\"rect\", x0=x - w / 2, x1=x + w / 2, y0=BAR_Y0, y1=BAR_Y1, fillcolor=INK, line={\"width\": 0})\n\n# --- Structural anatomy annotations ---\n# Horizontal bracket line spanning the full barcode (above bars)\nBRACKET_Y = BAR_Y1 + 14\nfig.add_shape(\n    type=\"line\", x0=START_X0, x1=stop_x1, y0=BRACKET_Y, y1=BRACKET_Y, line={\"color\": INK_SOFT, \"width\": 1}, opacity=0.55\n)\n\n# Vertical tick marks at each region boundary\nfor bx in [START_X0, START_X1, data_end_x, check_x1, stop_x1]:\n    fig.add_shape(\n        type=\"line\",\n        x0=bx,\n        x1=bx,\n        y0=BRACKET_Y - 6,\n        y1=BRACKET_Y + 6,\n        line={\"color\": INK_SOFT, \"width\": 1},\n        opacity=0.55,\n    )\n\n# Region labels just above the bracket line (narrow regions use smaller font)\nLABEL_Y = BRACKET_Y + 10\nfor x0, x1, label, fsize in [\n    (START_X0, START_X1, \"START B\", 10),\n    (data_start_x, data_end_x, f\"DATA  ({len(content)} chars)\", 11),\n    (check_x0, check_x1, \"CHK\", 10),\n    (stop_x0, stop_x1, \"STOP\", 10),\n]:\n    fig.add_annotation(\n        x=(x0 + x1) / 2,\n        y=LABEL_Y,\n        text=label,\n        showarrow=False,\n        font={\"size\": fsize, \"color\": INK_SOFT},\n        xanchor=\"center\",\n        yanchor=\"bottom\",\n    )\n\n# --- Hover interactivity (distinctive plotly feature) ---\n# Per-character data hover points — reveals encoded value for each character\nchar_xs = [data_start_x + (i * 11 + 5.5) * MODULE_W for i in range(len(content))]\nchar_labels = [\n    f\"<b>'{char}'</b>  ·  Code 128B value: {val}<br>Position {i + 1} / {len(content)}\"\n    for i, (char, val) in enumerate(zip(content, values[1:-1], strict=False))\n]\nfig.add_trace(\n    go.Scatter(\n        x=char_xs,\n        y=[mid_bar_y] * len(char_xs),\n        mode=\"markers\",\n        marker={\"opacity\": 0, \"size\": 30, \"color\": INK},\n        text=char_labels,\n        hovertemplate=\"%{text}<extra></extra>\",\n        showlegend=False,\n        hoverlabel={\"bgcolor\": PAGE_BG, \"bordercolor\": INK_SOFT, \"font\": {\"color\": INK, \"size\": 13}},\n    )\n)\n\n# Structural region hover points\nfor cx, hover_text in [\n    ((START_X0 + START_X1) / 2, \"<b>START B Pattern</b><br>Signals Code 128 subset B (ASCII 32–127)<br>11 modules\"),\n    ((check_x0 + check_x1) / 2, f\"<b>Check Digit: {checksum}</b><br>Modulo 103 of weighted symbol sum<br>11 modules\"),\n    ((stop_x0 + stop_x1) / 2, \"<b>STOP Pattern</b><br>Terminates every Code 128 barcode<br>13 modules\"),\n]:\n    fig.add_trace(\n        go.Scatter(\n            x=[cx],\n            y=[mid_bar_y],\n            mode=\"markers\",\n            marker={\"opacity\": 0, \"size\": 20},\n            hovertemplate=f\"{hover_text}<extra></extra>\",\n            showlegend=False,\n            hoverlabel={\"bgcolor\": PAGE_BG, \"bordercolor\": INK_SOFT, \"font\": {\"color\": INK, \"size\": 13}},\n        )\n    )\n\n# Human-readable text below barcode\nfig.add_annotation(\n    x=total_width / 2,\n    y=45,\n    text=content,\n    showarrow=False,\n    font={\"size\": 26, \"family\": \"Courier New, monospace\", \"color\": INK},\n    xanchor=\"center\",\n    yanchor=\"middle\",\n)\n\n# Subset label above anatomy bracket\nfig.add_annotation(\n    x=total_width / 2,\n    y=600,\n    text=\"Code 128B  ·  ASCII Subset (32–127)\",\n    showarrow=False,\n    font={\"size\": 18, \"color\": INK_SOFT},\n    xanchor=\"center\",\n    yanchor=\"middle\",\n)\n\n# Layout\nfig.update_layout(\n    autosize=False,\n    title={\n        \"text\": \"barcode-code128 · python · plotly · anyplot.ai\",\n        \"font\": {\"size\": 16, \"color\": INK},\n        \"x\": 0.5,\n        \"xanchor\": \"center\",\n    },\n    xaxis={\"visible\": False, \"range\": [0, total_width], \"fixedrange\": True},\n    yaxis={\"visible\": False, \"range\": [0, 650], \"fixedrange\": True},\n    plot_bgcolor=PAGE_BG,\n    paper_bgcolor=PAGE_BG,\n    margin={\"l\": 80, \"r\": 40, \"t\": 80, \"b\": 60},\n    showlegend=False,\n)\n\n# Save\nfig.write_image(f\"plot-{THEME}.png\", width=800, height=450, scale=4)\nfig.write_html(f\"plot-{THEME}.html\", include_plotlyjs=\"cdn\")\n"}