From 6fd5c886da277b572f470bd80e7755421ff16209 Mon Sep 17 00:00:00 2001
From: Fontrodona Nicolas <nicolas.fontrodona@ens-lyon.fr>
Date: Mon, 15 Mar 2021 18:17:05 +0100
Subject: [PATCH] src/gc_content/stat_annot.py: major pep8 modifications

---
 src/gc_content/stat_annot.py | 220 ++++++++++++++++++-----------------
 1 file changed, 114 insertions(+), 106 deletions(-)

diff --git a/src/gc_content/stat_annot.py b/src/gc_content/stat_annot.py
index 6223c48..4c45b2d 100644
--- a/src/gc_content/stat_annot.py
+++ b/src/gc_content/stat_annot.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python3
 
-# -*- coding;: utf-8 -*-
+# -*- coding: UTF-8 -*-
 
 """
 Description:
@@ -9,6 +9,7 @@ Description:
     github.com/webermarcolivier/statannot/blob/master/statannot/statannot.py.
 """
 
+
 import matplotlib.pyplot as plt
 from matplotlib import lines
 import matplotlib.transforms as mtransforms
@@ -19,196 +20,203 @@ from seaborn.utils import remove_na
 
 
 def add_stat_annotation(ax, data=None, x=None, y=None, hue=None, order=None,
-                        hue_order=None, boxPairList=None, loc='inside',
-                        useFixedOffset=False, lineYOffsetToBoxAxesCoord=None,
-                        lineYOffsetAxesCoord=None, lineHeightAxesCoord=0.02,
-                        textYOffsetPoints=1, color='0.2', linewidth=1.5,
-                        fontsize='medium', verbose=1):
+                        hue_order=None, box_pair_list=None, loc='inside',
+                        use_fixed_offset=False,
+                        liney_offset2box_axes_coord=None,
+                        liney_offset_axes_coord=None,
+                        line_height_axes_coord=0.02,
+                        text_y_offset_points=1, color='0.2', linewidth=1.5,
+                        fontsize='medium', verbose=1, min_pval = 1e-16):
     """
     User should use the same argument for the data, x, y, hue, order, \
     hue_order as the seaborn boxplot function.
-    boxPairList can be of either form:
+    box_pair_list can be of either form:
     boxplot: [(cat1, cat2, pval), (cat3, cat4, pval)]
     """
 
-    def find_x_position_box(boxPlotter, boxName):
+    def find_x_position_box(box_plotter, box_name):
         """
-        boxName can be either a name "cat" or a tuple ("cat", "hue")
+        box_name can be either a name "cat" or a tuple ("cat", "hue")
         """
-        if boxPlotter.plot_hues is None:
-            cat = boxName
-            hueOffset = 0
+        if box_plotter.plot_hues is None:
+            cat = box_name
+            hue_offset = 0
         else:
-            cat = boxName[0]
-            hue = boxName[1]
-            hueOffset = boxPlotter.hue_offsets[
-                boxPlotter.hue_names.index(hue)]
+            cat = box_name[0]
+            chue = box_name[1]
+            hue_offset = box_plotter.hue_offsets[
+                box_plotter.hue_names.index(chue)]
 
-        groupPos = boxPlotter.group_names.index(cat)
-        boxPos = groupPos + hueOffset
-        return boxPos
+        group_pos = box_plotter.group_names.index(cat)
+        box_pos = group_pos + hue_offset
+        return box_pos
 
-    def get_box_data(boxPlotter, boxName):
+    def get_box_data(cbox_plotter, box_name):
         """
-        boxName can be either a name "cat" or a tuple ("cat", "hue")
+        box_name can be either a name "cat" or a tuple ("cat", "hue")
         Here we really have to duplicate seaborn code, because there is not
         direct access to the
         box_data in the BoxPlotter class.
         """
-        cat = boxName
-        if boxPlotter.plot_hues is None:
+        cat = box_name
+        if cbox_plotter.plot_hues is None:
             box_max_l = []
-            for cat in boxPlotter.group_names:
-                i = boxPlotter.group_names.index(cat)
-                group_data = boxPlotter.plot_data[i]
+            for cat in cbox_plotter.group_names:
+                i = cbox_plotter.group_names.index(cat)
+                group_data = cbox_plotter.plot_data[i]
                 box_data = remove_na(group_data)
-                box_max_l.append(np.max(box_data))
+                box_max_l.append(np.mean(box_data))
             return max(box_max_l)
         else:
-            i = boxPlotter.group_names.index(cat[0])
-            group_data = boxPlotter.plot_data[i]
+            i = cbox_plotter.group_names.index(cat[0])
+            group_data = cbox_plotter.plot_data[i]
             box_data = []
