Skip to content
Merged
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
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
## v0.7
### v0.7.2
### Features
- Add option to capitalize "p" in annotations
(PR [#172](https://github.com/trevismd/statannotations/pull/172) by
[Pentabyteman](https://github.com/Pentabyteman))
- Add option to change spacing in annotations
(PR [#173](https://github.com/trevismd/statannotations/pull/173))

### v0.7.1
#### Fixes
- Fix minimum Python requirements in setup.py
Expand Down
4 changes: 2 additions & 2 deletions coverage.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
49 changes: 39 additions & 10 deletions statannotations/PValueFormat.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
from statannotations.stats.StatResult import StatResult
from typing import Tuple, Union

from statannotations.format_annotations import pval_annotation_text, \
simple_text
from statannotations.stats.StatResult import StatResult
from statannotations.utils import DEFAULT, check_valid_text_format, \
InvalidParametersError

CONFIGURABLE_PARAMETERS = [
'correction_format',
'fontsize',
'pvalue_format_string',
'simple_format_string',
'text_format',
'pvalue_format_string',
'pvalue_thresholds',
'p_capitalized',
'p_separators',
'show_test_name',
'p_capitalized'
]


Expand All @@ -40,6 +42,7 @@ def __init__(self):
self._correction_format = "{star} ({suffix})"
self.show_test_name = True
self.p_capitalized = False
self._p_separators = (" ", " ")

def config(self, **parameters):

Expand Down Expand Up @@ -69,6 +72,30 @@ def text_format(self, text_format):
check_valid_text_format(text_format)
self._text_format = text_format

@property
def p_separators(self):
return {
(" ", " "): 'both',
("", " "): 'after',
("", ""): 'none',
}.get(self._p_separators, self._p_separators)

@p_separators.setter
def p_separators(self, p_separators: Union[bool, str, Tuple[str]] = True):
"""
:param p_separators:
'both' (or True)(default), 'none' (or False), 'after',
or tuple[bool] for before and after
"""
if isinstance(p_separators, tuple):
self._p_separators = p_separators
elif p_separators in {'none', False}:
self._p_separators = ("", "")
elif p_separators == 'after':
self._p_separators = ("", " ")
else:
self._p_separators = (" ", " ")

def _get_pvalue_thresholds(self, pvalue_thresholds):
if self._default_pvalue_thresholds:
if self.text_format == "star":
Expand Down Expand Up @@ -179,10 +206,10 @@ def format_data(self, result):
else "")

p_letter = "P" if self.p_capitalized else "p"

return ("{}{} = {}{}"
.format('{}', p_letter, self.pvalue_format_string, '{}')
.format(text, result.pvalue, result.significance_suffix))
equals = f"{self._p_separators[0]}={self._p_separators[1]}"
formatted_pvalue = self.pvalue_format_string.format(result.pvalue)
full_pvalue = f"{formatted_pvalue}{result.significance_suffix}"
return f"{text}{p_letter}{equals}{full_pvalue}"

elif self.text_format == 'star':
was_list = False
Expand All @@ -200,10 +227,12 @@ def format_data(self, result):

return annotations[0]

# elif self.text_format == 'simple':
else:
return simple_text(result, self.simple_format_string,
self.pvalue_thresholds, self.show_test_name, self.p_capitalized)
return simple_text(
result, self.simple_format_string, self.pvalue_thresholds,
short_test_name=self.show_test_name,
p_capitalized=self.p_capitalized, separators=self._p_separators
)

def get_configuration(self):
return {key: getattr(self, key) for key in CONFIGURABLE_PARAMETERS}
Expand Down
2 changes: 1 addition & 1 deletion statannotations/_version.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "0.7.1"
__version__ = "0.7.2"
24 changes: 16 additions & 8 deletions statannotations/format_annotations.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
from statannotations.stats.StatResult import StatResult
from typing import List
from operator import itemgetter
from typing import List, Tuple

import numpy as np
import pandas as pd
from operator import itemgetter

from statannotations.stats.StatResult import StatResult


def pval_annotation_text(result: List[StatResult],
Expand Down Expand Up @@ -32,32 +34,38 @@ def pval_annotation_text(result: List[StatResult],
return [(star, res) for star, res in zip(x_annot, result)]


def simple_text(result: StatResult, pvalue_format, pvalue_thresholds,
short_test_name=True, p_capitalized=False) -> str:
def simple_text(result: StatResult, pvalue_format: str,
pvalue_thresholds: List[list],
short_test_name: bool = True, p_capitalized: bool = False,
separators: Tuple[str] = (" ", " ")) -> str:
"""
Generates simple text for test name and pvalue.

:param result: StatResult instance
:param pvalue_format: format string for pvalue
:param pvalue_thresholds: String to display per pvalue range
:param short_test_name: whether to display the test (short) name
:param p_capitalized: set True to show "P" instead of "p" in annotations
:param separators: separators for before and after '=' or '≤'
:returns: simple annotation

"""
# Sort thresholds
thresholds = sorted(pvalue_thresholds, key=lambda x: x[0])

text = (f"{result.test_short_name} "
if short_test_name and result.test_short_name
else "")

p_letter = "P" if p_capitalized else "p"
p_equals = f"{p_letter}{separators[0]}={separators[1]}"
p_lte = f"{p_letter}{separators[0]}≤{separators[1]}"

for threshold in thresholds:
if result.pvalue < threshold[0]:
pval_text = "{} ≤ {}".format(p_letter, threshold[1])
pval_text = f"{p_lte}{threshold[1]}"
break
else:
pval_text = "{} = {}".format(p_letter, pvalue_format).format(result.pvalue)
formatted_pvalue = pvalue_format.format(result.pvalue)
pval_text = f"{p_equals}{formatted_pvalue}"

return result.adjust(text + pval_text)
76 changes: 58 additions & 18 deletions tests/test_pvalue_format.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,22 +111,26 @@ def test_print_pvalue_other(self):

def test_get_configuration(self):
pvalue_format = PValueFormat()
self.assertDictEqual(pvalue_format.get_configuration(),
{'correction_format': '{star} ({suffix})',
'fontsize': 'medium',
'p_capitalized': False,
'pvalue_format_string': '{:.3e}',
'show_test_name': True,
'simple_format_string': '{:.2f}',
'text_format': 'star',
'pvalue_thresholds': [
[1e-4, "****"],
[1e-3, "***"],
[1e-2, "**"],
[0.05, "*"],
[1, "ns"]]
}
)
self.assertDictEqual(
pvalue_format.get_configuration(),
{
'correction_format': '{star} ({suffix})',
'fontsize': 'medium',
'p_capitalized': False,
'p_separators': 'both',
'pvalue_format_string': '{:.3e}',
'pvalue_thresholds': [
[1e-4, "****"],
[1e-3, "***"],
[1e-2, "**"],
[0.05, "*"],
[1, "ns"]
],
'show_test_name': True,
'simple_format_string': '{:.2f}',
'text_format': 'star',
}
)

def test_config_pvalue_thresholds(self):
pvalue_format = PValueFormat()
Expand All @@ -138,7 +142,7 @@ def test_config_pvalue_thresholds(self):
" ns: 5.00e-02 < p <= 1.00e+00\n"
" <= 0.05: 1.00e-03 < p <= 5.00e-02\n"
"<= 0.001: p <= 1.00e-03\n\n")

def test_pvalue_simple_capitalized(self):
self.annotator.configure(pvalue_format={"text_format": "simple",
"p_capitalized": True})
Expand All @@ -153,4 +157,40 @@ def test_pvalue_full_capitalized(self):
"pvalue_format_string": "{:.2f}"})
annotations = self.annotator._get_results("auto", pvalues=self.pvalues)
self.assertEqual(["P = 0.04", "P = 0.03", "P = 0.90"],
[annotation.text for annotation in annotations])
[annotation.text for annotation in annotations])

def test_pvalue_simple_separators(self):
self.annotator.configure(pvalue_format={"text_format": "simple"})
for separator, expected_results in [
(None, ["p ≤ 0.05", "p ≤ 0.05", "p = 0.90"]),
(True, ["p ≤ 0.05", "p ≤ 0.05", "p = 0.90"]),
('both', ["p ≤ 0.05", "p ≤ 0.05", "p = 0.90"]),
('none', ["p≤0.05", "p≤0.05", "p=0.90"]),
('after', ["p≤ 0.05", "p≤ 0.05", "p= 0.90"]),
]:
with self.subTest(separator=separator):
config = {"pvalue_format": {"p_separators": separator}}
self.annotator.configure(**config)
annotations = self.annotator._get_results("auto", pvalues=self.pvalues)
self.assertEqual(expected_results, [a.text for a in annotations])

def test_pvalue_full_separators(self):
self.annotator.configure(
pvalue_format={
"text_format": "full",
"show_test_name": False,
"pvalue_format_string": "{:.2f}"
},
)
for separator, expected_results in [
(None, ["p = 0.04", "p = 0.03", "p = 0.90"]),
(True, ["p = 0.04", "p = 0.03", "p = 0.90"]),
('both', ["p = 0.04", "p = 0.03", "p = 0.90"]),
('none', ["p=0.04", "p=0.03", "p=0.90"]),
('after', ["p= 0.04", "p= 0.03", "p= 0.90"]),
]:
with self.subTest(separator=separator):
config = {"pvalue_format": {"p_separators": separator}}
self.annotator.configure(**config)
annotations = self.annotator._get_results("auto", pvalues=self.pvalues)
self.assertEqual(expected_results, [a.text for a in annotations])