{"spec_id":"histogram-returns-distribution","library":"plotly","language":"python","code":"\"\"\" anyplot.ai\nhistogram-returns-distribution: Returns Distribution Histogram\nLibrary: plotly 6.7.0 | Python 3.13.13\nQuality: 89/100 | Updated: 2026-05-20\n\"\"\"\n\nimport os\n\nimport numpy as np\nimport plotly.graph_objects as go\nfrom scipy import stats\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 = \"rgba(26,26,23,0.10)\" if THEME == \"light\" else \"rgba(240,239,232,0.10)\"\n\n# Okabe-Ito palette\nBRAND = \"#009E73\"  # position 1 — normal return bars\nVERMILLION = \"#C475FD\"  # position 2 — tail region bars\nBLUE = \"#4467A3\"  # position 3 — normal distribution curve\n\n# Data - Simulated daily stock returns (504 trading days / 2 years)\nnp.random.seed(42)\nn_days = 504\ndaily_returns = np.random.normal(loc=0.0005, scale=0.015, size=n_days)\n\n# Add fat tails (realistic financial returns)\noutliers = np.random.choice(n_days, size=20, replace=False)\ndaily_returns[outliers] *= np.random.uniform(2, 4, size=20) * np.random.choice([-1, 1], size=20)\n\nreturns_pct = daily_returns * 100\n\n# Statistics\nmean_ret = np.mean(returns_pct)\nstd_ret = np.std(returns_pct)\nskewness = stats.skew(returns_pct)\nkurtosis = stats.kurtosis(returns_pct)\n\n# Histogram bins\nn_bins = 40\nhist_values, bin_edges = np.histogram(returns_pct, bins=n_bins, density=True)\nbin_centers = (bin_edges[:-1] + bin_edges[1:]) / 2\nbin_width = bin_edges[1] - bin_edges[0]\n\n# Normal distribution overlay\nx_norm = np.linspace(returns_pct.min(), returns_pct.max(), 200)\ny_norm = stats.norm.pdf(x_norm, mean_ret, std_ret)\n\n# Tail region thresholds (±2 std dev)\nlower_tail = mean_ret - 2 * std_ret\nupper_tail = mean_ret + 2 * std_ret\n\n# Split bins into normal-range and tail for correct legend swatches\nnormal_mask = (bin_centers >= lower_tail) & (bin_centers <= upper_tail)\ntail_mask = ~normal_mask\n\nnormal_x = bin_centers[normal_mask]\nnormal_y = hist_values[normal_mask]\ntail_x = bin_centers[tail_mask]\ntail_y = hist_values[tail_mask]\n\n# Figure\nfig = go.Figure()\n\n# Normal-range bars (green, primary legend entry)\nfig.add_trace(\n    go.Bar(\n        x=normal_x,\n        y=normal_y,\n        width=bin_width * 0.9,\n        marker_color=BRAND,\n        name=\"Returns Distribution\",\n        opacity=0.75,\n        hovertemplate=\"Return: %{x:.2f}%<br>Density: %{y:.4f}<br>Range: Normal<extra></extra>\",\n    )\n)\n\n# Tail bins (vermillion, separate legend entry)\nfig.add_trace(\n    go.Bar(\n        x=tail_x,\n        y=tail_y,\n        width=bin_width * 0.9,\n        marker_color=VERMILLION,\n        name=\"Tail Region (>±2σ)\",\n        opacity=0.75,\n        hovertemplate=\"Return: %{x:.2f}%<br>Density: %{y:.4f}<br>Range: Tail<extra></extra>\",\n    )\n)\n\nfig.add_trace(\n    go.Scatter(x=x_norm, y=y_norm, mode=\"lines\", line={\"color\": BLUE, \"width\": 3}, name=\"Normal Distribution\")\n)\n\nfig.add_vline(\n    x=mean_ret,\n    line={\"color\": INK, \"width\": 2, \"dash\": \"dash\"},\n    annotation_text=\"Mean\",\n    annotation_position=\"top\",\n    annotation_font={\"color\": INK, \"size\": 11},\n)\nfig.add_vline(x=lower_tail, line={\"color\": VERMILLION, \"width\": 1.5, \"dash\": \"dot\"})\nfig.add_vline(x=upper_tail, line={\"color\": VERMILLION, \"width\": 1.5, \"dash\": \"dot\"})\n\nstats_text = (\n    f\"<b>Statistics</b><br>\"\n    f\"Mean: {mean_ret:.3f}%<br>\"\n    f\"Std Dev: {std_ret:.3f}%<br>\"\n    f\"Skewness: {skewness:.3f}<br>\"\n    f\"Kurtosis: {kurtosis:.3f}\"\n)\n\nfig.add_annotation(\n    x=0.98,\n    y=0.98,\n    xref=\"paper\",\n    yref=\"paper\",\n    text=stats_text,\n    showarrow=False,\n    font={\"size\": 12, \"family\": \"monospace\", \"color\": INK},\n    align=\"left\",\n    bgcolor=ELEVATED_BG,\n    bordercolor=INK_SOFT,\n    borderwidth=1,\n    borderpad=8,\n)\n\nfig.update_layout(\n    autosize=False,\n    margin={\"l\": 80, \"r\": 40, \"t\": 80, \"b\": 60},\n    paper_bgcolor=PAGE_BG,\n    plot_bgcolor=PAGE_BG,\n    font={\"color\": INK},\n    title={\n        \"text\": \"histogram-returns-distribution · python · plotly · anyplot.ai\",\n        \"font\": {\"size\": 16, \"color\": INK},\n        \"x\": 0.5,\n        \"xanchor\": \"center\",\n    },\n    xaxis={\n        \"title\": {\"text\": \"Daily Returns (%)\", \"font\": {\"size\": 12, \"color\": INK}},\n        \"tickfont\": {\"size\": 10, \"color\": INK_SOFT},\n        \"tickformat\": \".1f\",\n        \"ticksuffix\": \"%\",\n        \"zeroline\": True,\n        \"zerolinewidth\": 1,\n        \"zerolinecolor\": INK_SOFT,\n        \"gridcolor\": GRID,\n        \"showline\": True,\n        \"linecolor\": INK_SOFT,\n        \"mirror\": False,\n    },\n    yaxis={\n        \"title\": {\"text\": \"Probability Density\", \"font\": {\"size\": 12, \"color\": INK}},\n        \"tickfont\": {\"size\": 10, \"color\": INK_SOFT},\n        \"gridcolor\": GRID,\n        \"showline\": True,\n        \"linecolor\": INK_SOFT,\n        \"mirror\": False,\n    },\n    legend={\n        \"x\": 0.02,\n        \"y\": 0.98,\n        \"bgcolor\": ELEVATED_BG,\n        \"bordercolor\": INK_SOFT,\n        \"borderwidth\": 1,\n        \"font\": {\"size\": 10, \"color\": INK_SOFT},\n    },\n    bargap=0.05,\n    barmode=\"overlay\",\n    showlegend=True,\n)\n\nfig.write_image(f\"plot-{THEME}.png\", width=800, height=450, scale=4)\nfig.write_html(f\"plot-{THEME}.html\", include_plotlyjs=\"cdn\")\n"}