diff --git a/__pycache__/live_wire.cpython-312.pyc b/__pycache__/live_wire.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..8404b8c9798df68288011af419140c3a717972bb
Binary files /dev/null and b/__pycache__/live_wire.cpython-312.pyc differ
diff --git a/data/AgamodonSlice.png b/data/AgamodonSlice.png
new file mode 100644
index 0000000000000000000000000000000000000000..b8d0db7cc7dc30c9c26d15ad9e2f43466e273097
Binary files /dev/null and b/data/AgamodonSlice.png differ
diff --git a/data/AngustifronsSlice35.png b/data/AngustifronsSlice35.png
new file mode 100644
index 0000000000000000000000000000000000000000..17cadf804cd3af6d626674f06419108cf792f7f1
Binary files /dev/null and b/data/AngustifronsSlice35.png differ
diff --git a/data/BipesSlice4.png b/data/BipesSlice4.png
new file mode 100644
index 0000000000000000000000000000000000000000..6d17dc3048990d94b3f195b693a1b112e7eb3a5e
Binary files /dev/null and b/data/BipesSlice4.png differ
diff --git a/data/BipesSlice4NoCropping.png b/data/BipesSlice4NoCropping.png
new file mode 100644
index 0000000000000000000000000000000000000000..42c1bf536eecb3458f1221869415059a4a6e9bc3
Binary files /dev/null and b/data/BipesSlice4NoCropping.png differ
diff --git a/modules/find_path.py b/modules/find_path.py
index 426563ddd4843ab49ab9c08f8424cbd21508d864..4ae9c7fa5afc77a9a29cf214956f55fbfd225fc7 100644
--- a/modules/find_path.py
+++ b/modules/find_path.py
@@ -1,17 +1,30 @@
 from skimage.graph import route_through_array
 
-def find_path(cost_image, points):
+def find_path(cost_image: "numpy.ndarray", points: list) -> list:
+    """
+    Find the optimal path through a cost image between two points.
 
+    Parameters:
+    cost_image (numpy.ndarray): A 2D array representing the cost of traversing each pixel.
+    points (list): A list containing two tuples, each representing the 
+    (row, column) coordinates of the seed and target points.
+
+    Returns:
+    list: A list of (row, column) tuples representing the path from the seed to the target point.
+    
+    Raises:
+    ValueError: If the points list does not contain exactly two points.
+    """
     if len(points) != 2:
         raise ValueError("Points should be a list of 2 points: seed and target.")
     
     seed_rc, target_rc = points
 
     path_rc, cost = route_through_array(
-        cost_image, 
-        start=seed_rc, 
-        end=target_rc, 
+        cost_image,
+        start=seed_rc,
+        end=target_rc,
         fully_connected=True
     )
 
-    return path_rc
\ No newline at end of file
+    return path_rc
diff --git a/modules/imageGraphicsView.py b/modules/imageGraphicsView.py
index c2c984755352faf36f90645adf1a771e9d306d6c..1855d717866a601eafe886b0e311da772f9322da 100644
--- a/modules/imageGraphicsView.py
+++ b/modules/imageGraphicsView.py
@@ -1,8 +1,8 @@
+import math
 from scipy.signal import savgol_filter
 from PyQt5.QtWidgets import QGraphicsScene, QGraphicsPixmapItem
 from PyQt5.QtGui import QPixmap, QColor
-from PyQt5.QtCore import Qt, QRectF
-import math
+from PyQt5.QtCore import Qt, QRectF, QPoint
 import numpy as np
 from panZoomGraphicsView import PanZoomGraphicsView
 from labeledPointItem import LabeledPointItem
@@ -10,6 +10,14 @@ from find_path import find_path
 
 
 class ImageGraphicsView(PanZoomGraphicsView):
+    """
+    A custom QGraphicsView for displaying and interacting with an image.
+
+    This class extends PanZoomGraphicsView to provide additional functionality
+    for loading images, adding labeled anchor points, and computing paths
+    between points based on a cost image.
+    """
+
     def __init__(self, parent=None):
         super().__init__(parent)
         self.scene = QGraphicsScene(self)
@@ -19,10 +27,10 @@ class ImageGraphicsView(PanZoomGraphicsView):
         self.image_item = QGraphicsPixmapItem()
         self.scene.addItem(self.image_item)
 
