Skip to content

Commit

Permalink
Merge pull request #77 from ACCLAB/v0.2.6-dev
Browse files Browse the repository at this point in the history
v0.2.6
  • Loading branch information
josesho committed Oct 8, 2019
2 parents d19e139 + 36f573e commit efc0732
Show file tree
Hide file tree
Showing 81 changed files with 671 additions and 366 deletions.
3 changes: 1 addition & 2 deletions .travis.yml
Expand Up @@ -22,8 +22,7 @@ install:
- conda config --add channels conda-forge
- conda create -n testenv --yes pip python=$PYTHON matplotlib
- source activate testenv
- pip install pytest==4.3
- pip install .
- pip install .[dev]


script: pytest dabest
4 changes: 2 additions & 2 deletions CONTRIBUTING.md
Expand Up @@ -8,9 +8,9 @@


## Did you write a patch that fixes a bug?
- Open a new GitHub [pull request](https://help.github.com/en/articles/about-pull-requests)(PR for short) with the patch.
- Open a new GitHub [pull request](https://help.github.com/en/articles/about-pull-requests) (PR for short) with the patch.

- Create the PR into the development branch, which is indicated by `v{latest version number}_dev`.
- Create the PR into the development branch, which is indicated by `v{latest version number}-dev`.

- Clearly state the problem and solution in the PR description. Include the relevant [issue number](https://guides.github.com/features/issues/) if applicable.

Expand Down
18 changes: 6 additions & 12 deletions README.md
Expand Up @@ -6,6 +6,7 @@
[![Free-to-view citation](https://zenodo.org/badge/DOI/10.1038/s41592-019-0470-3.svg)](https://rdcu.be/bHhJ4)
[![License](https://img.shields.io/badge/License-BSD%203--Clause--Clear-orange.svg)](https://spdx.org/licenses/BSD-3-Clause-Clear.html)


## About

DABEST is a package for **D**ata **A**nalysis using **B**ootstrap-Coupled **EST**imation.
Expand All @@ -22,21 +23,12 @@ An estimation plot has two key features.

DABEST powers [estimationstats.com](https://www.estimationstats.com/), allowing everyone access to high-quality estimation plots.

## Requirements

DABEST has been tested on Python 3.5, 3.6, and 3.7.

In addition, the following packages are also required:
- [numpy](https://www.numpy.org) (1.15)
- [scipy](https://www.scipy.org) (1.2)
- [matplotlib](https://www.matplotlib.org) (3.0)
- [seaborn](https://seaborn.pydata.org) (0.9)
- [pandas](https://pandas.pydata.org) (0.24).

To obtain these package dependencies easily, it is highly recommended to download the [Anaconda distribution](https://www.continuum.io/downloads) of Python.

## Installation

This package is tested on Python 3.5, 3.6, and 3.7.
It is highly recommended to download the [Anaconda distribution](https://www.continuum.io/downloads) of Python in order to obtain the dependencies easily.

You can install this package via `pip`.

To install, at the command line run
Expand All @@ -56,6 +48,7 @@ Then, navigate to the cloned repo in the command line and run
pip install .
```


## Usage

```python3
Expand Down Expand Up @@ -99,6 +92,7 @@ All contributions are welcome; please read the [Guidelines for contributing](htt

We also have a [Code of Conduct](https://github.com/ACCLAB/DABEST-python/blob/master/CODE_OF_CONDUCT.md) to foster an inclusive and productive space.


## Acknowledgements

We would like to thank alpha testers from the [Claridge-Chang lab](https://www.claridgechang.net/): [Sangyu Xu](https://github.com/sangyu), [Xianyuan Zhang](https://github.com/XYZfar), [Farhan Mohammad](https://github.com/farhan8igib), Jurga Mituzaitė, and Stanislav Ott.
Expand Down
2 changes: 1 addition & 1 deletion dabest/__init__.py
Expand Up @@ -23,4 +23,4 @@
from ._stats_tools import effsize as effsize
from ._classes import TwoGroupsEffectSize

__version__ = "0.2.5"
__version__ = "0.2.6"
40 changes: 36 additions & 4 deletions dabest/_classes.py
Expand Up @@ -460,7 +460,7 @@ def __init__(self, control, test, effect_size,
'statistic_wilcoxon': nan}
"""

from numpy import array, isnan
from numpy import array, isnan, isinf
from numpy import sort as npsort
from numpy.random import choice, seed

Expand Down Expand Up @@ -522,6 +522,20 @@ def __init__(self, control, test, effect_size,
control, test, is_paired, effect_size,
resamples, random_seed)
self.__bootstraps = npsort(bootstraps)

# Added in v0.2.6.
# Raises a UserWarning if there are any infiinities in the bootstraps.
num_infinities = len(self.__bootstraps[isinf(self.__bootstraps)])

if num_infinities > 0:
warn_msg = "There are {} bootstrap(s) that are not defined. "\
"This is likely due to smaple sample sizes. "\
"The values in a bootstrap for a group will be more likely "\
"to be all equal, with a resulting variance of zero. "\
"The computation of Cohen's d and Hedges' g thus "\
"involved a division by zero. "
warnings.warn(warn_msg.format(num_infinities),
category=UserWarning)

self.__bias_correction = ci2g.compute_meandiff_bias_correction(
self.__bootstraps, self.__difference)
Expand Down Expand Up @@ -1103,6 +1117,7 @@ def plot(self, color_col=None,

fig_size=None,
dpi=100,
ax=None,

swarmplot_kwargs=None,
violinplot_kwargs=None,
Expand All @@ -1112,6 +1127,7 @@ def plot(self, color_col=None,
legend_kwargs=None):
"""
Creates an estimation plot for the effect size of interest.
Parameters
----------
Expand Down Expand Up @@ -1176,6 +1192,9 @@ def plot(self, color_col=None,
The desired dimensions of the figure as a (length, width) tuple.
dpi : int, default 100
The dots per inch of the resulting figure.
ax : matplotlib.Axes, default None
Provide an existing Axes for the plots to be created. If no Axes is
specified, a new matplotlib Figure will be created.
swarmplot_kwargs : dict, default None
Pass any keyword arguments accepted by the seaborn `swarmplot`
command here, as a dict. If None, the following keywords are
Expand Down Expand Up @@ -1206,9 +1225,14 @@ def plot(self, color_col=None,
Returns
-------
A :class:`matplotlib.figure.Figure` with 2 Axes.
A :class:`matplotlib.figure.Figure` with 2 Axes, if ``ax = None``.
The first axes (accessible with ``FigName.axes[0]``) contains the rawdata swarmplot; the second axes (accessible with ``FigName.axes[1]``) has the bootstrap distributions and effect sizes (with confidence intervals) plotted on it.
If ``ax`` is specified, the rawdata swarmplot is accessed at ``ax``
itself, while the effect size axes is accessed at ``ax.contrast_axes``.
See the last example below.
Examples
--------
Expand Down Expand Up @@ -1244,6 +1268,14 @@ def plot(self, color_col=None,
... "Test 2", "Test 3")
... )
>>> fig6 = my_shared_control.mean_diff.plot()
Creating estimation plots in individual panels of a figure.
>>> f, axx = plt.subplots(nrows=2, ncols=2, figsize=(15, 15))
>>> my_data.mean_diff.plot(ax=axx.flat[0])
>>> my_data_paired.mean_diff.plot(ax=axx.flat[1])
>>> my_shared_control.mean_diff.plot(ax=axx.flat[2])
>>> my_shared_control.mean_diff.plot(ax=axx.flat[3], float_contrast=False)
"""

Expand Down Expand Up @@ -1344,4 +1376,4 @@ def dabest_obj(self):
Returns the `dabest` object that invoked the current EffectSizeDataFrame
class.
"""
return self.__dabest_obj
return self.__dabest_obj
19 changes: 18 additions & 1 deletion dabest/_stats_tools/confint_2group_diff.py
Expand Up @@ -159,7 +159,24 @@ def compute_bootstrapped_diff(x0, x1, is_paired, effect_size,

# reset seed
np.random.seed()


# check whether there are any infinities in the bootstrap,
# which likely indicates the sample sizes are too small as
# the computation of Cohen's d and Hedges' g necessitated
# a division by zero.
# Added in v0.2.6.

# num_infinities = len(out[np.isinf(out)])
# print(num_infinities)
# if num_infinities > 0:
# warn_msg = "There are {} bootstraps that are not defined. "\
# "This is likely due to smaple sample sizes. "\
# "The values in a bootstrap for a group will be more likely "\
# "to be all equal, with a resulting variance of zero. "\
# "The computation of Cohen's d and Hedges' g will therefore "\
# "involved a division by zero. "
# warnings.warn(warn_msg.format(num_infinities), category="UserWarning")

return out


Expand Down
6 changes: 4 additions & 2 deletions dabest/_stats_tools/effsize.py
Expand Up @@ -217,11 +217,13 @@ def cohens_d(control, test, is_paired=False):
# assume the two arrays are ordered already.
delta = test - control
M = np.mean(delta)
return M / average_sd
divisor = average_sd

else:
M = np.mean(test) - np.mean(control)
return M / pooled_sd
divisor = pooled_sd

return M / divisor



Expand Down
98 changes: 74 additions & 24 deletions dabest/plotter.py
Expand Up @@ -31,6 +31,7 @@ def EffectSizeDataFramePlotter(EffectSizeDataFrame, **plot_kwargs):
fig_size=None,
dpi=100,
ax=None,
swarmplot_kwargs=None,
violinplot_kwargs=None,
Expand Down Expand Up @@ -254,28 +255,76 @@ def EffectSizeDataFramePlotter(EffectSizeDataFrame, **plot_kwargs):

# Initialise the figure.
# sns.set(context="talk", style='ticks')
init_fig_kwargs = dict(figsize=fig_size, dpi=plot_kwargs["dpi"])
init_fig_kwargs = dict(figsize=fig_size, dpi=plot_kwargs["dpi"],
tight_layout=True)

width_ratios_ga = [2.5, 1]
h_space_cummings = 0.3
if plot_kwargs["ax"] is not None:
# New in v0.2.6.
# Use inset axes to create the estimation plot inside a single axes.
# Author: Adam L Nekimken. (PR #73)
inset_contrast = True
rawdata_axes = plot_kwargs["ax"]
ax_position = rawdata_axes.get_position() # [[x0, y0], [x1, y1]]

fig = rawdata_axes.get_figure()

if float_contrast is True:
axins = rawdata_axes.inset_axes(
[1, 0,
width_ratios_ga[1]/width_ratios_ga[0], 1])
rawdata_axes.set_position( # [l, b, w, h]
[ax_position.x0,
ax_position.y0,
(ax_position.x1 - ax_position.x0) * (width_ratios_ga[0] /
sum(width_ratios_ga)),
(ax_position.y1 - ax_position.y0)])

contrast_axes = axins

# Here, we hardcode some figure parameters.
if float_contrast is True:
fig, axx = plt.subplots(ncols=2,
gridspec_kw={"width_ratios": [2.5, 1],
"wspace": 0},
**init_fig_kwargs)
else:
axins = rawdata_axes.inset_axes([0, -1 - h_space_cummings, 1, 1])
plot_height = ((ax_position.y1 - ax_position.y0) /
(2 + h_space_cummings))
rawdata_axes.set_position(
[ax_position.x0,
ax_position.y0 + (1 + h_space_cummings) * plot_height,
(ax_position.x1 - ax_position.x0),
plot_height])

# If the contrast axes are NOT floating, create lists to store
# raw ylims and raw tick intervals, so that I can normalize
# their ylims later.
contrast_ax_ylim_low = list()
contrast_ax_ylim_high = list()
contrast_ax_ylim_tickintervals = list()
contrast_axes = axins
rawdata_axes.contrast_axes = axins

else:
fig, axx = plt.subplots(nrows=2,
gridspec_kw={"hspace": 0.3},
**init_fig_kwargs)

# If the contrast axes are NOT floating, create lists to store raw ylims
# and raw tick intervals, so that I can normalize their ylims later.
contrast_ax_ylim_low = list()
contrast_ax_ylim_high = list()
contrast_ax_ylim_tickintervals = list()
inset_contrast = False
# Here, we hardcode some figure parameters.
if float_contrast is True:
fig, axx = plt.subplots(
ncols=2,
gridspec_kw={"width_ratios": width_ratios_ga,
"wspace": 0},
**init_fig_kwargs)

rawdata_axes = axx[0]
contrast_axes = axx[1]
else:
fig, axx = plt.subplots(nrows=2,
gridspec_kw={"hspace": 0.3},
**init_fig_kwargs)
# If the contrast axes are NOT floating, create lists to store
# raw ylims and raw tick intervals, so that I can normalize
# their ylims later.
contrast_ax_ylim_low = list()
contrast_ax_ylim_high = list()
contrast_ax_ylim_tickintervals = list()

rawdata_axes = axx[0]
contrast_axes = axx[1]

rawdata_axes.set_frame_on(False)
contrast_axes.set_frame_on(False)
Expand Down Expand Up @@ -423,7 +472,8 @@ def EffectSizeDataFramePlotter(EffectSizeDataFrame, **plot_kwargs):
current_ci_high = results.bca_high[j]

# Create the violinplot.
v = contrast_axes.violinplot(current_bootstrap,
# New in v0.2.6: drop negative infinities before plotting.
v = contrast_axes.violinplot(current_bootstrap[~np.isinf(current_bootstrap)],
positions=[tick],
**violinplot_kwargs)
# Turn the violinplot into half, and color it the same as the swarmplot.
Expand Down Expand Up @@ -651,19 +701,19 @@ def EffectSizeDataFramePlotter(EffectSizeDataFrame, **plot_kwargs):

# Compute the end of each x-axes line.
rightend_ticks = np.array([len(i)-1 for i in idx]) + np.array(ticks_to_skip)

for ax in fig.axes:
for ax in [rawdata_axes, contrast_axes]:
sns.despine(ax=ax, bottom=True)

ylim = ax.get_ylim()
xlim = ax.get_xlim()
redraw_axes_kwargs['y'] = ylim[0]

for k, start_tick in enumerate(ticks_to_skip):
end_tick = rightend_ticks[k]
ax.hlines(xmin=start_tick, xmax=end_tick,
**redraw_axes_kwargs)

ax.set_ylim(ylim)
del redraw_axes_kwargs['y']

Expand Down
7 changes: 6 additions & 1 deletion dabest/pytest.ini
@@ -1,4 +1,9 @@
[pytest]
filterwarnings =
ignore::UserWarning
ignore::DeprecationWarning
ignore::DeprecationWarning

addopts = --mpl --mpl-baseline-path=dabest/tests/baseline_images

markers =
mpl_image_compare: mark a test as implementing mpl image comparison.
3 changes: 1 addition & 2 deletions dabest/tests/README.md
@@ -1,9 +1,8 @@
# Testing

We use [pytest](https://docs.pytest.org/en/latest) to execute the tests. More documentation of the testing paradigm will be added in the near future.
We use [pytest](https://docs.pytest.org/en/latest) to execute the tests. For testing of plot generation, we use the [mpl plugin](https://github.com/matplotlib/pytest-mpl) for pytest. A range of different plots are created, and compared against the baseline images in the `baseline_images` subfolder.

To run the tests, go to the root of this repo directory and run

```shell
pytest dabest
```
Expand Down
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added dabest/tests/baseline_images/test_18_desat.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit efc0732

Please sign in to comment.