{"spec_id":"contour-map-geographic","library":"bokeh","language":"python","code":"\"\"\" anyplot.ai\ncontour-map-geographic: Contour Lines on Geographic Map\nLibrary: bokeh 3.9.0 | Python 3.13.13\nQuality: 88/100 | Updated: 2026-05-20\n\"\"\"\n\nimport os\nimport sys\nimport time\nfrom pathlib import Path\n\n\n# Remove the current directory from sys.path to avoid shadowing the bokeh package\nsys.path = [p for p in sys.path if p not in (\"\", \".\", os.getcwd(), os.path.dirname(__file__))]\n\nimport numpy as np\nfrom bokeh.io import output_file, save\nfrom bokeh.models import ColorBar, ColumnDataSource, Label, LabelSet, LinearColorMapper\nfrom bokeh.palettes import Viridis256\nfrom bokeh.plotting import figure\nfrom contourpy import contour_generator\nfrom selenium import webdriver\nfrom selenium.webdriver.chrome.options import Options\n\n\nTHEME = os.getenv(\"ANYPLOT_THEME\", \"light\")\n\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# --- Data: simulated elevation, Pacific Northwest (Oregon → Washington) ---\nnp.random.seed(42)\n\nlat_min, lat_max = 42.0, 49.0\nlon_min, lon_max = -125.0, -117.0\n\nn_points = 50\nlons = np.linspace(lon_min, lon_max, n_points)\nlats = np.linspace(lat_min, lat_max, n_points)\nlon_grid, lat_grid = np.meshgrid(lons, lats)\n\n# Base: elevation rises west → east\nbase_elevation = (lon_grid - lon_min) / (lon_max - lon_min) * 1000\n\n# Cascade Range — two-peak morphology from sin modulation\ncascade_center_lon = -121.5\ncascade_width = 1.0\ncascade_height = np.exp(-((lon_grid - cascade_center_lon) ** 2) / (2 * cascade_width**2))\ncascade_elevation = cascade_height * 3000 * (1 + 0.3 * np.sin(lat_grid * 2))\n\n# Terrain noise (smoothed)\nterrain_noise = np.random.randn(n_points, n_points) * 100\nfor _ in range(3):\n    terrain_noise = (\n        np.roll(terrain_noise, 1, axis=0)\n        + np.roll(terrain_noise, -1, axis=0)\n        + np.roll(terrain_noise, 1, axis=1)\n        + np.roll(terrain_noise, -1, axis=1)\n    ) / 4\n\nelevation = np.clip(base_elevation + cascade_elevation + terrain_noise, 0, None)\n\n# Find the two Cascade Range peaks for narrative annotation\nnorth_elev = np.where(lat_grid > 46.5, elevation, 0)\nnorth_idx = np.unravel_index(np.argmax(north_elev), north_elev.shape)\nnorth_lat, north_lon = lats[north_idx[0]], lons[north_idx[1]]\n\nsouth_elev = np.where(lat_grid <= 46.5, elevation, 0)\nsouth_idx = np.unravel_index(np.argmax(south_elev), south_elev.shape)\nsouth_lat, south_lon = lats[south_idx[0]], lons[south_idx[1]]\n\n# Extract contour paths with contourpy (no matplotlib import needed here)\nlevels = list(np.arange(250, 3500, 250))\ngen = contour_generator(x=lon_grid, y=lat_grid, z=elevation)\n\n# --- Figure ---\nW, H = 3200, 1800\np = figure(\n    width=W,\n    height=H,\n    title=\"contour-map-geographic · python · bokeh · anyplot.ai\",\n    x_axis_label=\"Longitude (°W)\",\n    y_axis_label=\"Latitude (°N)\",\n    x_range=(lon_min, lon_max),\n    y_range=(lat_min, lat_max),\n    toolbar_location=None,\n    tools=\"pan,wheel_zoom,reset\",\n    min_border_bottom=160,\n    min_border_left=180,\n    min_border_top=110,\n    min_border_right=80,\n)\n\n# --- Typography ---\np.title.text_font_size = \"50pt\"\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\np.xaxis.axis_line_color = INK_SOFT\np.yaxis.axis_line_color = INK_SOFT\np.xaxis.major_tick_line_color = INK_SOFT\np.yaxis.major_tick_line_color = INK_SOFT\n\n# --- Background & chrome ---\np.background_fill_color = PAGE_BG\np.border_fill_color = PAGE_BG\np.outline_line_color = INK_SOFT\n\np.xgrid.grid_line_color = INK\np.ygrid.grid_line_color = INK\np.xgrid.grid_line_alpha = 0.10\np.ygrid.grid_line_alpha = 0.10\n\n# --- Elevation raster ---\ncolor_mapper = LinearColorMapper(palette=Viridis256, low=0, high=3000)\np.image(\n    image=[elevation],\n    x=lon_min,\n    y=lat_min,\n    dw=lon_max - lon_min,\n    dh=lat_max - lat_min,\n    color_mapper=color_mapper,\n    alpha=0.72,\n)\n\n# --- Contour lines with overlap-aware label placement ---\nMIN_LABEL_DIST = 0.8  # minimum degrees between elevation label centers\nlabel_data = {\"x\": [], \"y\": [], \"text\": []}\nfor level in levels:\n    paths = gen.lines(level)\n    for path in paths:\n        if path is None or len(path) < 5:\n            continue\n        line_width = 3.5 if level % 1000 == 0 else 2.0\n        p.line(x=path[:, 0], y=path[:, 1], line_color=INK_SOFT, line_width=line_width, line_alpha=0.85)\n        if level % 500 == 0 and len(path) > 20:\n            mid = len(path) // 2\n            cx, cy = path[mid, 0], path[mid, 1]\n            too_close = any(\n                (cx - ex) ** 2 + (cy - ey) ** 2 < MIN_LABEL_DIST**2\n                for ex, ey in zip(label_data[\"x\"], label_data[\"y\"], strict=False)\n            )\n            if not too_close:\n                label_data[\"x\"].append(cx)\n                label_data[\"y\"].append(cy)\n                label_data[\"text\"].append(f\"{int(level)}m\")\n\n# --- Contour elevation labels ---\nlabel_source = ColumnDataSource(data=label_data)\nlabels = LabelSet(\n    x=\"x\",\n    y=\"y\",\n    text=\"text\",\n    source=label_source,\n    text_font_size=\"28pt\",\n    text_color=INK,\n    text_font_style=\"bold\",\n    background_fill_color=ELEVATED_BG,\n    background_fill_alpha=0.90,\n    border_line_color=INK_SOFT,\n    border_line_alpha=0.35,\n)\np.add_layout(labels)\n\n# --- Approximate Pacific coastline (Okabe-Ito #4467A3: blue = water, semantically justified) ---\ncoast_lons = [-125.0, -124.8, -124.5, -124.2, -124.0, -123.8, -124.0, -124.3, -124.5]\ncoast_lats = [42.0, 43.5, 45.0, 46.0, 46.5, 47.5, 48.0, 48.5, 49.0]\np.line(x=coast_lons, y=coast_lats, line_color=\"#4467A3\", line_width=5, legend_label=\"Coastline (approx.)\")\n\n# --- Oregon / Washington state border (lat ≈ 46.2) for geographic context ---\np.line(\n    x=[lon_min, -124.0],\n    y=[46.2, 46.2],\n    line_color=\"#C475FD\",  # Okabe-Ito orange\n    line_width=3.5,\n    line_dash=\"dashed\",\n    legend_label=\"OR / WA Border\",\n)\n\n# --- Cascade Range peak markers and annotations for geographic narrative ---\nfor peak_lon, peak_lat, peak_elev, name in [\n    (south_lon, south_lat, int(elevation[south_idx]), \"S. Cascades\"),\n    (north_lon, north_lat, int(elevation[north_idx]), \"N. Cascades\"),\n]:\n    p.add_layout(\n        Label(\n            x=peak_lon + 0.15,\n            y=peak_lat + 0.12,\n            text=f\"{name}\\n~{peak_elev:,} m\",\n            text_font_size=\"24pt\",\n            text_color=INK,\n            text_font_style=\"bold\",\n            background_fill_color=ELEVATED_BG,\n            background_fill_alpha=0.88,\n            border_line_color=INK_SOFT,\n            border_line_alpha=0.5,\n        )\n    )\np.scatter(\n    x=[south_lon, north_lon], y=[south_lat, north_lat], marker=\"inverted_triangle\", size=28, color=INK, alpha=0.75\n)\n\n# --- Colorbar ---\ncolor_bar = ColorBar(\n    color_mapper=color_mapper,\n    label_standoff=14,\n    width=55,\n    location=(0, 0),\n    title=\"Elevation (m)\",\n    title_text_font_size=\"28pt\",\n    title_text_color=INK,\n    major_label_text_font_size=\"22pt\",\n    major_label_text_color=INK_SOFT,\n)\np.add_layout(color_bar, \"right\")\n\n# --- Legend ---\np.legend.location = \"bottom_right\"\np.legend.label_text_font_size = \"28pt\"\np.legend.label_text_color = INK_SOFT\np.legend.background_fill_color = ELEVATED_BG\np.legend.border_line_color = INK_SOFT\np.legend.background_fill_alpha = 0.92\n\n# --- Save HTML + PNG via headless Chrome ---\noutput_file(f\"plot-{THEME}.html\")\nsave(p)\n\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}\",\n    \"--hide-scrollbars\",\n):\n    opts.add_argument(arg)\n\ndriver = webdriver.Chrome(options=opts)\ndriver.execute_cdp_cmd(\n    \"Emulation.setDeviceMetricsOverride\", {\"width\": W, \"height\": H, \"deviceScaleFactor\": 1, \"mobile\": False}\n)\ndriver.get(f\"file://{Path(f'plot-{THEME}.html').resolve()}\")\ntime.sleep(3)\ndriver.save_screenshot(f\"plot-{THEME}.png\")\ndriver.quit()\n"}