Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion doc/users/whats_new.rst
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,8 @@ New Boxplot Functionality
Users can now incorporate their own methods for computing the median and its
confidence intervals into the :meth:`~matplotlib.axes.boxplot` method. For
every column of data passed to boxplot, the user can specify an accompanying
median and confidence interval.
median and confidence interval. Similarly, a custom function that computes the
median and confidence interval can now be passed to `boxplot`.

.. plot:: mpl_examples/pylab_examples/boxplot_demo3.py

Expand Down
49 changes: 25 additions & 24 deletions examples/pylab_examples/boxplot_demo3.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,18 @@
import matplotlib.transforms as mtransforms
import numpy as np

def fakeBootStrapper(n):
def fakeBootStrapper(data):
'''
This is just a placeholder for the user's method of
bootstrapping the median and its confidence intervals.

Returns an arbitrary median and confidence intervals
packed into a tuple
'''
if n == 1:
med = 0.1
CI = (-0.25, 0.25)
else:
med = 0.2
CI = (-0.35, 0.50)

return med, CI


med, q25, q75 = np.percentile(data, [50,25,75])
ci_lo = med - (med-q25)/2.0
ci_hi = med + (q75-med)/3.0
return med, (ci_lo, ci_hi)

np.random.seed(2)
inc = 0.1
Expand All @@ -29,21 +23,28 @@ def fakeBootStrapper(n):
e4 = np.random.normal(0, 1 + 2*inc, size=(500,))

treatments = [e1,e2,e3,e4]
med1, CI1 = fakeBootStrapper(1)
med2, CI2 = fakeBootStrapper(2)
med1, CI1 = fakeBootStrapper(e3)
med2, CI2 = fakeBootStrapper(e4)
medians = [None, None, med1, med2]
conf_intervals = [None, None, CI1, CI2]

fig = plt.figure()
ax = fig.add_subplot(111)
fig, (ax1, ax2) = plt.subplots(nrows=2)
pos = np.array(range(len(treatments)))+1
bp = ax.boxplot(treatments, sym='k+', positions=pos,
notch=1, bootstrap=5000,
usermedians=medians,
conf_intervals=conf_intervals)

ax.set_xlabel('treatment')
ax.set_ylabel('response')
plt.setp(bp['whiskers'], color='k', linestyle='-' )
plt.setp(bp['fliers'], markersize=3.0)

# specify the medians and CIs manually
bp1 = ax1.boxplot(treatments, sym='k+', positions=pos,
notch=1, bootstrap=5000,
usermedians=medians,
conf_intervals=conf_intervals)

# let the function `fakeBootStrapper` compute the med. and CIs
bp2 = ax2.boxplot(treatments, sym='k+', positions=pos,
notch=1, bootstrap=5000,
ci_func=fakeBootStrapper)

for ax, bp in zip([ax1, ax2], [bp1, bp2]):
ax.set_xlabel('treatment')
ax.set_ylabel('response')
plt.setp(bp['whiskers'], color='k', linestyle='-' )
plt.setp(bp['fliers'], markersize=3.0)
plt.show()
33 changes: 23 additions & 10 deletions lib/matplotlib/axes.py
Original file line number Diff line number Diff line change
Expand Up @@ -5615,7 +5615,8 @@ def xywhere(xs, ys, mask):

