{"spec_id":"range-interval","library":"seaborn","language":"python","code":"\"\"\" anyplot.ai\nrange-interval: Range Interval Chart\nLibrary: seaborn 0.13.2 | Python 3.13.13\nQuality: 89/100 | Updated: 2026-05-18\n\"\"\"\n\nimport os\n\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport pandas as pd\nimport seaborn as sns\n\n\n# Theme tokens (see prompts/default-style-guide.md)\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\"\nBRAND = \"#009E73\"  # Okabe-Ito position 1 — ALWAYS first series\nSECONDARY = \"#C475FD\"  # Okabe-Ito position 2\n\n# Data - Salary ranges by job title in tech industry\nnp.random.seed(42)\njob_titles = [\n    \"Junior Developer\",\n    \"Senior Developer\",\n    \"DevOps Engineer\",\n    \"Data Scientist\",\n    \"Product Manager\",\n    \"UX Designer\",\n    \"QA Engineer\",\n    \"Engineering Manager\",\n]\n\n# Realistic salary ranges (in thousands USD)\nmin_salaries = np.array([65, 95, 85, 75, 80, 70, 60, 100])\nmax_salaries = np.array([95, 160, 140, 130, 150, 120, 100, 180])\n\n# Create DataFrame for plotting\ndf = pd.DataFrame(\n    {\"Job Title\": job_titles, \"Min Salary\": min_salaries, \"Max Salary\": max_salaries, \"idx\": range(len(job_titles))}\n)\n\n# Create plot\nfig, ax = plt.subplots(figsize=(16, 9), facecolor=PAGE_BG)\nax.set_facecolor(PAGE_BG)\n\n# Draw vertical range bars connecting min and max salaries\nfor i, row in df.iterrows():\n    ax.plot(\n        [i, i],\n        [row[\"Min Salary\"], row[\"Max Salary\"]],\n        color=BRAND,\n        linewidth=14,\n        alpha=0.85,\n        solid_capstyle=\"round\",\n        zorder=2,\n    )\n\n# Add min/max markers\nsns.scatterplot(\n    data=df, x=\"idx\", y=\"Min Salary\", color=BRAND, s=300, edgecolor=PAGE_BG, linewidth=2, ax=ax, zorder=3, legend=False\n)\n\nsns.scatterplot(\n    data=df,\n    x=\"idx\",\n    y=\"Max Salary\",\n    color=SECONDARY,\n    s=300,\n    edgecolor=PAGE_BG,\n    linewidth=2,\n    ax=ax,\n    zorder=3,\n    legend=False,\n)\n\n# Configure axes\nax.set_xticks(range(len(job_titles)))\nax.set_xticklabels(job_titles, rotation=45, ha=\"right\")\nax.set_xlabel(\"Job Title\", fontsize=20, color=INK)\nax.set_ylabel(\"Annual Salary (thousands USD)\", fontsize=20, color=INK)\nax.set_title(\"range-interval · python · seaborn · anyplot.ai\", fontsize=24, fontweight=\"medium\", color=INK)\nax.tick_params(axis=\"both\", labelsize=16, colors=INK_SOFT)\n\n# Style spines\nax.spines[\"top\"].set_visible(False)\nax.spines[\"right\"].set_visible(False)\nfor spine in [\"left\", \"bottom\"]:\n    ax.spines[spine].set_color(INK_SOFT)\n\n# Grid styling\nax.yaxis.grid(True, alpha=0.10, linewidth=0.8, color=INK)\nax.set_axisbelow(True)\n\nplt.tight_layout()\nplt.savefig(f\"plot-{THEME}.png\", dpi=300, bbox_inches=\"tight\", facecolor=PAGE_BG)\n"}