@@ -216,25 +216,65 @@ There are two possible approaches to #2. The first and most direct would
216
216
be to mirror the new ``transform_in `` and ``tranform_out `` parameters of
217
217
``cbook.boxplot_stats `` in ``Axes.boxplot `` and pass them directly.
218
218
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
-
224
219
The second approach would be to add ``statfxn `` and ``statfxn_args ``
225
220
parameters to ``Axes.boxplot ``. Under this implementation, the default
226
221
value of ``statfxn `` would be ``cbook.boxplot_stats ``, but users could
227
222
pass their own function. Then ``transform_in `` and ``tranform_out `` would
228
223
then be passed as elements of the ``statfxn_args `` parameter.
229
224
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:
231
258
232
259
.. 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
+
236
264
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
238
278
239
279
.. python:
240
280
fig, ax = plt.subplots()
@@ -244,30 +284,22 @@ Or more alternatively (depending on the implementation)
244
284
Users could also pass their own function to compute the stats:
245
285
246
286
.. 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')
257
290
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:
260
295
261
296
.. 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')
271
303
272
304
This type of flexibility was the intention behind splitting the overall
273
305
boxplot API in the current three functions. In practice however, downstream
0 commit comments