def boxplot(self, x, notch=False, sym='b+', vert=True, whis=1.5,
positions=None, widths=None, patch_artist=False,
bootstrap=None, usermedians=None, conf_intervals=None):
bootstrap=None, usermedians=None, conf_intervals=None,
ci_func=None):
"""
Make a box and whisker plot.

Expand Down Expand Up @@ -5663,20 +5664,27 @@ def boxplot(self, x, notch=False, sym='b+', vert=True, whis=1.5,
bootstrap the median to determine it's 95% confidence intervals.
Values between 1000 and 10000 are recommended.

*ci_func* : [ function ]
A user-specified function that Computes the median and its
confidence intervals. This function should return the median and
the confidence intervals stored in an iterable of shape=(2,). Use
of this kwarg will override the default computation of the median.

*usermedians* : [ default None ]
An array or sequence whose first dimension (or length) is
compatible with *x*. This overrides the medians computed by
matplotlib for each element of *usermedians* that is not None.
When an element of *usermedians* == None, the median will be
computed directly as normal.
When an element of *usermedians* is None, boxplot computes notches
per the method specified by the other kwargs (e.g. *bootstrap*,
*ci_func*).

*conf_intervals* : [ default None ]
Array or sequence whose first dimension (or length) is compatible
with *x* and whose second dimension is 2. When the current element
of *conf_intervals* is not None, the notch locations computed by
matplotlib are overridden (assuming notch is True). When an element of
*conf_intervals* is None, boxplot compute notches the method
specified by the other kwargs (e.g. *bootstrap*).
matplotlib are overridden (assuming notch is True). When an element
of *conf_intervals* is None, boxplot computes notches per the
method specified by the other kwargs (e.g. *bootstrap*, *ci_func*).

*positions* : [ default 1,2,...,n ]
Sets the horizontal positions of the boxes. The ticks and limits
Expand Down Expand Up @@ -5707,7 +5715,7 @@ def boxplot(self, x, notch=False, sym='b+', vert=True, whis=1.5,

**Example:**

.. plot:: pyplots/boxplot_demo.py
.. plot:: mpl_examples/pylab_examples/boxplot_demo3.py
"""
def bootstrapMedian(data, N=5000):
# determine 95% confidence intervals of the median
Expand Down Expand Up @@ -5768,7 +5776,7 @@ def computeConfInterval(data, med, iq, bootstrap):
# sanitize user-input medians
msg1 = "usermedians must either be a list/tuple or a 1d array"
msg2 = "usermedians' length must be compatible with x"
if usermedians is not None:
if usermedians is not None and ci_func is None:
if hasattr(usermedians, 'shape'):
if len(usermedians.shape) != 1:
raise ValueError(msg1)
Expand All @@ -5781,7 +5789,7 @@ def computeConfInterval(data, med, iq, bootstrap):
msg1 = "conf_intervals must either be a list of tuples or a 2d array"
msg2 = "conf_intervals' length must be compatible with x"
msg3 = "each conf_interval, if specificied, must have two values"
if conf_intervals is not None:
if conf_intervals is not None and ci_func is None:
if hasattr(conf_intervals, 'shape'):
if len(conf_intervals.shape) != 2:
raise ValueError(msg1)
Expand Down Expand Up @@ -5818,9 +5826,11 @@ def computeConfInterval(data, med, iq, bootstrap):
q1, med, q3 = mlab.prctile(d,[25,50,75])

# replace with input medians if available
if usermedians is not None:
if usermedians is not None and ci_func is None:
if usermedians[i] is not None:
med = usermedians[i]
elif ci_func is not None:
med, CIs = ci_func(d)

# get high extreme
iq = q3 - q1
Expand Down Expand Up @@ -5867,6 +5877,9 @@ def computeConfInterval(data, med, iq, bootstrap):
if conf_intervals is not None and conf_intervals[i] is not None:
notch_max = np.max(conf_intervals[i])
notch_min = np.min(conf_intervals[i])
elif ci_func is not None:
notch_min = np.min(CIs)
notch_max = np.max(CIs)
else:
notch_min, notch_max = computeConfInterval(d, med, iq,
bootstrap)
Expand Down
7 changes: 4 additions & 3 deletions lib/matplotlib/pyplot.py
Original file line number Diff line number Diff line change
Expand Up @@ -2413,7 +2413,7 @@ def broken_barh(xranges, yrange, hold=None, **kwargs):
@_autogen_docstring(Axes.boxplot)
def boxplot(x, notch=False, sym='b+', vert=True, whis=1.5, positions=None,
widths=None, patch_artist=False, bootstrap=None, usermedians=None,
conf_intervals=None, hold=None):
conf_intervals=None, ci_func=None, hold=None):
ax = gca()
# allow callers to override the hold state by passing hold=True|False
washold = ax.ishold()
Expand All @@ -2424,7 +2424,8 @@ def boxplot(x, notch=False, sym='b+', vert=True, whis=1.5, positions=None,
ret = ax.boxplot(x, notch=notch, sym=sym, vert=vert, whis=whis,
positions=positions, widths=widths,
patch_artist=patch_artist, bootstrap=bootstrap,
usermedians=usermedians, conf_intervals=conf_intervals)
usermedians=usermedians,
conf_intervals=conf_intervals, ci_func=ci_func)
draw_if_interactive()
finally:
ax.hold(washold)
Expand Down Expand Up @@ -3058,7 +3059,7 @@ def streamplot(x, y, u, v, density=1, linewidth=None, color=None, cmap=None,
draw_if_interactive()
finally:
ax.hold(washold)
sci(ret.lines)
sci(ret)
return ret

# This function was autogenerated by boilerplate.py. Do not edit as
Expand Down
Binary file modified lib/matplotlib/tests/baseline_images/test_axes/boxplot.pdf
Binary file not shown.
Binary file modified lib/matplotlib/tests/baseline_images/test_axes/boxplot.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading