{"spec_id":"density-rug","library":"altair","language":"python","code":"\"\"\" anyplot.ai\ndensity-rug: Density Plot with Rug Marks\nLibrary: altair 6.1.0 | Python 3.13.13\nQuality: 91/100 | Updated: 2026-05-18\n\"\"\"\n\nimport os\nimport sys\n\n\n# Remove current directory from path IMMEDIATELY to avoid import shadowing\nif sys.path[0] == \"\" or sys.path[0] == \".\":\n    sys.path.pop(0)\n# Also remove the script directory if it's there\nscript_dir = os.path.dirname(os.path.abspath(__file__))\nsys.path = [p for p in sys.path if os.path.abspath(p) != script_dir]\n\nimport altair as alt\nimport numpy as np\nimport pandas as pd\nfrom scipy.stats import gaussian_kde\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\"\nBRAND = \"#009E73\"  # Okabe-Ito position 1\n\n# Data - response times (ms) with realistic distribution\nnp.random.seed(42)\n# Mix of normal response times with some slower outliers\nresponse_times = np.concatenate(\n    [\n        np.random.normal(150, 30, 80),  # Most responses ~150ms\n        np.random.normal(250, 40, 40),  # Slower cluster ~250ms\n        np.random.uniform(350, 500, 15),  # Some slow outliers\n    ]\n)\nresponse_times = np.clip(response_times, 50, 500)  # Realistic bounds\n\n# Compute KDE for smooth density curve\nkde = gaussian_kde(response_times, bw_method=0.3)\nx_range = np.linspace(response_times.min() - 20, response_times.max() + 20, 300)\ndensity_values = kde(x_range)\n\n# Create DataFrames\ndensity_df = pd.DataFrame({\"Response Time (ms)\": x_range, \"Density\": density_values})\n\n# For rug marks, add a small y value to position marks above the x-axis\nrug_df = pd.DataFrame({\"Response Time (ms)\": response_times, \"rug_y\": [0.0] * len(response_times)})\n\n# Density curve with filled area\ndensity_chart = (\n    alt.Chart(density_df)\n    .mark_area(opacity=0.4, color=BRAND, line={\"color\": BRAND, \"strokeWidth\": 3})\n    .encode(x=alt.X(\"Response Time (ms):Q\", title=\"Response Time (ms)\"), y=alt.Y(\"Density:Q\", title=\"Density\"))\n)\n\n# Rug marks as tick marks along the bottom using a secondary layer\nrug_chart = (\n    alt.Chart(rug_df)\n    .mark_tick(color=BRAND, opacity=0.6, thickness=2, size=40)\n    .encode(\n        x=alt.X(\"Response Time (ms):Q\"),\n        y=alt.Y(\"rug_y:Q\", scale=alt.Scale(domain=[density_values.min(), density_values.max()])),\n    )\n)\n\n# Combine charts with layering\nchart = (\n    alt.layer(density_chart, rug_chart)\n    .properties(\n        width=1600,\n        height=900,\n        background=PAGE_BG,\n        title=alt.Title(\"density-rug · Python · altair · anyplot.ai\", fontSize=28, anchor=\"middle\", color=INK),\n    )\n    .configure_axis(\n        domainColor=INK_SOFT,\n        tickColor=INK_SOFT,\n        gridColor=INK,\n        gridOpacity=0.10,\n        labelColor=INK_SOFT,\n        titleColor=INK,\n        labelFontSize=18,\n        titleFontSize=22,\n    )\n    .configure_view(fill=PAGE_BG, stroke=INK_SOFT, strokeWidth=1)\n    .interactive()\n)\n\n# Save\nchart.save(f\"plot-{THEME}.png\", scale_factor=3.0)\nchart.save(f\"plot-{THEME}.html\")\n"}