{"spec_id":"barcode-ean13","library":"altair","language":"python","code":"\"\"\" anyplot.ai\nbarcode-ean13: EAN-13 Barcode\nLibrary: altair 6.1.0 | Python 3.13.13\nQuality: 87/100 | Updated: 2026-05-21\n\"\"\"\n\nimport os\nimport sys\n\n\n# Remove this script's directory from sys.path to prevent self-import\n# (Python adds the script dir to sys.path[0], which would shadow the altair package)\n_d = os.path.dirname(os.path.abspath(__file__))\nsys.path = [p for p in sys.path if os.path.abspath(p or \".\") != _d]\ndel _d\n\nimport altair as alt\nimport pandas as pd\nfrom PIL import Image\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# EAN-13 encoding patterns (7 modules per digit)\n# L-codes (left side, odd parity): space, bar, space, bar\nL_CODES = {\n    \"0\": [3, 2, 1, 1],\n    \"1\": [2, 2, 2, 1],\n    \"2\": [2, 1, 2, 2],\n    \"3\": [1, 4, 1, 1],\n    \"4\": [1, 1, 3, 2],\n    \"5\": [1, 2, 3, 1],\n    \"6\": [1, 1, 1, 4],\n    \"7\": [1, 3, 1, 2],\n    \"8\": [1, 2, 1, 3],\n    \"9\": [3, 1, 1, 2],\n}\n# G-codes (left side, even parity): space, bar, space, bar\nG_CODES = {\n    \"0\": [1, 1, 2, 3],\n    \"1\": [1, 2, 2, 2],\n    \"2\": [2, 2, 1, 2],\n    \"3\": [1, 1, 4, 1],\n    \"4\": [2, 3, 1, 1],\n    \"5\": [1, 3, 2, 1],\n    \"6\": [4, 1, 1, 1],\n    \"7\": [2, 1, 3, 1],\n    \"8\": [3, 1, 2, 1],\n    \"9\": [2, 1, 1, 3],\n}\n# R-codes (right side): bar, space, bar, space\nR_CODES = {\n    \"0\": [3, 2, 1, 1],\n    \"1\": [2, 2, 2, 1],\n    \"2\": [2, 1, 2, 2],\n    \"3\": [1, 4, 1, 1],\n    \"4\": [1, 1, 3, 2],\n    \"5\": [1, 2, 3, 1],\n    \"6\": [1, 1, 1, 4],\n    \"7\": [1, 3, 1, 2],\n    \"8\": [1, 2, 1, 3],\n    \"9\": [3, 1, 1, 2],\n}\n# First digit determines L/G pattern for left 6 digits\nFIRST_DIGIT_PATTERNS = {\n    \"0\": \"LLLLLL\",\n    \"1\": \"LLGLGG\",\n    \"2\": \"LLGGLG\",\n    \"3\": \"LLGGGL\",\n    \"4\": \"LGLLGG\",\n    \"5\": \"LGGLLG\",\n    \"6\": \"LGGGLL\",\n    \"7\": \"LGLGLG\",\n    \"8\": \"LGLGGL\",\n    \"9\": \"LGGLGL\",\n}\n\n# Data - German product EAN-13 code\ncode = \"4006381333931\"\n\n# Inline check digit calculation (no function)\nif len(code) == 12:\n    _total = sum(int(d) * (1 if i % 2 == 0 else 3) for i, d in enumerate(code))\n    code = code + str((10 - (_total % 10)) % 10)\n\nfirst_digit = code[0]\nleft_digits = code[1:7]\nright_digits = code[7:13]\n\n# Build barcode bar data\nbars_data = []\nquiet_zone = 9\nx_pos = quiet_zone\n\n# Start guard: 101 (bar, space, bar)\nfor i, width in enumerate([1, 1, 1]):\n    if i % 2 == 0:\n        bars_data.append({\"x\": x_pos, \"x2\": x_pos + width, \"y\": 0, \"y2\": 1.1})\n    x_pos += width\n\n# Left 6 digits using L or G codes per first-digit pattern\nencoding_pattern = FIRST_DIGIT_PATTERNS[first_digit]\nis_bar = False\nfor i, digit in enumerate(left_digits):\n    widths = L_CODES[digit] if encoding_pattern[i] == \"L\" else G_CODES[digit]\n    for width in widths:\n        if is_bar:\n            bars_data.append({\"x\": x_pos, \"x2\": x_pos + width, \"y\": 0, \"y2\": 1.0})\n        x_pos += width\n        is_bar = not is_bar\n\n# Center guard: 01010 (space, bar, space, bar, space)\nfor i, width in enumerate([1, 1, 1, 1, 1]):\n    if i % 2 == 1:\n        bars_data.append({\"x\": x_pos, \"x2\": x_pos + width, \"y\": 0, \"y2\": 1.1})\n    x_pos += width\n\n# Right 6 digits using R codes\nis_bar = True\nfor digit in right_digits:\n    for width in R_CODES[digit]:\n        if is_bar:\n            bars_data.append({\"x\": x_pos, \"x2\": x_pos + width, \"y\": 0, \"y2\": 1.0})\n        x_pos += width\n        is_bar = not is_bar\n\n# End guard: 101 (bar, space, bar)\nfor i, width in enumerate([1, 1, 1]):\n    if i % 2 == 0:\n        bars_data.append({\"x\": x_pos, \"x2\": x_pos + width, \"y\": 0, \"y2\": 1.1})\n    x_pos += width\n\ntotal_width = x_pos + quiet_zone\ndf_bars = pd.DataFrame(bars_data)\n\n# Human-readable digit labels positioned below barcode\ntext_data = [\n    {\"x\": quiet_zone - 3, \"y\": -0.12, \"text\": first_digit},\n    {\"x\": quiet_zone + 3 + 21, \"y\": -0.12, \"text\": left_digits},\n    {\"x\": quiet_zone + 3 + 42 + 5 + 21, \"y\": -0.12, \"text\": right_digits},\n]\ndf_text = pd.DataFrame(text_data)\n\n# Structural zone annotations above barcode (EAN-13 anatomy)\n# Left group (x=12–54): country prefix + manufacturer; Right group (x=59–101): product + check\nzone_data = [\n    {\"x\": 33, \"y\": 1.20, \"text\": f\"Country · Mfr  ({left_digits})\"},\n    {\"x\": 80, \"y\": 1.20, \"text\": f\"Product · Check  ({right_digits})\"},\n]\ndf_zones = pd.DataFrame(zone_data)\n\n# Barcode bars chart\nbars_chart = (\n    alt.Chart(df_bars)\n    .mark_rect(color=INK)\n    .encode(\n        x=alt.X(\"x:Q\", scale=alt.Scale(domain=[0, total_width]), axis=None),\n        x2=\"x2:Q\",\n        y=alt.Y(\"y:Q\", scale=alt.Scale(domain=[-0.25, 1.38]), axis=None),\n        y2=\"y2:Q\",\n    )\n)\n\n# Digit labels below barcode\ntext_chart = (\n    alt.Chart(df_text)\n    .mark_text(fontSize=18, font=\"monospace\", fontWeight=\"bold\", color=INK)\n    .encode(x=\"x:Q\", y=\"y:Q\", text=\"text:N\")\n)\n\n# Zone annotation labels above barcode\nzone_chart = (\n    alt.Chart(df_zones).mark_text(fontSize=12, font=\"monospace\", color=INK_SOFT).encode(x=\"x:Q\", y=\"y:Q\", text=\"text:N\")\n)\n\n# Combined chart with canonical landscape canvas\nTITLE = \"barcode-ean13 · python · altair · anyplot.ai\"\nchart = (\n    (bars_chart + text_chart + zone_chart)\n    .properties(\n        width=620,\n        height=320,\n        background=PAGE_BG,\n        title=alt.Title(TITLE, fontSize=16, anchor=\"middle\", offset=20, color=INK),\n    )\n    .configure_view(fill=PAGE_BG, strokeWidth=0)\n    .configure_title(color=INK)\n)\n\n# Save PNG with padding to exact 3200×1800\nchart.save(f\"plot-{THEME}.png\", scale_factor=4.0)\n\nTW, TH = 3200, 1800\n_img = Image.open(f\"plot-{THEME}.png\").convert(\"RGB\")\n_w, _h = _img.size\nif _w > TW or _h > TH:\n    raise SystemExit(\n        f\"altair vl-convert produced {_w}×{_h}, exceeds target {TW}×{TH}. \"\n        f\"Shrink chart .properties(width=, height=) values and re-render.\"\n    )\nif _w < TW or _h < TH:\n    _canvas = Image.new(\"RGB\", (TW, TH), PAGE_BG)\n    _canvas.paste(_img, ((TW - _w) // 2, (TH - _h) // 2))\n    _canvas.save(f\"plot-{THEME}.png\")\n\nchart.save(f\"plot-{THEME}.html\")\n"}