{"spec_id":"sudoku-basic","library":"bokeh","language":"python","code":"\"\"\" anyplot.ai\nsudoku-basic: Basic Sudoku Grid\nLibrary: bokeh 3.9.1 | Python 3.13.14\nQuality: 90/100 | Updated: 2026-06-25\n\"\"\"\n\nimport io\nimport os\nimport sys\nimport time\nfrom pathlib import Path\n\n\n# Remove script directory from sys.path to avoid shadowing the bokeh package\nsys.path = [p for p in sys.path if Path(p).resolve() != Path(__file__).resolve().parent]\n\nfrom bokeh.io import output_file, save\nfrom bokeh.models import ColumnDataSource, LabelSet\nfrom bokeh.plotting import figure\nfrom PIL import Image\nfrom selenium import webdriver\nfrom selenium.webdriver.chrome.options import Options\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\"\nBRAND_GREEN = \"#009E73\"\n\n# Data - 9x9 Sudoku puzzle (0 = empty)\ngrid = [\n    [0, 0, 0, 2, 6, 0, 7, 0, 1],\n    [6, 8, 0, 0, 7, 0, 0, 9, 0],\n    [1, 9, 0, 0, 0, 4, 5, 0, 0],\n    [8, 2, 0, 1, 0, 0, 0, 4, 0],\n    [0, 0, 4, 6, 0, 2, 9, 0, 0],\n    [0, 5, 0, 0, 0, 3, 0, 2, 8],\n    [0, 0, 9, 3, 0, 0, 0, 7, 4],\n    [0, 4, 0, 0, 5, 0, 0, 3, 6],\n    [7, 0, 3, 0, 1, 8, 0, 0, 0],\n]\n\n# Alternating 3x3 box fills — brand-green alpha tint for clear regional contrast\n# Higher alpha in dark mode compensates for the lower ambient contrast\nBOX_TINT_ALPHA = 0.10 if THEME == \"light\" else 0.20\nbox_rects = {\"x\": [], \"y\": [], \"fill_color\": [], \"fill_alpha\": []}\nfor box_row in range(3):\n    for box_col in range(3):\n        cx = box_col * 3 + 1.5\n        cy = (2 - box_row) * 3 + 1.5\n        if (box_row + box_col) % 2 == 0:\n            color = BRAND_GREEN\n            alpha = BOX_TINT_ALPHA\n        else:\n            color = PAGE_BG\n            alpha = 1.0\n        box_rects[\"x\"].append(cx)\n        box_rects[\"y\"].append(cy)\n        box_rects[\"fill_color\"].append(color)\n        box_rects[\"fill_alpha\"].append(alpha)\nbox_source = ColumnDataSource(box_rects)\n\n# Number labels — given clue numbers in brand green to visually distinguish\n# pre-filled cells from empty solving space\nnumber_rows = {\"x\": [], \"y\": [], \"text\": [], \"text_color\": []}\nfor row in range(9):\n    for col in range(9):\n        value = grid[row][col]\n        if value != 0:\n            number_rows[\"x\"].append(col + 0.5)\n            number_rows[\"y\"].append(8 - row + 0.5)\n            number_rows[\"text\"].append(str(value))\n            number_rows[\"text_color\"].append(BRAND_GREEN)\nnumbers = ColumnDataSource(number_rows)\n\n# Thin lines for individual cells\nthin_rows = {\"x0\": [], \"y0\": [], \"x1\": [], \"y1\": []}\nfor i in range(10):\n    thin_rows[\"x0\"].extend([0, i])\n    thin_rows[\"y0\"].extend([i, 0])\n    thin_rows[\"x1\"].extend([9, i])\n    thin_rows[\"y1\"].extend([i, 9])\nthin_lines = ColumnDataSource(thin_rows)\n\n# Thick lines for 3x3 box boundaries\nthick_rows = {\"x0\": [], \"y0\": [], \"x1\": [], \"y1\": []}\nfor i in range(0, 10, 3):\n    thick_rows[\"x0\"].extend([0, i])\n    thick_rows[\"y0\"].extend([i, 0])\n    thick_rows[\"x1\"].extend([9, i])\n    thick_rows[\"y1\"].extend([i, 9])\nthick_lines = ColumnDataSource(thick_rows)\n\n# Title — correct format with language token; 42 chars < 67 baseline, no scaling\ntitle = \"sudoku-basic · python · bokeh · anyplot.ai\"\nn = len(title)\nratio = 67 / n if n > 67 else 1.0\ntitle_pt = f\"{round(50 * ratio)}pt\"\n\n# Plot — 2400×2400 square canvas (canonical 1:1 for symmetric grid)\np = figure(\n    width=2400,\n    height=2400,\n    x_range=(-0.25, 9.25),\n    y_range=(-0.25, 9.25),\n    title=title,\n    tools=\"\",\n    toolbar_location=None,\n    background_fill_color=PAGE_BG,\n    border_fill_color=PAGE_BG,\n    min_border_top=120,\n    min_border_bottom=80,\n    min_border_left=80,\n    min_border_right=80,\n)\n\n# Draw alternating box tints first (underneath grid lines)\np.rect(\n    x=\"x\",\n    y=\"y\",\n    width=3,\n    height=3,\n    fill_color=\"fill_color\",\n    fill_alpha=\"fill_alpha\",\n    line_color=None,\n    source=box_source,\n)\n\n# Thin cell lines, then thick box boundaries on top\np.segment(x0=\"x0\", y0=\"y0\", x1=\"x1\", y1=\"y1\", source=thin_lines, line_width=3, line_color=INK)\np.segment(x0=\"x0\", y0=\"y0\", x1=\"x1\", y1=\"y1\", source=thick_lines, line_width=10, line_color=INK)\n\n# Centered bold numbers — text_color per-glyph from source (brand green for given clues)\np.add_layout(\n    LabelSet(\n        x=\"x\",\n        y=\"y\",\n        text=\"text\",\n        source=numbers,\n        text_font_size=\"50pt\",\n        text_font_style=\"bold\",\n        text_align=\"center\",\n        text_baseline=\"middle\",\n        text_color=\"text_color\",\n    )\n)\n\n# Style — hide all axis/grid chrome; center the title\np.title.text_font_size = title_pt\np.title.align = \"center\"\np.title.text_font_style = \"bold\"\np.title.text_color = INK\np.axis.visible = False\np.grid.visible = False\np.outline_line_color = None\n\n# Save HTML artifact\noutput_file(f\"plot-{THEME}.html\", title=title)\nsave(p)\n\n# Screenshot with headless Chrome — add 200px height buffer to absorb ~139px\n# Chrome UI overhead; crop to exact canvas dims afterwards.\nW, H = 2400, 2400\nopts = Options()\nfor arg in (\n    \"--headless=new\",\n    \"--no-sandbox\",\n    \"--disable-dev-shm-usage\",\n    \"--disable-gpu\",\n    f\"--window-size={W},{H + 200}\",\n    \"--hide-scrollbars\",\n    \"--force-device-scale-factor=1\",\n):\n    opts.add_argument(arg)\ndriver = webdriver.Chrome(options=opts)\ndriver.set_window_size(W, H + 200)\ndriver.get(f\"file://{Path(f'plot-{THEME}.html').resolve()}\")\ntime.sleep(3)\nraw = driver.get_screenshot_as_png()\ndriver.quit()\nimg = Image.open(io.BytesIO(raw)).crop((0, 0, W, H))\nimg.save(f\"plot-{THEME}.png\")\n"}