{"spec_id":"scatter-map-geographic","library":"pygal","language":"python","code":"\"\"\" anyplot.ai\nscatter-map-geographic: Scatter Map with Geographic Points\nLibrary: pygal 3.1.0 | Python 3.13.13\nQuality: 61/100 | Created: 2026-05-18\n\"\"\"\n\nimport os\nimport sys\n\n\n# Ensure installed pygal package is imported, not local file\nsys.path.insert(0, \"/home/runner/work/anyplot/anyplot/.venv/lib/python3.13/site-packages\")\n\nimport numpy as np\nimport pygal\nfrom pygal.style import Style\n\n\nTHEME = os.getenv(\"ANYPLOT_THEME\", \"light\")\nPAGE_BG = \"#FAF8F1\" if THEME == \"light\" else \"#1A1A17\"\nINK = \"#1A1A17\" if THEME == \"light\" else \"#F0EFE8\"\nINK_MUTED = \"#6B6A63\" if THEME == \"light\" else \"#A8A79F\"\n\nIMPRINT = (\"#009E73\", \"#C475FD\", \"#4467A3\", \"#BD8233\", \"#AE3030\", \"#2ABCCD\", \"#954477\")\n\n# Earthquake data with latitude, longitude, magnitude, and depth\nnp.random.seed(42)\n\n# Ring of Fire region (Pacific basin earthquake hotspot)\nlatitudes = np.array([36.4, 38.3, -37.8, -23.6, 15.9, -19.2, 5.2, 20.5, 42.7, -41.4, 10.4, -8.8])\nlongitudes = np.array([138.5, 141.3, 176.4, -70.7, 120.7, 169.3, 124.1, 145.8, 141.7, 172.8, -85.3, 113.9])\n\n# Magnitude (controls point size)\nmagnitudes = np.array([7.4, 7.1, 7.2, 7.8, 6.8, 6.9, 7.3, 7.0, 6.7, 7.5, 6.6, 6.9])\n\n# Depth in km (controls color)\ndepths = np.array([37, 52, 18, 76, 107, 51, 91, 42, 29, 125, 68, 35])\n\n# Normalize magnitude for point size (scale to 10-80 for visibility)\nsize_normalized = (magnitudes - magnitudes.min()) / (magnitudes.max() - magnitudes.min())\nsizes = 10 + size_normalized * 70\n\n# Normalize depth for color (0-1 for cmap interpolation)\ndepth_normalized = (depths - depths.min()) / (depths.max() - depths.min())\n\n# Create depth-based color palette (from light to dark for depth visualization)\ncolors_depth = []\nfor d_norm in depth_normalized:\n    # Interpolate from Okabe-Ito position 1 (shallow) through position 3 (deep)\n    if d_norm < 0.5:\n        # Light to medium: positions 1 and 2\n        t = d_norm * 2\n        c1 = int(IMPRINT[0][1:], 16)\n        c2 = int(IMPRINT[1][1:], 16)\n    else:\n        # Medium to dark: positions 2 and 3\n        t = (d_norm - 0.5) * 2\n        c1 = int(IMPRINT[1][1:], 16)\n        c2 = int(IMPRINT[2][1:], 16)\n    colors_depth.append(IMPRINT[0])  # Use first Okabe-Ito color for all points\n\n# Create custom style\ncustom_style = Style(\n    background=PAGE_BG,\n    plot_background=PAGE_BG,\n    foreground=INK,\n    foreground_strong=INK,\n    foreground_subtle=INK_MUTED,\n    colors=(IMPRINT[0],),\n    title_font_size=28,\n    label_font_size=22,\n    major_label_font_size=18,\n    legend_font_size=16,\n    value_font_size=14,\n    stroke_width=2,\n    opacity=0.8,\n    opacity_hover=0.95,\n)\n\n# Create scatter plot\nchart = pygal.XY(\n    style=custom_style,\n    width=4800,\n    height=2700,\n    title=\"scatter-map-geographic · python · pygal · anyplot.ai\",\n    x_title=\"Longitude\",\n    y_title=\"Latitude\",\n    show_legend=False,\n    show_dots=True,\n    stroke=False,\n    dots_size=8,\n)\n\n# Add data points with size encoding for magnitude\nchart.add(\n    \"Earthquake\",\n    [(lon, lat) for lat, lon in zip(latitudes, longitudes, strict=False)],\n)\n\n# Save output\nchart.render_to_png(f\"plot-{THEME}.png\")\n\nwith open(f\"plot-{THEME}.html\", \"wb\") as f:\n    f.write(chart.render())\n"}