{"spec_id":"scatter-color-mapped","library":"pygal","language":"python","code":"\"\"\" anyplot.ai\nscatter-color-mapped: Color-Mapped Scatter Plot\nLibrary: pygal 3.1.0 | Python 3.13.13\nQuality: 89/100 | Updated: 2026-05-08\n\"\"\"\n\nimport os\nimport sys\n\n\n# Prevent importing local pygal.py file\nsys.path = [p for p in sys.path if not p.endswith(\"/implementations/python\")]\n\nimport numpy as np\nimport pygal\nfrom pygal.style import Style\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\"\nINK_MUTED = \"#6B6A63\" if THEME == \"light\" else \"#A8A79F\"\n\n# Okabe-Ito palette (not used here; viridis for continuous data)\nIMPRINT = (\"#009E73\", \"#C475FD\", \"#4467A3\", \"#BD8233\", \"#AE3030\", \"#2ABCCD\", \"#954477\")\n\n# Data - Temperature readings across sensor grid\nnp.random.seed(42)\nn_points = 100\nx = np.random.uniform(0, 100, n_points)  # Grid X position (meters)\ny = np.random.uniform(0, 100, n_points)  # Grid Y position (meters)\n# Temperature increases toward center with some noise\ncenter_dist = np.sqrt((x - 50) ** 2 + (y - 50) ** 2)\ntemperature = 35 - 0.3 * center_dist + np.random.normal(0, 3, n_points)\n\n# Create color bins for the continuous variable (pygal uses discrete series)\nn_bins = 8\ntemp_min, temp_max = temperature.min(), temperature.max()\nbin_edges = np.linspace(temp_min, temp_max, n_bins + 1)\nbin_indices = np.digitize(temperature, bin_edges[:-1]) - 1\nbin_indices = np.clip(bin_indices, 0, n_bins - 1)\n\n# Viridis-inspired colorblind-safe palette (dark to light)\nviridis_colors = (\n    \"#440154\",  # Dark purple\n    \"#482878\",  # Purple\n    \"#3E4A89\",  # Blue-purple\n    \"#31688E\",  # Blue\n    \"#26828E\",  # Teal\n    \"#35B779\",  # Green\n    \"#6DCD59\",  # Light green\n    \"#FDE725\",  # Yellow\n)\n\n# Custom style for large canvas with theme support\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=viridis_colors,\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.85,\n)\n\n# Create XY scatter chart\nchart = pygal.XY(\n    width=4800,\n    height=2700,\n    style=custom_style,\n    title=\"scatter-color-mapped · pygal · anyplot.ai\",\n    x_title=\"Grid X Position (meters)\",\n    y_title=\"Grid Y Position (meters)\",\n    show_dots=True,\n    dots_size=12,\n    stroke=False,\n    show_x_guides=True,\n    show_y_guides=True,\n    legend_at_bottom=True,\n    legend_box_size=20,\n    truncate_legend=-1,\n)\n\n# Add data as separate series for each color bin (creates color-mapped effect)\nfor i in range(n_bins):\n    mask = bin_indices == i\n    if mask.sum() > 0:\n        points = [(float(x[j]), float(y[j])) for j in range(n_points) if mask[j]]\n        label = f\"{bin_edges[i]:.0f}–{bin_edges[i + 1]:.0f}°C\"\n        chart.add(label, points)\n\n# Save outputs\nchart.render_to_png(f\"plot-{THEME}.png\")\nchart.render_to_file(f\"plot-{THEME}.html\")\n"}