{"spec_id":"polar-scatter","library":"plotly","language":"python","code":"\"\"\" anyplot.ai\npolar-scatter: Polar Scatter Plot\nLibrary: plotly 6.7.0 | Python 3.13.13\nQuality: 93/100 | Updated: 2026-05-09\n\"\"\"\n\nimport os\n\nimport numpy as np\nimport plotly.graph_objects as go\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\"\nGRID = \"rgba(26,26,23,0.10)\" if THEME == \"light\" else \"rgba(240,239,232,0.10)\"\n\n# Okabe-Ito palette\nIMPRINT = [\"#009E73\", \"#C475FD\", \"#4467A3\"]\n\n# Data - synthetic wind measurements with prevailing directions\nnp.random.seed(42)\nn_points = 120\n\n# Create wind data with prevailing directions (NW and SE winds common)\n# Cluster 1: Northwest winds (~315°)\nn1 = 45\nangles1 = np.random.normal(315, 25, n1)\nspeeds1 = np.random.gamma(3, 3, n1) + 5\n\n# Cluster 2: Southeast winds (~135°)\nn2 = 40\nangles2 = np.random.normal(135, 30, n2)\nspeeds2 = np.random.gamma(2.5, 2.5, n2) + 3\n\n# Cluster 3: Scattered winds from other directions\nn3 = n_points - n1 - n2\nangles3 = np.random.uniform(0, 360, n3)\nspeeds3 = np.random.gamma(2, 2, n3) + 2\n\n# Combine all data\nangles = np.concatenate([angles1, angles2, angles3])\nangles = angles % 360  # Normalize to 0-360\nspeeds = np.concatenate([speeds1, speeds2, speeds3])\n\n# Create time of day categories for color encoding\nhours = np.random.choice([6, 9, 12, 15, 18], n_points)\ntime_labels = np.array([\"Morning\" if h <= 9 else \"Afternoon\" if h <= 15 else \"Evening\" for h in hours])\n\n# Create figure\nfig = go.Figure()\n\n# Color mapping for time of day using Okabe-Ito\ncolors = {\"Morning\": IMPRINT[0], \"Afternoon\": IMPRINT[1], \"Evening\": IMPRINT[2]}\n\n# Add traces for each time period\nfor period in [\"Morning\", \"Afternoon\", \"Evening\"]:\n    mask = time_labels == period\n    fig.add_trace(\n        go.Scatterpolar(\n            r=speeds[mask],\n            theta=angles[mask],\n            mode=\"markers\",\n            name=period,\n            marker={\"size\": 14, \"color\": colors[period], \"opacity\": 0.75, \"line\": {\"width\": 1, \"color\": PAGE_BG}},\n        )\n    )\n\n# Update layout for 4800x2700 px canvas\nfig.update_layout(\n    title={\n        \"text\": \"Wind Observations · polar-scatter · plotly · anyplot.ai\",\n        \"font\": {\"size\": 28, \"color\": INK},\n        \"x\": 0.5,\n        \"xanchor\": \"center\",\n    },\n    font={\"size\": 18, \"color\": INK},\n    paper_bgcolor=PAGE_BG,\n    plot_bgcolor=PAGE_BG,\n    polar={\n        \"bgcolor\": PAGE_BG,\n        \"angularaxis\": {\n            \"tickmode\": \"array\",\n            \"tickvals\": [0, 45, 90, 135, 180, 225, 270, 315],\n            \"ticktext\": [\"N (0°)\", \"NE\", \"E (90°)\", \"SE\", \"S (180°)\", \"SW\", \"W (270°)\", \"NW\"],\n            \"tickfont\": {\"size\": 18, \"color\": INK_SOFT},\n            \"direction\": \"clockwise\",\n            \"rotation\": 90,\n            \"gridcolor\": GRID,\n            \"linecolor\": INK_SOFT,\n        },\n        \"radialaxis\": {\n            \"title\": {\"text\": \"Wind Speed (m/s)\", \"font\": {\"size\": 22, \"color\": INK}},\n            \"tickfont\": {\"size\": 16, \"color\": INK_SOFT},\n            \"gridcolor\": GRID,\n            \"linecolor\": INK_SOFT,\n            \"range\": [0, max(speeds) * 1.1],\n        },\n    },\n    legend={\n        \"title\": {\"text\": \"Time of Day\", \"font\": {\"size\": 20, \"color\": INK}},\n        \"font\": {\"size\": 18, \"color\": INK_SOFT},\n        \"bgcolor\": ELEVATED_BG,\n        \"bordercolor\": INK_SOFT,\n        \"borderwidth\": 1,\n        \"x\": 1.02,\n        \"y\": 0.98,\n        \"xanchor\": \"left\",\n        \"yanchor\": \"top\",\n    },\n    margin={\"l\": 80, \"r\": 180, \"t\": 100, \"b\": 80},\n)\n\n# Save as PNG and HTML with theme suffix\nfig.write_image(f\"plot-{THEME}.png\", width=1600, height=900, scale=3)\nfig.write_html(f\"plot-{THEME}.html\", include_plotlyjs=\"cdn\")\n"}