{"spec_id":"barcode-ean13","library":"letsplot","language":"python","code":"\"\"\" anyplot.ai\nbarcode-ean13: EAN-13 Barcode\nLibrary: letsplot 4.10.1 | Python 3.13.13\nQuality: 85/100 | Updated: 2026-05-21\n\"\"\"\n\nimport os\n\nimport pandas as pd\nfrom lets_plot import (\n    LetsPlot,\n    aes,\n    element_blank,\n    element_rect,\n    geom_rect,\n    geom_text,\n    ggplot,\n    ggsave,\n    ggsize,\n    layer_tooltips,\n    scale_fill_identity,\n    theme,\n    theme_void,\n    xlim,\n    ylim,\n)\n\n\nLetsPlot.setup_html()\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\"\nBAR_COLOR = \"#1A1A17\" if THEME == \"light\" else \"#F0EFE8\"\n\n# EAN-13 encoding patterns (L, G, R codes — 7 modules each)\nL_CODES = {\n    \"0\": \"0001101\",\n    \"1\": \"0011001\",\n    \"2\": \"0010011\",\n    \"3\": \"0111101\",\n    \"4\": \"0100011\",\n    \"5\": \"0110001\",\n    \"6\": \"0101111\",\n    \"7\": \"0111011\",\n    \"8\": \"0110111\",\n    \"9\": \"0001011\",\n}\nG_CODES = {\n    \"0\": \"0100111\",\n    \"1\": \"0110011\",\n    \"2\": \"0011011\",\n    \"3\": \"0100001\",\n    \"4\": \"0011101\",\n    \"5\": \"0111001\",\n    \"6\": \"0000101\",\n    \"7\": \"0010001\",\n    \"8\": \"0001001\",\n    \"9\": \"0010111\",\n}\nR_CODES = {\n    \"0\": \"1110010\",\n    \"1\": \"1100110\",\n    \"2\": \"1101100\",\n    \"3\": \"1000010\",\n    \"4\": \"1011100\",\n    \"5\": \"1001110\",\n    \"6\": \"1010000\",\n    \"7\": \"1000100\",\n    \"8\": \"1001000\",\n    \"9\": \"1110100\",\n}\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 (4006381333931)\nraw_code = \"4006381333931\"\nmodule_width = 3\nbar_y_min = 35\nbar_y_max = bar_y_min + 80  # 80-unit bar height\nguard_y_max = bar_y_max + 10  # guard bars extend 10 units lower\n\n# Inline check digit calculation\ndigits_12 = raw_code[:12]\ncheck_total = sum(int(d) * (1 if i % 2 == 0 else 3) for i, d in enumerate(digits_12))\ncheck_digit = str((10 - (check_total % 10)) % 10)\nfull_code = digits_12 + check_digit if len(raw_code) == 12 else raw_code\n\n# Inline EAN-13 bit-pattern encoding\nfirst_digit = full_code[0]\nleft_digits = full_code[1:7]\nright_digits = full_code[7:13]\nparity = FIRST_DIGIT_PATTERNS[first_digit]\n\nbars_pattern = \"101\"\nfor i, d in enumerate(left_digits):\n    bars_pattern += L_CODES[d] if parity[i] == \"L\" else G_CODES[d]\nbars_pattern += \"01010\"\nfor d in right_digits:\n    bars_pattern += R_CODES[d]\nbars_pattern += \"101\"\n\n# Section label for each bit position — used in interactive HTML tooltips\nsection_labels = [\"Start Guard\"] * 3\nfor i in range(6):\n    section_labels += [f\"Left digit {i + 1}: {left_digits[i]}\"] * 7\nsection_labels += [\"Center Guard\"] * 5\nfor i in range(6):\n    section_labels += [f\"Right digit {i + 7}: {right_digits[i]}\"] * 7\nsection_labels += [\"End Guard\"] * 3\n\n# Guard bar bit positions (start, center, end) — extend lower than regular bars\nguard_positions = set(range(3)) | set(range(45, 50)) | set(range(92, 95))\n\n# Inline bar rectangle generation\nbars = []\nx_pos = 9 * module_width  # quiet zone offset\nfor i, bit in enumerate(bars_pattern):\n    if bit == \"1\":\n        y_max = guard_y_max if i in guard_positions else bar_y_max\n        bars.append(\n            {\n                \"xmin\": float(x_pos),\n                \"xmax\": float(x_pos + module_width),\n                \"ymin\": float(bar_y_min),\n                \"ymax\": float(y_max),\n                \"fill\": BAR_COLOR,\n                \"section\": section_labels[i],\n                \"position\": i,\n            }\n        )\n    x_pos += module_width\n\ntotal_width = x_pos + 9 * module_width  # right quiet zone\ndf_bars = pd.DataFrame(bars)\n\n# Digit label positions\nquiet_zone = 9 * module_width\nstart_guard_end = quiet_zone + 3 * module_width\nleft_digit_width = 7 * module_width\ncenter_guard_start = start_guard_end + 42 * module_width\nright_start = center_guard_start + 5 * module_width\n\ntext_y = bar_y_min - 15\ndigit_labels = [{\"x\": quiet_zone - 5 * module_width, \"y\": text_y, \"label\": full_code[0]}]\nfor i, d in enumerate(full_code[1:7]):\n    digit_labels.append({\"x\": start_guard_end + (i + 0.5) * left_digit_width, \"y\": text_y, \"label\": d})\nfor i, d in enumerate(full_code[7:13]):\n    digit_labels.append({\"x\": right_start + (i + 0.5) * left_digit_width, \"y\": text_y, \"label\": d})\ndf_digits = pd.DataFrame(digit_labels)\n\ntitle_str = \"barcode-ean13 · python · letsplot · anyplot.ai\"\ndf_title = pd.DataFrame({\"x\": [total_width / 2], \"y\": [guard_y_max + 25], \"label\": [title_str]})\n\n# Plot\nplot = (\n    ggplot()\n    + geom_rect(\n        aes(xmin=\"xmin\", xmax=\"xmax\", ymin=\"ymin\", ymax=\"ymax\", fill=\"fill\"),\n        data=df_bars,\n        tooltips=layer_tooltips().line(\"@section\").line(\"Module @position\"),\n    )\n    + scale_fill_identity()\n    + geom_text(aes(x=\"x\", y=\"y\", label=\"label\"), data=df_digits, size=16, family=\"monospace\", color=INK)\n    + geom_text(aes(x=\"x\", y=\"y\", label=\"label\"), data=df_title, size=15, color=INK_SOFT)\n    + xlim(0, total_width)\n    + ylim(-20, guard_y_max + 45)\n    + theme_void()\n    + theme(\n        plot_background=element_rect(fill=PAGE_BG, color=PAGE_BG),\n        panel_background=element_rect(fill=PAGE_BG),\n        panel_border=element_blank(),\n    )\n    + ggsize(800, 450)\n)\n\n# Save\nggsave(plot, f\"plot-{THEME}.png\", scale=4, path=\".\")\nggsave(plot, f\"plot-{THEME}.html\", path=\".\")\n"}