-        self.anchor_points = []    # List[(x, y)]
-        self.point_items = []      # LabeledPointItem
-        self.full_path_points = [] # QGraphicsEllipseItems for path
-        self._full_path_xy = []    # entire path coords (smoothed)
+        self.anchor_points = []
+        self.point_items = []
+        self.full_path_points = []
+        self._full_path_xy = []
 
         self.dot_radius = 4
         self.path_radius = 1
@@ -49,16 +57,18 @@ class ImageGraphicsView(PanZoomGraphicsView):
         self._savgol_window_length = 7
 
     def set_rainbow_enabled(self, enabled: bool):
+        """Enable rainbow coloring of the path."""
         self._rainbow_enabled = enabled
         self._rebuild_full_path()
 
     def toggle_rainbow(self):
+        """Toggle rainbow coloring of the path."""
         self._rainbow_enabled = not self._rainbow_enabled
         self._rebuild_full_path()
 
     def set_savgol_window_length(self, wlen: int):
-        if wlen < 3:
-            wlen = 3
+        """Set the window length for Savitzky-Golay smoothing."""
+        wlen = max(3, wlen)
         if wlen % 2 == 0:
             wlen += 1
         self._savgol_window_length = wlen
@@ -68,7 +78,8 @@ class ImageGraphicsView(PanZoomGraphicsView):
     # --------------------------------------------------------------------
     # LOADING
     # --------------------------------------------------------------------
-    def load_image(self, path):
+    def load_image(self, path: str):
+        """Load an image from a file path."""
         pixmap = QPixmap(path)
         if not pixmap.isNull():
             self.image_item.setPixmap(pixmap)
@@ -90,7 +101,9 @@ class ImageGraphicsView(PanZoomGraphicsView):
     # --------------------------------------------------------------------
     # ANCHOR POINTS
     # --------------------------------------------------------------------
-    def _insert_anchor_point(self, idx, x, y, label="", removable=True, z_val=0, radius=4):
+    def _insert_anchor_point(self, idx, x: float, y: float, label="", removable=True,
+                             z_val=0, radius=4):
+        """Insert an anchor point at a specific index."""
         x_clamped = self._clamp(x, radius, self._img_w - radius)
         y_clamped = self._clamp(y, radius, self._img_h - radius)
 
@@ -110,7 +123,7 @@ class ImageGraphicsView(PanZoomGraphicsView):
         self.scene.addItem(item)
 
     def _add_guide_point(self, x, y):
-        # Ensure we clamp properly
+        """Add a guide point to the path."""
         x_clamped = self._clamp(x, self.dot_radius, self._img_w - self.dot_radius)
         y_clamped = self._clamp(y, self.dot_radius, self._img_h - self.dot_radius)
 
@@ -125,7 +138,8 @@ class ImageGraphicsView(PanZoomGraphicsView):
         self._apply_all_guide_points_to_cost()
         self._rebuild_full_path()
 
-    def _insert_anchor_between_subpath(self, x_new, y_new):
+    def _insert_anchor_between_subpath(self, x_new: float, y_new: float ):
+        """Insert an anchor point between existing anchor points."""
         # If somehow we have no path yet
         if not self._full_path_xy:
             self._insert_anchor_point(-1, x_new, y_new)
@@ -147,9 +161,11 @@ class ImageGraphicsView(PanZoomGraphicsView):
             return
 
         def approx_equal(xa, ya, xb, yb, tol=1e-3):
+            """Check if two points are approximately equal."""
             return (abs(xa - xb) < tol) and (abs(ya - yb) < tol)
 
         def is_anchor(coord):
+            """Check if a point is an anchor point."""
             cx, cy = coord
             for (ax, ay) in self.anchor_points:
                 if approx_equal(ax, ay, cx, cy):
@@ -158,23 +174,23 @@ class ImageGraphicsView(PanZoomGraphicsView):
 
         # Walk left
         left_anchor_pt = None
-        iL = best_idx
-        while iL >= 0:
-            px, py = self._full_path_xy[iL]
+        i_l = best_idx
+        while i_l >= 0:
+            px, py = self._full_path_xy[i_l]
             if is_anchor((px, py)):
                 left_anchor_pt = (px, py)
                 break
-            iL -= 1
+            i_l -= 1
 
         # Walk right
         right_anchor_pt = None
