{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\n# Boxplots\n\nVisualizing boxplots with matplotlib.\n\nThe following examples show off how to visualize boxplots with\nMatplotlib. There are many options to control their appearance and\nthe statistics that they use to summarize the data.\n\n.. redirect-from:: /gallery/pyplots/boxplot_demo_pyplot\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "import matplotlib.pyplot as plt\nimport numpy as np\n\nfrom matplotlib.patches import Polygon\n\n# Fixing random state for reproducibility\nnp.random.seed(19680801)\n\n# fake up some data\nspread = np.random.rand(50) * 100\ncenter = np.ones(25) * 50\nflier_high = np.random.rand(10) * 100 + 100\nflier_low = np.random.rand(10) * -100\ndata = np.concatenate((spread, center, flier_high, flier_low))\n\nfig, axs = plt.subplots(2, 3)\n\n# basic plot\naxs[0, 0].boxplot(data)\naxs[0, 0].set_title('basic plot')\n\n# notched plot\naxs[0, 1].boxplot(data, notch=True)\naxs[0, 1].set_title('notched plot')\n\n# change outlier point symbols\naxs[0, 2].boxplot(data, sym='gD')\naxs[0, 2].set_title('change outlier\\npoint symbols')\n\n# don't show outlier points\naxs[1, 0].boxplot(data, sym='')\naxs[1, 0].set_title(\"don't show\\noutlier points\")\n\n# horizontal boxes\naxs[1, 1].boxplot(data, sym='rs', orientation='horizontal')\naxs[1, 1].set_title('horizontal boxes')\n\n# change whisker length\naxs[1, 2].boxplot(data, sym='rs', orientation='horizontal', whis=0.75)\naxs[1, 2].set_title('change whisker length')\n\nfig.subplots_adjust(left=0.08, right=0.98, bottom=0.05, top=0.9,\n                    hspace=0.4, wspace=0.3)\n\n# fake up some more data\nspread = np.random.rand(50) * 100\ncenter = np.ones(25) * 40\nflier_high = np.random.rand(10) * 100 + 100\nflier_low = np.random.rand(10) * -100\nd2 = np.concatenate((spread, center, flier_high, flier_low))\n# Making a 2-D array only works if all the columns are the\n# same length.  If they are not, then use a list instead.\n# This is actually more efficient because boxplot converts\n# a 2-D array into a list of vectors internally anyway.\ndata = [data, d2, d2[::2]]\n\n# Multiple box plots on one Axes\nfig, ax = plt.subplots()\nax.boxplot(data)\n\nplt.show()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Below we'll generate data from five different probability distributions,\neach with different characteristics. We want to play with how an IID\nbootstrap resample of the data preserves the distributional\nproperties of the original sample, and a boxplot is one visual tool\nto make this assessment\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "random_dists = ['Normal(1, 1)', 'Lognormal(1, 1)', 'Exp(1)', 'Gumbel(6, 4)',\n                'Triangular(2, 9, 11)']\nN = 500\n\nnorm = np.random.normal(1, 1, N)\nlogn = np.random.lognormal(1, 1, N)\nexpo = np.random.exponential(1, N)\ngumb = np.random.gumbel(6, 4, N)\ntria = np.random.triangular(2, 9, 11, N)\n\n# Generate some random indices that we'll use to resample the original data\n# arrays. For code brevity, just use the same random indices for each array\nbootstrap_indices = np.random.randint(0, N, N)\ndata = [\n    norm, norm[bootstrap_indices],\n    logn, logn[bootstrap_indices],\n    expo, expo[bootstrap_indices],\n    gumb, gumb[bootstrap_indices],\n    tria, tria[bootstrap_indices],\n]\n\nfig, ax1 = plt.subplots(figsize=(10, 6))\nfig.canvas.manager.set_window_title('A Boxplot Example')\nfig.subplots_adjust(left=0.075, right=0.95, top=0.9, bottom=0.25)\n\nbp = ax1.boxplot(data, notch=False, sym='+', orientation='vertical', whis=1.5)\nplt.setp(bp['boxes'], color='black')\nplt.setp(bp['whiskers'], color='black')\nplt.setp(bp['fliers'], color='red', marker='+')\n\n# Add a horizontal grid to the plot, but make it very light in color\n# so we can use it for reading data values but not be distracting\nax1.yaxis.grid(True, linestyle='-', which='major', color='lightgrey',\n               alpha=0.5)\n\nax1.set(\n    axisbelow=True,  # Hide the grid behind plot objects\n    title='Comparison of IID Bootstrap Resampling Across Five Distributions',\n    xlabel='Distribution',\n    ylabel='Value',\n)\n\n# Now fill the boxes with desired colors\nbox_colors = ['darkkhaki', 'royalblue']\nnum_boxes = len(data)\nmedians = np.empty(num_boxes)\nfor i in range(num_boxes):\n    box = bp['boxes'][i]\n    box_x = []\n    box_y = []\n    for j in range(5):\n        box_x.append(box.get_xdata()[j])\n        box_y.append(box.get_ydata()[j])\n    box_coords = np.column_stack([box_x, box_y])\n    # Alternate between Dark Khaki and Royal Blue\n    ax1.add_patch(Polygon(box_coords, facecolor=box_colors[i % 2]))\n    # Now draw the median lines back over what we just filled in\n    med = bp['medians'][i]\n    median_x = []\n    median_y = []\n    for j in range(2):\n        median_x.append(med.get_xdata()[j])\n        median_y.append(med.get_ydata()[j])\n        ax1.plot(median_x, median_y, 'k')\n    medians[i] = median_y[0]\n    # Finally, overplot the sample averages, with horizontal alignment\n    # in the center of each box\n    ax1.plot(np.average(med.get_xdata()), np.average(data[i]),\n             color='w', marker='*', markeredgecolor='k')\n\n# Set the axes ranges and axes labels\nax1.set_xlim(0.5, num_boxes + 0.5)\ntop = 40\nbottom = -5\nax1.set_ylim(bottom, top)\nax1.set_xticklabels(np.repeat(random_dists, 2),\n                    rotation=45, fontsize=8)\n\n# Due to the Y-axis scale being different across samples, it can be\n# hard to compare differences in medians across the samples. Add upper\n# X-axis tick labels with the sample medians to aid in comparison\n# (just use two decimal places of precision)\npos = np.arange(num_boxes) + 1\nupper_labels = [str(round(s, 2)) for s in medians]\nweights = ['bold', 'semibold']\nfor tick, label in zip(range(num_boxes), ax1.get_xticklabels()):\n    k = tick % 2\n    ax1.text(pos[tick], .95, upper_labels[tick],\n             transform=ax1.get_xaxis_transform(),\n             horizontalalignment='center', size='x-small',\n             weight=weights[k], color=box_colors[k])\n\n# Finally, add a basic legend\nfig.text(0.80, 0.08, f'{N} Random Numbers',\n         backgroundcolor=box_colors[0], color='black', weight='roman',\n         size='x-small')\nfig.text(0.80, 0.045, 'IID Bootstrap Resample',\n         backgroundcolor=box_colors[1],\n         color='white', weight='roman', size='x-small')\nfig.text(0.80, 0.015, '*', color='white', backgroundcolor='silver',\n         weight='roman', size='medium')\nfig.text(0.815, 0.013, ' Average Value', color='black', weight='roman',\n         size='x-small')\n\nplt.show()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Here we write a custom function to bootstrap confidence intervals.\nWe can then use the boxplot along with this function to show these intervals.\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "def fake_bootstrapper(n):\n    \"\"\"\n    This is just a placeholder for the user's method of\n    bootstrapping the median and its confidence intervals.\n\n    Returns an arbitrary median and confidence interval packed into a tuple.\n    \"\"\"\n    if n == 1:\n        med = 0.1\n        ci = (-0.25, 0.25)\n    else:\n        med = 0.2\n        ci = (-0.35, 0.50)\n    return med, ci\n\ninc = 0.1\ne1 = np.random.normal(0, 1, size=500)\ne2 = np.random.normal(0, 1, size=500)\ne3 = np.random.normal(0, 1 + inc, size=500)\ne4 = np.random.normal(0, 1 + 2*inc, size=500)\n\ntreatments = [e1, e2, e3, e4]\nmed1, ci1 = fake_bootstrapper(1)\nmed2, ci2 = fake_bootstrapper(2)\nmedians = [None, None, med1, med2]\nconf_intervals = [None, None, ci1, ci2]\n\nfig, ax = plt.subplots()\npos = np.arange(len(treatments)) + 1\nbp = ax.boxplot(treatments, sym='k+', positions=pos,\n                notch=True, bootstrap=5000,\n                usermedians=medians,\n                conf_intervals=conf_intervals)\n\nax.set_xlabel('treatment')\nax.set_ylabel('response')\nplt.setp(bp['whiskers'], color='k', linestyle='-')\nplt.setp(bp['fliers'], markersize=3.0)\nplt.show()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Here we customize the widths of the caps .\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "x = np.linspace(-7, 7, 140)\nx = np.hstack([-25, x, 25])\nfig, ax = plt.subplots()\n\nax.boxplot([x, x], notch=True, capwidths=[0.01, 0.2])\n\nplt.show()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        ".. tags:: domain: statistics, plot-type: boxplot\n\n.. admonition:: References\n\n   The use of the following functions, methods, classes and modules is shown\n   in this example:\n\n   - `matplotlib.axes.Axes.boxplot` / `matplotlib.pyplot.boxplot`\n   - `matplotlib.artist.Artist.set` / `matplotlib.pyplot.setp`\n\n"
      ]
    }
  ],
  "metadata": {
    "kernelspec": {
      "display_name": "Python 3",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "codemirror_mode": {
        "name": "ipython",
        "version": 3
      },
      "file_extension": ".py",
      "mimetype": "text/x-python",
      "name": "python",
      "nbconvert_exporter": "python",
      "pygments_lexer": "ipython3",
      "version": "3.14.6"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}