{"spec_id":"bar-basic","library":"bokeh","language":"python","code":"\"\"\" anyplot.ai\nbar-basic: Basic Bar Chart\nLibrary: bokeh 3.9.0 | Python 3.13.13\nQuality: 90/100 | Updated: 2026-05-28\n\"\"\"\n\nimport io\nimport os\nimport sys\n\n\n# Prevent bokeh.py from shadowing the installed bokeh package\n_this_dir = os.path.dirname(os.path.abspath(__file__))\nsys.path = [p for p in sys.path if os.path.realpath(p) != os.path.realpath(_this_dir)]\n\nimport time\nfrom pathlib import Path\n\nfrom bokeh.io import output_file, save\nfrom bokeh.models import ColumnDataSource, HoverTool, LabelSet, NumeralTickFormatter\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\"\nELEVATED_BG = \"#FFFDF6\" if THEME == \"light\" else \"#242420\"\nINK = \"#1A1A17\" if THEME == \"light\" else \"#F0EFE8\"\nINK_SOFT = \"#4A4A44\" if THEME == \"light\" else \"#B8B7B0\"\nBRAND = \"#009E73\"\n\n# Data - Quarterly revenue by department, sorted descending for ranking clarity\n_raw = {\n    \"Engineering\": 38200,\n    \"Marketing\": 21500,\n    \"Sales\": 45800,\n    \"Support\": 14300,\n    \"Design\": 27600,\n    \"Operations\": 19100,\n}\ncategories = [k for k, _ in sorted(_raw.items(), key=lambda x: -x[1])]\nvalues = [_raw[k] for k in categories]\nvalue_labels = [f\"${v / 1000:.1f}K\" for v in values]\n# Emphasize the top-ranked bar; others at reduced alpha to create a focal point\nbar_alphas = [1.0 if i == 0 else 0.55 for i in range(len(categories))]\n\nsource = ColumnDataSource(\n    data={\"categories\": categories, \"values\": values, \"value_labels\": value_labels, \"alpha\": bar_alphas}\n)\n\ntitle = \"bar-basic · python · bokeh · anyplot.ai\"\n\n# HoverTool for bokeh-native interactivity (works even with toolbar_location=None)\nhover = HoverTool(tooltips=[(\"Department\", \"@categories\"), (\"Revenue\", \"@values{$0,0}\")])\n\n# Create figure — toolbar_location=None prevents extra height being added above canvas\np = figure(\n    x_range=categories,\n    width=3200,\n    height=1800,\n    title=title,\n    x_axis_label=\"Department\",\n    y_axis_label=\"Quarterly Revenue ($)\",\n    toolbar_location=None,\n    tools=[hover],\n    min_border_bottom=160,\n    min_border_left=180,\n    min_border_top=110,\n    min_border_right=60,\n)\n\n# Bars — top bar fully saturated (focal point), others muted; page-bg edge for separation\np.vbar(\n    x=\"categories\", top=\"values\", source=source, width=0.7, color=BRAND, alpha=\"alpha\", line_color=PAGE_BG, line_width=2\n)\n\n# Value labels positioned above bars\nlabels_glyph = LabelSet(\n    x=\"categories\",\n    y=\"values\",\n    text=\"value_labels\",\n    level=\"glyph\",\n    x_offset=0,\n    y_offset=10,\n    source=source,\n    text_font_size=\"34pt\",\n    text_color=INK_SOFT,\n    text_align=\"center\",\n)\np.add_layout(labels_glyph)\n\n# Title and axis font sizes (canonical 3200×1800 values)\np.title.text_font_size = \"50pt\"\np.title.align = \"center\"\np.title.text_color = INK\np.xaxis.axis_label_text_font_size = \"42pt\"\np.yaxis.axis_label_text_font_size = \"42pt\"\np.xaxis.major_label_text_font_size = \"34pt\"\np.yaxis.major_label_text_font_size = \"34pt\"\np.xaxis.axis_label_text_color = INK\np.yaxis.axis_label_text_color = INK\np.xaxis.major_label_text_color = INK_SOFT\np.yaxis.major_label_text_color = INK_SOFT\n\n# L-shaped frame: remove outline box, keep left + bottom axes\np.outline_line_color = None\np.xaxis.axis_line_color = INK_SOFT\np.yaxis.axis_line_color = INK_SOFT\np.xaxis.axis_line_width = 2\np.yaxis.axis_line_width = 2\n\n# Remove tick marks, keep labels\np.xaxis.major_tick_line_color = None\np.yaxis.major_tick_line_color = None\np.xaxis.minor_tick_line_color = None\np.yaxis.minor_tick_line_color = None\n\n# Grid — y-axis only, subtle\np.xgrid.grid_line_color = None\np.ygrid.grid_line_color = INK\np.ygrid.grid_line_alpha = 0.15\n\n# Y-axis: dollar formatter, start at 0, headroom for labels\np.yaxis.formatter = NumeralTickFormatter(format=\"$0,0\")\np.y_range.start = 0\np.y_range.end = max(values) * 1.18\n\n# Theme-adaptive backgrounds\np.background_fill_color = PAGE_BG\np.border_fill_color = PAGE_BG\n\n# Save interactive HTML\noutput_file(f\"plot-{THEME}.html\")\nsave(p)\n\n# Screenshot with headless Chrome — window is H+200 tall so bokeh canvas fills\n# exactly W×H; PIL crops to the target rect before saving.\nW, H = 3200, 1800\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()\nImage.open(io.BytesIO(raw)).crop((0, 0, W, H)).save(f\"plot-{THEME}.png\")\n"}