{"spec_id":"polar-scatter","library":"matplotlib","language":"python","code":"\"\"\" anyplot.ai\npolar-scatter: Polar Scatter Plot\nLibrary: matplotlib 3.10.9 | Python 3.13.13\nQuality: 95/100 | Updated: 2026-05-09\n\"\"\"\n\nimport os\n\nimport matplotlib.pyplot as plt\nimport numpy as np\nfrom matplotlib.lines import Line2D\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\"\n\n# Okabe-Ito palette\nCOLORS = [\"#009E73\", \"#C475FD\", \"#4467A3\"]\n\n# Data - Wind measurement data with prevailing directions\nnp.random.seed(42)\n\nn_points = 120\n\n# Create clusters around prevailing wind directions (SW and NW winds common)\n# Cluster 1: Southwest winds (around 225 degrees) - morning observations\nmorning_angles = np.random.normal(225, 30, 40)\nmorning_speeds = np.random.gamma(2, 3, 40)\n\n# Cluster 2: Northwest winds (around 315 degrees) - afternoon observations\nafternoon_angles = np.random.normal(315, 25, 40)\nafternoon_speeds = np.random.gamma(2.5, 3, 40)\n\n# Cluster 3: Variable winds - evening observations\nevening_angles = np.random.uniform(0, 360, 40)\nevening_speeds = np.random.gamma(1.5, 3, 40)\n\n# Combine all observations\nangles_deg = np.concatenate([morning_angles, afternoon_angles, evening_angles])\nspeeds = np.concatenate([morning_speeds, afternoon_speeds, evening_speeds])\ncategories = np.array([\"Morning\"] * 40 + [\"Afternoon\"] * 40 + [\"Evening\"] * 40)\n\n# Normalize angles to 0-360 range\nangles_deg = angles_deg % 360\n\n# Convert to radians for polar plot\nangles_rad = np.deg2rad(angles_deg)\n\n# Plot\nfig, ax = plt.subplots(figsize=(12, 12), subplot_kw={\"projection\": \"polar\"}, facecolor=PAGE_BG)\nax.set_facecolor(PAGE_BG)\n\n# Color mapping for categories using Okabe-Ito palette\ncolor_map = {\"Morning\": COLORS[0], \"Afternoon\": COLORS[1], \"Evening\": COLORS[2]}\ncolor_list = [color_map[cat] for cat in categories]\n\n# Plot scatter with size based on data density considerations (120 points)\nax.scatter(angles_rad, speeds, c=color_list, s=150, alpha=0.7, edgecolors=PAGE_BG, linewidths=0.5)\n\n# Configure angular axis (theta)\nax.set_theta_zero_location(\"N\")\nax.set_theta_direction(-1)\nax.set_thetagrids(\n    [0, 45, 90, 135, 180, 225, 270, 315],\n    labels=[\"N\", \"NE\", \"E\", \"SE\", \"S\", \"SW\", \"W\", \"NW\"],\n    fontsize=18,\n    color=INK_SOFT,\n)\n\n# Configure radial axis\nmax_speed = np.ceil(speeds.max() / 10) * 10\nax.set_rlim(0, max_speed)\nax.set_rticks(np.arange(0, max_speed + 1, 10))\nax.tick_params(axis=\"both\", labelsize=16, colors=INK_SOFT)\n\n# Radial gridlines\nax.grid(True, alpha=0.2, linewidth=0.8, color=INK_SOFT)\n\n# Radial label\nax.set_ylabel(\"Wind Speed (m/s)\", fontsize=20, color=INK, labelpad=35)\n\n# Title\nax.set_title(\"polar-scatter · matplotlib · anyplot.ai\", fontsize=24, color=INK, pad=20)\n\n# Create custom legend\nlegend_elements = [\n    Line2D([0], [0], marker=\"o\", color=\"w\", markerfacecolor=COLORS[0], markersize=14, label=\"Morning\"),\n    Line2D([0], [0], marker=\"o\", color=\"w\", markerfacecolor=COLORS[1], markersize=14, label=\"Afternoon\"),\n    Line2D([0], [0], marker=\"o\", color=\"w\", markerfacecolor=COLORS[2], markersize=14, label=\"Evening\"),\n]\nleg = ax.legend(\n    handles=legend_elements,\n    loc=\"upper left\",\n    bbox_to_anchor=(1.02, 1.0),\n    fontsize=16,\n    title=\"Time of Day\",\n    title_fontsize=18,\n)\nif leg:\n    leg.get_frame().set_facecolor(ELEVATED_BG)\n    leg.get_frame().set_edgecolor(INK_SOFT)\n    leg.get_frame().set_linewidth(0.8)\n    leg.get_frame().set_alpha(0.95)\n    for text in leg.get_texts():\n        text.set_color(INK_SOFT)\n    leg.get_title().set_color(INK)\n\nplt.tight_layout()\nplt.savefig(f\"plot-{THEME}.png\", dpi=300, bbox_inches=\"tight\", facecolor=PAGE_BG)\n"}