-            for hue in boxPlotter.hue_names:
-                hue_mask = boxPlotter.plot_hues[i] == hue
+            for chue in cbox_plotter.hue_names:
+                hue_mask = cbox_plotter.plot_hues[i] == chue
                 box_data.append(np.max(remove_na(group_data[hue_mask])))
             return max(box_data)
 
     fig = plt.gcf()
 
-    validList = ['inside', 'outside']
-    if loc not in validList:
+    valid_list = ['inside', 'outside']
+    if loc not in valid_list:
         raise ValueError(f"loc value should be one of the following: "
-                         f"{', '.join(validList)}.")
+                         f"{', '.join(valid_list)}.")
 
     # Create the same BoxPlotter object as seaborn's boxplot
-    boxPlotter = sns.categorical._BoxPlotter(x, y, hue, data, order, hue_order,
-                                             orient=None, width=.8, color=None,
-                                             palette=None, saturation=.75,
-                                             dodge=True, fliersize=5,
-                                             linewidth=None)
+    box_plotter = sns.categorical._BoxPlotter(x, y, hue, data, order,
+                                              hue_order, orient=None, width=.8,
+                                              color=None, palette=None,
+                                              saturation=.75, dodge=True,
+                                              fliersize=5, linewidth=None)
     ylim = ax.get_ylim()
-    yRange = ylim[1] - ylim[0]
+    y_range = ylim[1] - ylim[0]
 
-    if lineYOffsetAxesCoord is None:
+    if liney_offset_axes_coord is None:
         if loc == 'inside':
-            lineYOffsetAxesCoord = 0.005
-            if lineYOffsetToBoxAxesCoord is None:
-                lineYOffsetToBoxAxesCoord = 0.1
+            liney_offset_axes_coord = 0.005
+            if liney_offset2box_axes_coord is None:
+                liney_offset2box_axes_coord = 0.1
         elif loc == 'outside':
-            lineYOffsetAxesCoord = 0.03
-            lineYOffsetToBoxAxesCoord = lineYOffsetAxesCoord
+            liney_offset_axes_coord = 0.03
+            liney_offset2box_axes_coord = liney_offset_axes_coord
     else:
         if loc == 'inside':
-            if lineYOffsetToBoxAxesCoord is None:
-                lineYOffsetToBoxAxesCoord = 0.06
+            if liney_offset2box_axes_coord is None:
+                liney_offset2box_axes_coord = 0.06
         elif loc == 'outside':
-            lineYOffsetToBoxAxesCoord = lineYOffsetAxesCoord
-    yOffset = lineYOffsetAxesCoord * yRange
-    yOffsetToBox = lineYOffsetToBoxAxesCoord * yRange
+            liney_offset2box_axes_coord = liney_offset_axes_coord
+    y_offset = liney_offset_axes_coord * y_range
+    y_offset_to_box = liney_offset2box_axes_coord * y_range
 
-    yStack = []
-    annList = []
-    for box1, box2, pval in boxPairList:
+    y_stack = []
+    ann_list = []
+    max_val = []
+    for box1, box2, pval in box_pair_list:
 
-        groupNames = boxPlotter.group_names
+        group_names = box_plotter.group_names
         cat1 = box1
         cat2 = box2
         if isinstance(cat1, tuple):
-            hue_names = boxPlotter.hue_names
-            valid = cat1[0] in groupNames and cat2[0] in groupNames and \
-                    cat1[1] in hue_names and cat2[1] in hue_names
+            hue_names = box_plotter.hue_names
+            valid = cat1[0] in group_names and cat2[0] in group_names and \
+                cat1[1] in hue_names and cat2[1] in hue_names
         else:
-            valid = cat1 in groupNames and cat2 in groupNames
+            valid = cat1 in group_names and cat2 in group_names
 
         if valid:
             # Get position of boxes
-            x1 = find_x_position_box(boxPlotter, box1)
-            x2 = find_x_position_box(boxPlotter, box2)
-            box_data1 = get_box_data(boxPlotter, box1)
-            box_data2 = get_box_data(boxPlotter, box2)
+            x1 = find_x_position_box(box_plotter, box1)
+            x2 = find_x_position_box(box_plotter, box2)
+            box_data1 = get_box_data(box_plotter, box1)
+            box_data2 = get_box_data(box_plotter, box2)
             ymax1 = box_data1
             ymax2 = box_data2
 
             if pval > 1e-16:
                 text = "p = {:.2e}".format(pval)
             else:
-                text = "p < 1e-16"
+                text = f"p < {min_pval:.0e}"
 
             if loc == 'inside':
-                yRef = max(ymax1, ymax2)
+                y_ref = max(ymax1, ymax2)
             else:
-                yRef = ylim[1]
-            if len(yStack) > 0 and isinstance(box1, str):
-                yRef2 = max(yRef, max(yStack))
+                y_ref = ylim[1]
+
+            if len(y_stack) > 0:
+                y_ref2 = max(y_ref, max(y_stack))
             else:
-                yRef2 = yRef
+                y_ref2 = y_ref
 
