{"spec_id":"choropleth-basic","library":"bokeh","language":"python","code":"\"\"\" anyplot.ai\nchoropleth-basic: Choropleth Map with Regional Coloring\nLibrary: bokeh 3.9.0 | Python 3.13.13\nQuality: 73/100 | Updated: 2026-05-15\n\"\"\"\n\nimport math\n\nfrom bokeh.io import export_png\nfrom bokeh.models import ColorBar, ColumnDataSource, LabelSet, LogColorMapper\nfrom bokeh.palettes import Blues9\nfrom bokeh.plotting import figure\n\n\n# Data: US states arranged in a tile grid map layout (all 50 states + DC)\n# Grid positions (col, row) - approximating geographic positions\nregions = {\n    \"AK\": (0, 5),\n    \"HI\": (0, 1),\n    \"WA\": (1, 5),\n    \"OR\": (1, 4),\n    \"CA\": (0, 3),\n    \"NV\": (1, 3),\n    \"ID\": (2, 5),\n    \"MT\": (3, 5),\n    \"WY\": (3, 4),\n    \"UT\": (2, 3),\n    \"AZ\": (2, 2),\n    \"CO\": (3, 3),\n    \"NM\": (3, 2),\n    \"ND\": (4, 5),\n    \"SD\": (4, 4),\n    \"NE\": (4, 3),\n    \"KS\": (4, 2),\n    \"OK\": (4, 1),\n    \"TX\": (3, 1),\n    \"MN\": (5, 5),\n    \"IA\": (5, 4),\n    \"MO\": (5, 3),\n    \"AR\": (5, 2),\n    \"LA\": (5, 1),\n    \"WI\": (6, 5),\n    \"IL\": (6, 4),\n    \"IN\": (7, 4),\n    \"MI\": (7, 5),\n    \"OH\": (8, 4),\n    \"KY\": (7, 3),\n    \"TN\": (6, 3),\n    \"MS\": (6, 2),\n    \"AL\": (7, 2),\n    \"GA\": (8, 2),\n    \"FL\": (8, 1),\n    \"SC\": (9, 2),\n    \"NC\": (9, 3),\n    \"VA\": (9, 4),\n    \"WV\": (8, 3),\n    \"PA\": (10, 4),\n    \"NY\": (10, 5),\n    \"VT\": (11, 5),\n    \"NH\": (11, 4),\n    \"ME\": (12, 5),\n    \"MA\": (11, 3),\n    \"RI\": (12, 3),\n    \"CT\": (11, 2),\n    \"NJ\": (10, 3),\n    \"DE\": (10, 2),\n    \"MD\": (9, 1),\n    \"DC\": (10, 1),\n}\n\n# Population density values (people per sq mile) - realistic ranges\ndensity_values = {\n    \"AK\": 1,\n    \"HI\": 226,\n    \"CA\": 253,\n    \"TX\": 112,\n    \"FL\": 411,\n    \"NY\": 408,\n    \"PA\": 286,\n    \"IL\": 227,\n    \"OH\": 289,\n    \"GA\": 185,\n    \"NC\": 218,\n    \"MI\": 177,\n    \"NJ\": 1263,\n    \"VA\": 218,\n    \"WA\": 117,\n    \"AZ\": 64,\n    \"MA\": 901,\n    \"TN\": 167,\n    \"IN\": 189,\n    \"MO\": 89,\n    \"MD\": 636,\n    \"WI\": 108,\n    \"CO\": 57,\n    \"MN\": 71,\n    \"SC\": 173,\n    \"AL\": 99,\n    \"LA\": 107,\n    \"KY\": 114,\n    \"OR\": 44,\n    \"OK\": 58,\n    \"CT\": 733,\n    \"IA\": 57,\n    \"MS\": 63,\n    \"AR\": 58,\n    \"UT\": 40,\n    \"NV\": 28,\n    \"KS\": 36,\n    \"NM\": 17,\n    \"NE\": 25,\n    \"WV\": 74,\n    \"ID\": 23,\n    \"ME\": 44,\n    \"NH\": 154,\n    \"RI\": 1061,\n    \"MT\": 8,\n    \"DE\": 508,\n    \"SD\": 12,\n    \"ND\": 11,\n    \"VT\": 68,\n    \"WY\": 6,\n    # DC intentionally missing to demonstrate missing data handling\n}\n\n# Prepare data for rectangles\nxs = []\nys = []\nwidths = []\nheights = []\ncolors = []\nabbrevs = []\nabbrev_x = []\nabbrev_y = []\n\n# Color mapping - use log scale to better differentiate low-density states\nmin_val = max(1, min(density_values.values()))  # Log scale needs min > 0\nmax_val = max(density_values.values())\npalette = list(reversed(Blues9))\ncolor_mapper = LogColorMapper(palette=palette, low=min_val, high=max_val, nan_color=\"#d0d0d0\")\n\n# Process each region - rect is centered, so adjust coords to center of tile\nfor abbrev, (col, row) in regions.items():\n    center_x = col * 1.1 + 0.5\n    center_y = row * 1.1 + 0.5\n    xs.append(center_x)\n    ys.append(center_y)\n    widths.append(1.0)\n    heights.append(1.0)\n    abbrev_x.append(center_x)\n    abbrev_y.append(center_y)\n    abbrevs.append(abbrev)\n\n    if abbrev in density_values:\n        density = density_values[abbrev]\n        # Map to color index using log scale for better low-value differentiation\n        log_min = math.log10(min_val)\n        log_max = math.log10(max_val)\n        log_val = math.log10(max(density, 1))  # Ensure positive for log\n        norm = (log_val - log_min) / (log_max - log_min)\n        idx = min(int(norm * (len(palette) - 1)), len(palette) - 1)\n        colors.append(palette[idx])\n    else:\n        # Missing data - gray with pattern indication\n        colors.append(\"#d0d0d0\")\n\n# Create data sources\nrect_source = ColumnDataSource(data={\"x\": xs, \"y\": ys, \"width\": widths, \"height\": heights, \"fill_color\": colors})\n\n# Determine text colors based on background (using log scale)\ntext_colors = []\nlog_min = math.log10(min_val)\nlog_max = math.log10(max_val)\nfor abbrev in abbrevs:\n    if abbrev not in density_values:\n        text_colors.append(\"#333333\")\n    else:\n        density = density_values[abbrev]\n        log_val = math.log10(max(density, 1))\n        norm = (log_val - log_min) / (log_max - log_min)\n        text_colors.append(\"white\" if norm > 0.5 else \"#306998\")\n\nlabel_source = ColumnDataSource(data={\"x\": abbrev_x, \"y\": abbrev_y, \"text\": abbrevs, \"text_color\": text_colors})\n\n# Create figure (4800x2700 for landscape)\np = figure(\n    width=4800,\n    height=2700,\n    title=\"choropleth-basic · bokeh · pyplots.ai\",\n    x_axis_location=None,\n    y_axis_location=None,\n    tools=\"\",\n    toolbar_location=None,\n    x_range=(-1, 14),\n    y_range=(0, 7),\n)\n\n# Remove grid and axes\np.grid.grid_line_color = None\np.outline_line_color = None\np.xaxis.visible = False\np.yaxis.visible = False\n\n# Draw rectangles for each state\np.rect(\n    x=\"x\",\n    y=\"y\",\n    width=\"width\",\n    height=\"height\",\n    source=rect_source,\n    fill_color=\"fill_color\",\n    fill_alpha=0.9,\n    line_color=\"white\",\n    line_width=2,\n)\n\n# Add state abbreviation labels\nlabels = LabelSet(\n    x=\"x\",\n    y=\"y\",\n    text=\"text\",\n    text_color=\"text_color\",\n    source=label_source,\n    text_align=\"center\",\n    text_baseline=\"middle\",\n    text_font_size=\"18pt\",\n    text_font_style=\"bold\",\n)\np.add_layout(labels)\n\n# Title styling\np.title.text_font_size = \"32pt\"\np.title.align = \"center\"\n\n# Color bar for legend - made larger for prominence\ncolor_bar = ColorBar(\n    color_mapper=color_mapper,\n    width=60,\n    height=1200,\n    location=(0, 0),\n    title=\"Population Density (per sq mile)\",\n    title_text_font_size=\"24pt\",\n    major_label_text_font_size=\"20pt\",\n    title_standoff=20,\n    padding=30,\n    margin=40,\n)\np.add_layout(color_bar, \"right\")\n\n# Save output\nexport_png(p, filename=\"plot.png\")\n"}