{"spec_id":"scatter-text","library":"letsplot","language":"python","code":"\"\"\" anyplot.ai\nscatter-text: Scatter Plot with Text Labels Instead of Points\nLibrary: letsplot 4.9.0 | Python 3.13.13\nQuality: 93/100 | Updated: 2026-05-17\n\"\"\"\n\nimport os\n\nimport numpy as np\nimport pandas as pd\nfrom lets_plot import (\n    LetsPlot,\n    aes,\n    element_blank,\n    element_line,\n    element_rect,\n    element_text,\n    geom_text,\n    ggplot,\n    ggsave,\n    ggsize,\n    labs,\n    layer_tooltips,\n    scale_color_manual,\n    theme,\n    theme_minimal,\n)\n\n\nLetsPlot.setup_html()\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 (first series always #009E73)\nIMPRINT = [\"#009E73\", \"#C475FD\", \"#4467A3\", \"#BD8233\", \"#AE3030\", \"#2ABCCD\", \"#954477\"]\n\n# Data - Programming languages positioned by paradigm (functional vs object-oriented)\n# and level of abstraction (low vs high)\nnp.random.seed(42)\n\nlanguages = [\n    \"Python\",\n    \"JavaScript\",\n    \"Java\",\n    \"C++\",\n    \"Ruby\",\n    \"Go\",\n    \"Rust\",\n    \"Swift\",\n    \"Kotlin\",\n    \"TypeScript\",\n    \"Scala\",\n    \"Haskell\",\n    \"Clojure\",\n    \"Elixir\",\n    \"F#\",\n    \"C#\",\n    \"PHP\",\n    \"Perl\",\n    \"R\",\n    \"Julia\",\n    \"MATLAB\",\n    \"Lua\",\n    \"Dart\",\n    \"Groovy\",\n    \"OCaml\",\n    \"Erlang\",\n    \"Fortran\",\n    \"COBOL\",\n    \"Assembly\",\n    \"Lisp\",\n]\n\n# Position languages with good spacing to minimize overlap\nparadigm_scores = {\n    \"Python\": (0.58, 0.88),\n    \"JavaScript\": (0.42, 0.72),\n    \"Java\": (0.28, 0.68),\n    \"C++\": (0.18, 0.38),\n    \"Ruby\": (0.72, 0.92),\n    \"Go\": (0.22, 0.58),\n    \"Rust\": (0.12, 0.48),\n    \"Swift\": (0.38, 0.80),\n    \"Kotlin\": (0.48, 0.85),\n    \"TypeScript\": (0.55, 0.68),\n    \"Scala\": (0.72, 0.62),\n    \"Haskell\": (0.95, 0.90),\n    \"Clojure\": (0.88, 0.82),\n    \"Elixir\": (0.82, 0.88),\n    \"F#\": (0.78, 0.72),\n    \"C#\": (0.32, 0.78),\n    \"PHP\": (0.35, 0.60),\n    \"Perl\": (0.48, 0.52),\n    \"R\": (0.68, 0.78),\n    \"Julia\": (0.62, 0.58),\n    \"MATLAB\": (0.52, 0.48),\n    \"Lua\": (0.42, 0.45),\n    \"Dart\": (0.32, 0.52),\n    \"Groovy\": (0.45, 0.62),\n    \"OCaml\": (0.90, 0.68),\n    \"Erlang\": (0.85, 0.58),\n    \"Fortran\": (0.08, 0.32),\n    \"COBOL\": (0.05, 0.22),\n    \"Assembly\": (0.02, 0.12),\n    \"Lisp\": (0.92, 0.52),\n}\n\nx_coords = [paradigm_scores[lang][0] for lang in languages]\ny_coords = [paradigm_scores[lang][1] for lang in languages]\n\n# Categorize by primary use\ncategories = [\n    \"General\",\n    \"Web\",\n    \"General\",\n    \"Systems\",\n    \"Web\",\n    \"Systems\",\n    \"Systems\",\n    \"Mobile\",\n    \"Mobile\",\n    \"Web\",\n    \"General\",\n    \"Functional\",\n    \"Functional\",\n    \"Functional\",\n    \"Functional\",\n    \"General\",\n    \"Web\",\n    \"Scripting\",\n    \"Data Science\",\n    \"Data Science\",\n    \"Data Science\",\n    \"Scripting\",\n    \"Mobile\",\n    \"General\",\n    \"Functional\",\n    \"Functional\",\n    \"Scientific\",\n    \"Legacy\",\n    \"Systems\",\n    \"Functional\",\n]\n\ndf = pd.DataFrame({\"x\": x_coords, \"y\": y_coords, \"label\": languages, \"category\": categories})\n\n# Map categories to Okabe-Ito colors\ncategory_order = [\n    \"General\",\n    \"Web\",\n    \"Systems\",\n    \"Mobile\",\n    \"Functional\",\n    \"Scripting\",\n    \"Data Science\",\n    \"Scientific\",\n    \"Legacy\",\n]\n\ncolor_palette = {\n    \"General\": IMPRINT[0],  # #009E73 (brand green)\n    \"Web\": IMPRINT[1],  # #C475FD (vermillion)\n    \"Systems\": IMPRINT[2],  # #4467A3 (blue)\n    \"Mobile\": IMPRINT[3],  # #BD8233 (reddish purple)\n    \"Functional\": IMPRINT[4],  # #AE3030 (orange)\n    \"Scripting\": IMPRINT[5],  # #2ABCCD (sky blue)\n    \"Data Science\": IMPRINT[6],  # #954477 (yellow)\n    \"Scientific\": INK_SOFT,  # Neutral for scientific\n    \"Legacy\": INK_SOFT,  # Neutral for legacy\n}\n\n# Create plot with interactive tooltips (lets-plot distinctive feature)\nplot = (\n    ggplot(df, aes(x=\"x\", y=\"y\", color=\"category\"))\n    + geom_text(\n        aes(label=\"label\"),\n        size=11,\n        alpha=0.9,\n        fontface=\"bold\",\n        tooltips=layer_tooltips()\n        .title(\"@label\")\n        .line(\"Category|@category\")\n        .line(\"Paradigm|@x\")\n        .line(\"Abstraction|@y\")\n        .format(\"x\", \".2f\")\n        .format(\"y\", \".2f\"),\n    )\n    + scale_color_manual(values=color_palette, limits=category_order, name=\"Primary Use\")\n    + labs(\n        x=\"Object-Oriented ← Paradigm → Functional\",\n        y=\"Abstraction Level (Low → High)\",\n        title=\"scatter-text · Python · letsplot · anyplot.ai\",\n    )\n    + theme_minimal()\n    + theme(\n        plot_background=element_rect(fill=PAGE_BG, color=PAGE_BG),\n        panel_background=element_rect(fill=PAGE_BG),\n        panel_grid_major=element_line(color=INK, size=0.1),\n        panel_grid_minor=element_blank(),\n        axis_title=element_text(size=20, color=INK),\n        axis_text=element_text(size=16, color=INK_SOFT),\n        axis_line=element_line(color=INK_SOFT, size=0.5),\n        plot_title=element_text(size=24, color=INK, face=\"bold\"),\n        legend_background=element_rect(fill=ELEVATED_BG, color=INK_SOFT),\n        legend_text=element_text(size=16, color=INK_SOFT),\n        legend_title=element_text(size=18, color=INK),\n    )\n    + ggsize(1600, 900)\n)\n\n# Save as PNG (scale 3x for 4800 × 2700 px)\nggsave(plot, f\"plot-{THEME}.png\", path=\".\", scale=3)\n\n# Save interactive HTML version with tooltips\nggsave(plot, f\"plot-{THEME}.html\", path=\".\")\n"}