{"spec_id":"radar-basic","library":"plotnine","language":"python","code":"\"\"\" anyplot.ai\nradar-basic: Basic Radar Chart\nLibrary: plotnine 0.15.7 | Python 3.13.14\nQuality: 87/100 | Updated: 2026-07-24\n\"\"\"\n\nimport math\nimport os\nimport sys\n\n\n# Prevent this file from shadowing the plotnine library when run from its own directory\nsys.path = [p for p in sys.path if not p or os.path.abspath(p) != os.path.abspath(os.path.dirname(__file__))]\n\nimport numpy as np\nimport pandas as pd\nfrom plotnine import (\n    aes,\n    coord_fixed,\n    element_blank,\n    element_rect,\n    element_text,\n    geom_path,\n    geom_point,\n    geom_polygon,\n    geom_text,\n    ggplot,\n    labs,\n    scale_color_manual,\n    scale_fill_manual,\n    scale_x_continuous,\n    scale_y_continuous,\n    theme,\n)\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_COLOR = \"#C8C8C0\" if THEME == \"light\" else \"#4A4A44\"\n\nIMPRINT = [\"#009E73\", \"#C475FD\"]\n\n# Data — employee performance metrics\ncategories = [\"Technical\", \"Communication\", \"Leadership\", \"Creativity\", \"Teamwork\", \"Problem Solving\"]\nvalues_alice = [85, 70, 60, 90, 75, 80]\nvalues_bob = [70, 85, 75, 65, 90, 70]\n\nn = len(categories)\nangles = [i * 2 * math.pi / n for i in range(n)]\n\n# Build cartesian coordinates for each series\ndata_rows = []\nfor i, (cat, val_a, val_b, angle) in enumerate(zip(categories, values_alice, values_bob, angles, strict=True)):\n    data_rows.append({\"category\": cat, \"value\": val_a, \"angle\": angle, \"series\": \"Alice\", \"order\": i})\n    data_rows.append({\"category\": cat, \"value\": val_b, \"angle\": angle, \"series\": \"Bob\", \"order\": i})\n\n# Close polygons by repeating the first point\ndata_rows.append(\n    {\"category\": categories[0], \"value\": values_alice[0], \"angle\": angles[0], \"series\": \"Alice\", \"order\": n}\n)\ndata_rows.append({\"category\": categories[0], \"value\": values_bob[0], \"angle\": angles[0], \"series\": \"Bob\", \"order\": n})\n\ndf = pd.DataFrame(data_rows)\ndf[\"x\"] = df[\"value\"] * np.cos(df[\"angle\"] - math.pi / 2)\ndf[\"y\"] = df[\"value\"] * np.sin(df[\"angle\"] - math.pi / 2)\n\n# Gridlines (concentric circles at 20, 40, 60, 80, 100)\ngrid_rows = []\ngrid_angles = np.linspace(0, 2 * math.pi, 101)\nfor radius in [20, 40, 60, 80, 100]:\n    for a in grid_angles:\n        grid_rows.append(\n            {\"x\": radius * math.cos(a - math.pi / 2), \"y\": radius * math.sin(a - math.pi / 2), \"radius\": radius}\n        )\ngrid_df = pd.DataFrame(grid_rows)\n\n# Spokes (axis lines from center to edge)\nspoke_rows = []\nfor angle in angles:\n    spoke_rows.append({\"x\": 0, \"y\": 0, \"angle_group\": angle})\n    spoke_rows.append(\n        {\"x\": 105 * math.cos(angle - math.pi / 2), \"y\": 105 * math.sin(angle - math.pi / 2), \"angle_group\": angle}\n    )\nspoke_df = pd.DataFrame(spoke_rows)\n\n# Category labels positioned just outside the chart\nlabel_rows = []\nfor cat, angle in zip(categories, angles, strict=True):\n    label_rows.append(\n        {\"label\": cat, \"x\": 115 * math.cos(angle - math.pi / 2), \"y\": 115 * math.sin(angle - math.pi / 2)}\n    )\nlabel_df = pd.DataFrame(label_rows)\n\n# Plot\nplot = (\n    ggplot()\n    + geom_path(aes(x=\"x\", y=\"y\", group=\"radius\"), data=grid_df, color=GRID_COLOR, size=0.25, linetype=\"dashed\")\n    + geom_path(aes(x=\"x\", y=\"y\", group=\"angle_group\"), data=spoke_df, color=GRID_COLOR, size=0.25)\n    + geom_polygon(aes(x=\"x\", y=\"y\", fill=\"series\", group=\"series\"), data=df, alpha=0.25)\n    + geom_path(aes(x=\"x\", y=\"y\", color=\"series\", group=\"series\"), data=df, size=0.75)\n    + geom_point(aes(x=\"x\", y=\"y\", color=\"series\"), data=df[df[\"order\"] < n], size=2.5)\n    + geom_text(aes(x=\"x\", y=\"y\", label=\"label\"), data=label_df, size=8, color=INK)\n    + scale_fill_manual(values=IMPRINT)\n    + scale_color_manual(values=IMPRINT)\n    + scale_x_continuous(limits=(-138, 138))\n    + scale_y_continuous(limits=(-138, 138))\n    + coord_fixed(ratio=1)\n    + labs(title=\"radar-basic · python · plotnine · anyplot.ai\", fill=\"Employee\", color=\"Employee\")\n    + theme(\n        figure_size=(6, 6),\n        plot_background=element_rect(fill=PAGE_BG, color=PAGE_BG),\n        panel_background=element_rect(fill=PAGE_BG),\n        plot_title=element_text(size=12, weight=\"bold\", color=INK),\n        legend_title=element_text(size=9, color=INK),\n        legend_text=element_text(size=8, color=INK_SOFT),\n        legend_background=element_rect(fill=ELEVATED_BG, color=INK_SOFT),\n        legend_margin=8,\n        legend_key_width=24,\n        axis_title=element_blank(),\n        axis_text=element_blank(),\n        axis_ticks=element_blank(),\n        axis_line=element_blank(),\n        panel_grid_major=element_blank(),\n        panel_grid_minor=element_blank(),\n    )\n)\n\n# Save\nplot.save(f\"plot-{THEME}.png\", dpi=400, width=6, height=6, units=\"in\")\n"}