-        iR = best_idx
-        while iR < len(self._full_path_xy):
-            px, py = self._full_path_xy[iR]
+        i_r = best_idx
+        while i_r < len(self._full_path_xy):
+            px, py = self._full_path_xy[i_r]
             if is_anchor((px, py)):
                 right_anchor_pt = (px, py)
                 break
-            iR += 1
+            i_r += 1
 
         # If we can't find distinct anchors on left & right,
         # just insert before E.
@@ -221,7 +237,8 @@ class ImageGraphicsView(PanZoomGraphicsView):
             if self.point_items[i].is_removable():
                 self._lower_cost_in_circle(ax, ay, self.radius_cost_image)
 
-    def _lower_cost_in_circle(self, x_f, y_f, radius):
+    def _lower_cost_in_circle(self, x_f: float, y_f: float, radius: int):
+        """Lower the cost in a circle centered at (x_f, y_f)."""
         if self.cost_image is None:
             return
         h, w = self.cost_image.shape
@@ -244,6 +261,7 @@ class ImageGraphicsView(PanZoomGraphicsView):
     # PATH BUILDING
     # --------------------------------------------------------------------
     def _rebuild_full_path(self):
+        """Rebuild the full path based on the anchor points."""
         for item in self.full_path_points:
             self.scene.removeItem(item)
         self.full_path_points.clear()
@@ -295,7 +313,8 @@ class ImageGraphicsView(PanZoomGraphicsView):
             if p_item._text_item:
                 p_item.setZValue(100)
 
-    def _compute_subpath_xy(self, xA, yA, xB, yB):
+    def _compute_subpath_xy(self, xA: float, yA: float, xB: float, yB: float):
+        """Compute a subpath between two points."""
         if self.cost_image is None:
             return []
         h, w = self.cost_image.shape
@@ -313,7 +332,8 @@ class ImageGraphicsView(PanZoomGraphicsView):
         # Convert from (row, col) to (x, y)
         return [(c, r) for (r, c) in path_rc]
 
-    def _rainbow_color(self, fraction):
+    def _rainbow_color(self, fraction: float):
+        """Get a rainbow color."""
         hue = int(300 * fraction)
         saturation = 255
         value = 255
@@ -322,7 +342,8 @@ class ImageGraphicsView(PanZoomGraphicsView):
     # --------------------------------------------------------------------
     # MOUSE EVENTS
     # --------------------------------------------------------------------
-    def mousePressEvent(self, event):
+    def mouse_press_event(self, event):
+        """Handle mouse press events for dragging a point or adding a point."""
         if event.button() == Qt.LeftButton:
             self._mouse_pressed = True
             self._was_dragging = False
@@ -341,9 +362,10 @@ class ImageGraphicsView(PanZoomGraphicsView):
         elif event.button() == Qt.RightButton:
             self._remove_point_by_click(event.pos())
 
-        super().mousePressEvent(event)
+        super().mouse_press_event(event)
 
-    def mouseMoveEvent(self, event):
+    def mouse_move_event(self, event):
+        """Handle mouse move events for dragging a point or dragging the view"""
         if self._dragging_idx is not None:
             scene_pos = self.mapToScene(event.pos())
             x_new = scene_pos.x() - self._drag_offset[0]
@@ -368,10 +390,11 @@ class ImageGraphicsView(PanZoomGraphicsView):
                 if dist > self._drag_threshold:
                     self._was_dragging = True
 
-        super().mouseMoveEvent(event)
+        super().mouse_move_event(event)
 
-    def mouseReleaseEvent(self, event):
-        super().mouseReleaseEvent(event)
+    def mouse_release_event(self, event):
+        """Handle mouse release events for dragging a point or adding a point."""
+        super().mouse_release_event(event)
         if event.button() == Qt.LeftButton and self._mouse_pressed:
             self._mouse_pressed = False
             self.setCursor(Qt.ArrowCursor)
@@ -394,7 +417,8 @@ class ImageGraphicsView(PanZoomGraphicsView):
 
             self._was_dragging = False
 
-    def _remove_point_by_click(self, view_pos):
+    def _remove_point_by_click(self, view_pos: QPoint):
+        """Remove a point by clicking on it."""
         idx = self._find_item_near(view_pos, threshold=10)
         if idx is None:
             return
