{"spec_id":"histogram-returns-distribution","library":"pygal","language":"python","code":"\"\"\" anyplot.ai\nhistogram-returns-distribution: Returns Distribution Histogram\nLibrary: pygal 3.1.0 | Python 3.13.13\nQuality: 88/100 | Updated: 2026-05-20\n\"\"\"\n\nimport sys\n\n\nsys.path.pop(0)  # Prevent self-import: pygal.py shadows the installed pygal package\n\nimport os\n\nimport numpy as np\nimport pygal\nfrom pygal.style import Style\n\n\nTHEME = os.getenv(\"ANYPLOT_THEME\", \"light\")\nPAGE_BG = \"#FAF8F1\" if THEME == \"light\" else \"#1A1A17\"\nINK = \"#1A1A17\" if THEME == \"light\" else \"#F0EFE8\"\nINK_MUTED = \"#6B6A63\" if THEME == \"light\" else \"#A8A79F\"\n\nIMPRINT = (\"#009E73\", \"#C475FD\", \"#4467A3\", \"#BD8233\", \"#AE3030\", \"#2ABCCD\", \"#954477\")\n\n# Data — 252 daily stock returns (1 trading year)\nnp.random.seed(42)\nreturns = np.random.normal(loc=0.0005, scale=0.015, size=252) * 100  # as percentage\n\nn = len(returns)\nmean_return = np.mean(returns)\nstd_return = np.std(returns, ddof=1)\nskewness = (n / ((n - 1) * (n - 2))) * np.sum(((returns - mean_return) / std_return) ** 3)\nkurtosis = ((n * (n + 1)) / ((n - 1) * (n - 2) * (n - 3))) * np.sum(((returns - mean_return) / std_return) ** 4) - (\n    3 * (n - 1) ** 2\n) / ((n - 2) * (n - 3))\n\nn_bins = 25\ncounts, bin_edges = np.histogram(returns, bins=n_bins, density=True)\n\nlower_tail = mean_return - 2 * std_return\nupper_tail = mean_return + 2 * std_return\n\n# Histogram bars: pygal.Histogram native format (value, xmin, xmax)\nnormal_bars = []\ntail_bars = []\nfor i, count in enumerate(counts):\n    left = float(bin_edges[i])\n    right = float(bin_edges[i + 1])\n    center = (left + right) / 2\n    height = float(count)\n    bar = (height, left, right)\n    if center < lower_tail or center > upper_tail:\n        tail_bars.append(bar)\n    else:\n        normal_bars.append(bar)\n\n# Normal distribution curve — 300 dense adjacent thin bins approximate a smooth overlay\nx_curve = np.linspace(float(bin_edges[0]), float(bin_edges[-1]), 300)\nnormal_pdf = (1 / (std_return * np.sqrt(2 * np.pi))) * np.exp(-0.5 * ((x_curve - mean_return) / std_return) ** 2)\ncurve_data = [(float(normal_pdf[i]), float(x_curve[i]), float(x_curve[i + 1])) for i in range(len(x_curve) - 1)]\n\n# Style\ncustom_style = Style(\n    background=PAGE_BG,\n    plot_background=PAGE_BG,\n    foreground=INK,\n    foreground_strong=INK,\n    foreground_subtle=INK_MUTED,\n    colors=IMPRINT,\n    title_font_size=66,\n    label_font_size=56,\n    major_label_font_size=44,\n    legend_font_size=44,\n    value_font_size=36,\n    stroke_width=2.5,\n    opacity=0.85,\n    opacity_hover=1.0,\n)\n\nstats_text = f\"Mean: {mean_return:.3f}% | Std: {std_return:.3f}% | Skew: {skewness:.2f} | Kurt: {kurtosis:.2f}\"\n\nchart = pygal.Histogram(\n    width=3200,\n    height=1800,\n    explicit_size=True,\n    style=custom_style,\n    title=f\"histogram-returns-distribution · python · pygal · anyplot.ai\\n{stats_text}\",\n    x_title=\"Returns (%)\",\n    y_title=\"Probability Density\",\n    show_legend=True,\n    legend_at_bottom=True,\n    legend_at_bottom_columns=3,\n    legend_box_size=32,\n    show_y_guides=False,\n    show_x_guides=False,\n    margin_bottom=200,\n    margin_left=120,\n    margin_right=80,\n    print_values=False,\n)\n\nchart.add(\"Returns (within 2σ)\", normal_bars)\nchart.add(\"Tails (beyond ±2σ)\", tail_bars)\nchart.add(\"Normal Distribution\", curve_data)\n\n# Save\nwith open(f\"plot-{THEME}.html\", \"wb\") as f:\n    f.write(chart.render())\nchart.render_to_png(f\"plot-{THEME}.png\")\n"}