{"spec_id":"strip-basic","library":"plotly","language":"python","code":"\"\"\" anyplot.ai\nstrip-basic: Basic Strip Plot\nLibrary: plotly 6.9.0 | Python 3.13.14\nQuality: 89/100 | Updated: 2026-08-05\n\"\"\"\n\nimport os\n\nimport numpy as np\nimport pandas as pd\nimport plotly.express as px\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\"\nINK = \"#1A1A17\" if THEME == \"light\" else \"#F0EFE8\"\nINK_SOFT = \"#4A4A44\" if THEME == \"light\" else \"#B8B7B0\"\nGRID = \"rgba(26,26,23,0.15)\" if THEME == \"light\" else \"rgba(240,239,232,0.15)\"\n\n# Imprint palette — first series always #009E73\nIMPRINT_PALETTE = [\"#009E73\", \"#C475FD\", \"#4467A3\", \"#BD8233\"]\n\n# Data - Commute time per trip, sampled across commonly used transport modes\nnp.random.seed(42)\n\nmodes = [\"Car\", \"Bus\", \"Bike\", \"Train\"]\nn_per_mode = [55, 60, 45, 50]\nmean_minutes = [28, 42, 35, 31]\nstd_minutes = [7, 9, 11, 5]\n\ncommute = pd.concat(\n    [\n        pd.DataFrame({\"mode\": mode, \"commute_time\": np.clip(np.random.normal(mean, std, n), 3, None)})\n        for mode, n, mean, std in zip(modes, n_per_mode, mean_minutes, std_minutes, strict=True)\n    ],\n    ignore_index=True,\n)\n\n# Quartile box summary (transparent fill, no whisker caps) layered behind the strip\n# points — a plotly-specific composite of an Express strip trace with a Graph\n# Objects box trace, giving each column distribution context the raw points alone\n# don't convey.\nfig = go.Figure()\nfor mode in modes:\n    values = commute.loc[commute[\"mode\"] == mode, \"commute_time\"]\n    fig.add_trace(\n        go.Box(\n            x=[mode] * len(values),\n            y=values,\n            name=mode,\n            boxpoints=False,\n            fillcolor=\"rgba(0,0,0,0)\",\n            line={\"color\": INK_SOFT, \"width\": 1.5},\n            whiskerwidth=0.4,\n            width=0.5,\n            showlegend=False,\n            hoverinfo=\"skip\",\n        )\n    )\n\nstrip = px.strip(\n    commute,\n    x=\"mode\",\n    y=\"commute_time\",\n    color=\"mode\",\n    category_orders={\"mode\": modes},\n    color_discrete_sequence=IMPRINT_PALETTE,\n)\nstrip.update_traces(\n    jitter=0.35,\n    marker={\"size\": 8, \"opacity\": 0.55, \"line\": {\"width\": 0.5, \"color\": PAGE_BG}},\n    hovertemplate=\"<b>%{x}</b><br>Commute time: %{y:.1f} min<extra></extra>\",\n)\nfor trace in strip.data:\n    fig.add_trace(trace)\n\n# Mean reference lines\nfor i, mode in enumerate(modes):\n    mean_val = commute.loc[commute[\"mode\"] == mode, \"commute_time\"].mean()\n    fig.add_shape(\n        type=\"line\", x0=i - 0.3, x1=i + 0.3, y0=mean_val, y1=mean_val, line={\"color\": INK, \"width\": 2, \"dash\": \"dot\"}\n    )\n\n# Style\nfig.update_layout(\n    autosize=False,\n    paper_bgcolor=PAGE_BG,\n    plot_bgcolor=PAGE_BG,\n    showlegend=False,\n    title={\n        \"text\": \"strip-basic · python · plotly · anyplot.ai\",\n        \"subtitle\": {\n            \"text\": \"Individual commute times with per-mode quartile range and mean\",\n            \"font\": {\"size\": 11, \"color\": INK_SOFT},\n        },\n        \"font\": {\"size\": 16, \"color\": INK},\n        \"x\": 0.5,\n        \"xanchor\": \"center\",\n    },\n    xaxis={\n        \"title\": {\"text\": \"Transportation Mode\", \"font\": {\"size\": 12, \"color\": INK}},\n        \"tickfont\": {\"size\": 10, \"color\": INK_SOFT},\n        \"categoryorder\": \"array\",\n        \"categoryarray\": modes,\n        \"showgrid\": False,\n        \"linecolor\": INK_SOFT,\n        \"zeroline\": False,\n    },\n    yaxis={\n        \"title\": {\"text\": \"Commute Time (minutes)\", \"font\": {\"size\": 12, \"color\": INK}},\n        \"tickfont\": {\"size\": 10, \"color\": INK_SOFT},\n        \"gridcolor\": GRID,\n        \"gridwidth\": 1,\n        \"linecolor\": INK_SOFT,\n        \"zerolinecolor\": INK_SOFT,\n    },\n    margin={\"l\": 80, \"r\": 40, \"t\": 95, \"b\": 60},\n)\n\n# Save\nfig.write_image(f\"plot-{THEME}.png\", width=800, height=450, scale=4)\nfig.write_html(f\"plot-{THEME}.html\", include_plotlyjs=\"cdn\")\n"}