@@ -409,7 +433,8 @@ class ImageGraphicsView(PanZoomGraphicsView):
         self._apply_all_guide_points_to_cost()
         self._rebuild_full_path()
 
-    def _find_item_near(self, view_pos, threshold=10):
+    def _find_item_near(self, view_pos: QPoint, threshold=10):
+        """Find the index of an item near a given position."""
         scene_pos = self.mapToScene(view_pos)
         x_click, y_click = scene_pos.x(), scene_pos.y()
 
@@ -431,6 +456,7 @@ class ImageGraphicsView(PanZoomGraphicsView):
         return max(mn, min(val, mx))
 
     def _clear_all_points(self):
+        """Clear all anchor points and guide points."""
         for it in self.point_items:
             self.scene.removeItem(it)
         self.point_items.clear()
@@ -442,6 +468,7 @@ class ImageGraphicsView(PanZoomGraphicsView):
         self._full_path_xy.clear()
 
     def clear_guide_points(self):
+        """Clear all guide points."""
         i = 0
         while i < len(self.anchor_points):
             if self.point_items[i].is_removable():
@@ -461,4 +488,5 @@ class ImageGraphicsView(PanZoomGraphicsView):
         self._rebuild_full_path()
 
     def get_full_path_xy(self):
-        return self._full_path_xy
\ No newline at end of file
+        """Returns the entire path as a list of (x, y) coordinates."""
+        return self._full_path_xy
diff --git a/modules/labeledPointItem.py b/modules/labeledPointItem.py
index ff9e263fd112579b1cb5e3467acb3b684effbcbf..f96bb8ff7875daead14c7ada43dc899e6ebad4b3 100644
--- a/modules/labeledPointItem.py
+++ b/modules/labeledPointItem.py
@@ -1,10 +1,20 @@
+import math
 from PyQt5.QtWidgets import QGraphicsEllipseItem, QGraphicsTextItem
 from PyQt5.QtGui import QPen, QBrush, QColor, QFont
 from PyQt5.QtCore import Qt
-import math
+
 
 class LabeledPointItem(QGraphicsEllipseItem):
-    def __init__(self, x, y, label="", radius=4, color=Qt.red, removable=True, z_value=0, parent=None):
+    """
+    A QGraphicsEllipseItem subclass that represents a labeled point in a 2D space.
+
+    This class creates a circular point.
+    The point can be customized with different colors, sizes, and labels, and can
+    be marked as removable.
+    """
+
+    def __init__(self, x: float, y: float, label: str ="", radius:int =4, 
+                 color=Qt.red, removable=True, z_value=0, parent=None):
         super().__init__(0, 0, 2*radius, 2*radius, parent)
         self._x = x
         self._y = y
@@ -30,6 +40,7 @@ class LabeledPointItem(QGraphicsEllipseItem):
         self.set_pos(x, y)
 
     def _scale_text_to_fit(self):
+        """Scales the text to fit inside the circle."""
         if not self._text_item:
             return
         self._text_item.setScale(1.0)
@@ -43,6 +54,7 @@ class LabeledPointItem(QGraphicsEllipseItem):
         self._center_label()
 
     def _center_label(self):
+        """Centers the text inside the circle."""
         if not self._text_item:
             return
         ellipse_w = 2 * self._r
@@ -62,10 +74,14 @@ class LabeledPointItem(QGraphicsEllipseItem):
         self.setPos(x - self._r, y - self._r)
 
     def get_pos(self):
+        """Returns the (x, y) coordinates of the center of the circle."""
         return (self._x, self._y)
 
     def distance_to(self, x_other, y_other):
+        """Returns the Euclidean distance from the center 
+        of the circle to another circle."""
         return math.sqrt((self._x - x_other)**2 + (self._y - y_other)**2)
 
     def is_removable(self):
-        return self._removable
\ No newline at end of file
+        """Returns True if the point is removable, False otherwise."""
+        return self._removable
diff --git a/modules/load_image.py b/modules/load_image.py
index 5bded2a55ebbc1a93d8f42d587920948d779965f..d2fa7eadf42d6098f0cc14bee50a4f015d9d0240 100644
--- a/modules/load_image.py
+++ b/modules/load_image.py
@@ -1,4 +1,13 @@
 import cv2
 
