Skip to content

Commit 3013010

Browse files
committed
WIP: add to TOC, redo examples
1 parent 2108e8b commit 3013010

File tree

2 files changed

+64
-31
lines changed

2 files changed

+64
-31
lines changed

doc/devel/MEP/MEP28.rst

Lines changed: 63 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -216,25 +216,65 @@ There are two possible approaches to #2. The first and most direct would
216216
be to mirror the new ``transform_in`` and ``tranform_out`` parameters of
217217
``cbook.boxplot_stats`` in ``Axes.boxplot`` and pass them directly.
218218

219-
.. python:
220-
fig, ax = plt.subplots()
221-
data = mylib.load_data()
222-
ax.boxplot(data, ..., transform_in=np.log, transform_out=np.exp)
223-
224219
The second approach would be to add ``statfxn`` and ``statfxn_args``
225220
parameters to ``Axes.boxplot``. Under this implementation, the default
226221
value of ``statfxn`` would be ``cbook.boxplot_stats``, but users could
227222
pass their own function. Then ``transform_in`` and ``tranform_out`` would
228223
then be passed as elements of the ``statfxn_args`` parameter.
229224

230-
Using matplotlib's stats function, this would look similar to this:
225+
.. python:
226+
def boxplot_stats(data, ..., transform_in=None, transform_out=None):
227+
if transform_in is None:
228+
transform_in = lambda x: x
229+
230+
if transform_out is None:
231+
transform_out = lambda x: x
232+
233+
output = []
234+
for _d in data:
235+
d = transform_in(_d)
236+
stat_dict = do_stats(d)
237+
for key, value in stat_dict.item():
238+
if key != 'label':
239+
stat_dict[key] = transform_out(value)
240+
output.append(d)
241+
return output
242+
243+
244+
class Axes(...):
245+
def boxplot_option1(data, ..., transform_in=None, transform_out=None):
246+
stats = cbook.boxplot_stats(data, ...,
247+
transform_in=transform_in,
248+
transform_out=transform_out)
249+
return self.bxp(stats, ...)
250+
251+
def boxplot_option2(data, ..., statfxn=None, **statopts):
252+
if statfxn is None:
253+
statfxn = boxplot_stats
254+
stats = statfxn(data, **statopts)
255+
return self.bxp(stats, ...)
256+
257+
Both cases would allow users to do the following:
231258

232259
.. python:
233-
fig, ax = plt.subplots()
234-
statopts = dict(transform_in=np.log, transform_out=np.exp)
235-
ax.boxplot(data, ..., statfxn_args=statopts)
260+
fig, ax1 = plt.subplots()
261+
artists1 = ax1.boxplot_optionX(data, transform_in=np.log,
262+
transform_out=np.exp)
263+
236264
237-
Or more alternatively (depending on the implementation)
265+
But Option Two lets a user write a completely custom stat function
266+
(e.g., ``my_box_stats``) with fancy BCA confidence intervals and the
267+
whiskers set differently depending on some attribute of the data.
268+
269+
This is available under the current API:
270+
271+
.. python:
272+
fig, ax1 = plt.subplots()
273+
my_stats = my_box_stats(data, bootstrap_method='BCA',
274+
whisker_method='dynamic')
275+
ax1.bxp(my_stats)
276+
277+
And would be more concise with Option Two
238278

239279
.. python:
240280
fig, ax = plt.subplots()
@@ -244,30 +284,22 @@ Or more alternatively (depending on the implementation)
244284
Users could also pass their own function to compute the stats:
245285

246286
.. python:
247-
from mylib import box_stats
248-
fig, ax = plt.subplots()
249-
statopts = dict(option1=True, niter_bootstrap=10000, bs_method='bca')
250-
ax.boxplot(data, ..., statfxn=box_stats, statfxn_args=statopts)
251-
## or:
252-
# ax.boxplot(data, ..., statfxn=box_stats, **statopts)
253-
254-
The second approach is by far more flexible, though could probably be
255-
considered more advanced usage. The first approach, though more limited,
256-
would likely cover a majority of the use cases.
287+
fig, ax1 = plt.subplots()
288+
ax1.boxplot(data, statfxn=my_box_stats, bootstrap_method='BCA',
289+
whisker_method='dynamic')
257290
258-
To match this proposed functionality in matplotlib v1.5.3 and v2.0.0b4,
259-
one would do the following:
291+
From the examples above, Option Two seems to have only marginal benifit,
292+
but in the context of downstream libraries like seaborn, its advantage
293+
is more apparent as the following would be possible without any patches
294+
to seaborn:
260295

261296
.. python:
262-
fig, ax = plt.subplots()
263-
log_data = [np.log(d) for d in data]
264-
stats = cbook.boxplot_stats(log_data)
265-
for s in stats:
266-
for key, value in s.items():
267-
if key != 'label':
268-
s[key] = np.exp(value)
269-
270-
ax.bxp(stats, ...)
297+
import seaborn
298+
tips = seaborn.load_data('tips')
299+
g = seaborn.factorplot(x="day", y="total_bill", hue="sex", data=tips,
300+
kind='box', palette="PRGn", shownotches=True,
301+
statfxn=my_box_stats, bootstrap_method='BCA',
302+
whisker_method='dynamic')
271303
272304
This type of flexibility was the intention behind splitting the overall
273305
boxplot API in the current three functions. In practice however, downstream

doc/devel/MEP/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,4 @@ Matplotlib Enhancement Proposals
2929
MEP25
3030
MEP26
3131
MEP27
32+
MEP28

0 commit comments

Comments
 (0)