-            if len(yStack) == 0 or not isinstance(box1, str):
-                y = yRef2 + yOffsetToBox
+            if len(y_stack) == 0:
+                y = y_ref2 + y_offset_to_box
             else:
-                y = yRef2 + yOffset
-            h = lineHeightAxesCoord * yRange
-            lineX, lineY = [x1, x1, x2, x2], [y, y + h, y + h, y]
+                y = y_ref2 + y_offset
+            h = line_height_axes_coord * y_range
+            line_x, line_y = [x1, x1, x2, x2], [y, y + h, y + h, y]
             if loc == 'inside':
-                ax.plot(lineX, lineY, lw=linewidth, c=color)
+                ax.plot(line_x, line_y, lw=linewidth, c=color)
             elif loc == 'outside':
-                line = lines.Line2D(lineX, lineY, lw=linewidth, c=color,
+                line = lines.Line2D(line_x, line_y, lw=linewidth, c=color,
                                     transform=ax.transData)
                 line.set_clip_on(False)
                 ax.add_line(line)
 
             if text is not None:
                 ann = ax.annotate(text, xy=(np.mean([x1, x2]), y + h),
-                                  xytext=(0, textYOffsetPoints),
+                                  xytext=(0, text_y_offset_points),
                                   textcoords='offset points',
                                   xycoords='data', ha='center', va='bottom',
-                                  fontsize=fontsize,
-                                  clip_on=False, annotation_clip=False)
-                annList.append(ann)
+                                  fontsize=fontsize, clip_on=False,
+                                  annotation_clip=False)
+                ann_list.append(ann)
 
-            new_max_ylim = 1.1 * (y + h)
+            new_max_ylim = 1.1*(y + h)
             if new_max_ylim > ylim[1]:
-                ax.set_ylim((ylim[0], 1.1 * (y + h)))
+                ax.set_ylim((ylim[0], 1.1*(y + h)))
 
             if text is not None:
                 plt.draw()
-                yTopAnnot = None
-                gotMatplotlibError = False
-                if not useFixedOffset:
+                y_top_annot = None
+                got_matplotlib_error = False
+                if not use_fixed_offset:
                     try:
                         bbox = ann.get_window_extent()
                         bbox_data = bbox.transformed(ax.transData.inverted())
-                        yTopAnnot = bbox_data.ymax
+                        y_top_annot = bbox_data.ymax
                     except RuntimeError:
-                        gotMatplotlibError = True
+                        got_matplotlib_error = True
 
-                if useFixedOffset or gotMatplotlibError:
+                if use_fixed_offset or got_matplotlib_error:
                     if verbose >= 1:
                         print("Warning: cannot get the text bounding box. "
                               "Falling back to a fixed y offset. Layout may "
                               "be not optimal.")
-                    # We will apply a fixed offset in points, based on the font size of the annotation.
-                    fontsizePoints = FontProperties(
-                        size='medium').get_size_in_points()
-                    offsetTrans = mtransforms.offset_copy(ax.transData,
-                                                          fig=fig,
-                                                          x=0,
-                                                          y=1.0 * fontsizePoints + textYOffsetPoints,
-                                                          units='points')
-                    yTopDisplay = offsetTrans.transform((0, y + h))
-                    yTopAnnot = ax.transData.inverted().transform(yTopDisplay)[
-                        1]
+                    #  We will apply a fixed offset in points,
+                    #  based on the font size of the annotation.
+                    fontsize_points = FontProperties(size='medium'
+                                                     ).get_size_in_points()
+                    offset_trans = mtransforms.offset_copy(
+                        ax.transData, fig=fig, x=0,
+                        y=1.0 * fontsize_points + text_y_offset_points,
+                        units='points')
+                    y_top_display = offset_trans.transform((0, y + h))
+                    y_top_annot = ax.transData.inverted().\
+                        transform(y_top_display)[1]
             else:
-                yTopAnnot = y + h
+                y_top_annot = y + h
 
-            yStack.append(yTopAnnot)
+            y_stack.append(y_top_annot)
+            max_val.append(max(y_stack))
+            if hue is not None and len(y_stack) == len(box_plotter.hue_names):
+                y_stack = []
         else:
-            raise ValueError("boxPairList contains an unvalid box pair.")
+            raise ValueError("box_pair_list contains an unvalid box pair.")
 
-    yStackMax = max(yStack)
+    y_stack_max = max(max_val + y_stack)
     if loc == 'inside':
-        if ylim[1] < 1.03 * yStackMax:
-            ax.set_ylim((ylim[0], 1.03 * yStackMax))
+        if ylim[1] < 1.03 * y_stack_max:
+            ax.set_ylim((ylim[0], 1.03 * y_stack_max))
     elif loc == 'outside':
         ax.set_ylim((ylim[0], ylim[1]))
-    return ax
+    return ax
\ No newline at end of file
-- 
GitLab