Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update 07-forest_plot.ipynb #175

Draft
wants to merge 11 commits into
base: vnbdev
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
26 changes: 21 additions & 5 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,29 @@

<!-- do not remove -->

## 2023.03.29
## v2024.03.29

### New Features
- Add new form of paired proportion plots for a better support of Repeated Measures

- **Standardized Delta-delta Effect Size**: We added a new metric akin to a Hedges’ g for delta-delta effect size, which allows comparisons between delta-delta effects generated from metrics with different units.

## 0.2.3
- **New Paired Proportion Plot**: This feature builds upon the existing proportional analysis capabilities by introducing advanced aesthetics and clearer visualization of changes in proportions between different groups, inspired by the informative nature of Sankey Diagrams. It's particularly useful for studies that require detailed examination of how proportions shift in paired observations.

### Bug Fixes
- Fixes a bug that jammed up when the xvar column was already a pandas Categorical. Now we check for this and act appropriately.
- **Customizable Swarm Plot**: Enhancements allow for tailored swarm plot aesthetics, notably the adjustment of swarm sides to produce asymmetric swarm plots. This customization enhances data representation, making visual distinctions more pronounced and interpretations clearer.

### Enhancement

- **Miscellaneous Improvements**: This version also encompasses a broad range of miscellaneous enhancements, including bug fixes, Bootstrapping speed improvements, new templates for raising issues, and updated unit tests. These improvements are designed to streamline the user experience, increase the software's stability, and expand its versatility. By addressing user feedback and identified issues, DABEST continues to refine its functionality and reliability.



## v2023.03.29

### New Features
- **Repeated measures**: Augments the prior function for plotting (independent) multiple test groups versus a shared control; it can now do the same for repeated-measures experimental designs. Thus, together, these two methods can be used to replace both flavors of the 1-way ANOVA with an estimation analysis.

- **Proportional data**: Generates proportional bar plots, proportional differences, and calculates Cohen’s h. Also enables plotting Sankey diagrams for paired binary data. This is the estimation equivalent to a bar chart with Fischer’s exact test.

- **The ∆∆ plot**: Calculates the delta-delta (∆∆) for 2 × 2 experimental designs and plots the four groups with their relevant effect sizes. This design can be used as a replacement for the 2 × 2 ANOVA.

- **Mini-meta**: Calculates and plots a weighted delta (∆) for meta-analysis of experimental replicates. Useful for summarizing data from multiple replicated experiments, for example by different scientists in the same lab, or the same scientist at different times. When the observed values are known (and share a common metric), this makes meta-analysis available as a routinely accessible tool.
85 changes: 46 additions & 39 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,34 +2,48 @@

<!-- WARNING: THIS FILE WAS AUTOGENERATED! DO NOT EDIT! -->