-def load_image(path):
+def load_image(path: str) -> "numpy.ndarray":
+    """
+    Loads an image from the specified file path in grayscale mode.
+
+    Args:
+        path (str): The file path to the image.
+
+    Returns:
+        numpy.ndarray: The loaded grayscale image.
+    """
     return cv2.imread(path, cv2.IMREAD_GRAYSCALE)
\ No newline at end of file
diff --git a/modules/panZoomGraphicsView.py b/modules/panZoomGraphicsView.py
index 85d5e1ac297ad469c8ff6416b9b6fc869df8aa5d..dc86430cf0f11138094e72876f8ec4aed95eacc0 100644
--- a/modules/panZoomGraphicsView.py
+++ b/modules/panZoomGraphicsView.py
@@ -1,8 +1,10 @@
 from PyQt5.QtWidgets import QGraphicsView, QSizePolicy
 from PyQt5.QtCore import Qt
 
-# A pan & zoom QGraphicsView
 class PanZoomGraphicsView(QGraphicsView):
+    """
+    A QGraphicsView subclass that supports panning and zooming with the mouse.
+    """
     def __init__(self, parent=None):
         super().__init__(parent)
         self.setDragMode(QGraphicsView.NoDrag)  # We'll handle panning manually
@@ -10,10 +12,10 @@ class PanZoomGraphicsView(QGraphicsView):
         self._panning = False
         self._pan_start = None
 
-        # Let it expand in layouts
+        # Expands layout
         self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
 
-    def wheelEvent(self, event):
+    def wheel_event(self, event):
         """ Zoom in/out with mouse wheel. """
         zoom_in_factor = 1.25
         zoom_out_factor = 1 / zoom_in_factor
@@ -23,25 +25,25 @@ class PanZoomGraphicsView(QGraphicsView):
             self.scale(zoom_out_factor, zoom_out_factor)
         event.accept()
 
-    def mousePressEvent(self, event):
+    def mouse_press_event(self, event):
         """ If left button: Start panning (unless overridden). """
         if event.button() == Qt.LeftButton:
             self._panning = True
             self._pan_start = event.pos()
             self.setCursor(Qt.ClosedHandCursor)
-        super().mousePressEvent(event)
+        super().mouse_press_event(event)
 
-    def mouseMoveEvent(self, event):
+    def mouse_move_event(self, event):
         """ If panning, translate the scene. """
         if self._panning and self._pan_start is not None:
             delta = event.pos() - self._pan_start
             self._pan_start = event.pos()
             self.translate(delta.x(), delta.y())
-        super().mouseMoveEvent(event)
+        super().mouse_move_event(event)
 
-    def mouseReleaseEvent(self, event):
+    def mouse_release_event(self, event):
         """ End panning. """
         if event.button() == Qt.LeftButton:
             self._panning = False
             self.setCursor(Qt.ArrowCursor)
-        super().mouseReleaseEvent(event)
+        super().mouse_release_event(event)
diff --git a/modules/preprocess_image.py b/modules/preprocess_image.py
index 403323faacb81a18905b08eb53a0a80bae6614e4..351988f1b00389c592d35e1913a0ca1221cb7224 100644
--- a/modules/preprocess_image.py
+++ b/modules/preprocess_image.py
@@ -1,11 +1,23 @@
 from skimage.filters import gaussian
 from skimage import exposure
 
-def preprocess_image(image, sigma=3, clip_limit=0.01):
-    # Apply histogram equalization
-    image_contrasted = exposure.equalize_adapthist(image, clip_limit=clip_limit)
 
-    # Apply smoothing
+def preprocess_image(image: "np.ndarray", sigma: int = 3, clip_limit: float = 0.01) -> "np.ndarray":
+    """
+    Preprocess the input image by applying histogram equalization and Gaussian smoothing.
+
+    Args:
+        image: (ndarray): Input image to be processed.
+        sigma: (float, optional): Standard deviation for Gaussian kernel. Default is 3.
+        clip_limit: (float, optional): Clipping limit for contrast enhancement. Default is 0.01.
+    Returns:
+    ndarray: The preprocessed image.
+    """
+    # Applies histogram equalization to enhance contrast
+    image_contrasted = exposure.equalize_adapthist(
+        image, clip_limit=clip_limit)
+
+    # Applies smoothing
     smoothed_img = gaussian(image_contrasted, sigma=sigma)
 
-    return smoothed_img
\ No newline at end of file
+    return smoothed_img