[![minimal Python
version](https://img.shields.io/badge/Python%3E%3D-3.8-6666ff.svg)](https://www.anaconda.com/distribution/)
[![PyPI
version](https://badge.fury.io/py/dabest.svg)](https://badge.fury.io/py/dabest)
[![Downloads](https://img.shields.io/pepy/dt/dabest.svg)](https://pepy.tech/project/dabest)
[![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)

## Recent Version Update

On 20 March 2023, we officially released **DABEST v2023.02.14 for
Python**. This new version provided the following new features:

1. **Repeated measures.** Augments the prior function for plotting
(independent) multiple test groups versus a shared control; it can
now do the same for repeated-measures experimental designs. Thus,
together, these two methods can be used to replace both flavors of
the 1-way ANOVA with an estimation analysis.

2. **Proportional data.** Generates proportional bar plots,
proportional differences, and calculates Cohen’s h. Also enables
plotting Sankey diagrams for paired binary data. This is the
estimation equivalent to a bar chart with Fisher’s exact test.

3. **The $\Delta\Delta$ plot.** Calculates the delta-delta
($\Delta\Delta$) for 2 × 2 experimental designs and plots the four
groups with their relevant effect sizes. This design can be used as
a replacement for the 2 × 2 ANOVA.

4. **Mini-meta.** Calculates and plots a weighted delta ($\Delta$) for
meta-analysis of experimental replicates. Useful for summarizing
data from multiple replicated experiments, for example by different
scientists in the same lab, or the same scientist at different
times. When the observed values are known (and share a common
metric), this makes meta-analysis available as a routinely
accessible tool.
We are proud to announce **DABEST Version Ondeh (v2024.03.29)**. This
new version of the DABEST Python library provides several new features
and includes performance improvements.

1. **New Paired Proportion Plot**: This feature builds upon the
existing proportional analysis capabilities by introducing advanced
aesthetics and clearer visualization of changes in proportions
between different groups, inspired by the informative nature of
Sankey Diagrams. It’s particularly useful for studies that require
detailed examination of how proportions shift in paired
observations.

2. **Customizable Swarm Plot**: Enhancements allow for tailored swarm
plot aesthetics, notably the adjustment of swarm sides to produce
asymmetric swarm plots. This customization enhances data
representation, making visual distinctions more pronounced and
interpretations clearer.

3. **Standardized Delta-delta Effect Size**: We added a new metric akin
to a Hedges’ g for delta-delta effect size, which allows comparisons
between delta-delta effects generated from metrics with different
units.

4. **Miscellaneous Improvements**: This version also encompasses a
broad range of miscellaneous enhancements, including bug fixes,
Bootstrapping speed improvements, new templates for raising issues,
and updated unit tests. These improvements are designed to
streamline the user experience, increase the software’s stability,
and expand its versatility. By addressing user feedback and
identified issues, DABEST continues to refine its functionality and
reliability.

## Contents

Expand Down Expand Up @@ -77,7 +91,7 @@ allowing everyone access to high-quality estimation plots.

## Installation

This package is tested on Python 3.6, 3.7, 3.8 and 3.10. It is highly
This package is tested on Python 3.8 and onwards. It is highly
recommended to download the [Anaconda
distribution](https://www.continuum.io/downloads) of Python in order to
obtain the dependencies easily.
Expand All @@ -86,13 +100,6 @@ You can install this package via `pip`.

To install, at the command line run

``` shell
conda config --add channels conda-forge
conda install dabest
```

or –\>

``` shell
pip install dabest
```
Expand Down Expand Up @@ -128,8 +135,8 @@ iris_dabest.mean_diff.plot();
dataset](iris.png)

Please refer to the official
[tutorial](https://acclab.github.io/DABEST-python-docs/tutorial.html)
for more useful code snippets.
[tutorial](https://acclab.github.io/DABEST-python/) for more useful code
snippets.

## How to cite

Expand All @@ -147,8 +154,8 @@ PDF](https://rdcu.be/bHhJ4)

## Bugs

Please report any bugs on the [Github issue
tracker](https://github.com/ACCLAB/DABEST-python/issues/new).
Please report any bugs on the [issue
page](https://github.com/ACCLAB/DABEST-python/issues/new).

## Contributing

Expand Down Expand Up @@ -184,7 +191,7 @@ To test DABEST, you need to install
- Run `pytest` in the root directory of the source distribution. This
runs the test suite in the folder `dabest/tests/mpl_image_tests`.
- Run `nbdev_test` in the root directory of the source distribution.
This runs the value assertion tests in parent folder `dabest/tests`
This runs the value assertion tests in the folder `dabest/tests`

The test suite ensures that the bootstrapping functions and the plotting
functions perform as expected.
Expand Down
2 changes: 1 addition & 1 deletion dabest/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@
from ._effsize_objects import TwoGroupsEffectSize, PermutationTest
from ._dabest_object import Dabest

__version__ = "2023.03.29"
__version__ = "2024.03.29"
4 changes: 3 additions & 1 deletion dabest/_modidx.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,9 @@
'dabest.forest_plot': { 'dabest.forest_plot.extract_plot_data': ( 'API/forest_plot.html#extract_plot_data',
'dabest/forest_plot.py'),
'dabest.forest_plot.forest_plot': ('API/forest_plot.html#forest_plot', 'dabest/forest_plot.py'),
'dabest.forest_plot.load_plot_data': ('API/forest_plot.html#load_plot_data', 'dabest/forest_plot.py')},
'dabest.forest_plot.load_plot_data': ('API/forest_plot.html#load_plot_data', 'dabest/forest_plot.py'),
'dabest.forest_plot.map_effect_attribute': ( 'API/forest_plot.html#map_effect_attribute',
'dabest/forest_plot.py')},
'dabest.misc_tools': { 'dabest.misc_tools.get_varname': ('API/misc_tools.html#get_varname', 'dabest/misc_tools.py'),
'dabest.misc_tools.merge_two_dicts': ('API/misc_tools.html#merge_two_dicts', 'dabest/misc_tools.py'),
'dabest.misc_tools.print_greeting': ('API/misc_tools.html#print_greeting', 'dabest/misc_tools.py'),
Expand Down
81 changes: 52 additions & 29 deletions dabest/forest_plot.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/API/forest_plot.ipynb.

# %% auto 0
__all__ = ['load_plot_data', 'extract_plot_data', 'forest_plot']
__all__ = ['load_plot_data', 'extract_plot_data', 'map_effect_attribute', 'forest_plot']

# %% ../nbs/API/forest_plot.ipynb 5
import matplotlib.pyplot as plt
Expand Down Expand Up @@ -72,28 +72,42 @@ def extract_plot_data(contrast_plot_data, contrast_type):

return bootstraps, differences, bcalows, bcahighs

def map_effect_attribute(attribute_key):
# Check if the attribute key exists in the dictionary
effect_attr_map = {
"mean_diff": "Mean Difference",
"median_diff": "Median Difference",
"cliffs_delta": "Cliffs Delta",
"cohens_d": "Cohens d",
"hedges_g": "Hedges g",
"delta_g": "Delta g"
}
if attribute_key in effect_attr_map:
return effect_attr_map[attribute_key]
else:
raise TypeError("The `effect_size` argument must be a string. Please choose from the following effect sizes: `mean_diff`,`median_diff`,`cliffs_delta`,`cohens_d``, and `hedges_g`.") # Return a default value or message if the key is not found

def forest_plot(
contrasts: List,
selected_indices: Optional[List] = None,
contrast_type: str = "delta2",
xticklabels: Optional[List] = None,
effect_size: str = "mean_diff",
contrast_labels: List[str] = None,
ylabel: str = "value",
ylabel: str = "effect size",
plot_elements_to_extract: Optional[List] = None,
title: str = "ΔΔ Forest",
custom_palette: Optional[Union[dict, list, str]] = None,
fontsize: int = 20,
fontsize: int = 12,
title_font_size: int =16,
violin_kwargs: Optional[dict] = None,
marker_size: int = 20,
ci_line_width: float = 2.5,
zero_line_width: int = 1,
desat_violin: float = 1,
remove_spines: bool = True,
ax: Optional[plt.Axes] = None,
additional_plotting_kwargs: Optional[dict] = None,
rotation_for_xlabels: int = 45,
alpha_violin_plot: float = 0.4,
alpha_violin_plot: float = 0.8,
horizontal: bool = False # New argument for horizontal orientation
)-> plt.Figure:
"""
Expand All @@ -106,11 +120,9 @@ def forest_plot(
selected_indices : Optional[List], default=None
Indices of specific contrasts to plot, if not plotting all.
analysis_type : str
the type of analysis (e.g., 'delta2', 'minimeta').
xticklabels : Optional[List], default=None
Custom labels for the x-axis ticks.
the type of analysis (e.g., 'delta2', 'mini_meta').
effect_size : str
Type of effect size to plot (e.g., 'mean_diff', 'median_diff').
Type of effect size to plot (e.g., 'mean_diff', 'median_diff', `cliffs_delta`,`cohens_d``, and `hedges_g`).
contrast_labels : List[str]
Labels for each contrast.
ylabel : str
Expand All @@ -125,14 +137,14 @@ def forest_plot(
Custom color palette for the plot.
fontsize : int
Font size for text elements in the plot.
title_font_size: int =16
Font size for text of plot title.
violin_kwargs : Optional[dict], default=None
Additional arguments for violin plot customization.
marker_size : int
Marker size for plotting mean differences or effect sizes.
ci_line_width : float
Width of confidence interval lines.
zero_line_width : int
Width of the line indicating zero effect size.
remove_spines : bool, default=False
If True, removes top and right plot spines.
ax : Optional[plt.Axes], default=None
Expand Down Expand Up @@ -161,14 +173,13 @@ def forest_plot(
if selected_indices is not None and not isinstance(selected_indices, (list, type(None))):
raise TypeError("The `selected_indices` must be a list of integers or `None`.")

# For the 'contrast_type' parameter
if not isinstance(contrast_type, str):
raise TypeError("The `contrast_type` argument must be a string.")

if xticklabels is not None and not all(isinstance(label, str) for label in xticklabels):
raise TypeError("The `xticklabels` must be a list of strings or `None`.")

raise TypeError("The `contrast_type` argument must be a string. Please choose from `delta2` and `mini_meta`.")

# For the 'effect_size' parameter
if not isinstance(effect_size, str):
raise TypeError("The `effect_size` argument must be a string.")
raise TypeError("The `effect_size` argument must be a string. Please choose from the following effect sizes: `mean_diff`, `median_diff`, `cliffs_delta`, `cohens_d`, and `hedges_g`.")

if contrast_labels is not None and not all(isinstance(label, str) for label in contrast_labels):
raise TypeError("The `contrast_labels` must be a list of strings or `None`.")
Expand All @@ -191,9 +202,6 @@ def forest_plot(
if not isinstance(ci_line_width, (int, float)) or ci_line_width <= 0:
raise TypeError("`ci_line_width` must be a positive integer or float.")

if not isinstance(zero_line_width, (int, float)) or zero_line_width <= 0:
raise TypeError("`zero_line_width` must be a positive integer or float.")

if not isinstance(remove_spines, bool):
raise TypeError("`remove_spines` must be a boolean value.")

Expand All @@ -209,6 +217,8 @@ def forest_plot(
if not isinstance(horizontal, bool):
raise TypeError("`horizontal` must be a boolean value.")

if (effect_size and isinstance(effect_size, str)):
ylabel = map_effect_attribute(effect_size)
# Load plot data
contrast_plot_data = load_plot_data(contrasts, effect_size, contrast_type)

Expand Down Expand Up @@ -250,7 +260,7 @@ def forest_plot(
if custom_palette:
if isinstance(custom_palette, dict):
violin_colors = [
custom_palette.get(c, sns.color_palette()[0]) for c in contrasts
custom_palette.get(c, sns.color_palette()[0]) for c in contrast_labels
]
elif isinstance(custom_palette, list):
violin_colors = custom_palette[: len(contrasts)]
Expand All @@ -262,12 +272,18 @@ def forest_plot(
f"The specified `custom_palette` {custom_palette} is not a recognized Matplotlib palette."
)
else:
violin_colors = sns.color_palette()[: len(contrasts)]
violin_colors = sns.color_palette(n_colors=len(contrasts))

violin_colors = [sns.desaturate(color, desat_violin) for color in violin_colors]

for patch, color in zip(v["bodies"], violin_colors):
patch.set_facecolor(color)
patch.set_alpha(alpha_violin_plot)

if horizontal:
ax.plot([0, 0], [0, len(contrasts)+1], 'k', linewidth = 1)
else:
ax.plot([0, len(contrasts)+1], [0, 0], 'k', linewidth = 1)

# Flipping the axes for plotting based on 'horizontal'
for k in range(1, len(contrasts) + 1):
if horizontal:
Expand All @@ -280,19 +296,26 @@ def forest_plot(
# Adjusting labels, ticks, and limits based on 'horizontal'
if horizontal:
ax.set_yticks(range(1, len(contrasts) + 1))
ax.set_yticklabels(contrast_labels, rotation=rotation_for_xlabels, fontsize=fontsize)
ax.set_yticklabels(contrast_labels, rotation=0, fontsize=fontsize)
ax.set_xlabel(ylabel, fontsize=fontsize)
ax.set_ylim([0.7, len(contrasts) + 0.5])
else:
ax.set_xticks(range(1, len(contrasts) + 1))
ax.set_xticklabels(contrast_labels, rotation=rotation_for_xlabels, fontsize=fontsize)
ax.set_ylabel(ylabel, fontsize=fontsize)
ax.set_xlim([0.7, len(contrasts) + 0.5])

# Setting the title and adjusting spines as before
ax.set_title(title, fontsize=fontsize)
ax.set_title(title, fontsize=title_font_size)
if remove_spines:
for spine in ax.spines.values():
spine.set_visible(False)

if horizontal:
ax.spines['left'].set_visible(False)
ax.spines['right'].set_visible(False)
ax.spines['top'].set_visible(False)
else:
ax.spines['top'].set_visible(False)
ax.spines['bottom'].set_visible(False)
ax.spines['right'].set_visible(False)
# Apply additional customizations if provided
if additional_plotting_kwargs:
ax.set(**additional_plotting_kwargs)
Expand Down